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