1 /*----------------------------------------------------------------------------
2 --
3 --  Module:           xtmDbMisc
4 --
5 --  Project:          Xdiary
6 --  System:           xtm - X Desktop Calendar
7 --    Subsystem:      <>
8 --    Function block: <>
9 --
10 --  Description:
11 --    High-level interface to the diary database. Provides functions that
12 --    work on databses with include lists.
13 --
14 --  Filename:         xtmDbMisc.c
15 --
16 --  Authors:          Roger Larsson, Ulrika Bornetun
17 --  Creation date:    1992-01-09
18 --
19 --
20 --  (C) Copyright Ulrika Bornetun, Roger Larsson (1995)
21 --      All rights reserved
22 --
23 --  Permission to use, copy, modify, and distribute this software and its
24 --  documentation for any purpose and without fee is hereby granted,
25 --  provided that the above copyright notice appear in all copies. Ulrika
26 --  Bornetun and Roger Larsson make no representations about the usability
27 --  of this software for any purpose. It is provided "as is" without express
28 --  or implied warranty.
29 ----------------------------------------------------------------------------*/
30 
31 /* SCCS module identifier. */
32 static char SCCSID[] = "@(#) Module: xtmDbMisc.c, Version: 1.1, Date: 95/02/18 15:52:09";
33 
34 
35 /*----------------------------------------------------------------------------
36 --  Include files
37 ----------------------------------------------------------------------------*/
38 
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43 
44 #include <X11/Intrinsic.h>
45 #include <X11/cursorfont.h>
46 
47 #include <Xm/Xm.h>
48 
49 #include "System.h"
50 #include "LstLinked.h"
51 #include "Message.h"
52 #include "TimDate.h"
53 
54 #include "msgXdiary.h"
55 #include "xtmGlobal.h"
56 #include "xtmAccBase.h"
57 #include "xtmCalDb.h"
58 #include "xtmCustBase.h"
59 #include "xtmDbTools.h"
60 #include "xitError.h"
61 #include "xitTools.h"
62 #include "xtmDbMisc.h"
63 
64 
65 /*----------------------------------------------------------------------------
66 --  Macro definitions
67 ----------------------------------------------------------------------------*/
68 
69 /* Priorities. */
70 #define  PRIO_TAG             (1<<0)
71 #define  PRIO_NOTE_NOT_DONE   (1<<1)
72 #define  PRIO_IMPORTANT       (1<<2)
73 
74 
75 /*----------------------------------------------------------------------------
76 --  Type declarations
77 ----------------------------------------------------------------------------*/
78 
79 
80 /*----------------------------------------------------------------------------
81 --  Global definitions
82 ----------------------------------------------------------------------------*/
83 
84 /* Name of module. */
85 static char  *module_name = "xtmDbMisc";
86 
87 
88 /*----------------------------------------------------------------------------
89 --  Function prototypes
90 ----------------------------------------------------------------------------*/
91 
92 static void
93   checkEntries( XTM_GL_BASE_DATA_REF  appl_data_ref,
94                 char                  *db_name,
95                 TIM_TIME_REF          date,
96                 int                   days,
97                 Boolean               show_standing,
98                 Boolean               entry_defined[] );
99 
100 static void
101   deleteEntryCB( void  *element );
102 
103 static LST_COMPARE
104   entrySortFunc( XTM_DB_ALL_ENTRY_REF  list_entry_ref,
105                  XTM_DB_ALL_ENTRY_REF  search_entry_ref );
106 
107 static XTM_DB_STATUS
108   fetchFilteredEntriesDay( XTM_GL_BASE_DATA_REF  appl_data_ref,
109                            char                  *db_name,
110                            UINT32                flags,
111                            XtAppContext          context,
112                            Widget                workW,
113                            TIM_TIME_REF          starts,
114                            TIM_TIME_REF          ends,
115                            XTM_DM_FILTER_REC     *filter_ref,
116                            LST_DESC_TYPE         entries );
117 
118 static Boolean
119   searchString( char     *search_string,
120                 Boolean  case_sens1,
121                 char     *in_string,
122                 Boolean  case_sens2 );
123 
124 
125 
126 /*----------------------------------------------------------------------------
127 --  Functions
128 ----------------------------------------------------------------------------*/
129 
130 void
xtmDmDeleteEntriesList(LST_DESC_TYPE entries)131   xtmDmDeleteEntriesList( LST_DESC_TYPE entries )
132 {
133 
134   /* Code. */
135 
136   LstLinkClearDataAndList( entries, deleteEntryCB );
137 
138 
139   return;
140 
141 } /* xtmDmDeleteEntriesList */
142 
143 
144 /*----------------------------------------------------------------------*/
145 
146 Boolean
xtmDmDeleteEntry(Widget parentW,XTM_DB_ENTRY_DATABASES * database,UINT32 entry_id)147   xtmDmDeleteEntry( Widget                  parentW,
148                     XTM_DB_ENTRY_DATABASES  *database,
149                     UINT32                  entry_id )
150 {
151 
152   /* Variables. */
153   XTM_DB_STATUS  db_status;
154 
155 
156   /* Code. */
157 
158   /* Delete the entry. */
159   db_status = xtmDbDeleteEntry( database, entry_id );
160 
161   if( db_status != XTM_DB_OK ) {
162     xitErMessage( parentW, XIT_ER_ERROR,
163                   module_name, "xtmDmDeleteEntry",
164                   msgGetText( MXDI_ERRMSG_DELETE_ENTRY ) );
165 
166     return( False );
167   }
168 
169 
170   return( True );
171 
172 } /* xtmDmDeleteEntry */
173 
174 
175 /*----------------------------------------------------------------------*/
176 
177 Boolean
xtmDmFetchEntry(Widget parentW,XTM_DB_ENTRY_DATABASES * database,UINT32 entry_id,XTM_DB_ALL_ENTRY_REF entry_ref,char ** entry_text)178   xtmDmFetchEntry( Widget                  parentW,
179                    XTM_DB_ENTRY_DATABASES  *database,
180                    UINT32                  entry_id,
181                    XTM_DB_ALL_ENTRY_REF    entry_ref,
182                    char                    **entry_text )
183 {
184 
185   /* Variables. */
186   XTM_DB_STATUS  db_status;
187 
188 
189   /* Code. */
190 
191   /* Fetch the entry. */
192   db_status = xtmDbFetchEntry( database,  entry_id,
193                                entry_ref, entry_text );
194 
195   if( db_status != XTM_DB_OK ) {
196     xitErMessage( parentW, XIT_ER_ERROR,
197                   module_name, "xtmDmFetchEntry",
198                   msgGetText( MXDI_NO_ENTRY ) );
199 
200     return( False );
201   }
202 
203 
204   return( True );
205 
206 } /* xtmDmFetchEntry */
207 
208 
209 /*----------------------------------------------------------------------*/
210 
211 XTM_DB_STATUS
xtmDmFetchFilteredEntriesRange(XTM_GL_BASE_DATA_REF appl_data_ref,char * db_name,XtAppContext context,Widget parent,TIM_TIME_REF starts,TIM_TIME_REF ends,UINT32 flags,XTM_DM_FILTER_REC * filter_ref,LST_DESC_TYPE * entries)212   xtmDmFetchFilteredEntriesRange( XTM_GL_BASE_DATA_REF  appl_data_ref,
213                                   char                  *db_name,
214                                   XtAppContext          context,
215                                   Widget                parent,
216                                   TIM_TIME_REF          starts,
217                                   TIM_TIME_REF          ends,
218                                   UINT32                flags,
219                                   XTM_DM_FILTER_REC     *filter_ref,
220                                   LST_DESC_TYPE         *entries )
221 {
222 
223   /* Variables. */
224   Boolean                 ok;
225   int                     index;
226   char                    buffer[ 100 ];
227   char                    *char_ref;
228   Cursor                  wait_cursor;
229   Widget                  workW = NULL;
230   TIM_DELTA_TYPE          delta;
231   XTM_DB_STATUS           db_status;
232   XTM_GL_CUSTOM_DATA_REF  custom_data;
233   XTM_CD_CAL_INFO         db_incl_info;
234   XTM_CD_CAL_INFO         db_info;
235   XTM_CD_INCL_CALS        db_incl;
236 
237 
238   /* Code. */
239 
240   custom_data = appl_data_ref -> custom_data;
241   *entries    = NULL;
242 
243   ok = xtmCdFetchNamedDb( custom_data -> cal_db_handle, db_name,
244                           &db_info, &db_incl );
245   if( ! ok )
246     return( XTM_DB_ERROR );
247 
248 
249   *entries = LstLinkNew( sizeof( XTM_DB_ALL_ENTRY_DEF ), NULL );
250 
251   /* Initialize search strings. */
252   if( flagIsClear( filter_ref -> flags, XTM_DM_FLAG_TEXT_CASE_SENS ) ) {
253     char_ref = filter_ref -> text_string;
254 
255     while( *char_ref != '\0' ) {
256       *char_ref = toupper( *char_ref );
257       char_ref++;
258     }
259   }
260 
261   if( flagIsClear( filter_ref -> flags, XTM_DM_FLAG_TAG_CASE_SENS ) ) {
262     char_ref = filter_ref -> tag_string;
263 
264     while( *char_ref != '\0' ) {
265       *char_ref = toupper( *char_ref );
266       char_ref++;
267     }
268   }
269 
270 
271   /* Display a working form? */
272   TimDelta( starts, ends, &delta );
273 
274   if( parent != NULL ) {
275     if( delta.days > 31 ) {
276       workW = xitCreateBusyDialog(
277                 parent, "WorkingDialog",
278                 msgGetText( MXDI_WORKING_TITLE ),
279                 msgGetText( MXDI_WORKING_MESSAGE ) );
280     } else {
281       wait_cursor = XCreateFontCursor( XtDisplay( parent ), XC_watch );
282       XDefineCursor( XtDisplay( parent ), XtWindow( parent ), wait_cursor );
283 
284       XFlush( XtDisplay( parent ) );
285     }
286   }
287 
288   /* Process the main database. */
289   db_status = fetchFilteredEntriesDay( appl_data_ref,
290                                        db_name, flags,
291                                        context, workW,
292                                        starts, ends,
293                                        filter_ref, *entries );
294   if( db_status != XTM_DB_OK )
295     raise exception;
296 
297   /* Process the included databases. */
298   if( db_status == XTM_DB_OK &&
299       db_incl.no > 0 &&
300       flagIsClear( flags, XTM_DB_FETCH_SKIP_INCLUDE ) ) {
301 
302     flagSet( flags, XTM_DB_FETCH_INCLUDE );
303 
304     for( index = 0; index < db_incl.no; index++ ) {
305 
306       /* Search the database info. */
307       ok = xtmCdFetchNamedDb( custom_data -> cal_db_handle,
308                               db_incl.db[ index ].name,
309                               &db_incl_info, NULL );
310       if( ! ok ) {
311         sprintf( buffer,
312                  msgGetText( MXDI_ERRMSG_FETCH_NAMED_DB ),
313                  db_incl_info.directory );
314 
315         xitErMessage( parent, XIT_ER_ERROR,
316                       module_name, "xtmDmFetchCompleteDay",
317                       buffer );
318         continue;
319       }
320 
321       /* We must have at least read access. */
322       if( ! flagIsSet( db_incl_info.operations, XTM_DB_FLAG_MODE_READ ) ) {
323         sprintf( buffer,
324                  msgGetText( MXDI_ERRMSG_NO_ACCESS_NAMED_DB ),
325                  db_incl_info.directory );
326 
327         xitErMessage( NULL, XIT_ER_ERROR,
328                       module_name, "xtmDmFetchCompleteDay",
329                       buffer );
330         continue;
331       }
332 
333       /* Fetch entries in the include database. */
334       db_status = fetchFilteredEntriesDay( appl_data_ref,
335                                            db_incl.db[ index ].name,
336                                            flags,
337                                            context, workW,
338                                            starts, ends,
339                                            filter_ref, *entries );
340       if( db_status != XTM_DB_OK )
341         raise exception;
342 
343     } /* loop */
344 
345   } /* if */
346 
347 
348   if( parent != NULL ) {
349     if( workW != NULL )
350       xitBusyDialogRemove( workW );
351     else
352       XUndefineCursor( XtDisplay( parent ), XtWindow( parent ) );
353   }
354 
355 
356   return( XTM_DB_OK );
357 
358 
359   /* Exception handler. */
360   exception:
361     if( workW != NULL )
362       xitBusyDialogRemove( workW );
363 
364     return( db_status );
365 
366 } /* xtmDmFetchFilteredEntriesRange */
367 
368 
369 /*----------------------------------------------------------------------*/
370 
371 Boolean
xtmDmInsertEntry(Widget parentW,XTM_DB_ENTRY_DATABASES * database,UINT32 entry_id,XTM_DB_ALL_ENTRY_REF entry_ref,char * entry_text)372   xtmDmInsertEntry( Widget                  parentW,
373                     XTM_DB_ENTRY_DATABASES  *database,
374                     UINT32                  entry_id,
375                     XTM_DB_ALL_ENTRY_REF    entry_ref,
376                     char                    *entry_text )
377 {
378 
379   /* Variables. */
380   UINT32             id;
381   XTM_DB_ID_REQUEST  id_request;
382   XTM_DB_STATUS      db_status;
383 
384 
385   /* Code. */
386 
387   /* Generate a new id for the entry. */
388   id_request.directory  = database -> database_dir;
389   id_request.operations = 0;
390   id_request.lock_file  = False;
391 
392   db_status = xtmDbGenerateId( &id_request, &id );
393   if( db_status != XTM_DB_OK )
394     xitErMessage( NULL, XIT_ER_FATAL,
395                   module_name, "xtmDmInsertEntry",
396                   msgGetText( MXDI_ERRMSG_GENERATE_ID ) );
397 
398   /* New data for entry to save. */
399   entry_ref -> entry.id       = id;
400   entry_ref -> stand_entry.id = id;
401 
402   /* Save the new entry. */
403   db_status = xtmDbInsertEntry( database,
404                                 entry_ref, entry_text );
405 
406   if( db_status != XTM_DB_OK )
407     xitErMessage( NULL, XIT_ER_FATAL,
408                   module_name, "xtmDmInsertEntry",
409                   msgGetText( MXDI_ERRMSG_INSERT_ENTRY ) );
410 
411 
412   return( True );
413 
414 } /* xtmDmInsertEntry */
415 
416 
417 /*----------------------------------------------------------------------*/
418 
419 void
xtmDmEntriesDefined(XTM_GL_BASE_DATA_REF appl_data_ref,char * db_name,TIM_TIME_REF date,int days,Boolean include_db,Boolean show_standing,Boolean entry_defined[])420   xtmDmEntriesDefined( XTM_GL_BASE_DATA_REF  appl_data_ref,
421                        char                  *db_name,
422                        TIM_TIME_REF          date,
423                        int                   days,
424                        Boolean               include_db,
425                        Boolean               show_standing,
426                        Boolean               entry_defined[] )
427 {
428 
429   /* Variables. */
430   Boolean                 ok;
431   int                     index;
432   XTM_GL_CUSTOM_DATA_REF  custom_data;
433   XTM_CD_CAL_INFO         db_incl_info;
434   XTM_CD_CAL_INFO         db_info;
435   XTM_CD_INCL_CALS        db_incl;
436 
437 
438   /* Code. */
439 
440   custom_data = appl_data_ref -> custom_data;
441 
442   for( index = 0; index < days; index++ )
443     entry_defined[ index ] = False;
444 
445 
446   /* Check the main database. */
447   checkEntries( appl_data_ref, db_name,
448                 date, days, show_standing, entry_defined );
449 
450 
451   /* Fetch the calendar information. */
452   (void) xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
453                             db_name,
454                             &db_info, &db_incl );
455 
456 
457   /* Check the included databases? */
458   if( db_incl.no == 0 || ! include_db )
459     return;
460 
461   for( index = 0; index < db_incl.no; index++ ) {
462     ok = xtmCdFetchNamedDb( custom_data -> cal_db_handle,
463                             db_incl.db[ index ].name,
464                             &db_incl_info, NULL );
465 
466     if( ! ok || flagIsSet( db_incl_info.flags, XTM_CD_FLAG_HIDE_IN_CAL ) )
467       continue;
468 
469     checkEntries( appl_data_ref,
470                   db_incl.db[ index ].name,
471                   date, days, show_standing, entry_defined );
472   } /* loop */
473 
474 
475   return;
476 
477 } /* xtmDmEntriesDefined */
478 
479 
480 /*----------------------------------------------------------------------*/
481 
482 Boolean
xtmDmOpenDatabase(XTM_GL_BASE_DATA_REF appl_data_ref,char * db_name,UINT32 access_mode,XTM_DB_ENTRY_DATABASES * database_ref)483   xtmDmOpenDatabase( XTM_GL_BASE_DATA_REF    appl_data_ref,
484                      char                    *db_name,
485                      UINT32                  access_mode,
486                      XTM_DB_ENTRY_DATABASES  *database_ref )
487 {
488 
489   /* Variables. */
490   Boolean              ok;
491   char                 buffer[ 200 ];
492   XTM_DB_OPEN_REQUEST  open_request;
493   XTM_DB_STATUS        db_status;
494   XTM_CD_CAL_INFO      db_info;
495 
496 
497   /* Code. */
498 
499   /* Fetch database information. */
500   ok = xtmCdFetchNamedDb( appl_data_ref -> custom_data -> cal_db_handle,
501                           db_name,
502                           &db_info, NULL );
503   if( ! ok )
504     return( False );
505 
506 
507   /* Do we have the necessary access? */
508   if( ! flagIsSet( db_info.operations, access_mode ) ) {
509     sprintf( buffer,
510              msgGetText( MXDI_ERRMSG_NO_ACCESS_NAMED_DB ),
511              db_info.short_name );
512 
513     xitMsgWinDisplayMessage( appl_data_ref -> msg_win_ref, buffer, 0 );
514     return( False );
515   }
516 
517 
518   /* Open the database to write the new entry. */
519   open_request.name       = db_info.short_name;
520   open_request.directory  = db_info.directory;
521   open_request.operations = access_mode;
522   open_request.database   = XTM_DB_ALL_ENTRY_DB;
523 
524   db_status = xtmDbOpenEntryDb( &open_request, database_ref );
525 
526   if( db_status != XTM_DB_OK ) {
527 
528     if( db_status == XTM_DB_LOCKED ) {
529       sprintf( buffer, "%s: %s",
530                db_info.short_name, msgGetText( MXDI_ERRMSG_DB_LOCKED ) );
531 
532       xitMsgWinDisplayMessage( appl_data_ref -> msg_win_ref, buffer, 0 );
533     } else {
534       sprintf( buffer, "%s: %s",
535                db_info.short_name, msgGetText( MXDI_ERRMSG_CANNOT_OPEN_DB ) );
536 
537       xitMsgWinDisplayMessage( appl_data_ref -> msg_win_ref, buffer, 0 );
538     }
539 
540     return( False );
541   }
542 
543 
544   return( True );
545 
546 } /* xtmDmOpenDatabase */
547 
548 
549 /*----------------------------------------------------------------------*/
550 
551 static void
checkEntries(XTM_GL_BASE_DATA_REF appl_data_ref,char * db_name,TIM_TIME_REF date,int days,Boolean show_standing,Boolean entry_defined[])552   checkEntries( XTM_GL_BASE_DATA_REF  appl_data_ref,
553                 char                  *db_name,
554                 TIM_TIME_REF          date,
555                 int                   days,
556                 Boolean               show_standing,
557                 Boolean               entry_defined[] )
558 {
559 
560   /* Variables. */
561   Boolean                 ok;
562   int                     index;
563   LST_DESC_TYPE           stand_entries[ 2 ];
564   TIM_TIME_REF            curr_date;
565   XTM_DB_ENTRY_DATABASES  database;
566 
567 
568   /* Code. */
569 
570   /* Open the database for this calendar. */
571   ok = xtmDmOpenDatabase( appl_data_ref,
572                           db_name, XTM_DB_FLAG_MODE_READ,
573                           &database );
574   if( ! ok )
575     return;
576 
577   /* Fetch all standing entries? */
578   stand_entries[ 0 ] = NULL;
579   stand_entries[ 1 ] = NULL;
580 
581   if( show_standing )
582     (void) xtmDbFetchStandEntries( &database,
583                                    &stand_entries[ 0 ],
584                                    &stand_entries[ 1 ] );
585 
586   /* Start the 1st of the month. */
587   curr_date = date;
588 
589   /* Check all days. */
590   for( index = 0; index < days; index++ ) {
591 
592     if( ! entry_defined[ index ] )
593       entry_defined[ index ] = xtmDbIsEntryDefined( &database,
594                                                     stand_entries, curr_date );
595     TimAddDays( &curr_date, 1 );
596 
597   } /* loop */
598 
599 
600   /* Free the standing entries. */
601   LstLinkClear( stand_entries[ 0 ] );
602   LstLinkClear( stand_entries[ 1 ] );
603 
604   /* Close the database again. */
605   xtmDbCloseEntryDb( &database );
606 
607 
608   return;
609 
610 } /* checkEntries */
611 
612 
613 /*----------------------------------------------------------------------*/
614 
615 static void
deleteEntryCB(void * element)616   deleteEntryCB( void  *element )
617 {
618 
619   /* Variables. */
620   XTM_DB_ALL_ENTRY_DEF  *entry_ref;
621 
622 
623   /* Code. */
624 
625   entry_ref = (XTM_DB_ALL_ENTRY_DEF *) element;
626 
627   if( entry_ref -> all_text != NULL )
628     SysFree( entry_ref -> all_text );
629 
630 
631   return;
632 
633 } /* deleteEntryCB */
634 
635 
636 /*----------------------------------------------------------------------*/
637 
638 static LST_COMPARE
entrySortFunc(XTM_DB_ALL_ENTRY_REF list_entry_ref,XTM_DB_ALL_ENTRY_REF search_entry_ref)639   entrySortFunc( XTM_DB_ALL_ENTRY_REF  list_entry_ref,
640                  XTM_DB_ALL_ENTRY_REF  search_entry_ref )
641 {
642 
643   /* Variables. */
644   UINT32  list_entry_prio   = 0;
645   UINT32  search_entry_prio = 0;
646   char    *list_tag;
647   char    *search_tag;
648 
649 
650   /* Code. */
651 
652   /* Correct day? */
653   if( search_entry_ref -> entry.date_stamp >
654       list_entry_ref   -> entry.date_stamp )
655     return( LST_NOT_EQUAL );
656 
657   if( search_entry_ref -> entry.date_stamp <
658       list_entry_ref   -> entry.date_stamp )
659     return( LST_EQUAL );
660 
661 
662 
663   /* Sort notes? */
664   if( search_entry_ref -> entry.entry_type == XTM_DB_DAY_NOTE ) {
665 
666     if( list_entry_ref -> entry.entry_type != XTM_DB_DAY_NOTE )
667       return( LST_EQUAL );
668 
669     /* Ranking for entry to insert. */
670     if( flagIsSet( search_entry_ref -> entry.flags, XTM_DB_FLAG_IMPORTANT ) )
671       flagSet( search_entry_prio, PRIO_IMPORTANT );
672 
673     if( flagIsClear( search_entry_ref -> entry.flags, XTM_DB_FLAG_NOTE_DONE ) )
674       flagSet( search_entry_prio, PRIO_NOTE_NOT_DONE );
675 
676     /* Ranking for entry in list. */
677     if( flagIsSet( list_entry_ref -> entry.flags, XTM_DB_FLAG_IMPORTANT ) )
678       flagSet( list_entry_prio, PRIO_IMPORTANT );
679 
680     if( flagIsClear( list_entry_ref -> entry.flags, XTM_DB_FLAG_NOTE_DONE ) )
681       flagSet( list_entry_prio, PRIO_NOTE_NOT_DONE );
682 
683     /* Tag priority. */
684     if( search_entry_ref -> entry.tag[ 0 ] == '\0' )
685       search_tag = "xxxx";
686     else
687       search_tag = search_entry_ref -> entry.tag;
688 
689     if( list_entry_ref -> entry.tag[ 0 ] == '\0' )
690       list_tag = "xxxx";
691     else
692       list_tag = list_entry_ref -> entry.tag;
693 
694     if( strcmp( search_tag, list_tag ) < 0 )
695       flagSet( search_entry_prio, PRIO_TAG );
696     else
697       flagSet( list_entry_prio, PRIO_TAG );
698 
699 
700     /* Insert the entry here? */
701     if( search_entry_prio > list_entry_prio )
702       return( LST_EQUAL );
703 
704 
705   /* Sort appointments? */
706   } else if( search_entry_ref -> entry.entry_type == XTM_DB_DAY_ENTRY ) {
707 
708     if( search_entry_ref -> entry.time_stamp <
709         list_entry_ref -> entry.time_stamp )
710       return( LST_EQUAL );
711 
712   } /* if */
713 
714 
715   return( LST_NOT_EQUAL );
716 
717 } /* entrySortFunc */
718 
719 
720 /*----------------------------------------------------------------------*/
721 
722 static XTM_DB_STATUS
fetchFilteredEntriesDay(XTM_GL_BASE_DATA_REF appl_data_ref,char * db_name,UINT32 flags,XtAppContext context,Widget workW,TIM_TIME_REF starts,TIM_TIME_REF ends,XTM_DM_FILTER_REC * filter_ref,LST_DESC_TYPE entries)723   fetchFilteredEntriesDay( XTM_GL_BASE_DATA_REF  appl_data_ref,
724                            char                  *db_name,
725                            UINT32                flags,
726                            XtAppContext          context,
727                            Widget                workW,
728                            TIM_TIME_REF          starts,
729                            TIM_TIME_REF          ends,
730                            XTM_DM_FILTER_REC     *filter_ref,
731                            LST_DESC_TYPE         entries )
732 {
733 
734   /* Variables. */
735   Boolean                 case_sens;
736   Boolean                 match;
737   Boolean                 ok;
738   int                     index;
739   UINT32                  filter;
740   char                    *char_ref;
741   TIM_TIME_REF            current_date;
742   XTM_DB_ALL_ENTRY_DEF    entry_record;
743   XTM_DB_ENTRY_DATABASES  database;
744   XTM_DB_STATUS           db_status;
745   LST_DESC_TYPE           list_ref[ 2 ];
746   LST_STATUS              lst_status;
747 
748 
749   /* Code. */
750 
751   /* Open the database for this calendar. */
752   ok = xtmDmOpenDatabase( appl_data_ref,
753                           db_name, XTM_DB_FLAG_MODE_READ,
754                           &database );
755   if( ! ok )
756     return( XTM_DB_ERROR );
757 
758 
759   filter       = filter_ref -> flags;
760   current_date = starts;
761 
762   /* Process all days. */
763   while( current_date <= ends ) {
764 
765     /* Fetch entries this day. */
766     flagSet( flags, (XTM_DB_FETCH_STANDING |
767                      XTM_DB_FETCH_STICKY |
768                      XTM_DB_FETCH_ALL_TEXT ) );
769 
770     db_status = xtmDbFetchEntriesInDay( &database, current_date, flags,
771                                         &list_ref[ 1 ], &list_ref[ 0 ] );
772 
773     if( db_status != XTM_DB_OK ) {
774       xtmDbCloseEntryDb( &database );
775 
776       return( XTM_DB_ERROR );
777     }
778 
779     /* Process the notes and entries. */
780     for( index = 0; index < 2; index++ ) {
781 
782       /* Any elements in the list? */
783       if( LstLinkElements( list_ref[ index ] ) > 0 ) {
784 
785         /* Process all the elements. */
786         lst_status = LstLinkCurrentFirst( list_ref[ index ] );
787         while( lst_status == LST_OK ) {
788 
789           XTM_DB_ENTRY_REF        entry_ref;
790           XTM_DB_STAND_ENTRY_REF  stand_entry_ref;
791 
792           lst_status = LstLinkGetCurrent( list_ref[ index ], &entry_record );
793 
794           entry_ref       = &entry_record.entry;
795           stand_entry_ref = &entry_record.stand_entry;
796 
797           match = False;
798 
799           if( flagIsSet( filter, XTM_DM_FLAG_ALL ) )
800             match = True;
801 
802           /* No other flags? */
803           if( flagIsSet( filter, ~ XTM_DM_FLAG_ALL ) ) {
804 
805             /* Pick type of entry. */
806             if( flagIsSet( filter, XTM_DM_FLAG_APPOINTMENTS ) &&
807                 entry_ref -> entry_type == XTM_DB_DAY_ENTRY )
808               match = True;
809 
810             if( flagIsSet( filter, XTM_DM_FLAG_NOTES ) &&
811                 entry_ref -> entry_type == XTM_DB_DAY_NOTE )
812               match = True;
813 
814 
815             /* Pick out all specialities. */
816             if( flagIsSet( filter, XTM_DM_FLAG_PRIVATE ) &&
817                 flagIsClear( entry_ref -> flags, XTM_DB_FLAG_PRIVATE ) )
818               match = False;
819 
820             if( flagIsSet( filter, XTM_DM_FLAG_IMPORTANT ) &&
821                 flagIsClear( entry_ref -> flags, XTM_DB_FLAG_IMPORTANT ) )
822               match = False;
823 
824             if( flagIsSet( filter, XTM_DM_FLAG_ALARMS ) &&
825                 flagIsClear( entry_ref -> flags, XTM_DB_FLAG_ALARM ) )
826               match = False;
827 
828             if( flagIsSet( filter, XTM_DM_FLAG_REPEATED ) &&
829                 entry_ref -> entry_category != XTM_DB_REP_ENTRY_LIST )
830               match = False;
831 
832             if( flagIsSet( filter, XTM_DM_FLAG_STICKY ) &&
833                 entry_ref -> entry_category != XTM_DB_STICKY_LIST )
834               match = False;
835 
836             if( entry_ref -> entry_type == XTM_DB_DAY_NOTE ) {
837               if( flagIsSet(   filter, XTM_DM_FLAG_DONE ) &&
838                   flagIsClear( filter, XTM_DM_FLAG_NOT_DONE ) &&
839                   flagIsClear( entry_ref -> flags, XTM_DB_FLAG_NOTE_DONE ) )
840                 match = False;
841 
842               if( flagIsSet(   filter, XTM_DM_FLAG_NOT_DONE ) &&
843                   flagIsClear( filter, XTM_DM_FLAG_DONE ) &&
844                   flagIsSet( entry_ref -> flags, XTM_DB_FLAG_NOTE_DONE ) )
845                 match = False;
846             }
847 
848 
849             /* Search in the entry text? */
850             if( match && flagIsSet( filter, XTM_DM_FLAG_SEARCH_TEXT ) ) {
851               case_sens = flagIsSet( filter, XTM_DM_FLAG_TEXT_CASE_SENS );
852 
853               if( entry_record.all_text != NULL )
854                 match = searchString( filter_ref -> text_string, True,
855                                       entry_record.all_text, case_sens );
856               else
857                 match = searchString( filter_ref -> text_string, True,
858                                       entry_ref -> text, case_sens );
859             }
860 
861             /* Search the tag? */
862             if( match && flagIsSet( filter, XTM_DM_FLAG_SEARCH_TAG ) ) {
863               case_sens = flagIsSet( filter, XTM_DM_FLAG_TAG_CASE_SENS );
864 
865               if( entry_ref -> tag[ 0 ] != '\0' )
866                 match = searchString( entry_ref -> tag, case_sens,
867                                       filter_ref -> tag_string, True );
868               else
869                 match = False;
870             }
871 
872           } /* if */
873 
874 
875           /* If there is a match, save the entry in the match list. */
876           if( match ) {
877 
878             /* The original will be freed when we delete list. */
879             if( entry_record.all_text != NULL ) {
880               char_ref = SysNewString( entry_record.all_text );
881 
882               entry_record.all_text = char_ref;
883 	    }
884 
885             /* Notes are inserted first in the day. */
886             if( entry_record.entry.entry_type == XTM_DB_DAY_NOTE )
887               entry_record.entry.time_stamp = 0;
888 
889             entry_record.entry.date_stamp = current_date;
890 
891             /* Insert the entry in the appointments list. */
892             lst_status = LstLinkSearchFirst(
893                            entries,
894                            &entry_record,
895                            (EQUALS_FUNC_TYPE) entrySortFunc );
896 
897             if( lst_status == LST_OK )
898               lst_status = LstLinkInsertCurrent( entries,
899                                                  &entry_record );
900             else
901               lst_status = LstLinkInsertLast( entries,
902 	  				      &entry_record );
903 
904           } /* if */
905 
906 
907           /* Next record. */
908           lst_status = LstLinkCurrentNext( list_ref[ index ] );
909 
910         } /* while */
911 
912       } /* if */
913 
914       /* Delete the database list. */
915       xtmDmDeleteEntriesList( list_ref[ index ] );
916 
917     } /* loop */
918 
919 
920     /* Did the user press the cancel button? */
921     if( workW != NULL ) {
922       if( xitBusyDialogCancelled( workW, context ) ) {
923         xtmDbCloseEntryDb( &database );
924 
925         return( XTM_DB_ERROR );
926       }
927     }
928 
929     /* The next day. */
930     TimAddDays( &current_date, 1 );
931 
932   } /* while */
933 
934   xtmDbCloseEntryDb( &database );
935 
936 
937   return( XTM_DB_OK );
938 
939 } /* fetchFilteredEntriesDay */
940 
941 
942 /*----------------------------------------------------------------------*/
943 
944 static Boolean
searchString(char * search_string,Boolean case_sens1,char * in_string,Boolean case_sens2)945   searchString( char     *search_string,
946                 Boolean  case_sens1,
947                 char     *in_string,
948                 Boolean  case_sens2 )
949 {
950 
951   /* Variables. */
952   char  *char_ref;
953   char  *new_in_string;
954   char  *new_search_string;
955 
956   /* Code. */
957 
958   new_search_string = SysNewString( search_string );
959   new_in_string     = SysNewString( in_string );
960 
961 
962   /* Convert to uppercase if not case sensitive. */
963   if( ! case_sens1 ) {
964     char_ref = new_search_string;
965 
966     while( *char_ref != '\0' ) {
967       *char_ref = toupper( *char_ref );
968       char_ref++;
969     }
970   }
971 
972   if( ! case_sens2 ) {
973     char_ref = new_in_string;
974 
975     while( *char_ref != '\0' ) {
976       *char_ref = toupper( *char_ref );
977       char_ref++;
978     }
979   }
980 
981   /* Search the string. */
982   char_ref = strstr( new_in_string, new_search_string );
983 
984   SysFree( new_search_string );
985   SysFree( new_in_string );
986 
987   if( char_ref == NULL )
988     return( False );
989 
990 
991   return( True );
992 
993 } /* searchString */
994