Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / server / lookup.c
1 /* $XConsortium: lookup.c /main/4 1995/11/09 12:46:28 rswiston $ */
2 /*
3  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
4  *  (c) Copyright 1993, 1994 International Business Machines Corp.
5  *  (c) Copyright 1993, 1994 Novell, Inc.
6  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
7  */
8
9 #include <EUSCompat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <signal.h>
14 #include <sys/stat.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <pwd.h>
18 #include <time.h>
19 #include <values.h>
20 #ifdef SunOS
21 #include <sys/systeminfo.h>
22 #endif
23 #include "attr.h"
24 #include "cmscalendar.h"
25 #include "lookup.h"
26 #include "cm.h"
27 #include "tree.h"
28 #include "list.h"
29 #include "iso8601.h"
30 #include "rerule.h"
31 #include "reutil.h"
32 #include "access.h"
33 #include "cmsmatch.h"
34 #include "cmsdata.h"
35 #include "cmsentry.h"
36 #include "repeat.h"
37 #include "v5ops.h"
38 #include "misc.h"
39
40 #define TIME_BUF_LEN    20
41
42 /******************************************************************************
43  * forward declaration of static functions used within the file
44  ******************************************************************************/
45 static CSA_return_code _AddToLinkedEntries(cms_entry *eptr, cms_entry **head,
46                                         cms_entry **tail, boolean_t sort, boolean_t time_only);
47 static CSA_return_code _EnumerateSequence(char *sender, uint access,
48                                         List_node *lnode, time_t start1,
49                                         time_t start2,
50                                         boolean_t no_end_time_range, time_t end1,
51                                         time_t end2, CSA_uint32 num_attrs,
52                                         cms_attribute *attrs, CSA_enum *ops,
53                                         cms_entry **head, cms_entry **tail);
54 static CSA_return_code _GetEntryAttrsByName(_DtCmsCalendar *cal,
55                                         cms_entry *entry, uint num_names,
56                                         cms_attr_name *names, uint *num_attrs_r,
57                                         cms_attribute **attrs_r);
58 static CSA_return_code _GetAllEntryAttrs(cms_entry *entry, uint *num_attrs_r,
59                                         cms_attribute **attrs_r);
60
61 /*****************************************************************************
62  * extern functions used in the library
63  *****************************************************************************/
64
65 extern CSA_return_code
66 _DtCmsLookupEntriesById(
67         _DtCmsCalendar  *cal,
68         char            *sender,
69         uint            access,
70         boolean_t       no_start_time_range,
71         boolean_t       no_end_time_range,
72         time_t          start1,
73         time_t          start2,
74         time_t          end1,
75         time_t          end2,
76         long            id,
77         CSA_uint32      num_attrs,
78         cms_attribute   *attrs,
79         CSA_enum        *ops,
80         cms_entry       **entries)
81 {
82         CSA_return_code stat = CSA_SUCCESS;
83         CSA_return_code stat2 = CSA_SUCCESS;
84         cms_entry       *eptr, *head = NULL, *tail = NULL;
85         cms_key         key;
86         time_t          endtick;
87         cms_attribute   *aptr;
88
89         if (no_start_time_range) {
90                 start1 = _DtCM_BOT;
91                 start2 = _DtCM_EOT;
92         }
93
94         /* do lookup on repeating entries first */      
95         stat = _DtCmsEnumerateSequenceById(cal, sender, access,
96                 no_start_time_range, no_end_time_range, start1, start2,
97                 end1, end2, id, num_attrs, attrs, ops, &head);
98         
99         if (stat != CSA_X_DT_E_ENTRY_NOT_FOUND) {
100                 if (stat == CSA_SUCCESS)
101                         *entries = head;
102                 return (stat);
103         }
104
105         key.time = start1;
106         key.id = id;
107         *entries = NULL;
108         while ((eptr = (cms_entry *)rb_lookup_next_larger(cal->tree,
109             (caddr_t)&key)) && eptr->key.time < start2) {
110                 if (eptr->key.id != id) {
111                         key.time = eptr->key.time;
112                         key.id = eptr->key.id;
113                 } else {
114                         aptr = &eptr->attrs[CSA_ENTRY_ATTR_END_DATE_I];
115                         if (!no_end_time_range) {
116                                 if (aptr->value == NULL)
117                                         return (CSA_SUCCESS);
118
119                                 _csa_iso8601_to_tick(
120                                         aptr->value->item.date_time_value,
121                                         &endtick);
122
123                                 if (endtick <= end1 || endtick >= end2)
124                                         return (CSA_SUCCESS);
125                         }
126                         
127                         if (_DtCmsMatchAttributes(eptr, num_attrs, attrs, ops)
128                             && ( ((stat2 = _DtCmsCheckViewAccess(sender, access, eptr)) == CSA_SUCCESS) || (stat2 == CSA_E_TIME_ONLY) ) ) {
129                                 stat = _AddToLinkedEntries(eptr, &head, &tail,
130                                         B_FALSE, B_FALSE);
131                         }
132                         *entries = head;
133                         return (stat);
134                 }
135         }
136
137         return (CSA_SUCCESS);
138 }
139
140 extern CSA_return_code
141 _DtCmsLookupEntries(
142         _DtCmsCalendar  *cal,
143         char            *sender,
144         uint            access,
145         time_t          start1,
146         time_t          start2,
147         boolean_t       no_end_time_range,
148         time_t          end1,
149         time_t          end2,
150         CSA_uint32      num_attrs,
151         cms_attribute   *attrs,
152         CSA_enum        *ops,
153         cms_entry       **entries)
154 {
155         CSA_return_code stat = CSA_SUCCESS;
156         CSA_return_code stat2 = CSA_SUCCESS;
157         cms_entry       *eptr, *head = NULL, *tail = NULL;
158         cms_key         key;
159         List_node       *lnode;
160         time_t          endtick;
161         cms_attribute   *aptr;
162
163         /* do lookup on one-time entries first */
164         key.time = start1;
165         key.id = 0;
166         while ((eptr = (cms_entry *)rb_lookup_next_larger(cal->tree,
167             (caddr_t)&key)) && eptr->key.time < start2) {
168
169                 aptr = &eptr->attrs[CSA_ENTRY_ATTR_END_DATE_I];
170
171                 if (!no_end_time_range) {
172                         if (aptr->value == NULL)
173                                 goto nextone;
174
175                         _csa_iso8601_to_tick(aptr->value->item.date_time_value,
176                                 &endtick);
177
178                         if (endtick <= end1 || endtick >= end2)
179                                 goto nextone;
180                 }
181
182                 if (_DtCmsMatchAttributes(eptr, num_attrs, attrs, ops) &&
183                     _DtCmsCheckViewAccess(sender, access, eptr) == CSA_SUCCESS)
184                 {
185                         /* the last argument "sort" is set to B_FALSE,
186                          * because the entries are in order already
187                          * as we get them out from the tree;
188                          * we don't want to sort it again
189                          */
190                         if ((stat = _AddToLinkedEntries(eptr, &head, &tail,
191                             B_FALSE, B_FALSE)) != CSA_SUCCESS)
192                                 break;
193                 }
194
195 nextone:
196                 key.time = eptr->key.time;
197                 key.id = eptr->key.id;
198         }
199
200         /* do lookup on repeating entries */    
201         lnode = cal->list->root;
202         while (lnode != NULL && stat == CSA_SUCCESS) {
203
204                 stat = _EnumerateSequence(sender, access, lnode, start1, start2,
205                         no_end_time_range, end1, end2, num_attrs, attrs,
206                         ops, &head, &tail);
207
208                 lnode = hc_lookup_next(lnode);
209         }
210
211         if (stat == CSA_SUCCESS)
212                 *entries = head;
213         else if (head)
214                 _DtCm_free_cms_entries(head);
215
216         return (stat);
217 }
218
219 extern CSA_return_code
220 _DtCmsEnumerateSequenceById(
221         _DtCmsCalendar  *cal,
222         char            *sender,
223         uint            access,
224         boolean_t       no_start_time_range,
225         boolean_t       no_end_time_range,
226         time_t          start1,
227         time_t          start2,
228         time_t          end1,
229         time_t          end2,
230         long            id,
231         CSA_uint32      num_attrs,
232         cms_attribute   *attrs,
233         CSA_enum        *ops,
234         cms_entry       **entries)
235 {
236         CSA_return_code stat;
237         cms_entry       *head = NULL, *tail = NULL;
238         cms_key         key;
239         List_node       *lnode;
240
241         key.id = id;
242         lnode = hc_lookup_node(cal->list, (caddr_t)&key);
243         if (lnode == NULL)
244                 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
245
246         if ( ((stat = _DtCmsCheckViewAccess(sender, access,
247             (cms_entry *)lnode->data)) != CSA_SUCCESS) && (stat != CSA_E_TIME_ONLY) )
248                 return (stat);
249
250         *entries = NULL;
251         if (no_start_time_range && no_end_time_range) {
252                 if (_DtCmsMatchAttributes((cms_entry *)lnode->data, num_attrs,
253                     attrs, ops)) {
254                         stat = _DtCmsGetCmsEntryForClient(
255                                 (cms_entry *)lnode->data, entries,B_FALSE);
256                 }
257         } else {
258                 stat = _EnumerateSequence(sender, access, lnode, start1, start2,
259                         no_end_time_range, end1, end2, num_attrs, attrs, ops,
260                         &head, &tail);
261
262                 if (stat == CSA_SUCCESS)
263                         *entries = head;
264                 else if (head)
265                         _DtCm_free_cms_entries(head);
266         }
267
268         return (stat);
269 }
270
271 extern CSA_return_code
272 _DtCmsLookupEntriesByKey(
273         _DtCmsCalendar  *cal,
274         char            *user,
275         uint            access,
276         uint            num_keys,
277         cms_key         *keys,
278         uint            num_names,
279         cms_attr_name   *names,
280         cms_get_entry_attr_res_item **res)
281 {
282         CSA_return_code                 stat = CSA_SUCCESS;
283         cms_get_entry_attr_res_item     *eptr, *head;
284         int                             i;
285
286         for (i = 0, head = NULL; i < num_keys; i++) {
287                 if ((stat = _DtCmsGetEntryAttrByKey(cal, user, access, keys[i],
288                     num_names, names, NULL, &eptr)) == CSA_SUCCESS) {
289                         eptr->next = head;
290                         head = eptr;
291                 } else {
292                         if (head) _DtCmsFreeEntryAttrResItem(head);
293                         return (stat);
294                 }
295         }
296
297         *res = head;
298         return (CSA_SUCCESS);
299 }
300
301 /*
302  * this routine returns either a cms_entry or 
303  * an cms_get_entry_attr_res_item structure
304  * depending which output argument is not null
305  */
306 extern CSA_return_code
307 _DtCmsGetEntryAttrByKey(
308         _DtCmsCalendar  *cal,
309         char            *user,
310         uint            access,
311         cms_key         key,
312         uint            num_names,
313         cms_attr_name   *names,
314         cms_entry       **entry_r,
315         cms_get_entry_attr_res_item **res_r)
316 {
317         CSA_return_code stat;
318         CSA_return_code stat2;
319         cms_entry       *entry = NULL;
320         char            *stime, *etime;
321         char            sbuf[TIME_BUF_LEN], ebuf[TIME_BUF_LEN];
322         time_t          firsttick = 0;
323         List_node       *lnode;
324         cms_get_entry_attr_res_item *res;
325
326         if (entry_r == NULL && res_r == NULL)
327                 return (CSA_E_INVALID_PARAMETER);
328
329         if (res_r && (res = (cms_get_entry_attr_res_item *)calloc(1,
330             sizeof(cms_get_entry_attr_res_item))) == NULL)
331                 return (CSA_E_INSUFFICIENT_MEMORY);
332
333         /* do lookup on one-time entries first */
334         if ((entry = (cms_entry *)rb_lookup(cal->tree, (caddr_t)&key)) == NULL)
335         {
336                 if ((lnode = (List_node *)hc_lookup_node(cal->list,
337                     (caddr_t)&key)) != NULL)
338                 {
339                         entry = (cms_entry *)lnode->data;
340                         if (_DtCmsInExceptionList(entry, key.time))
341                                 entry = NULL;
342                 }
343         }
344
345         if ( (entry == NULL) || ( ((stat2 = _DtCmsCheckViewAccess(user, access, entry)) != CSA_SUCCESS) && (stat2 != CSA_E_TIME_ONLY)) ) {
346                 if (entry == NULL)
347                         stat = CSA_X_DT_E_ENTRY_NOT_FOUND;
348                 else
349                         stat = CSA_E_NO_AUTHORITY;
350
351                 if (entry_r)
352                         return (stat);
353                 else {
354                         res->stat = stat;
355                         *res_r = res;
356                         return (CSA_SUCCESS);
357                 }
358         }
359
360         if (entry->key.time != key.time) {
361                 /* set start and end time of the instance */
362                 firsttick = entry->key.time;
363                 entry->key.time = key.time;
364
365                 stime = entry->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
366                         item.date_time_value;
367                 _csa_tick_to_iso8601(key.time, sbuf);
368                 entry->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
369                         item.date_time_value = sbuf;
370
371                 if (entry->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
372                         etime = entry->attrs[CSA_ENTRY_ATTR_END_DATE_I].\
373                                 value->item.date_time_value;
374                         _csa_tick_to_iso8601(key.time + lnode->duration, ebuf);
375                         entry->attrs[CSA_ENTRY_ATTR_END_DATE_I].value->\
376                                 item.date_time_value = ebuf;
377                 }
378         }
379
380         if (entry_r)
381                 stat = _DtCmsGetCmsEntryForClient(entry, entry_r,B_FALSE);
382         else {
383                 if (num_names == 0)
384                         stat = _GetAllEntryAttrs(entry, &res->num_attrs,
385                                 &res->attrs);
386                 else
387                         stat = _GetEntryAttrsByName(cal, entry, num_names,
388                                 names, &res->num_attrs, &res->attrs);
389
390                 if (stat == CSA_SUCCESS) {
391                         res->key = key;
392                         *res_r = res;
393                 } else
394                         free(res);
395         }
396
397         if (firsttick > 0) {
398                 entry->key.time = firsttick;
399                 entry->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
400                         item.date_time_value = stime;
401                 if (entry->attrs[CSA_ENTRY_ATTR_END_DATE_I].value)
402                         entry->attrs[CSA_ENTRY_ATTR_END_DATE_I].value->\
403                                 item.date_time_value = etime;
404         }
405
406         return (stat);
407 }
408
409 /*****************************************************************************
410  * static functions used within the file
411  *****************************************************************************/
412
413 static CSA_return_code
414 _AddToLinkedEntries(
415         cms_entry       *eptr,
416         cms_entry       **head,
417         cms_entry       **tail,
418         boolean_t       sort,
419         boolean_t       time_only)
420 {
421         CSA_return_code stat;
422         cms_entry       *newptr, *prev, *ptr;
423
424         if ((stat = _DtCmsGetCmsEntryForClient(eptr, &newptr,time_only)) != CSA_SUCCESS)
425                 return (stat);
426
427         if (sort == B_FALSE) {
428                 /* just add to the end of the list */
429
430                 if ((*head) == NULL)
431                         *head = newptr;
432                 else
433                         (*tail)->next = newptr;
434
435                 *tail = newptr;
436         } else {
437                 /* add item in ascending order */
438                 for (prev = NULL, ptr = *head; ptr != NULL;
439                     prev = ptr, ptr = ptr->next) {
440                         if (eptr->key.time <= ptr->key.time)
441                                 break;
442                 }
443
444                 newptr->next = ptr;
445                 if (prev == NULL)
446                         *head = newptr;
447                 else
448                         prev->next = newptr;
449
450                 if ((*tail) == prev)
451                         *tail = newptr;
452         }
453
454         return (CSA_SUCCESS);
455 }
456
457 static CSA_return_code
458 _EnumerateSequence(
459         char            *sender,
460         uint            access,
461         List_node       *lnode,
462         time_t          start1,
463         time_t          start2,
464         boolean_t       no_end_time_range,
465         time_t          end1,
466         time_t          end2,
467         CSA_uint32      num_attrs,
468         cms_attribute   *attrs,
469         CSA_enum        *ops,
470         cms_entry       **head,
471         cms_entry       **tail)
472 {
473         CSA_return_code stat = CSA_SUCCESS;
474         CSA_return_code stat2 = CSA_SUCCESS;
475         cms_entry       *eptr;
476         time_t          fsttick, tick;
477         RepeatEventState *restate;
478
479         eptr = (cms_entry *)lnode->data;
480         fsttick = eptr->key.time;
481
482         if (lnode->lasttick == 0) {
483                 lnode->lasttick = LastTick(fsttick, lnode->re);
484                 lnode->duration = _DtCmsGetDuration(eptr);
485         }
486
487         if (lnode->lasttick <= start1 || fsttick >= start2 ||
488             (!no_end_time_range &&
489              eptr->attrs[CSA_ENTRY_ATTR_END_DATE_I].value == NULL) ||
490             (!no_end_time_range && (lnode->lasttick+lnode->duration) <= end1) ||
491             (!no_end_time_range && (fsttick + lnode->duration) >= end2) ||
492             _DtCmsCheckViewAccess(sender, access, eptr) ||
493             !_DtCmsMatchAttributes(eptr, num_attrs, attrs, ops))
494                 return (CSA_SUCCESS);
495
496         if (!no_end_time_range && start1 < (end1 - lnode->duration))
497                 start1 = end1 - lnode->duration;
498
499         if (!no_end_time_range && ((end2 - lnode->duration) < start2))
500                 start2 = end2 - lnode->duration;
501
502         for (tick = ClosestTick(start1, fsttick, lnode->re, &restate);
503             stat == CSA_SUCCESS && tick < start2;
504             tick = NextTick(tick, fsttick, lnode->re, restate))
505         {
506                 char *stime, *etime;
507                 char sbuf[TIME_BUF_LEN], ebuf[TIME_BUF_LEN];
508
509                 if (tick <= 0 || tick > lnode->lasttick)
510                         break;
511
512                 if (tick <= start1 || _DtCmsInExceptionList(eptr, tick))
513                         continue;
514
515                 /* set start and end time of the instance */
516                 eptr->key.time = tick;
517
518                 stime = eptr->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
519                         item.date_time_value;
520                 _csa_tick_to_iso8601(tick, sbuf);
521                 eptr->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
522                         item.date_time_value = sbuf;
523
524                 if (eptr->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
525                         etime = eptr->attrs[CSA_ENTRY_ATTR_END_DATE_I].\
526                                 value->item.date_time_value;
527                         _csa_tick_to_iso8601(tick + lnode->duration, ebuf);
528                         eptr->attrs[CSA_ENTRY_ATTR_END_DATE_I].value->\
529                                 item.date_time_value = ebuf;
530                 }
531
532                 stat = _AddToLinkedEntries(eptr, head, tail, B_TRUE,B_FALSE);
533
534                 eptr->key.time = fsttick;
535                 eptr->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
536                         item.date_time_value = stime;
537                 if (eptr->attrs[CSA_ENTRY_ATTR_END_DATE_I].value)
538                         eptr->attrs[CSA_ENTRY_ATTR_END_DATE_I].value->\
539                                 item.date_time_value = etime;
540         }
541
542         return (stat);
543 }
544
545 static CSA_return_code
546 _GetEntryAttrsByName(
547         _DtCmsCalendar  *cal,
548         cms_entry       *entry,
549         uint            num_names,
550         cms_attr_name   *names,
551         uint            *num_attrs_r,
552         cms_attribute   **attrs_r)
553 {
554         CSA_return_code stat = CSA_SUCCESS;
555         cms_attribute   *attrs;
556         int             i;
557
558         if ((attrs = calloc(1, sizeof(cms_attribute)*num_names)) == NULL)
559                 return (CSA_E_INSUFFICIENT_MEMORY);
560
561         /* return all attrs names with hash number
562          * so that caller knows which one does not
563          * have value and which one does not even exist
564          */
565         for (i = 0; i < num_names && stat == CSA_SUCCESS; i++) {
566                 if (names[i].name == NULL)
567                         continue;
568
569                 if (names[i].num <= 0)
570                         names[i].num = _DtCm_get_index_from_table(
571                                         cal->entry_tbl, names[i].name);
572
573                 if (names[i].num > 0) {
574                         stat = _DtCm_copy_cms_attribute(&attrs[i],
575                             &entry->attrs[names[i].num], B_TRUE);
576                 } else {
577                         attrs[i].name.num = -1;
578                         if ((attrs[i].name.name = strdup(names[i].name))==NULL)
579                                 stat = CSA_E_INSUFFICIENT_MEMORY;
580                 }
581         }
582
583         if (stat == CSA_SUCCESS) {
584                 *num_attrs_r = num_names;
585                 *attrs_r = attrs;
586         } else {
587                 _DtCm_free_cms_attributes(i, attrs);
588                 free(attrs);
589         }
590
591         return (stat);
592 }
593
594 static CSA_return_code
595 _GetAllEntryAttrs(
596         cms_entry       *entry,
597         uint            *num_attrs_r,
598         cms_attribute   **attrs_r)
599 {
600         CSA_return_code stat = CSA_SUCCESS;
601         cms_attribute   *attrs;
602         int             i, j;
603
604         if ((attrs = calloc(1, sizeof(cms_attribute)*entry->num_attrs)) == NULL)
605                 return (CSA_E_INSUFFICIENT_MEMORY);
606
607         /* first element is not used */
608         for (i = 1, j = 0; i <= entry->num_attrs && stat == CSA_SUCCESS; i++) {
609                 if (entry->attrs[i].value) {
610                         if ((stat = _DtCm_copy_cms_attribute(&attrs[j],
611                             &entry->attrs[i], B_TRUE))
612                             == CSA_SUCCESS)
613                         {
614                                 j++;
615                         }
616                 }
617         }
618
619         if (stat == CSA_SUCCESS) {
620                 if (j > 0) {
621                         *num_attrs_r = j;
622                         *attrs_r = attrs;
623                 } else {
624                         *num_attrs_r = 0;
625                         *attrs_r = NULL;
626                         free(attrs);
627                 }
628         } else {
629                 _DtCm_free_cms_attributes(j, attrs);
630                 free(attrs);
631         }
632
633         return (stat);
634 }
635
636