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