Solaris Common Desktop Environment: Programmer's Guide

To Register Callback and Keep Reminders

/* The example code shows the usage of csa_register_callback,
  * csa_read_next_reminder, and csa_call_callbacks.
  * The skeleton code registers a callback routine for
  * events CSA_CB_ENTRY_ADDED, CSA_CB_ENTRY_DELETED, and
  * CSA_CB_ENTRY_UPDATED; and another callback routine for the
  * CSA_CB_CALENDAR_ATTRIBUTE_UPDATED event.
  * It also shows how to set up a timer for reminder delivery.
  * Two utilities routines for conversion between time representation
  * in the ISO 8601 format and the tick representing time in seconds
  * since 00:00:00 UTC 1/1/70 are also included.
  */ 

 #include <csa/csa.h> 
#include <time.h> 
#include <unistd.h>  

CSA_session_handle	cal;	 /* a calendar session */ 
time_t			run_time; /* the time the reminders is to be run */ 
CSA_uint32		num_rems; /* number of reminders returned */ 
CSA_reminder_reference	*rems;	  /* an array of reminder information */  

void 
set_up_callback_handler() 
{
 	CSA_return_code		stat;
 	CSA_flags		flags;

  	/* Xt based applications can use the CSA_X_XT_APP_CONTEXT_EXT
 	 * extension to specify the Xt application context so that
 	 * callback routines will be invoked asynchronously
 	 *
 	 *	CSA_extension callback_ext;
 	 *	callback_ext.item_code = CSA_X_XT_APP_CONTEXT_EXT;
 	 * 	callback_ext.item_data = (CSA_uint32)application_context;
 	 *	callback_ext.extension_flags = CSA_EXT_LAST_ELEMENT;
 	 *
 	 * Pass the callback_ext as the last parameter to
 	 * csa_register_callback.
 	 */

  	flags = CSA_CB_ENTRY_ADDED|CSA_CB_ENTRY_DELETED|CSA_CB_ENTRY_UPDATED;
 	stat = csa_register_callback(cal, flags, entry_update_callback,
 		NULL, NULL);

  	if (stat != CSA_SUCCESS) {
 		/* error handling code */
 	}

  	stat = csa_register_callback(cal, CSA_CB_CALENDAR_ATTRIBUTE_UPDATED,
 		calendar_update_callback, NULL, NULL);
  	if (stat != CSA_SUCCESS) {
 		/* error handling code */
 	} 
}  

/*  * This routine polls the library and causes the registered
  * callback to be invoked if the interested event has occurred.
  * If an application does not use the CSA_X_XT_APP_CONTEXT_EXT
  * extension to set up asynchronously callback invocation,
  * it needs to call csa_call_callbacks to force the invocation
  * of callbacks.
  */ 

check_events(CSA_flags event)
{
 	csa_call_callbacks(cal, event, NULL); 
}

  /*
  * This is the callback routine for events CSA_CB_ENTRY_ADDED,
  * CSA_CB_ENTRY_ADDED, and CSA_CB_ENTRY_UPDATED.
  */ 
void 
entry_update_callback(
 	CSA_session_handle	cal,
 	CSA_flags		flags,
 	CSA_buffer		call_data,
 	CSA_buffer		client_data,
 	CSA_extension		*ext) 
{
 	/* An entry is either added, deleted or updated.
 	 * Possible things to do in this callback routine:
	 *
 	 * 1. Update the calendar view, or
 	 * 2. If this is your own calendar, update reminder information.
 	 *
 	 * The sample code in this routine updates reminder information
 	 */ 	reset_reminder();
}

  /*
  * This is the callback routine for the CSA_CB_CALENDAR_ATTRIBUTE_UPDATED
  * event
  */ 
void 
calendar_update_callback(
 	CSA_session_handle	cal,
 	CSA_flags		flags,
 	CSA_buffer		call_data,
 	CSA_buffer		client_data,
 	CSA_extension		*ext) 
{
 	/* update calendar attributes */ 
}

   /*
  * This routine updates reminder information:
  *	- get rid of existing information if any
  *	- call csa_read_next_reminder() to get the next
  *	 reminder to deliver
  *	- check the run time and set timer
  */ 
void 
reset_reminder() {
 	CSA_return_code		stat;
 	time_t			current_time;
 	char			isotime[BUFSIZ];
 	CSA_uint32		number_reminders;
 	CSA_reminder_reference	*reminders;
 
  	current_time = time(NULL);

  	/* get rid of existing information */
 	if (rems) {
 		/* this comparison is to make sure that we don't lose
 		 * any reminders whose run time is between the last
 		 * run time and the current time
 		 */
 		if (current_time > run_time)
 			current_time = run_time;

  		csa_free((CSA_buffer)rems);
 	}

 	to_iso8601_time(current_time, isotime);
 	stat = csa_read_next_reminder(cal, 0, NULL, isotime,
 		&number_reminders, &reminders, NULL);

  	if (stat == CSA_SUCCESS && num_rems > 0) {
 		num_rems = number_reminders;
 		rems = reminders;

  		/* Set timer to deliver the reminder.
 		 * sigset() should be used to set up the signal
 		 * disposition for the SIGALRM signal.
 		 */
 		from_iso8601_time(reminders[0].run_time, &run_time);
 		remain = run_time - time(NULL);
 		alarm((remain > 0) ? remain : 1);

  		/* Xt based application can set the timer using
 		 * XtAppAddTimeOut
 		 */
 	}
}
  
/*
  * This routine converts a time value in the iso8601 format to
  * a tick (representing time in seconds since 00:00:00 UTC, 1/1/70).
  * The tick is adjusted to the local time.
  */ int from_iso8601_time(char *buf, time_t *tick_out) 
{
  	int		year, month, day, hour, min, sec;
 	struct tm	time_str;

  	sscanf(buf, "%4d%2d%2dT%2d%2d%2dZ",
 	    &year, &month, &day, &hour, &min, &sec);

  	time_str.tm_year	= year - 1900;
 	time_str.tm_mon		= month - 1;
 	time_str.tm_mday	= day;
 	time_str.tm_hour	= hour;
 	time_str.tm_min		= min;
 	time_str.tm_sec		= sec;
 	time_str.tm_isdst	= -1;
  	*tick_out = mktime(&time_str);

  	if (*tick_out != (long)-1) {

  		/* adjust for local time zone */
 		if (time_str.tm_isdst == 0)
 			*tick_out -= timezone;
 		else
 			*tick_out -= altzone;
  		return(0);
 	} else
 		return(-1); 
}  

/*
  * This routine converts a tick (representing time in seconds
  * since 00:00:00 UTC, 1/1/70) to the iso8601 format.
  */ 
int 
to_iso8601_time(time_t tick, char *buf_out) 
{
 	struct tm	time_str;
  	if (gmtime_r(&tick, &time_str)) {

  		/* format string forces fixed width (zero-padded) fields */
 		sprintf(buf_out, "%04d%02d%02dT%02d%02d%02dZ",
 			time_str.tm_year + 1900,
 			time_str.tm_mon + 1,
 			time_str.tm_mday,
 			time_str.tm_hour,
 			time_str.tm_min,
 			time_str.tm_sec);
  		return (0);
 	} else {
 		return (-1);
 	} 
}