1 /*----------------------------------------------------------------------------
2 --
3 --  Module:           xtmAlarmProc
4 --
5 --  Project:          Xdiary
6 --  System:           xtm - X Desktop Calendar
7 --    Subsystem:      <>
8 --    Function block: <>
9 --
10 --  Description:
11 --    Process that alarms the user of evebts defined in the XDiary
12 --    database. Each process controls a single diary database and can be
13 --    started as a standalone program or be integrated in the XDiary
14 --    environment.
15 --
16 --    Syntax:
17 --      XDalarm [flags]
18 --
19 --    Flags:
20 --      -alarmTags : Display alarms containing one of these tags.
21 --      -dbName    : Name of the database(s) to use.
22 --      -usage     : Displays some help.
23 --      -help      : Same as above.
24 --
25 --  Filename:         xtmAlarmProc.c
26 --
27 --  Authors:          Roger Larsson, Ulrika Bornetun
28 --  Creation date:    1991-07-01
29 --
30 --
31 --  (C) Copyright Ulrika Bornetun, Roger Larsson (1995)
32 --      All rights reserved
33 --
34 --  Permission to use, copy, modify, and distribute this software and its
35 --  documentation for any purpose and without fee is hereby granted,
36 --  provided that the above copyright notice appear in all copies. Ulrika
37 --  Bornetun and Roger Larsson make no representations about the usability
38 --  of this software for any purpose. It is provided "as is" without express
39 --  or implied warranty.
40 ----------------------------------------------------------------------------*/
41 
42 /* SCCS module identifier. */
43 static char SCCSID[] = "@(#) Module: xtmAlarmProc.c, Version: 1.1, Date: 95/02/18 16:01:50";
44 
45 
46 /*----------------------------------------------------------------------------
47 --  Include files
48 ----------------------------------------------------------------------------*/
49 
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <time.h>
56 #include <unistd.h>
57 #include <ctype.h>
58 #include <sys/signal.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 
62 #include <X11/Intrinsic.h>
63 #include <X11/Shell.h>
64 #include <X11/StringDefs.h>
65 
66 #include <Xm/Xm.h>
67 #include <Xm/BulletinB.h>
68 #include <Xm/Form.h>
69 #include <Xm/RowColumn.h>
70 #include <Xm/Scale.h>
71 #include <Xm/SeparatoG.h>
72 
73 #include "System.h"
74 #include "LstLinked.h"
75 #include "Message.h"
76 #include "SigHandler.h"
77 #include "TimDate.h"
78 
79 #include "msgXdiary.h"
80 #include "xtmGlobal.h"
81 #include "xtmCalDb.h"
82 #include "xtmCustBase.h"
83 #include "xtmDbTools.h"
84 #include "xtmIcons.h"
85 #include "xtmResource.h"
86 #include "xtmUpdate.h"
87 #include "xitError.h"
88 #include "xitStickyMsg.h"
89 #include "xitTools.h"
90 #include "xtmTools.h"
91 #include "xtmHoliday.h"
92 #include "xtmFormat.h"
93 #include "xtmDbTools.h"
94 
95 /*----------------------------------------------------------------------------
96 --  Macro definitions
97 ----------------------------------------------------------------------------*/
98 
99 /* Name of program. */
100 #define PROGRAM_NAME   "xdalarm"
101 
102 /* Program class (also the name of the application defaults file). */
103 #define PROGRAM_CLASS  "XDiary"
104 
105 
106 /* Local widgets in the day list view window. */
107 #define markerPx        dataLocalW[ 0 ]
108 #define messageLa       dataLocalW[ 1 ]
109 
110 /* Local widgets in the snooze window. */
111 #define snoozeLa        dataLocalW[ 0 ]
112 #define snoozeSc        dataLocalW[ 1 ]
113 
114 
115 /* Number of alarms per entry. */
116 #define MAX_ALARMS          5
117 
118 /* Number of tune files. */
119 #define MAX_TUNES           5
120 
121 /* The number of database we can watch simultaneously. */
122 #define MAX_DATABASE_CHECK  50
123 
124 /* Maximun number of entry alarms that can be ignored. */
125 #define MAX_ENTRIES_IGNORE  100
126 
127 /* Maximum number of snooze alarms. */
128 #define MAX_SNOOZE_ALARM    100
129 
130 /* Maximum number of alarms in the cache. */
131 #define MAX_ALARM_CACHE     200
132 
133 /* Maximum number of displayed alarm windows we keep track of. */
134 #define MAX_TRACK_ALARM_WIN  100
135 
136 /* Name of database file (we should actually no know this!). */
137 #define DATABASE_FILE       "idDB.pag"
138 
139 
140 
141 /*----------------------------------------------------------------------------
142 --  Type declarations
143 ----------------------------------------------------------------------------*/
144 
145 /* A single alarm record. */
146 typedef struct {
147   Boolean       can_do_action;
148   UINT32        id;
149   UINT32        flags;
150   char          db_name[ XTM_GL_MAX_CAL_NAME + 1 ];
151   TIM_TIME_REF  entry_date;
152   TIM_TIME_REF  time;
153 } ALARM_CACHE;
154 
155 
156 /* Information about the databases we check. */
157 typedef struct {
158   char    db_name[ XTM_GL_MAX_CAL_NAME + 1 ];
159   time_t  last_modified;
160 } DATABASE_CHECK;
161 
162 
163 /* Entries to ignore. */
164 typedef struct {
165   UINT32  id;
166   char    db_name[ XTM_GL_MAX_CAL_NAME + 1 ];
167 } IGNORE_ENTRY;
168 
169 
170 /* Basic data structure for the XDalarm appliaction. */
171 typedef struct {
172 
173   /* Command line flags. */
174   Boolean  startup_help;
175   Boolean  version_help;
176 
177   /* Do animation when displaying alarms. */
178   Boolean  do_animate_alarm;
179 
180   /* Volume for alarms. */
181   int  alarm_volume;
182 
183   /* Default snooze time. */
184   int  snooze_minutes;
185 
186   /* Pipe to use when communicating with the parent. */
187   char  *cmd_pipe_id;
188 
189   /* Alarms for these databases. */
190   char  *default_db_alarms;
191 
192   /* Display alarms inluding one of these tags. */
193   char  *filter_alarm_tags;
194 
195   /* Default script (program) to use. */
196   char  *launch_def_script;
197 
198   /* Shell to use when starting alarm action. */
199   char  *launch_use_shell;
200 
201   /* We keep track of displayed windows. */
202   Widget  *track_alarm_win;
203 
204   /* The X application context. */
205   XtAppContext  context;
206 
207   /* The alarm cache containing alarms to check. */
208   ALARM_CACHE  alarms[ MAX_ALARM_CACHE ];
209 
210   /* Snooze alarms. */
211   ALARM_CACHE  snooze[ MAX_SNOOZE_ALARM ];
212 
213   /* The databases we check. */
214   DATABASE_CHECK  db_check[ MAX_DATABASE_CHECK ];
215 
216   /* File pointer for the command pipe. */
217   int  cmd_pipe_ref;
218 
219   /* Entries that can be ignored. */
220   IGNORE_ENTRY  ignore_entry[ MAX_ENTRIES_IGNORE ];
221 
222   /* The current date. */
223   TIM_TIME_REF  current_date;
224 
225   /* Customization data. */
226   XTM_GL_CUSTOM_DATA_REF  custom_data;
227 
228 } XTM_AP_BASE_DATA, *XTM_AP_BASE_DATA_REF;
229 
230 
231 /* User data necessary for alarm window. */
232 typedef struct {
233   Boolean               important;
234   int                   curr_pixmap;
235   UINT32                id;
236   char                  db_name[ XTM_GL_MAX_CAL_NAME + 1 ];
237   Widget                alarmW;
238   Widget                snoozeW;
239   XtIntervalId          timer_id;
240   TIM_TIME_REF          entry_date;
241   XTM_AP_BASE_DATA_REF  appl_data_ref;
242 } USER_DATA, *USER_DATA_REF;
243 
244 
245 
246 /*----------------------------------------------------------------------------
247 --  Global definitions
248 ----------------------------------------------------------------------------*/
249 
250 /* Name of program. */
251 static char  *program_name;
252 
253 /* Name of text domain. */
254 static char  *text_domain = "XDiary";
255 
256 /* Name of module. */
257 static char  *module_name = "xtmAlarmProcess";
258 
259 /* Application data. */
260 static  XTM_AP_BASE_DATA  appl_data;
261 
262 static  Widget  toplevel;
263 
264 /* Pixmaps and pixmap sequence used. */
265 static  Boolean  init_pixmap = True;
266 static  Pixmap   ani_pixmap[ 10 ];
267 
268 static  int ani_pixmap_blink[] = {
269   0, 5, 0, 5, 0, 5, 0, -1
270 };
271 
272 static  int ani_pixmap_seq[] = {
273   1, 2, 3, 4, 5, 6, 7, 8, 9,
274   8, 7, 6, 5, 4, 3, 2, 1,
275   2, 3, 4, 5, 6, 7, 8,
276   7, 6, 5, 4, 3, 2,
277   3, 4, 5, 6, 7,
278   6, 5, 4,
279   3, 4, 5, 6, 7,
280   6, 5, 4, 3,
281   4, 5, 6,
282   6, 5,
283   4, 5, 6,
284   6, 5, 4,
285   5, -1
286 };
287 
288 
289 /* Program options. */
290 static XrmOptionDescRec options[] = {
291   { "-alarmTags",   "*.FilterAlarmTags", XrmoptionSepArg, NULL },
292   { "-alarmtags",   "*.FilterAlarmTags", XrmoptionSepArg, NULL },
293   { "-cmdPipeId",   "*.CmdPipeId",       XrmoptionSepArg, NULL },
294   { "-dbName",      "*.DefaultDbAlarms", XrmoptionSepArg, NULL },
295   { "-dbname",      "*.DefaultDbAlarms", XrmoptionSepArg, NULL },
296   { "-calendars",   "*.DefaultDbAlarms", XrmoptionSepArg, NULL },
297   { "-debug",       "*.debug",           XrmoptionNoArg,  "True" },
298   { "-h",           "*.StartupHelp",     XrmoptionNoArg,  "True" },
299   { "-help",        "*.StartupHelp",     XrmoptionNoArg,  "True" },
300   { "-lan",         "*.msgLanguage",     XrmoptionSepArg, NULL },
301   { "-language",    "*.msgLanguage",     XrmoptionSepArg, NULL },
302   { "-noFileLock",  "*.useFileLock",     XrmoptionNoArg,  "False" },
303   { "-nofilelock",  "*.useFileLock",     XrmoptionNoArg,  "False" },
304   { "-usage",       "*.StartupHelp",     XrmoptionNoArg,  "True" },
305   { "-version",     "*.VersionHelp",     XrmoptionNoArg,  "True" },
306 };
307 
308 /* Application resources. */
309 static XtResource  base_resources[] = {
310 
311   { "cmdPipeId", "CmdPipeId", XtRString, sizeof( String ),
312     XtOffset( XTM_AP_BASE_DATA_REF, cmd_pipe_id ),
313     XtRString, "" },
314 
315   { "defaultDbAlarms", "DefaultDbAlarms", XtRString, sizeof( String ),
316     XtOffset( XTM_AP_BASE_DATA_REF, default_db_alarms ),
317     XtRString, "" },
318 
319   { "doAnimateAlarm", "DoAnimateAlarm", XtRBoolean, sizeof( Boolean ),
320     XtOffset( XTM_AP_BASE_DATA_REF, do_animate_alarm ),
321     XtRString, "True" },
322 
323   { "filterAlarmTags", "FilterAlarmTags", XtRString, sizeof( String ),
324     XtOffset( XTM_AP_BASE_DATA_REF, filter_alarm_tags ),
325     XtRString, "" },
326 
327   { "launchDefScript", "LaunchDefScript", XtRString, sizeof( String ),
328     XtOffset( XTM_AP_BASE_DATA_REF, launch_def_script ),
329     XtRString, "XDiary.alarmdo" },
330 
331   { "launchUseShell", "LaunchUseShell", XtRString, sizeof( String ),
332     XtOffset( XTM_AP_BASE_DATA_REF, launch_use_shell ),
333     XtRString, "/bin/sh" },
334 
335   { "startupHelp", "StartupHelp", XtRBoolean, sizeof( Boolean ),
336     XtOffset( XTM_AP_BASE_DATA_REF, startup_help ),
337     XtRString, "False" },
338 
339   { "snoozeMinutes", "SnoozeMinutes", XtRInt, sizeof( int ),
340     XtOffset( XTM_AP_BASE_DATA_REF, snooze_minutes ),
341     XtRString, "5" },
342 
343   { "versionHelp", "VersionHelp", XtRBoolean, sizeof( Boolean ),
344     XtOffset( XTM_AP_BASE_DATA_REF, version_help ),
345     XtRString, "False" },
346 
347 };
348 
349 
350 /*----------------------------------------------------------------------------
351 --  Function prototypes
352 ----------------------------------------------------------------------------*/
353 
354 static void
355   alarmConfirmCB( Widget               widget,
356                   USER_DATA_REF        user_data,
357                   XmAnyCallbackStruct  *call_data );
358 
359 static void
360   alarmDeleteCB( Widget         widget,
361                  USER_DATA_REF  user_data,
362                  XtPointer      call_data );
363 
364 static void
365   alarmNoMoreCB( Widget         widget,
366                  USER_DATA_REF  user_data,
367                  XtPointer      call_data );
368 
369 static void
370   alarmSnoozeCB( Widget         widget,
371                  USER_DATA_REF  user_data,
372                  XtPointer      call_data );
373 
374 static void
375   alarmViewCB( Widget         widget,
376                USER_DATA_REF  user_data,
377                XtPointer      call_data );
378 
379 static void
380   checkAlarms( XTM_AP_BASE_DATA_REF  appl_data_ref,
381                TIM_TIME_REF          time_now );
382 
383 static void
384   deleteEntryCB( Widget         widget,
385                  USER_DATA_REF  user_data,
386                  XtPointer      call_data );
387 
388 static void
389   destroyCB( Widget         widget,
390              USER_DATA_REF  user_data,
391              XtPointer      call_data );
392 
393 static void
394   displayAlarm( XTM_AP_BASE_DATA_REF  appl_data_ref,
395                 ALARM_CACHE           *alarm_ref );
396 
397 static void
398   displayUsage();
399 
400 static void
401   doActionAlarm( XTM_AP_BASE_DATA_REF  appl_data_ref,
402                  ALARM_CACHE           *alarm_ref );
403 
404 static void
405   doAnimateCB( USER_DATA_REF  user_data );
406 
407 static void
408   doBlinkCB( USER_DATA_REF  user_data );
409 
410 static Boolean
411   fetchAlarms( XTM_AP_BASE_DATA_REF  appl_data_ref,
412                XTM_CD_CAL_INFO       *db_info );
413 
414 static void
415   processCommandCB( XTM_AP_BASE_DATA_REF  appl_data_ref,
416                     int                   *fd,
417                     XtInputId             *id );
418 
419 static Boolean
420   setupCmdPipe( XTM_AP_BASE_DATA_REF  appl_data_ref );
421 
422 static void
423   snoozeOkCB( Widget         widget,
424               USER_DATA_REF  user_data,
425               XtPointer      call_data );
426 
427 static void
428   startAlarmForCal( XTM_AP_BASE_DATA_REF  appl_data_ref,
429                     char                  *db_name,
430                     char                  *db_location );
431 
432 int
433   startProcess( Widget  parent,
434                 char    *process_args[] );
435 
436 static void
437   stopAlarmForCal( XTM_AP_BASE_DATA_REF  appl_data_ref,
438                    char                  *db_name );
439 
440 static void
441   terminateCB( int   this_signal,
442                void  *user_data );
443 
444 static void
445   updateCB( UINT32  flags,
446             void    *user_data,
447             void    *update_user_data );
448 
449 
450 
451 /*----------------------------------------------------------------------------
452 --  Functions
453 ----------------------------------------------------------------------------*/
454 
455 int
main(int argc,char * argv[])456   main( int argc, char *argv[] )
457 {
458 
459   /* Variables. */
460   int                 index;
461   char                *char_ref;
462   Arg                 args[ 10 ];
463   Cardinal            n;
464   Display             *display;
465   TIM_STATUS_TYPE     time_status;
466   XTM_CB_STATUS       custom_status;
467   XTM_GL_CUSTOM_DATA  custom_data;
468 
469 
470   /* Code. */
471 
472   /* Fetch the name of the program. */
473   program_name = PROGRAM_NAME;
474   xitErSetApplicationName( program_name );
475 
476 
477   /* Save the original command parameters. */
478   custom_data.orig_argc = argc;
479   custom_data.orig_argv = (char**) XtMalloc( argc * sizeof( char* ) );
480 
481   for( index = 0; index < argc; index++ )
482     custom_data.orig_argv[ index ] = XtNewString( argv[ index ] );
483 
484   /* NLS enabled. */
485   xtmToSetLocale( program_name );
486 
487 
488   /* Initialize the signal handler module. */
489   SigInitialize();
490 
491   /* Initialize. */
492   SysInitializeEnvironment();
493   xtmDbInitializeProcessId();
494 
495 
496   /* Initialize toolkit and open display. */
497   XtToolkitInitialize();
498 
499   appl_data.context = XtCreateApplicationContext();
500   display = XtOpenDisplay( appl_data.context, NULL,
501                            NULL, PROGRAM_CLASS,
502                            options, XtNumber( options ),
503 #if XtSpecificationRelease < 5
504                            (Cardinal *) &argc,
505 #else
506                            (int *) &argc,
507 #endif
508                            argv );
509 
510   if( display == NULL )
511     xitErMessage( NULL, XIT_ER_FATAL,
512                   module_name, "main",
513                   "Cannot open display, check your DISPLAY variable." );
514 
515   /* Resource mapping.*/
516   xtmToInitializeResourceMapping( argc, argv, display );
517 
518   /* Create application shell. */
519   n = 0;
520   toplevel = XtAppCreateShell( NULL, PROGRAM_CLASS,
521                                applicationShellWidgetClass,
522                                display,
523                                args, n );
524 
525 
526   /* Get base application resources. */
527   XtGetApplicationResources( toplevel, (XtPointer) &appl_data,
528                              base_resources,
529                              XtNumber( base_resources ),
530                              NULL, 0 );
531 
532   /* Get customize resources. */
533   xtmRsFetchCustomResources( &custom_data, toplevel );
534 
535   /* Reset application data. */
536   custom_data.cal_db_handle   = NULL;
537   custom_data.group_db_handle = NULL;
538   custom_data.archive_files   = NULL;
539   custom_data.include_files   = NULL;
540 
541   appl_data.current_date = 0;
542   appl_data.cmd_pipe_ref = -1;
543   appl_data.custom_data  = &custom_data;
544 
545   for( index = 0; index < MAX_DATABASE_CHECK; index++ )
546     appl_data.db_check[ index ].db_name[ 0 ] = '\0';
547 
548   for( index = 0; index < MAX_ALARM_CACHE; index++ )
549     appl_data.alarms[ index ].id = 0;
550 
551   for( index = 0; index < MAX_ENTRIES_IGNORE; index++ )
552     appl_data.ignore_entry[ index ].id = 0;
553 
554   for( index = 0; index < MAX_SNOOZE_ALARM; index++ )
555     appl_data.snooze[ index ].id = 0;
556 
557 
558   appl_data.track_alarm_win = (Widget *)
559     SysMalloc( sizeof( Widget ) * MAX_TRACK_ALARM_WIN );
560 
561   for( index = 0; index < MAX_TRACK_ALARM_WIN; index++ )
562     *(appl_data.track_alarm_win + index) = NULL;
563 
564 
565   /* Display current version? */
566   if( appl_data.version_help ) {
567     printf( "%s: Version: %s\n", program_name, VERSION_ID );
568     exit( 0 );
569   }
570 
571   /* Help requested? */
572   if( appl_data.startup_help ) {
573     displayUsage();
574     exit( 0 );
575   }
576 
577 
578   /* Get customized data from file. */
579   custom_status = xtmCbGetDataFromFile( appl_data.custom_data );
580 
581   if( custom_status == XTM_CB_WRONG_VERSION ) {
582     char_ref = (char *)
583       SysMalloc( strlen( msgGetText( MXDI_CUST_WRONG_VERSION ) ) + 50 );
584 
585     sprintf( char_ref, msgGetText( MXDI_CUST_WRONG_VERSION ),
586              xtmCbWhatVersion() );
587 
588     xitStDisplaySticky( toplevel, char_ref, XmUNSPECIFIED_PIXMAP,
589                         msgGetText( MXDI_OK_BUTTON ), NULL,
590                         NULL, NULL, NULL,
591                         NULL );
592     SysFree( char_ref );
593   }
594 
595 
596   /* Initialize necessary text domains. */
597   msgInitialize();
598   msgInitCatalogue( text_domain, NULL, custom_data.msg_language,
599                     msgXdiaryTexts );
600 
601   /* Default catalogue Xdiary. */
602   msgTextDomain( text_domain );
603 
604 
605   /* Initialize the time formats. */
606   time_status = TimInitializeFormat( custom_data.date_format,
607                                      custom_data.time_format );
608   if( time_status != TIM_OK )
609     xitErMessage( toplevel, XIT_ER_ERROR,
610                   module_name, "main",
611                   msgGetText( MXDI_ERRMSG_DATE_OR_TIME_FORMAT ) );
612 
613 
614   /* Set colors and fonts in the resource database. */
615   xtmRsFetchColors( &custom_data, toplevel );
616 
617 
618   /* Initialize holidays. */
619   xtmHoInitialize( custom_data.holidays_db_dir, custom_data.workdays );
620 
621 
622   /* Use file locking? */
623   xtmDbUseFileLock( custom_data.use_file_lock );
624 
625   /* Initialize the update module. */
626   xtmUpInitialize( appl_data.context, 0 );
627 
628 
629   /* If controlled by the XDiary process, watch out for commands. */
630   if( *appl_data.cmd_pipe_id != '\0' )
631     (void) setupCmdPipe( &appl_data );
632 
633 
634   /* Any default databases given? */
635   if( strlen( appl_data.default_db_alarms ) > 0 )
636     startAlarmForCal( &appl_data, appl_data.default_db_alarms, "" );
637 
638 
639   /* Signal handlers. */
640   (void) SigRegister( SIGHUP,  0, terminateCB, &appl_data );
641   (void) SigRegister( SIGTERM, 0, terminateCB, &appl_data );
642   (void) SigRegister( SIGINT,  0, terminateCB, &appl_data );
643   (void) SigRegister( SIGILL,  0, terminateCB, &appl_data );
644   (void) SigRegister( SIGQUIT, 0, terminateCB, &appl_data );
645   (void) SigRegister( SIGABRT, 0, terminateCB, &appl_data );
646 
647   /* Register for updates? */
648   (void) xtmUpRegister( XTM_UP_MINUTE_TICK, updateCB, (void *) &appl_data );
649 
650 
651   /* Enter the event loop. */
652   XtAppMainLoop( appl_data.context );
653 
654 
655 } /* main */
656 
657 
658 /*----------------------------------------------------------------------*/
659 
660 static void
checkAlarms(XTM_AP_BASE_DATA_REF appl_data_ref,TIM_TIME_REF time_now)661   checkAlarms( XTM_AP_BASE_DATA_REF  appl_data_ref,
662                TIM_TIME_REF          time_now )
663 {
664 
665   /* Variables. */
666   Boolean  give_alarm;
667   int      index;
668   int      index1;
669 
670 
671   /* Code. */
672 
673   /* Debug information? */
674   if( appl_data_ref -> custom_data -> debug_mode ) {
675     char  buffer[ 50 ];
676 
677     xtmFoFormatTime( time_now, buffer, sizeof( buffer ) );
678 
679     printf( "Time now: %s\n", buffer );
680   }
681 
682   /* Check all alarms in the list. */
683   for( index = 0; index < MAX_ALARM_CACHE; index++ ) {
684 
685     ALARM_CACHE  *alarm_ref;
686 
687     alarm_ref = &appl_data_ref -> alarms[ index ];
688 
689     /* A valid alarm? */
690     if( alarm_ref -> id == 0 )
691       continue;
692 
693     give_alarm = False;
694 
695     /* Debug information? */
696     if( appl_data_ref -> custom_data -> debug_mode ) {
697       char  buffer[ 50 ];
698 
699       xtmFoFormatTime( alarm_ref -> time, buffer, sizeof( buffer ) );
700       printf( "  Checking time: %s\n", buffer );
701     }
702 
703     if( TimTimeInSecondsRange( alarm_ref -> time, time_now, 50 ) == TIM_YES ) {
704 
705       give_alarm = True;
706 
707       /* Ignore this alarm? */
708       for( index1 = 0; index1 < MAX_ENTRIES_IGNORE; index1++ ) {
709 
710         if( appl_data_ref -> ignore_entry[ index1 ].id == alarm_ref -> id ) {
711           if( strcmp( appl_data_ref -> ignore_entry[ index1 ].db_name,
712                       alarm_ref -> db_name ) == 0 ) {
713 
714             give_alarm = False;
715             break;
716           }
717         }
718 
719       } /* loop */
720 
721 
722       if( give_alarm ) {
723 
724         /* Visual alarm? */
725         if( flagIsSet( alarm_ref -> flags, XTM_DB_FLAG_ALARM ) )
726           displayAlarm( appl_data_ref, alarm_ref );
727 
728         /* Action alarm (call script)? */
729         if( flagIsSet( alarm_ref -> flags, XTM_DB_FLAG_ACTION_SCRIPT ) )
730           doActionAlarm( appl_data_ref, alarm_ref );
731 
732         /* Action alarm (use text as script)? */
733         if( flagIsSet( alarm_ref -> flags, XTM_DB_FLAG_ACTION_TEXT ) )
734           doActionAlarm( appl_data_ref, alarm_ref );
735 
736       } /* if */
737 
738     } /* if */
739 
740   } /* loop */
741 
742 
743   /* Check all snooze alarms. */
744   for( index = 0; index < MAX_SNOOZE_ALARM; index++ ) {
745 
746     ALARM_CACHE  *snooze_ref;
747 
748     snooze_ref = &appl_data_ref -> snooze[ index ];
749 
750     /* Valid snooze alarm? */
751     if( snooze_ref -> id != 0 ) {
752 
753       if( TimTimeInSecondsRange( snooze_ref -> time,
754           time_now, 50 ) == TIM_YES )
755         displayAlarm( appl_data_ref, snooze_ref );
756 
757     }
758 
759   } /* loop */
760 
761 
762   return;
763 
764 } /* checkAlarms */
765 
766 
767 /*----------------------------------------------------------------------*/
768 
769 static void
displayAlarm(XTM_AP_BASE_DATA_REF appl_data_ref,ALARM_CACHE * alarm_ref)770   displayAlarm( XTM_AP_BASE_DATA_REF  appl_data_ref,
771                 ALARM_CACHE           *alarm_ref )
772 {
773 
774   /* Variables. */
775   int                     alarm_melody;
776   int                     index;
777   int                     lines_read;
778   int                     size;
779   UINT32                  can_do;
780   UINT32                  operations;
781   char                    buffer[ 100 ];
782   char                    *char_ref;
783   char                    *entry_text_ref = NULL;
784   char                    *message;
785   char                    *tune_file;
786   Arg                     args[ 10 ];
787   Cardinal                n;
788   Widget                  alarmTl;
789   Widget                  dataLocalW[ 2 ];
790   Widget                  tempW;
791   Widget                  workFo;
792   USER_DATA_REF           user_data;
793   XTM_DB_ALL_ENTRY_DEF    entry_record;
794   XTM_DB_ENTRY_DATABASES  database;
795   XTM_DB_OPEN_REQUEST     open_request;
796   XTM_DB_STATUS           db_status;
797   XTM_CD_CAL_INFO         db_info;
798 
799   static XIT_ACTION_AREA_ITEM  action_buttons[] = {
800     { "", alarmConfirmCB, NULL },
801     { "", alarmNoMoreCB,  NULL },
802     { "", alarmSnoozeCB,  NULL },
803     { "", alarmViewCB,    NULL },
804     { "", alarmDeleteCB,  NULL },
805   };
806 
807 
808   /* Code. */
809 
810   /* Alarm is hidden? */
811   if( flagIsSet( alarm_ref -> flags, XTM_DB_FLAG_HIDE_IN_ALARM ) )
812     return;
813 
814 
815   /* Fetch database information. */
816   (void) xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
817                             alarm_ref -> db_name,
818                             &db_info, NULL );
819 
820   /* Check operations. */
821   xtmDbCheckDbOperations( db_info.directory, True, &operations );
822 
823 
824   /* Open the database. */
825   open_request.name       = db_info.short_name;
826   open_request.directory  = db_info.directory;
827   open_request.operations = XTM_DB_FLAG_MODE_READ;
828   open_request.database   = XTM_DB_ALL_ENTRY_DB;
829 
830 
831   /* Try to open the database. */
832   db_status = xtmDbOpenEntryDb( &open_request, &database );
833 
834   if( db_status != XTM_DB_OK ) {
835 
836     if( db_status == XTM_DB_LOCKED )
837       xitErMessage( toplevel, XIT_ER_ERROR,
838                     module_name, "displayAlarm",
839                     msgGetText( MXDI_ERRMSG_DB_LOCKED ) );
840     else
841       xitErMessage( toplevel, XIT_ER_ERROR,
842                     module_name, "displayAlarm",
843                     msgGetText( MXDI_ERRMSG_CANNOT_OPEN_DB ) );
844 
845     raise exception;
846 
847   } /* if */
848 
849 
850   /* Fetch the entry to display. */
851   db_status = xtmDbFetchEntry( &database, alarm_ref -> id,
852                                &entry_record, &entry_text_ref );
853 
854   xtmDbCloseEntryDb( &database );
855 
856   if( db_status != XTM_DB_OK ) {
857     xitErMessage( NULL, XIT_ER_ERROR,
858                   module_name, "displayAlarm",
859                   msgGetText( MXDI_ERRMSG_FETCH_ENTRY ) );
860 
861     raise exception;
862   }
863 
864 
865   /* Does the entry have the correct tag? */
866   if( *appl_data_ref -> filter_alarm_tags != '\0' &&
867       strstr( appl_data_ref -> filter_alarm_tags,
868               entry_record.entry.tag ) == NULL )
869     raise exception;
870 
871 
872   /* No messages for private entries (if you are not privileged). */
873   if(   flagIsSet( entry_record.entry.flags, XTM_DB_FLAG_PRIVATE ) &&
874       ! flagIsSet( operations, XTM_DB_FLAG_MODE_PRIV ) )
875     raise exception;
876 
877 
878   /* Allocate memory for our user data. */
879   user_data = SysNew( USER_DATA );
880 
881   user_data -> appl_data_ref = appl_data_ref;
882   user_data -> entry_date    = alarm_ref -> entry_date;
883   user_data -> id            = alarm_ref -> id;
884 
885   strcpy( user_data -> db_name, alarm_ref -> db_name );
886 
887   if( flagIsSet( entry_record.entry.flags, XTM_DB_FLAG_IMPORTANT ) )
888     user_data -> important = True;
889   else
890     user_data -> important = False;
891 
892 
893   /* Create a separate window. */
894   action_buttons[ 0 ].label = msgGetText( MXDI_ALARM_CONFIRM );
895   action_buttons[ 0 ].data  = user_data;
896   action_buttons[ 1 ].label = msgGetText( MXDI_ALARM_NO_MORE );
897   action_buttons[ 1 ].data  = user_data;
898   action_buttons[ 2 ].label = msgGetText( MXDI_ALARM_SNOOZE );
899   action_buttons[ 2 ].data  = user_data;
900   action_buttons[ 3 ].label = msgGetText( MXDI_ALARM_VIEW );
901   action_buttons[ 3 ].data  = user_data;
902   action_buttons[ 4 ].label = msgGetText( MXDI_ALARM_DELETE );
903   action_buttons[ 4 ].data  = user_data;
904 
905   alarmTl = xitCreateToplevelDialog( toplevel, "AlarmTl",
906                                      1, 0,
907                                      action_buttons,
908                                      XtNumber( action_buttons ) );
909 
910   XtAddCallback( alarmTl, XmNdestroyCallback,
911                  (XtCallbackProc) destroyCB, (XtPointer) user_data );
912 
913 
914   /* Create the message window. */
915   sprintf( buffer, "%s %s",
916            alarm_ref -> db_name, msgGetText( MXDI_ALARM_TITLE ) );
917 
918   n = 0;
919   XtSetArg( args[ n ], XmNtitle, buffer    ); n++;
920   XtSetArg( args[ n ], XmNiconName, buffer ); n++;
921   XtSetValues( alarmTl, args, n );
922 
923 
924   /* Form to hold the alarm message. */
925   workFo = XtNameToWidget( alarmTl, "AlarmTlBase.AlarmTlFo" );
926 
927 
928 
929   /* Pixelmap label. */
930   markerPx = xitCreateLabel( workFo, "MarkerPx", "", -1 );
931 
932 
933   /* Initialize the pixmaps? */
934   if( init_pixmap ) {
935     ani_pixmap[ 0 ] = xtmIcFetchSimplePixmap(
936                         workFo, XTM_IC_ICON_ALARM_CLOCK5INV, False );
937     ani_pixmap[ 1 ] = xtmIcFetchSimplePixmap(
938                         workFo, XTM_IC_ICON_ALARM_CLOCK1, False );
939     ani_pixmap[ 2 ] = xtmIcFetchSimplePixmap(
940                         workFo, XTM_IC_ICON_ALARM_CLOCK2, False );
941     ani_pixmap[ 3 ] = xtmIcFetchSimplePixmap(
942                         workFo, XTM_IC_ICON_ALARM_CLOCK3, False );
943     ani_pixmap[ 4 ] = xtmIcFetchSimplePixmap(
944                         workFo, XTM_IC_ICON_ALARM_CLOCK4, False );
945     ani_pixmap[ 5 ] = xtmIcFetchSimplePixmap(
946                         workFo, XTM_IC_ICON_ALARM_CLOCK5, False );
947     ani_pixmap[ 6 ] = xtmIcFetchSimplePixmap(
948                         workFo, XTM_IC_ICON_ALARM_CLOCK6, False );
949     ani_pixmap[ 7 ] = xtmIcFetchSimplePixmap(
950                         workFo, XTM_IC_ICON_ALARM_CLOCK7, False );
951     ani_pixmap[ 8 ] = xtmIcFetchSimplePixmap(
952                         workFo, XTM_IC_ICON_ALARM_CLOCK8, False );
953     ani_pixmap[ 9 ] = xtmIcFetchSimplePixmap(
954                         workFo, XTM_IC_ICON_ALARM_CLOCK9, False );
955 
956     init_pixmap = False;
957   }
958 
959   n = 0;
960   XtSetArg( args[ n ], XmNlabelPixmap, ani_pixmap[ 1 ] ); n++;
961   XtSetArg( args[ n ], XmNlabelType, XmPIXMAP ); n++;
962   XtSetValues( markerPx, args, n );
963 
964 
965   /* We cannot delete entries in a read only db. */
966   xtmDbGetEntryPermissions( operations,
967                             entry_record.entry.owner,
968                             entry_record.entry.flags,
969                             &can_do );
970 
971   if( flagIsClear( can_do, XTM_DB_PROT_DELETE ) ) {
972     tempW = XtNameToWidget( alarmTl, "AlarmTlBase.Bu5" );
973 
974     XtSetSensitive( tempW, False );
975   }
976 
977 
978   /* Make a copy of the entry text. */
979   if( entry_text_ref != NULL )
980     size = strlen( entry_text_ref ) + 75;
981   else
982     size = strlen( entry_record.entry.text ) + 75;
983 
984   message = SysMalloc( size );
985   *message = '\0';
986 
987   xtmFoFormatDate( alarm_ref -> entry_date,
988                    buffer, sizeof( buffer ) );
989 
990   strcat( message, buffer );
991   strcat( message, ", " );
992 
993   TimFormatStrTime( alarm_ref -> entry_date, "%A",
994                     buffer, sizeof( buffer ) );
995 
996   strcat( message, buffer );
997   strcat( message, " " );
998 
999   xtmFoFormatTime( entry_record.entry.time_stamp,
1000                    buffer, sizeof( buffer ) );
1001 
1002   strcat( message, buffer );
1003   strcat( message, "\n" );
1004 
1005 
1006   if( entry_text_ref != NULL )
1007     strcat( message, entry_text_ref );
1008   else
1009     strcat( message, entry_record.entry.text );
1010 
1011 
1012 
1013   /* Number of lines to write? */
1014   lines_read = 0;
1015   char_ref   = message;
1016 
1017   while( lines_read < entry_record.entry.alarm_lines + 1 ) {
1018     char_ref = strchr( char_ref, '\n' );
1019     if( char_ref == NULL )
1020       break;
1021     lines_read++;
1022     char_ref++;
1023   }
1024 
1025   if( char_ref != NULL )
1026     *char_ref = '\0';
1027 
1028 
1029   /* Message label. */
1030   messageLa = xitCreateLabel( workFo,  "MessageLa",
1031                               message, XmALIGNMENT_BEGINNING );
1032 
1033 
1034   /* Put the Parts together. */
1035   xitAttachWidget( markerPx,
1036                    XmATTACH_FORM, NULL, XmATTACH_FORM, NULL,
1037                    XmATTACH_NONE, NULL, XmATTACH_NONE, NULL );
1038   xitAttachWidget( messageLa,
1039                    XmATTACH_FORM, NULL, XmATTACH_WIDGET, markerPx,
1040                    XmATTACH_NONE, NULL, XmATTACH_NONE,   NULL );
1041 
1042   /* Make sure there is enough space between the children. */
1043   n = 0;
1044   XtSetArg( args[ n ], XmNtopOffset,    5 ); n++;
1045   XtSetArg( args[ n ], XmNleftOffset,   5 ); n++;
1046   XtSetArg( args[ n ], XmNrightOffset,  5 ); n++;
1047   XtSetArg( args[ n ], XmNbottomOffset, 5 ); n++;
1048   XtSetValues( markerPx,  args, n );
1049   XtSetValues( messageLa, args, n );
1050 
1051   /* Manage the widgets. */
1052   xitManageChildren( dataLocalW, XtNumber( dataLocalW ) );
1053 
1054 
1055   /* Set icon for this window. */
1056   xtmIcSetSimpleIcon( alarmTl, workFo, XTM_IC_ICON_DEFAULT );
1057 
1058   /* Set the size of the window. */
1059   xitSetSizeToplevelDialog( alarmTl, True );
1060 
1061 
1062   XtPopup( alarmTl, XtGrabNone );
1063 
1064 
1065   /* Free allocated data. */
1066   if( entry_text_ref != NULL )
1067     SysFree( entry_text_ref );
1068 
1069 
1070   /* Give an alarm, a boring bell or a nice melody. */
1071   alarm_melody = entry_record.entry.alarm_melody;
1072 
1073   if( alarm_melody > 0 && alarm_melody < 6 )
1074     tune_file = appl_data_ref -> custom_data -> tune_file[ alarm_melody - 1 ];
1075   else
1076     tune_file = NULL;
1077 
1078   xtmToPlayMelody( alarmTl,
1079                    appl_data_ref -> custom_data -> tune_player,
1080                    appl_data_ref -> custom_data -> tune_player_param,
1081                    tune_file,
1082                    appl_data_ref -> alarm_volume,
1083                    appl_data_ref -> custom_data -> tune_dur_delta );
1084 
1085   /* Display animation pixmap. */
1086   user_data -> timer_id = (XtIntervalId) 0;
1087 
1088   if( appl_data_ref -> do_animate_alarm ) {
1089     user_data -> curr_pixmap = 0;
1090     user_data -> timer_id = XtAppAddTimeOut(
1091                               appl_data_ref -> context, 0L,
1092                               (XtTimerCallbackProc) doAnimateCB,
1093                               (XtPointer) user_data );
1094   }
1095 
1096 
1097   /* We keep track of windows on the screen. */
1098   for( index = 0; index < MAX_TRACK_ALARM_WIN; index++ ) {
1099     if( *(appl_data_ref -> track_alarm_win + index) == NULL ) {
1100       *(appl_data_ref -> track_alarm_win + index) = alarmTl;
1101       break;
1102     }
1103   }
1104 
1105   user_data -> alarmW = alarmTl;
1106 
1107   return;
1108 
1109 
1110   /* Exception handler. */
1111   exception:
1112 
1113     if( entry_text_ref != NULL )
1114       SysFree( entry_text_ref );
1115 
1116     return;
1117 
1118 } /* displayAlarm */
1119 
1120 
1121 /*----------------------------------------------------------------------*/
1122 
1123 static void
displayUsage()1124   displayUsage()
1125 {
1126 
1127   printf(
1128     "\n"
1129     "%s (%s): Alarm process for a single diary database\n"
1130     "\n"
1131     "Start an alarm process for one or more diary databases. The\n"
1132     "default database in Diary in your home directory.\n"
1133     "\n"
1134     "Usage:\n"
1135     "  %s [flags]\n"
1136     "\n"
1137     "Flags:\n"
1138     "  -alarmTags       : Display alarms containing one of these tags.\n"
1139     "  -fmap large      : Use a large font.\n"
1140     "  -fmap medium     : Use a medium font.\n"
1141     "  -fmap small      : Use a small font.\n"
1142     "  -help            : Display this help.\n"
1143     "  -h               : See above.\n"
1144     "  -language <lan>  : Use the language <lan>.\n"
1145     "  -lan <lan>       : See above.\n"
1146     "  -noFileLock      : Don't use any file locking.\n"
1147     "  -palette gray    : Use color palette Gray.\n"
1148     "  -palette lila    : Use color palette Lila.\n"
1149     "  -palette motif   : Use color palette Motif.\n"
1150     "  -palette neon    : Use color palette Neon.\n"
1151     "  -palette nordic  : Use color palette Nordic.\n"
1152     "  -palette red     : Use color palette Red.\n"
1153     "  -palette sea     : Use color palette Sea.\n"
1154     "  -palette sky     : Use color palette Sky.\n"
1155     "  -palette wood    : Use color palette Wood.\n"
1156     "  -usage           : Display this help.\n"
1157     "  -version         : Display the current version.\n"
1158     "\n",
1159     program_name, VERSION_ID, program_name );
1160 
1161 
1162   return;
1163 
1164 } /* displayUsage */
1165 
1166 
1167 /*----------------------------------------------------------------------*/
1168 
1169 static void
doActionAlarm(XTM_AP_BASE_DATA_REF appl_data_ref,ALARM_CACHE * alarm_ref)1170   doActionAlarm( XTM_AP_BASE_DATA_REF  appl_data_ref,
1171                  ALARM_CACHE           *alarm_ref )
1172 {
1173 
1174   /* Variables. */
1175   int                     pid;
1176   UINT32                  operations;
1177   char                    date_buffer[ 50 ];
1178   char                    time_buffer[ 50 ];
1179   char                    *process_args[ 10 ];
1180   char                    *entry_text_ref;
1181   XTM_DB_ALL_ENTRY_DEF    entry_record;
1182   XTM_DB_ENTRY_DATABASES  database;
1183   XTM_DB_OPEN_REQUEST     open_request;
1184   XTM_DB_STATUS           db_status;
1185   XTM_CD_CAL_INFO         db_info;
1186 
1187 
1188   /* Code. */
1189 
1190   /* Should we do action alarm? */
1191   if( ! alarm_ref -> can_do_action )
1192     return;
1193 
1194   /* Fetch database information. */
1195   (void) xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
1196                             alarm_ref -> db_name,
1197                             &db_info, NULL );
1198 
1199   /* Check operations. */
1200   xtmDbCheckDbOperations( db_info.directory, True, &operations );
1201 
1202 
1203   /* Open the database. */
1204   open_request.name       = db_info.short_name;
1205   open_request.directory  = db_info.directory;
1206   open_request.operations = XTM_DB_FLAG_MODE_READ;
1207   open_request.database   = XTM_DB_ALL_ENTRY_DB;
1208 
1209   /* Try to open the database. */
1210   db_status = xtmDbOpenEntryDb( &open_request, &database );
1211 
1212   if( db_status != XTM_DB_OK ) {
1213 
1214     if( db_status == XTM_DB_LOCKED )
1215       xitErMessage( toplevel, XIT_ER_ERROR,
1216                     module_name, "doActionAlarm",
1217                     msgGetText( MXDI_ERRMSG_DB_LOCKED ) );
1218     else
1219       xitErMessage( toplevel, XIT_ER_ERROR,
1220                     module_name, "doActionAlarm",
1221                     msgGetText( MXDI_ERRMSG_CANNOT_OPEN_DB ) );
1222     return;
1223 
1224   } /* if */
1225 
1226 
1227   /* Fetch the entry to use. */
1228   db_status = xtmDbFetchEntry( &database, alarm_ref -> id,
1229                                &entry_record, &entry_text_ref );
1230 
1231   xtmDbCloseEntryDb( &database );
1232 
1233   if( db_status != XTM_DB_OK ) {
1234     xitErMessage( NULL, XIT_ER_ERROR,
1235                   module_name, "doActionAlarm",
1236                   msgGetText( MXDI_ERRMSG_FETCH_ENTRY ) );
1237 
1238     return;
1239   }
1240 
1241   /* Does the entry have the correct tag? */
1242   if( *appl_data_ref -> filter_alarm_tags != '\0' &&
1243       strstr( appl_data_ref -> filter_alarm_tags,
1244               entry_record.entry.tag ) == NULL )
1245     return;
1246 
1247 
1248   /* No actions for private entries (if you are not privileged). */
1249   if(   flagIsSet( entry_record.entry.flags, XTM_DB_FLAG_PRIVATE ) &&
1250       ! flagIsSet( operations, XTM_DB_FLAG_MODE_PRIV ) )
1251     return;
1252 
1253 
1254   /* Entry date and time. */
1255   xtmFoFormatDate( entry_record.entry.time_stamp,
1256                    date_buffer, sizeof( date_buffer ) );
1257 
1258   xtmFoFormatTime( entry_record.entry.time_stamp,
1259                    time_buffer, sizeof( time_buffer ) );
1260 
1261 
1262   /* Start entry action shell script? */
1263   if( flagIsSet( entry_record.entry.flags, XTM_DB_FLAG_ACTION_TEXT ) ) {
1264 
1265     /* Process arguments. */
1266     process_args[ 0 ] = appl_data_ref -> launch_use_shell;
1267     process_args[ 1 ] = "-c";
1268 
1269     if( entry_text_ref == NULL )
1270       process_args[ 2 ] = entry_record.entry.text;
1271     else
1272       process_args[ 2 ] = entry_text_ref;
1273 
1274     process_args[ 3 ] = NULL;
1275 
1276     pid = startProcess( toplevel, process_args );
1277 
1278   } /* if */
1279 
1280 
1281   /* Start entry action with entry text as shell script? */
1282   if( flagIsSet( entry_record.entry.flags, XTM_DB_FLAG_ACTION_SCRIPT ) ) {
1283 
1284     /* Process arguments. */
1285     process_args[ 0 ] = appl_data_ref -> launch_def_script;
1286     process_args[ 1 ] = entry_record.entry.tag;
1287     process_args[ 2 ] = date_buffer;
1288     process_args[ 3 ] = time_buffer;
1289 
1290     if( entry_text_ref != NULL )
1291       process_args[ 4 ] = entry_text_ref;
1292     else
1293       process_args[ 4 ] = entry_record.entry.text;
1294 
1295     process_args[ 5 ] = NULL;
1296 
1297     pid = startProcess( toplevel, process_args );
1298 
1299   } /* if */
1300 
1301   if( entry_text_ref != NULL )
1302     SysFree( entry_text_ref );
1303 
1304 
1305   return;
1306 
1307 } /* doActionAlarm */
1308 
1309 
1310 /*----------------------------------------------------------------------*/
1311 
1312 static Boolean
fetchAlarms(XTM_AP_BASE_DATA_REF appl_data_ref,XTM_CD_CAL_INFO * db_info)1313   fetchAlarms( XTM_AP_BASE_DATA_REF  appl_data_ref,
1314                XTM_CD_CAL_INFO       *db_info )
1315 {
1316 
1317   /* Variables. */
1318   int                     index;
1319   UINT32                  search_flags;
1320   LST_DESC_TYPE           list_ref[ 2 ];
1321   LST_STATUS              lst_status;
1322   TIM_TIME_REF            current_day;
1323   TIM_TIME_REF            end_day;
1324   TIM_TIME_REF            now;
1325   TIM_TIME_REF            start_day;
1326   XTM_DB_ALL_ENTRY_DEF    entry_record;
1327   XTM_DB_ENTRY_DATABASES  database;
1328   XTM_DB_OPEN_REQUEST     open_request;
1329   XTM_DB_STATUS           db_status;
1330 
1331 
1332   /* Code. */
1333 
1334   if( appl_data_ref -> custom_data -> debug_mode )
1335     printf( "Fetching db: %s\n", db_info -> short_name );
1336 
1337 
1338   /* Remove all old alarms for this database. */
1339   for( index = 0; index < MAX_ALARM_CACHE; index++ ) {
1340     if( strcmp( appl_data_ref -> alarms[ index ].db_name,
1341                 db_info -> short_name ) == 0 )
1342       appl_data_ref -> alarms[ index ].id = 0;
1343   }
1344 
1345 
1346   /* Open the database. */
1347   open_request.name       = db_info -> short_name;
1348   open_request.directory  = db_info -> directory;
1349   open_request.operations = XTM_DB_FLAG_MODE_READ;
1350   open_request.database   = XTM_DB_ALL_ENTRY_DB;
1351 
1352   db_status = xtmDbOpenEntryDb( &open_request, &database );
1353 
1354   if( db_status != XTM_DB_OK ) {
1355 
1356     if( db_status == XTM_DB_LOCKED )
1357       xitErMessage( toplevel, XIT_ER_ERROR,
1358                     module_name, "fetchAlarms",
1359                     msgGetText( MXDI_ERRMSG_DB_LOCKED ) );
1360     else
1361       xitErMessage( toplevel, XIT_ER_ERROR,
1362                     module_name, "fetchAlarms",
1363                     msgGetText( MXDI_ERRMSG_CANNOT_OPEN_DB ) );
1364 
1365     return( False );
1366 
1367   } /* if */
1368 
1369   /* Fetch entries from today and 7 days before/after. */
1370   now       = TimLocalTime( TimMakeTimeNow() );
1371   start_day = TimMakeTime( TimIndexOfYear(  now ),
1372                            TimIndexOfMonth( now ),
1373                            TimIndexOfDay(   now ),
1374                            0, 0, 0 );
1375 
1376   TimAddDays( &start_day, -7 );
1377   current_day = start_day;
1378   end_day     = start_day;
1379   TimAddDays( &end_day, 14 );
1380 
1381   /* Fetch all entries. */
1382   while( current_day <= end_day ) {
1383 
1384     db_status = xtmDbFetchEntriesInDay( &database,
1385                                         current_day,
1386                                         XTM_DB_FETCH_STANDING,
1387                                         &list_ref[ 0 ], &list_ref[ 1 ] );
1388 
1389     if( db_status != XTM_DB_OK ) {
1390       xitErMessage( NULL, XIT_ER_ERROR,
1391                     module_name, "displayAlarm",
1392                     msgGetText( MXDI_ERRMSG_FETCH_ENTRY ) );
1393 
1394       return( False );
1395     }
1396 
1397     search_flags = (XTM_DB_FLAG_ALARM |
1398                     XTM_DB_FLAG_ACTION_SCRIPT |
1399                     XTM_DB_FLAG_ACTION_TEXT);
1400 
1401     /* Ignore any notes and save the alarms. */
1402     lst_status = LstLinkCurrentFirst( list_ref[ 0 ] );
1403 
1404     while( lst_status == LST_OK ) {
1405 
1406       lst_status = LstLinkGetCurrent( list_ref[ 0 ], &entry_record );
1407 
1408       /* Do we want alarms for this entry? */
1409       if( flagIsClear( entry_record.entry.flags, search_flags ) ) {
1410         lst_status = LstLinkCurrentNext( list_ref[ 0 ] );
1411 
1412         continue;
1413       }
1414 
1415 
1416       /* Process all alarms. */
1417       for( index = 0; index < MAX_ALARMS; index++ ) {
1418 
1419         int           minute_offset;
1420         int           slot;
1421         UINT32        entry_id;
1422         UINT32        flags;
1423         TIM_TIME_REF  alarm_time;
1424 
1425         /* Is the alarm valid? */
1426         if( entry_record.entry.alarm_valid[ index ] ) {
1427           minute_offset = entry_record.entry.alarm_offset[ index ];
1428           entry_id      = entry_record.entry.id;
1429           flags         = entry_record.entry.flags;
1430 
1431           /* Calculate the absolute alarm time. */
1432           alarm_time = current_day;
1433           alarm_time = TimAddTime( alarm_time,
1434                                    entry_record.entry.time_stamp );
1435           TimAddMinutes( &alarm_time, minute_offset );
1436 
1437           /* Find a free slot where the alarm can be stored. */
1438           for( slot = 0; slot < MAX_ALARM_CACHE; slot++ ) {
1439             if( appl_data_ref -> alarms[ slot ].id == 0 )
1440               break;
1441           }
1442 
1443 
1444           /* Save alarm time and other data. */
1445           if( slot < MAX_ALARM_CACHE ) {
1446 
1447             UINT32  action_flag = 0;
1448 
1449             /* Can do action alarm? */
1450             switch( index + 1 ) {
1451               case 1:
1452                 action_flag = XTM_DB_FLAG_ACTION_ALARM1;
1453                 break;
1454               case 2:
1455                 action_flag = XTM_DB_FLAG_ACTION_ALARM2;
1456                 break;
1457               case 3:
1458                 action_flag = XTM_DB_FLAG_ACTION_ALARM3;
1459                 break;
1460               case 4:
1461                 action_flag = XTM_DB_FLAG_ACTION_ALARM4;
1462                 break;
1463               case 5:
1464                 action_flag = XTM_DB_FLAG_ACTION_ALARM5;
1465                 break;
1466             }
1467 
1468             appl_data_ref -> alarms[ slot ].entry_date    = current_day;
1469             appl_data_ref -> alarms[ slot ].time          = alarm_time;
1470             appl_data_ref -> alarms[ slot ].id            = entry_id;
1471             appl_data_ref -> alarms[ slot ].flags         = flags;
1472             appl_data_ref -> alarms[ slot ].can_do_action = False;
1473 
1474             if( flagIsSet( flags, action_flag ) )
1475               appl_data_ref -> alarms[ slot ].can_do_action = True;
1476 
1477             strcpy( appl_data_ref -> alarms[ slot ].db_name,
1478                     db_info -> short_name );
1479 
1480             if( appl_data_ref -> custom_data -> debug_mode )
1481               printf( "Alarm time %d (%d) '%s'\n",
1482                       (int) alarm_time, slot,
1483                       entry_record.entry.text );
1484           }
1485 
1486         } /* if */
1487 
1488       } /* loop */
1489 
1490 
1491       /* Next entry. */
1492       lst_status = LstLinkCurrentNext( list_ref[ 0 ] );
1493 
1494     } /* while */
1495 
1496 
1497     /* Free any data occupied. */
1498     LstLinkClear( list_ref[ 0 ] );
1499     LstLinkClear( list_ref[ 1 ] );
1500 
1501     /* Next day. */
1502     TimAddDays( &current_day, 1 );
1503 
1504   } /* while */
1505 
1506 
1507   /* Close the database. */
1508   xtmDbCloseEntryDb( &database );
1509 
1510 
1511   return( True );
1512 
1513 } /* fetchAlarms */
1514 
1515 
1516 /*----------------------------------------------------------------------*/
1517 
1518 static Boolean
setupCmdPipe(XTM_AP_BASE_DATA_REF appl_data_ref)1519   setupCmdPipe( XTM_AP_BASE_DATA_REF  appl_data_ref )
1520 {
1521 
1522   /* Variables. */
1523   int  fd;
1524 
1525 
1526   /* Code. */
1527 
1528   if( *appl_data_ref -> cmd_pipe_id == '\0' )
1529     return( False );
1530 
1531 
1532   fd = open( appl_data_ref -> cmd_pipe_id, O_RDONLY );
1533   if( fd < 0 )
1534     return( False );
1535 
1536   appl_data_ref -> cmd_pipe_ref = fd;
1537 
1538 
1539   /* Add callback to call when input is pending. */
1540   XtAppAddInput( appl_data_ref -> context,
1541                  appl_data_ref -> cmd_pipe_ref,
1542                  (XtPointer) XtInputReadMask,
1543                  (XtInputCallbackProc) processCommandCB,
1544                  (XtPointer) appl_data_ref );
1545 
1546 
1547   return( True );
1548 
1549 } /* setupCmdPipe */
1550 
1551 
1552 /*----------------------------------------------------------------------*/
1553 
1554 static void
startAlarmForCal(XTM_AP_BASE_DATA_REF appl_data_ref,char * db_name,char * db_location)1555   startAlarmForCal( XTM_AP_BASE_DATA_REF  appl_data_ref,
1556                     char                  *db_name,
1557                     char                  *db_location )
1558 {
1559 
1560   /* Variables. */
1561   Boolean          ok;
1562   UINT32           operations;
1563   int              save_to_index;
1564   int              index;
1565   XTM_CD_CAL_INFO  db_info;
1566 
1567 
1568   /* Code. */
1569 
1570   /* Fetch database information. */
1571   ok = xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
1572                           db_name, &db_info, NULL );
1573 
1574   /* If we did not find the database, see if we can add it 'on the fly'. */
1575   if( ! ok ) {
1576 
1577     /* We need at least read access. */
1578     xtmDbCheckDbOperations( db_location, True, &operations );
1579 
1580     if( flagIsClear( operations, XTM_DB_FLAG_MODE_READ ) )
1581       return;
1582 
1583     /* Add the calendar. */
1584     xtmCdAddDatabase( appl_data_ref -> custom_data -> cal_db_handle,
1585                       db_name, db_location, 0 );
1586 
1587     (void) xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
1588                               db_name, &db_info, NULL );
1589 
1590   } /* if */
1591 
1592 
1593   save_to_index = -1;
1594 
1595   /* Save the database name (if already there, ignore it). */
1596   for( index = 0; index < MAX_DATABASE_CHECK; index++ ) {
1597 
1598     DATABASE_CHECK  *db_ref;
1599 
1600     db_ref = &appl_data_ref -> db_check[ index ];
1601 
1602     /* Already there? */
1603     if( strcmp( db_ref -> db_name, db_name ) == 0 ) {
1604         save_to_index = -1;
1605         break;
1606       }
1607 
1608     /* Free slot? */
1609     if( db_ref -> db_name[ 0 ] == '\0' && save_to_index == -1 )
1610       save_to_index = index;
1611 
1612   } /* loop */
1613 
1614 
1615   /* Save the database? */
1616   if( save_to_index >= 0 ) {
1617     if( appl_data_ref -> custom_data -> debug_mode )
1618       printf( "Starting alarm for: %s\n", db_name );
1619 
1620     strcpy( appl_data_ref -> db_check[ save_to_index ].db_name, db_name );
1621     appl_data_ref -> db_check[ save_to_index ].last_modified = 0;
1622   }
1623 
1624 
1625   return;
1626 
1627 } /* startAlarmForCal */
1628 
1629 
1630 /*----------------------------------------------------------------------*/
1631 
1632 static void
stopAlarmForCal(XTM_AP_BASE_DATA_REF appl_data_ref,char * db_name)1633   stopAlarmForCal( XTM_AP_BASE_DATA_REF  appl_data_ref,
1634                    char                  *db_name )
1635 {
1636 
1637   /* Variables. */
1638   int  index;
1639 
1640 
1641   /* Code. */
1642 
1643   /* Remove from databases db. */
1644   for( index = 0; index < MAX_DATABASE_CHECK; index++ ) {
1645     if( strcmp( appl_data_ref -> db_check[ index ].db_name, db_name ) == 0 )
1646       appl_data_ref -> db_check[ index ].db_name[ 0 ] = '\0';
1647   }
1648 
1649 
1650   /* Remove from alarm_cache. */
1651   for( index = 0; index < MAX_ALARM_CACHE; index++ ) {
1652     if( strcmp( appl_data_ref -> alarms[ index ].db_name, db_name ) == 0 )
1653       appl_data_ref -> alarms[ index ].id = 0;
1654   }
1655 
1656 
1657   /* Remove from ignore entries. */
1658   for( index = 0; index < MAX_ENTRIES_IGNORE; index++ ) {
1659     if( strcmp( appl_data_ref -> ignore_entry[ index ].db_name,
1660                 db_name ) == 0 )
1661       appl_data_ref -> ignore_entry[ index ].id = 0;
1662   }
1663 
1664 
1665   /* Remove from snooze. */
1666   for( index = 0; index < MAX_SNOOZE_ALARM; index++ ) {
1667     if( strcmp( appl_data_ref -> snooze[ index ].db_name, db_name ) == 0 )
1668       appl_data_ref -> snooze[ index ].id = 0;
1669   }
1670 
1671 
1672   return;
1673 
1674 } /* stopAlarmForCal */
1675 
1676 
1677 /*----------------------------------------------------------------------*/
1678 
1679 int
startProcess(Widget parent,char * process_args[])1680   startProcess( Widget  parent,
1681                 char    *process_args[] )
1682 {
1683 
1684   /* Variables. */
1685   int      pid;
1686   int      status;
1687   Display  *display = NULL;
1688 
1689 
1690   /* Code. */
1691 
1692   if( parent != NULL )
1693     display = XtDisplay( parent );
1694 
1695   /* Does the executable file exist? */
1696   status = access( process_args[ 0 ], (R_OK | X_OK) );
1697 
1698   if( status != 0 ) {
1699     xitErMessage( parent, XIT_ER_ERROR,
1700                   module_name, "startProcess",
1701                   msgGetText( MXDI_PROCESS_NO_FILE ) );
1702     return( 0 );
1703   }
1704 
1705   /* Start the alarm process. */
1706   pid = fork();
1707 
1708   switch( pid ) {
1709 
1710     /* Child running. */
1711     case 0:
1712       if( display != NULL )
1713         close( ConnectionNumber( display ) );
1714 
1715       /* Start the process. */
1716       execv( process_args[ 0 ], process_args );
1717 
1718       {
1719         char  buffer[ 200 ];
1720 
1721         sprintf( buffer,
1722                  msgGetText( MXDI_ERRMSG_EXECUTE_PROCESS ),
1723                  process_args[ 0 ] );
1724 
1725         xitErMessage( NULL, XIT_ER_ERROR,
1726                       module_name, "startProcess",
1727                       buffer );
1728       } /* block */
1729 
1730       exit( 1 );
1731 
1732     /* Error in fork. */
1733     case -1:
1734       xitErMessage( parent, XIT_ER_ERROR,
1735                     module_name, "startProcess",
1736                     msgGetText( MXDI_PROCESS_CANNOT_FORK ) );
1737       return( 0 );
1738 
1739     /* Parent */
1740     default:
1741       break;
1742 
1743   } /* switch */
1744 
1745   /* Catch this process when we return. */
1746   (void) SigRegister( SIGCHLD, pid, NULL, NULL );
1747 
1748 
1749   return( pid );
1750 
1751 } /* startProcess */
1752 
1753 
1754 /*----------------------------------------------------------------------*/
1755 
1756 static void
alarmConfirmCB(Widget widget,USER_DATA_REF user_data,XmAnyCallbackStruct * call_data)1757   alarmConfirmCB( Widget               widget,
1758                   USER_DATA_REF        user_data,
1759                   XmAnyCallbackStruct  *call_data )
1760 {
1761 
1762   /* Variables. */
1763   int                   index;
1764   XTM_AP_BASE_DATA_REF  appl_data_ref;
1765 
1766 
1767   /* Code. */
1768 
1769   appl_data_ref = user_data -> appl_data_ref;
1770 
1771 
1772   /* The shift modifier key confirms all alarm windows on screen. */
1773   if( (call_data -> event -> xbutton.state & ShiftMask) != 0 ) {
1774 
1775     for( index = 0; index < MAX_TRACK_ALARM_WIN; index++ ) {
1776       if( *(appl_data_ref -> track_alarm_win + index) == user_data -> alarmW )
1777         ;
1778       else if( *(appl_data_ref -> track_alarm_win + index) != NULL )
1779         XtDestroyWidget( *(appl_data_ref -> track_alarm_win + index) );
1780     }
1781 
1782   }
1783 
1784 
1785   XtDestroyWidget( user_data -> alarmW );
1786 
1787 
1788   return;
1789 
1790 } /* alarmConfirmCB */
1791 
1792 
1793 /*----------------------------------------------------------------------*/
1794 
1795 static void
alarmDeleteCB(Widget widget,USER_DATA_REF user_data,XtPointer call_data)1796   alarmDeleteCB( Widget         widget,
1797                  USER_DATA_REF  user_data,
1798                  XtPointer      call_data )
1799 {
1800 
1801   /* Variables. */
1802   Widget  tempW;
1803 
1804 
1805   /* Code. */
1806 
1807   /* Does the user confirm? */
1808   if( user_data -> appl_data_ref -> custom_data -> confirm_actions ) {
1809 
1810     tempW = xitCreateQuestionDialog(
1811               user_data -> alarmW, "QuestionDialog",
1812               msgGetText( MXDI_DELETE_ENTRY_TITLE ),
1813               msgGetText( MXDI_DELETE_ENTRY_CONF ),
1814               deleteEntryCB, user_data,
1815               NULL, NULL );
1816 
1817     return;
1818   }
1819 
1820   /* Remove the entry. */
1821   deleteEntryCB( widget, user_data, NULL );
1822 
1823 
1824   return;
1825 
1826 } /* alarmDeleteCB */
1827 
1828 
1829 /*----------------------------------------------------------------------*/
1830 
1831 static void
alarmNoMoreCB(Widget widget,USER_DATA_REF user_data,XtPointer call_data)1832   alarmNoMoreCB( Widget         widget,
1833                  USER_DATA_REF  user_data,
1834                  XtPointer      call_data )
1835 {
1836 
1837   /* Variables. */
1838   int     index;
1839 
1840 
1841   /* Code. */
1842 
1843   /* Mark this entry as ignored. */
1844   for( index = 0; index < MAX_ENTRIES_IGNORE; index++ ) {
1845 
1846     if( user_data -> appl_data_ref -> ignore_entry[ index ].id == 0 ) {
1847       user_data -> appl_data_ref -> ignore_entry[ index ].id =
1848         user_data -> id;
1849       strcpy( user_data -> appl_data_ref -> ignore_entry[ index ].db_name,
1850               user_data -> db_name );
1851       break;
1852     }
1853 
1854   } /* loop */
1855 
1856   XtDestroyWidget( user_data -> alarmW );
1857 
1858 
1859   return;
1860 
1861 } /* alarmNoMoreCB */
1862 
1863 
1864 /*----------------------------------------------------------------------*/
1865 
1866 static void
alarmSnoozeCB(Widget widget,USER_DATA_REF user_data,XtPointer call_data)1867   alarmSnoozeCB( Widget         widget,
1868                  USER_DATA_REF  user_data,
1869                  XtPointer      call_data )
1870 {
1871 
1872   /* Variables. */
1873   Arg       args[ 10 ];
1874   Cardinal  n;
1875   Widget    dataLocalW[ 2 ];
1876   Widget    snoozeFd;
1877   Widget    snoozeFo;
1878 
1879   static XIT_ACTION_AREA_ITEM  action_buttons[] = {
1880     { "",   snoozeOkCB, NULL },
1881     { NULL, NULL,       NULL },
1882     { NULL, NULL,       NULL },
1883     { NULL, NULL,       NULL },
1884     { NULL, NULL,       NULL },
1885     { "",   NULL,       NULL },
1886   };
1887 
1888 
1889   /* Code. */
1890 
1891   action_buttons[ 0 ].label = msgGetText( MXDI_OK_BUTTON );
1892   action_buttons[ 0 ].data  = user_data;
1893   action_buttons[ 5 ].label = msgGetText( MXDI_CANCEL_BUTTON );
1894   action_buttons[ 5 ].data  = user_data;
1895 
1896 
1897   /* Create a form dialog with buttons. */
1898   snoozeFd = xitCreateFormDialog( user_data -> alarmW, "SnoozeFd",
1899                                   1, 0,
1900                                   action_buttons,
1901                                   XtNumber( action_buttons ) );
1902 
1903   n = 0;
1904   XtSetArg( args[ n ], XmNtitle, msgGetText( MXDI_SNOOZE_TITLE ) ); n++;
1905   XtSetValues( XtParent( snoozeFd ), args, n );
1906 
1907   n = 0;
1908   XtSetArg( args[ n ], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL ); n++;
1909   XtSetValues( snoozeFd, args, n );
1910 
1911 
1912   /* Container for the contents of the snooze window. */
1913   snoozeFo = XtNameToWidget( snoozeFd, "SnoozeFdFo" );
1914 
1915 
1916   snoozeLa = xitCreateLabel( snoozeFo, "SnoozeLa",
1917                              msgGetText( MXDI_SNOOZE_LABEL ), -1 );
1918 
1919   /* Create a slide bar with the time in minutes to wait. */
1920   n = 0;
1921   XtSetArg( args[ n ], XmNvalue, 1 ); n++;
1922   XtSetArg( args[ n ], XmNminimum, 1 ); n++;
1923   XtSetArg( args[ n ], XmNmaximum, 120 ); n++;
1924   XtSetArg( args[ n ], XmNprocessingDirection, XmMAX_ON_RIGHT ); n++;
1925   XtSetArg( args[ n ], XmNshowValue, True ); n++;
1926   XtSetArg( args[ n ], XmNorientation, XmHORIZONTAL ); n++;
1927   snoozeSc = XmCreateScale( snoozeFo, "SnoozeSc", args, n );
1928 
1929 
1930   /* Put the elements together. */
1931   xitAttachWidget( snoozeLa,
1932                    XmATTACH_FORM, NULL, XmATTACH_FORM, NULL,
1933                    XmATTACH_NONE, NULL, XmATTACH_NONE, NULL );
1934   xitAttachWidget( snoozeSc,
1935                    XmATTACH_WIDGET, snoozeLa, XmATTACH_FORM, NULL,
1936                    XmATTACH_FORM,   NULL,     XmATTACH_NONE, NULL );
1937 
1938 
1939   /* Make sure there is enough space between the children. */
1940   n = 0;
1941   XtSetArg( args[ n ], XmNtopOffset,    5 ); n++;
1942   XtSetArg( args[ n ], XmNleftOffset,   5 ); n++;
1943   XtSetArg( args[ n ], XmNrightOffset,  5 ); n++;
1944   XtSetArg( args[ n ], XmNbottomOffset, 5 ); n++;
1945   XtSetValues( snoozeLa,  args, n );
1946   XtSetValues( snoozeSc,  args, n );
1947 
1948 
1949   /* Manage the widgets. */
1950   xitManageChildren( dataLocalW, XtNumber( dataLocalW ) );
1951 
1952   XtManageChild( snoozeFd );
1953 
1954 
1955   /* Default snooze minutes. */
1956   XmScaleSetValue( snoozeSc, user_data -> appl_data_ref -> snooze_minutes );
1957 
1958 
1959   user_data -> snoozeW = snoozeFd;
1960 
1961 
1962   return;
1963 
1964 } /* alarmSnoozeCB */
1965 
1966 
1967 /*----------------------------------------------------------------------*/
1968 
1969 static void
alarmViewCB(Widget widget,USER_DATA_REF user_data,XtPointer call_data)1970   alarmViewCB( Widget         widget,
1971                USER_DATA_REF  user_data,
1972                XtPointer      call_data )
1973 {
1974 
1975   /* Variables. */
1976   char                    *char_ref;
1977   char                    *entry_text_ref;
1978   XTM_AP_BASE_DATA_REF    appl_data_ref;
1979   XTM_DB_ALL_ENTRY_DEF    entry_record;
1980   XTM_DB_ENTRY_DATABASES  database;
1981   XTM_DB_OPEN_REQUEST     open_request;
1982   XTM_DB_STATUS           db_status;
1983   XTM_CD_CAL_INFO         db_info;
1984 
1985 
1986   /* Code. */
1987 
1988   appl_data_ref = user_data -> appl_data_ref;
1989 
1990 
1991   /* Fetch database information. */
1992   (void) xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
1993                             user_data -> db_name,
1994                             &db_info, NULL );
1995 
1996   /* Open the database. */
1997   open_request.name       = db_info.short_name;
1998   open_request.directory  = db_info.directory;
1999   open_request.operations = XTM_DB_FLAG_MODE_READ;
2000   open_request.database   = XTM_DB_ALL_ENTRY_DB;
2001 
2002   db_status = xtmDbOpenEntryDb( &open_request, &database );
2003 
2004   if( db_status != XTM_DB_OK ) {
2005 
2006     if( db_status == XTM_DB_LOCKED )
2007       xitErMessage( user_data -> alarmW, XIT_ER_ERROR,
2008                     module_name, "alarmViewCB",
2009                     msgGetText( MXDI_ERRMSG_DB_LOCKED ) );
2010     else
2011       xitErMessage( user_data -> alarmW, XIT_ER_ERROR,
2012                     module_name, "alarmViewCB",
2013                     msgGetText( MXDI_ERRMSG_CANNOT_OPEN_DB ) );
2014 
2015     return;
2016 
2017   } /* if */
2018 
2019 
2020   /* Fetch the entry to display. */
2021   db_status = xtmDbFetchEntry( &database, user_data -> id,
2022                                &entry_record, &entry_text_ref );
2023 
2024   xtmDbCloseEntryDb( &database );
2025 
2026   if( db_status != XTM_DB_OK ) {
2027     xitErMessage( user_data -> alarmW, XIT_ER_ERROR,
2028                   module_name, "alarmViewCB",
2029                   msgGetText( MXDI_ERRMSG_FETCH_ENTRY ) );
2030     return;
2031   }
2032 
2033 
2034   /* View the entry. */
2035   if( entry_text_ref != NULL )
2036     char_ref = entry_text_ref;
2037   else
2038     char_ref = entry_record.entry.text;
2039 
2040   xitViewText( user_data -> alarmW, char_ref,
2041                " ", msgGetText( MXDI_CLOSE_BUTTON ) );
2042 
2043 
2044   return;
2045 
2046 } /* alarmViewCB */
2047 
2048 
2049 /*----------------------------------------------------------------------*/
2050 
2051 static void
deleteEntryCB(Widget widget,USER_DATA_REF user_data,XtPointer call_data)2052   deleteEntryCB( Widget         widget,
2053                  USER_DATA_REF  user_data,
2054                  XtPointer      call_data )
2055 {
2056 
2057   /* Variables. */
2058   Widget                  tempW;
2059   XTM_AP_BASE_DATA_REF    appl_data_ref;
2060   XTM_DB_ENTRY_DATABASES  database;
2061   XTM_DB_OPEN_REQUEST     open_request;
2062   XTM_DB_STATUS           db_status;
2063   XTM_CD_CAL_INFO         db_info;
2064 
2065 
2066   /* Code. */
2067 
2068   appl_data_ref = user_data -> appl_data_ref;
2069 
2070 
2071   /* Fetch database information. */
2072   (void) xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
2073                             user_data -> db_name,
2074                             &db_info, NULL );
2075 
2076   /* Open the database. */
2077   open_request.name       = db_info.short_name;
2078   open_request.directory  = db_info.directory;
2079   open_request.operations = XTM_DB_FLAG_MODE_WRITE;
2080   open_request.database   = XTM_DB_ALL_ENTRY_DB;
2081 
2082   db_status = xtmDbOpenEntryDb( &open_request, &database );
2083 
2084   if( db_status != XTM_DB_OK ) {
2085 
2086     if( db_status == XTM_DB_LOCKED )
2087       xitErMessage( user_data -> alarmW, XIT_ER_ERROR,
2088                     module_name, "deleteEntryCB",
2089                     msgGetText( MXDI_ERRMSG_DB_LOCKED ) );
2090     else
2091       xitErMessage( user_data -> alarmW, XIT_ER_ERROR,
2092                     module_name, "deleteEntryCB",
2093                     msgGetText( MXDI_ERRMSG_CANNOT_OPEN_DB ) );
2094 
2095     return;
2096 
2097   } /* if */
2098 
2099 
2100   /* Delete the entry. */
2101   db_status = xtmDbDeleteEntry( &database, user_data -> id );
2102 
2103   xtmDbCloseEntryDb( &database );
2104 
2105   if( db_status != XTM_DB_OK ) {
2106     xitErMessage( user_data -> alarmW, XIT_ER_ERROR,
2107                   module_name, "deleteEntryCB",
2108                   msgGetText( MXDI_NO_ENTRY ) );
2109     return;
2110   }
2111 
2112 
2113   /* If the entry could be deleted, invalidate some buttons. */
2114   if( db_status == XTM_DB_OK ) {
2115     tempW = XtNameToWidget( user_data -> alarmW, "AlarmTlBase.Bu2" );
2116     XtSetSensitive( tempW, False );
2117 
2118     tempW = XtNameToWidget( user_data -> alarmW, "AlarmTlBase.Bu3" );
2119     XtSetSensitive( tempW, False );
2120 
2121     tempW = XtNameToWidget( user_data -> alarmW, "AlarmTlBase.Bu4" );
2122     XtSetSensitive( tempW, False );
2123 
2124     tempW = XtNameToWidget( user_data -> alarmW, "AlarmTlBase.Bu5" );
2125     XtSetSensitive( tempW, False );
2126   }
2127 
2128   /* Inform the user that it's time to refresh the day list. */
2129   tempW = xitCreateInformationDialog(
2130             user_data -> alarmW, "InformationDialog",
2131             msgGetText( MXDI_INFORMATION_LABEL ),
2132             msgGetText( MXDI_ALARM_ENTRY_DELETE_INFO ),
2133             NULL, NULL );
2134 
2135 
2136   return;
2137 
2138 } /* deleteEntryCB */
2139 
2140 
2141 /*----------------------------------------------------------------------*/
2142 
2143 static void
destroyCB(Widget widget,USER_DATA_REF user_data,XtPointer call_data)2144   destroyCB( Widget         widget,
2145              USER_DATA_REF  user_data,
2146              XtPointer      call_data )
2147 {
2148 
2149   /* Variables. */
2150   int                   index;
2151   XTM_AP_BASE_DATA_REF  appl_data_ref;
2152 
2153 
2154   /* Code. */
2155 
2156   appl_data_ref = user_data -> appl_data_ref;
2157 
2158 
2159   for( index = 0; index < MAX_TRACK_ALARM_WIN; index++ ) {
2160     if( *(appl_data_ref -> track_alarm_win + index) == user_data -> alarmW )
2161       *(appl_data_ref -> track_alarm_win + index) = NULL;
2162   }
2163 
2164   SysFree( user_data );
2165 
2166   /* Remove timeout ID? */
2167   if( user_data -> timer_id != (XtIntervalId) 0 )
2168     XtRemoveTimeOut( user_data -> timer_id );
2169 
2170 
2171   return;
2172 
2173 } /* destroyCB */
2174 
2175 
2176 /*----------------------------------------------------------------------*/
2177 
2178 static void
doAnimateCB(USER_DATA_REF user_data)2179   doAnimateCB( USER_DATA_REF  user_data )
2180 {
2181 
2182   /* Variables. */
2183   int                   pixmap_no;
2184   Arg                   args[ 10 ];
2185   Cardinal              n;
2186   Widget                tempW;
2187   XTM_AP_BASE_DATA_REF  appl_data_ref;
2188 
2189 
2190   /* Code. */
2191 
2192   appl_data_ref = user_data -> appl_data_ref;
2193   pixmap_no = ani_pixmap_seq[ user_data -> curr_pixmap ];
2194 
2195   /* Are we done? */
2196   if( pixmap_no < 0 ) {
2197     if( user_data -> important ) {
2198       user_data -> curr_pixmap = 0;
2199       user_data -> timer_id = XtAppAddTimeOut(
2200                                 appl_data_ref -> context, 0L,
2201                                 (XtTimerCallbackProc) doBlinkCB,
2202                                 (XtPointer) user_data );
2203     } else {
2204       user_data -> timer_id = (XtIntervalId) 0;
2205     }
2206 
2207     return;
2208   }
2209 
2210   /* Display the pixmap. */
2211   tempW = XtNameToWidget( user_data -> alarmW,
2212                           "AlarmTlBase.AlarmTlFo.MarkerPx" );
2213 
2214   n = 0;
2215   XtSetArg( args[ n ], XmNlabelPixmap, ani_pixmap[ pixmap_no ] ); n++;
2216   XtSetValues( tempW, args, n );
2217 
2218   /* Next pixmap in the sequence. */
2219   user_data -> curr_pixmap++;
2220 
2221   user_data -> timer_id = XtAppAddTimeOut(
2222                               appl_data_ref -> context, 150L,
2223                               (XtTimerCallbackProc) doAnimateCB,
2224                               (XtPointer) user_data );
2225 
2226 
2227   return;
2228 
2229 } /* doAnimateCB */
2230 
2231 
2232 /*----------------------------------------------------------------------*/
2233 
2234 static void
doBlinkCB(USER_DATA_REF user_data)2235   doBlinkCB( USER_DATA_REF  user_data )
2236 {
2237 
2238   /* Variables. */
2239   int                   pixmap_no;
2240   Arg                   args[ 10 ];
2241   Cardinal              n;
2242   Widget                tempW;
2243   XTM_AP_BASE_DATA_REF  appl_data_ref;
2244 
2245 
2246   /* Code. */
2247 
2248   appl_data_ref = user_data -> appl_data_ref;
2249   pixmap_no = ani_pixmap_blink[ user_data -> curr_pixmap ];
2250 
2251   /* Are we done? */
2252   if( pixmap_no < 0 ) {
2253     user_data -> timer_id = (XtIntervalId) 0;
2254     return;
2255   }
2256 
2257   /* Display the pixmap. */
2258   tempW = XtNameToWidget( user_data -> alarmW,
2259                           "AlarmTlBase.AlarmTlFo.MarkerPx" );
2260 
2261   n = 0;
2262   XtSetArg( args[ n ], XmNlabelPixmap, ani_pixmap[ pixmap_no ] ); n++;
2263   XtSetValues( tempW, args, n );
2264 
2265   /* Next pixmap in the sequence. */
2266   user_data -> curr_pixmap++;
2267 
2268   user_data -> timer_id = XtAppAddTimeOut(
2269                             appl_data_ref -> context, 500L,
2270                             (XtTimerCallbackProc) doBlinkCB,
2271                             (XtPointer) user_data );
2272 
2273 
2274   return;
2275 
2276 } /* doBlinkCB */
2277 
2278 
2279 /*----------------------------------------------------------------------*/
2280 
2281 static void
processCommandCB(XTM_AP_BASE_DATA_REF appl_data_ref,int * fd,XtInputId * id)2282   processCommandCB( XTM_AP_BASE_DATA_REF  appl_data_ref,
2283                     int                   *fd,
2284                     XtInputId             *id )
2285 {
2286 
2287   /* Variables. */
2288   int   bytes;
2289   int   items;
2290   char  buffer[ 5000 ];
2291   char  cal_name[ 50 ];
2292   char  command[ 60 ];
2293   char  location[ 150 ];
2294   char  line[ 300 ];
2295   char  *buffer_ref;
2296 
2297 
2298   /* Code. */
2299 
2300   /* Read the command pipe. */
2301   bytes = read( appl_data_ref -> cmd_pipe_ref, buffer, sizeof( buffer ) );
2302 
2303   if( bytes == 0 )
2304     return;
2305 
2306   if( bytes == -1 ) {
2307     xitErMessage( NULL, XIT_ER_FATAL,
2308                   module_name, "processCommandCB", "Exiting!" );
2309 
2310     terminateCB( SIGTERM, (void *) appl_data_ref );
2311   }
2312 
2313   buffer[ bytes ] = '\0';
2314 
2315   if( appl_data_ref -> custom_data -> debug_mode )
2316     printf( "Command over pipe:\n" );
2317 
2318 
2319   /* There can be one or more commands in the buffer. */
2320   buffer_ref = buffer;
2321 
2322   while( True ) {
2323 
2324     while( isspace( *buffer_ref ) )
2325       buffer_ref++;
2326 
2327     if( *buffer_ref == '\0' )
2328       return;
2329 
2330     bytes = strlen( buffer_ref );
2331     sscanf( buffer_ref, "%[^\n]%n", line, &bytes );
2332     buffer_ref = buffer_ref + bytes + 1;
2333 
2334     /* Fetch the command (if any). */
2335     items = sscanf( line, "%50s", command );
2336     if( items == 0 )
2337       return;
2338 
2339 
2340     /* Start alarm process? */
2341     if( strcmp( command, "start:" ) == 0 ) {
2342 
2343       cal_name[ 0 ] = '\0';
2344       location[ 0 ] = '\0';
2345 
2346       sscanf( line, "%s %s %s", command, cal_name, location );
2347 
2348       if( appl_data_ref -> custom_data -> debug_mode )
2349         printf( "  command: '%s' '%s' '%s'\n", command, cal_name, location );
2350 
2351       startAlarmForCal( appl_data_ref, cal_name, location );
2352 
2353 
2354     /* Stop running process. */
2355     } else if( strcmp( command, "stop:" ) == 0 ) {
2356 
2357       cal_name[ 0 ] = '\0';
2358 
2359       sscanf( line, "%s %s", command, cal_name );
2360 
2361       if( appl_data_ref -> custom_data -> debug_mode )
2362         printf( "  command: '%s' '%s'\n", command, cal_name );
2363 
2364       stopAlarmForCal( appl_data_ref, cal_name );
2365 
2366 
2367     /* Unknown command. */
2368     } else {
2369       sprintf( line, "Unexpected command: %s\n", command );
2370 
2371       xitErMessage( NULL, XIT_ER_FATAL,
2372                     module_name, "processCommandCB", line );
2373 
2374     } /* if */
2375 
2376   } /* while */
2377 
2378 
2379 } /* processCommandCB */
2380 
2381 
2382 /*----------------------------------------------------------------------*/
2383 
2384 static void
snoozeOkCB(Widget widget,USER_DATA_REF user_data,XtPointer call_data)2385   snoozeOkCB( Widget         widget,
2386               USER_DATA_REF  user_data,
2387               XtPointer      call_data )
2388 {
2389 
2390   /* Variables. */
2391   int                   index;
2392   int                   minutes;
2393   Widget                tempW;
2394   TIM_TIME_REF          alarm_time;
2395   TIM_TIME_REF          now;
2396   XTM_AP_BASE_DATA_REF  appl_data_ref;
2397 
2398 
2399   /* Code. */
2400 
2401   appl_data_ref = user_data -> appl_data_ref;
2402 
2403 
2404   /* Fetch the slider value. */
2405   tempW = XtNameToWidget( user_data -> snoozeW, "SnoozeFdFo.SnoozeSc" );
2406 
2407   XmScaleGetValue( tempW, &minutes );
2408 
2409   if( minutes <= 0 )
2410     return;
2411 
2412 
2413   /* Calculate the alarm time. */
2414   now = TimMakeTimeNow();
2415 
2416   alarm_time = TimMakeTime( TimIndexOfYear(  now ),
2417                             TimIndexOfMonth( now ),
2418                             TimIndexOfDay(   now ),
2419                             TimHour(         now ),
2420                             TimMinute(       now ),
2421                             0 );
2422   alarm_time = TimLocalTime( alarm_time );
2423 
2424   TimAddMinutes( &alarm_time, minutes );
2425 
2426 
2427   /* Store the time. */
2428   for( index = 0; index < MAX_SNOOZE_ALARM; index++ ) {
2429 
2430     if( appl_data_ref -> snooze[ index ].id == 0 ) {
2431 
2432       appl_data_ref -> snooze[ index ].id         = user_data -> id;
2433       appl_data_ref -> snooze[ index ].entry_date = user_data -> entry_date;
2434       appl_data_ref -> snooze[ index ].time       = alarm_time;
2435 
2436       strcpy( appl_data_ref -> snooze[ index ].db_name,
2437               user_data -> db_name );
2438       break;
2439     }
2440 
2441   } /* loop */
2442 
2443   XtDestroyWidget( user_data -> snoozeW );
2444 
2445 
2446   return;
2447 
2448 } /* snoozeOkCB */
2449 
2450 
2451 /*----------------------------------------------------------------------*/
2452 
2453 static void
updateCB(UINT32 flags,void * user_data,void * update_user_data)2454   updateCB( UINT32  flags,
2455             void    *user_data,
2456             void    *update_user_data )
2457 {
2458 
2459   /* Variables. */
2460   Boolean               new_day = False;
2461   int                   parent_id;
2462   int                   index;
2463   TIM_TIME_REF          time_now;
2464   XTM_AP_BASE_DATA_REF  appl_data_ref;
2465 
2466 
2467   /* Code. */
2468 
2469   appl_data_ref = (XTM_AP_BASE_DATA_REF) user_data;
2470 
2471 
2472   if( appl_data_ref -> custom_data -> debug_mode )
2473     printf( "UpdateCB called\n" );
2474 
2475   /* If our parent process is 1 the our real parent died. */
2476   parent_id = getppid();
2477   if( parent_id <= 1 )
2478     terminateCB( SIGTERM, (void *) appl_data_ref );
2479 
2480   time_now = TimLocalTime( TimMakeTimeNow() );
2481 
2482   /* Has the date changed (over midnight)? */
2483   if( TimIsSameDate( appl_data_ref -> current_date, time_now ) != TIM_YES ) {
2484 
2485     appl_data_ref -> current_date = time_now;
2486 
2487     new_day = True;
2488   }
2489 
2490 
2491   /* If this is a new day, cancel all 'no more' entries. */
2492   if( new_day ) {
2493     for( index = 0; index < MAX_ENTRIES_IGNORE; index++ )
2494       appl_data.ignore_entry[ index ].id = 0;
2495   }
2496 
2497 
2498   /* Did any of our databases change since last checked? */
2499   for( index = 0; index < MAX_DATABASE_CHECK; index++ ) {
2500 
2501     Boolean          ok;
2502     char             buffer[ 200 ];
2503     struct stat      file_status;
2504     XTM_DB_STATUS    db_status;
2505     XTM_CD_CAL_INFO  db_info;
2506 
2507     if( appl_data_ref -> db_check[ index ].db_name[ 0 ] == '\0' )
2508       continue;
2509 
2510     if( appl_data_ref -> custom_data -> debug_mode )
2511       printf( "Check db changed: '%s'\n",
2512               appl_data_ref -> db_check[ index ].db_name );
2513 
2514     /* Fetch complete information for the database. */
2515     ok = xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
2516                             appl_data_ref -> db_check[ index ].db_name,
2517                             &db_info, NULL );
2518     if( ! ok )
2519       continue;
2520 
2521     /* Build the file name for the database. */
2522     sprintf( buffer, "%s/%s",
2523              db_info.directory, DATABASE_FILE );
2524 
2525     /* If the database changed, fetch new information. */
2526     db_status = xtmDbFetchFileInfo( buffer, &file_status );
2527 
2528     if( new_day ||
2529         (db_status == XTM_DB_OK &&
2530          file_status.st_mtime !=
2531          appl_data_ref -> db_check[ index ].last_modified) ) {
2532 
2533       fetchAlarms( appl_data_ref, &db_info );
2534 
2535       appl_data_ref -> db_check[ index ].last_modified =
2536         file_status.st_mtime;
2537     }
2538 
2539   } /* loop */
2540 
2541 
2542   /* Check if any alarms to give? */
2543   checkAlarms( appl_data_ref, time_now );
2544 
2545 
2546   return;
2547 
2548 } /* updateCB */
2549 
2550 
2551 /*----------------------------------------------------------------------*/
2552 
2553 static void
terminateCB(int this_signal,void * user_data)2554   terminateCB( int   this_signal,
2555                void  *user_data )
2556 {
2557 
2558   /* Variables. */
2559   XTM_AP_BASE_DATA_REF  appl_data_ref;
2560 
2561 
2562   /* Code. */
2563 
2564   appl_data_ref = (XTM_AP_BASE_DATA_REF) user_data;
2565 
2566   if( appl_data_ref -> cmd_pipe_ref != -1 ) {
2567     close( appl_data_ref -> cmd_pipe_ref );
2568 
2569     (void) unlink( appl_data_ref -> cmd_pipe_id );
2570   }
2571 
2572   exit( 0 );
2573 
2574 } /* terminateCB */
2575