dtcm: Resolve CID 87822
[oweals/cde.git] / cde / programs / dtcm / server / rtable4.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: rtable4.c /main/5 1996/10/02 17:31:51 drk $ */
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 /*
32  * version 4 of calendar manager rpc protocol functions.
33  */
34
35 #include <EUSCompat.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <errno.h>
40 #include <time.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include "rtable4.h"
44 #include <sys/param.h>
45 #include <sys/time.h>
46 #include <sys/signal.h>
47 #include <rpc/rpc.h>
48 #if defined(CSRG_BASED)
49 #define MAXINT INT_MAX
50 #else
51 #include <values.h>
52 #endif
53 #include <string.h>
54 #include <pwd.h>
55 #ifdef SUNOS
56 #include <netdir.h>
57 #else
58 #include <sys/socket.h>
59 #include <netdb.h>
60 #endif
61 #include "cm.h"
62 #include "access.h"
63 #include "laccess.h"
64 #include "callback.h"
65 #include "appt4.h"              
66 #include "log.h"
67 #include "tree.h"
68 #include "list.h"
69 #include "cmscalendar.h"
70 #include "v4ops.h"
71 #include "v5ops.h"
72 #include "reminder.h"
73 #include "repeat.h"
74 #include "utility.h"
75 #include "lutil.h"
76 #include "rpcextras.h"
77 #include "rtable4_tbl.i"
78 #include "lookup.h"
79 #include "cmsdata.h"
80 #include "attr.h"
81 #include "convert5-4.h"
82 #include "convert4-5.h"
83 #include "cmsconvert.h"
84 #include "misc.h"
85 #include "insert.h"
86 #include "delete.h"
87 #include "update.h"
88
89
90 extern  int     debug;
91 extern  char    *pgname;
92
93 /*****************************************************************************
94  * forward declaration of static functions used within the file
95  *****************************************************************************/
96
97 static Appt_4 * rtable_lookup_internal(_DtCmsCalendar *cal, char **p_src,
98                         Id_4 *key);
99
100 static Access_Status_4 csastat2accessstat(CSA_return_code stat);
101
102 static Registration_Status_4 csastat2regstat(CSA_return_code stat);
103
104 static Table_Status_4 csastat2tablestat(CSA_return_code stat);
105
106 static Table_Res_4 * table_lookup_next(Table_Args_4 *args,
107                         struct svc_req *svcrq, caddr_t (* rb_func)(),
108                         Appt_4 *(* rp_func)());
109
110 static Appt_4 * repeater_next_smaller(List_node *p_lnode, Id_4 *key);
111
112 static Appt_4 * repeater_next_larger(List_node *p_lnode, Id_4 *key);
113
114 /*****************************************************************************
115  * extern functions used in the library
116  *****************************************************************************/
117
118 /*
119  * supports both data format
120  */
121 extern Table_Res_4 *
122 _DtCm_rtable_lookup_4_svc (Table_Args_4 *args, struct svc_req *svcrq)
123 {
124         static Table_Res_4 res;
125         CSA_return_code         stat;
126         Appt_4          *p_appt;
127         Appt_4          *h = NULL;
128         _DtCmsCalendar  *cal;
129         Uid_4           *p_keys;
130         Id_4            *key;
131         char            *user;
132         uint            access;
133         cms_entry       *entries;
134         cms_key         cmskey;
135         time_t          tmptick = 0;
136
137         if (debug)
138                 fprintf(stderr, "_DtCm_rtable_lookup_4_svc called\n");
139
140         if (res.res.Table_Res_List_4_u.a)
141                 _DtCm_free_appt4(res.res.Table_Res_List_4_u.a);
142
143         res.status = access_other_4;
144         res.res.tag = AP_4;
145         res.res.Table_Res_List_4_u.a = NULL;
146         if ((p_keys = args->args.Args_4_u.key) == NULL)
147                 return (&res);
148
149         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
150             &access, &cal)) == CSA_SUCCESS) {
151                 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
152                         if (_DTCMS_HAS_V4_BROWSE_ACCESS(access))
153                                 res.status = access_ok_4;
154                         else
155                                 res.status = access_failed_4;
156                 } else if (!_DTCMS_HAS_VIEW_ACCESS(access)) {
157                         res.status = access_failed_4;
158                         return (&res);
159                 } else
160                         res.status = access_ok_4;
161         } else {
162                 res.status = csastat2accessstat(stat);
163                 return (&res);
164         }
165
166         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
167                 while (p_keys != NULL) {
168                         cmskey.time = p_keys->appt_id.tick;
169                         cmskey.id = p_keys->appt_id.key;
170
171                         if ((stat = _DtCmsGetEntryAttrByKey(cal, user, access,
172                             cmskey, 0, NULL, &entries, NULL))
173                             == CSA_SUCCESS) {
174
175                                 if ((stat = _DtCmsCmsentriesToAppt4ForClient(
176                                     entries, &p_appt)) == CSA_SUCCESS) {
177                                         /* link to appt list */
178                                         h = _AddApptInOrder(h, p_appt);
179                                 }
180                                 _DtCm_free_cms_entries(entries);
181                         }
182
183                         if (stat != CSA_SUCCESS) {
184                                 res.status = csastat2accessstat(stat);
185                                 if (h) {
186                                         _DtCm_free_appt4(h);
187                                         h = NULL;
188                                 }
189                                 break;
190                         }
191                         p_keys = p_keys->next;
192                 }
193
194                 res.res.Table_Res_List_4_u.a = h;
195                 return (&res);
196         }
197
198         /* do lookup on old format calendar */
199         while (p_keys != NULL)
200         {
201                 key = &p_keys->appt_id;
202
203                 if (debug) {
204                         fprintf(stderr,
205                             "_DtCm_rtable_lookup_4_svc at (key %ld)%s\n",
206                             key->key, ctime(&key->tick));
207                 }
208
209                 p_appt = (Appt_4 *)rb_lookup(APPT_TREE(cal), (caddr_t)key);
210                 if (p_appt == NULL) {
211                         if ((p_appt = (Appt_4 *)hc_lookup(REPT_LIST(cal),
212                             (caddr_t)key)) != NULL) {
213                                 if (!_DtCms_in_repeater(key, p_appt, B_FALSE))
214                                         p_appt = NULL;
215                         }
216                 }
217
218                 if (p_appt != NULL) {
219                         if (p_appt->appt_id.tick != key->tick) {
220                                 tmptick = p_appt->appt_id.tick;
221                                 p_appt->appt_id.tick = key->tick;
222                         }
223
224                         stat = _AddToLinkedAppts(p_appt, user, access,
225                                         (caddr_t *)&h);
226
227                         if (tmptick) p_appt->appt_id.tick = tmptick;
228
229                         if (stat != CSA_SUCCESS) {
230                                 if (h) {
231                                         _DtCm_free_appt4(h);
232                                         h = NULL;
233                                 }
234                                 res.status = csastat2accessstat(stat);
235                         }
236                         break;
237                 }
238
239                 p_keys = p_keys->next;
240         }
241
242         res.res.Table_Res_List_4_u.a = h;
243         return (&res);
244 }
245
246 /*
247  * supports old data format only
248  */
249 extern Table_Res_4 *
250 _DtCm_rtable_lookup_next_larger_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
251 {
252         Table_Res_4 *res;
253
254         if (debug)
255                 fprintf(stderr, "_DtCm_rtable_lookup_next_larger_4_svc called\n");
256
257         res = table_lookup_next(args, svcrq, rb_lookup_next_larger,
258                                 repeater_next_larger);
259         return (res);
260 }
261
262 /*
263  * supports old data format only
264  */
265 extern Table_Res_4 *
266 _DtCm_rtable_lookup_next_smaller_4_svc(
267         Table_Args_4    *args,
268         struct svc_req  *svcrq)
269 {
270         Table_Res_4 *res;
271
272         if (debug)
273                 fprintf(stderr, "_DtCm_rtable_lookup_next_smaller_4_svc called\n");
274
275         res = table_lookup_next(args, svcrq, rb_lookup_next_smaller,
276                                 repeater_next_smaller);
277         return (res);
278 }
279
280 /*
281  * supports both data format
282  */
283 extern Table_Res_4 *
284 _DtCm_rtable_lookup_range_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
285 {
286         static Table_Res_4 res;
287         CSA_return_code stat;
288         _DtCmsCalendar  *cal;
289         char            *user;
290         uint            access;
291
292         if (debug)
293                 fprintf(stderr, "_DtCm_rtable_lookup_range_4_svc called\n");
294
295         if (res.res.Table_Res_List_4_u.a)
296                 _DtCm_free_appt4(res.res.Table_Res_List_4_u.a);
297
298         res.res.tag = AP_4;
299         res.res.Table_Res_List_4_u.a = NULL;
300
301         res.status = access_other_4;
302         if (args->args.Args_4_u.range == NULL)
303                 return (&res);
304
305         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
306             &access, &cal)) == CSA_SUCCESS) {
307                 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
308                         if (_DTCMS_HAS_V4_BROWSE_ACCESS(access))
309                                 res.status = access_ok_4;
310                         else
311                                 res.status = access_failed_4;
312                 }
313         } else {
314                 res.status = csastat2accessstat(stat);
315                 return (&res);
316         }
317
318         stat = _DtCmsLookupRangeV4(cal, user, access, args->args.Args_4_u.range,
319                 B_TRUE, 0, 0, NULL, 0, NULL, NULL,
320                 &res.res.Table_Res_List_4_u.a, NULL);
321
322         res.status = csastat2accessstat(stat);
323         return (&res);
324 }
325
326 /*
327  * supports both data format
328  */
329 extern Table_Res_4 *
330 _DtCm_rtable_abbreviated_lookup_range_4_svc(
331         Table_Args_4    *args,
332         struct svc_req  *svcrq)
333 {
334         static Table_Res_4 res;
335         CSA_return_code stat;
336         _DtCmsCalendar  *cal;
337         char            *user;
338         uint            access;
339
340         if (debug)
341                 fprintf(stderr,
342                         "_DtCm_rtable_abbreviated_lookup_range_4_svc called\n");
343
344         if (res.res.Table_Res_List_4_u.b)
345                 _DtCm_free_abbrev_appt4(res.res.Table_Res_List_4_u.b);
346
347         res.res.tag = AB_4;
348         res.res.Table_Res_List_4_u.b = NULL;
349
350         res.status = access_other_4;
351         if (args->args.Args_4_u.range == NULL)
352                 return (&res);
353
354         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
355             &access, &cal)) == CSA_SUCCESS) {
356                 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
357                         if (_DTCMS_HAS_V4_BROWSE_ACCESS(access))
358                                 res.status = access_ok_4;
359                         else
360                                 res.status = access_failed_4;
361                 }
362         } else {
363                 res.status = csastat2accessstat(stat);
364                 return (&res);
365         }
366
367         stat = _DtCmsLookupRangeV4(cal, user, access, args->args.Args_4_u.range,
368                 B_TRUE, 0, 0, NULL, 0, NULL, NULL, NULL,
369                 &res.res.Table_Res_List_4_u.b);
370
371         res.status = csastat2accessstat(stat);
372         return (&res);
373 }
374
375 extern Table_Res_4 *
376 _DtCm_rtable_insert_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
377 {
378         static Table_Res_4      res;
379         _DtCmsCalendar          *cal;
380         CSA_return_code         stat;
381         char                    *author;
382         char                    *user;
383         uint                    access;
384         Appt_4                  *ap, *appt, *prev=NULL, *a;
385         cms_entry               *entry;
386
387         if (debug)
388                 fprintf(stderr, "_DtCm_rtable_insert_4_svc called\n");
389
390         /* clean out left over */
391         if (res.res.Table_Res_List_4_u.a != NULL)
392                 _DtCm_free_appt4(res.res.Table_Res_List_4_u.a);
393
394         res.status = access_other_4;
395         res.res.tag = AP_4;
396         res.res.Table_Res_List_4_u.a = NULL;
397
398         /* check arguments */
399         if (args->target == NULL)
400                 return (&res);
401         if ((ap = args->args.Args_4_u.appt) == NULL)
402                 return (&res);
403
404         /* do some sanity checks before inserting : check appt data */
405         for (appt = args->args.Args_4_u.appt; appt != NULL; appt = appt->next)
406         {
407                 /* ntimes should be 0 or positive */
408                 if (appt->ntimes < 0 ||
409                     (appt->period.period > single_4 && appt->ntimes == 0))
410                         return(&res);
411
412                 /* period beyond daysOfWeek is not supported */
413                 if (appt->period.period > daysOfWeek_4) {
414                         res.status = access_notsupported_4;
415                         return(&res);
416                 }
417
418                 /* if weekmask of daysOfWeek appt is set incorrectly, return */
419                 if (appt->period.period == daysOfWeek_4 &&
420                         (appt->period.nth == 0 || appt->period.nth > 127))
421                         return(&res);
422         }
423
424         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
425             &access, &cal)) == CSA_SUCCESS) {
426                 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
427                         if (!_DTCMS_HAS_V4_WRITE_ACCESS(access)) {
428                                 res.status = access_failed_4;
429                                 return (&res);
430                         }
431                 } else if (!_DTCMS_HAS_INSERT_ACCESS(access)) {
432                         res.status = access_failed_4;
433                         return (&res);
434                 } else
435                         res.status = access_ok_4;
436         } else {
437                 res.status = csastat2accessstat(stat);
438                 return (&res);
439         }
440
441         /* make copy of the appointments */
442         /* this copy is used in the result and will be freed
443          * when this routine is called again
444          */
445         if ((appt = _DtCm_copy_appt4(args->args.Args_4_u.appt)) == NULL) {
446                 /* memory problem */
447                 return (&res);
448         }
449
450         ap = appt;
451         while (appt != NULL) {
452
453                 /*
454                  * we used to calculate the correct start day,
455                  * but we should return an error instead
456                  */
457                 _DtCms_adjust_appt_startdate(appt);
458
459                 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
460                         /* convert to attributes */
461                         if (_DtCmsAppt4ToCmsentry(args->target, appt, &entry,
462                             B_TRUE))
463                                 goto insert_error;
464
465                         /* null out readonly attributes */
466                         _DtCm_free_cms_attribute_value(entry->attrs\
467                                 [CSA_ENTRY_ATTR_ORGANIZER_I].value);
468                         entry->attrs[CSA_ENTRY_ATTR_ORGANIZER_I].value = NULL;
469                         _DtCm_free_cms_attribute_value(entry->attrs\
470                                 [CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I].value);
471                         entry->attrs[CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I].\
472                                 value = NULL;
473
474                         if (_DtCmsCheckInitialAttributes(entry)) {
475                                 _DtCm_free_cms_entry(entry);
476                                 goto insert_error;
477                         }
478
479                         /* set organizer */
480                         if (_DtCm_set_string_attrval(user, &entry->attrs\
481                             [CSA_ENTRY_ATTR_ORGANIZER_I].value,
482                             CSA_VALUE_CALENDAR_USER) != CSA_SUCCESS) {
483                                 _DtCm_free_cms_entry(entry);
484                                 goto insert_error;
485                         }
486
487                         /* insert entry and log it */
488                         if (_DtCmsInsertEntryAndLog(cal, entry)) {
489                                 _DtCm_free_cms_entry(entry);
490                                 goto insert_error;
491                         }
492
493                         appt->appt_id.key = entry->key.id;
494                         _DtCm_free_cms_entry(entry);
495
496                 } else {
497                         if ((a = _DtCm_copy_one_appt4(appt)) == NULL)
498                                 goto insert_error;
499
500                         /* We don't trust the author field; we set our own. */
501                         free(a->author);
502                         if ((a->author = strdup(user)) == NULL) {
503                                 _DtCm_free_appt4(a);
504                                 goto insert_error;
505                         }
506
507                         /* Note, the key in appt will be set if its value is 0. */
508                         if ((stat = _DtCmsInsertApptAndLog(cal, a)) != CSA_SUCCESS) {
509                                 res.status = csastat2accessstat(stat);
510                                 goto insert_error;
511                         }
512
513                         /* get the new key */
514                         appt->appt_id.key = a->appt_id.key;
515                 }
516
517                 prev = appt;
518                 appt = appt->next;
519         }
520
521         cal->modified = B_TRUE;
522
523         /* do callbacks */
524         cal->rlist = _DtCmsDoV1Callback(cal->rlist, user, args->pid, ap);
525
526         for (appt = ap; appt != NULL; appt = appt->next) {
527                 cal->rlist = _DtCmsDoInsertEntryCallback(cal->rlist,
528                                 cal->calendar, user, appt->appt_id.key,
529                                 args->pid);
530         }
531
532         res.status = access_ok_4;
533         res.res.Table_Res_List_4_u.a = ap;
534
535         return (&res);
536
537 insert_error:
538         if (prev != NULL) {
539                 cal->modified = B_TRUE;
540                 /* some appts were inserted successfully */
541                 res.status = access_partial_4;
542                 prev->next = NULL;
543                 res.res.Table_Res_List_4_u.a = ap;
544
545                 /* do callback */
546                 cal->rlist = _DtCmsDoV1Callback(cal->rlist, user, args->pid,
547                         ap);
548                 for (appt = ap; appt != NULL; appt = appt->next) {
549                         cal->rlist = _DtCmsDoInsertEntryCallback(cal->rlist,
550                                         cal->calendar, user,
551                                         appt->appt_id.key, args->pid);
552                 }
553
554         } else {
555                 /* first appt in bunch that failed */
556                 res.status = csastat2accessstat(stat);
557         }
558         _DtCm_free_appt4(appt);
559
560         return (&res);
561 }
562
563 extern Table_Res_4 *
564 _DtCm_rtable_delete_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
565 {
566         static Table_Res_4      res;
567         _DtCmsCalendar          *cal;
568         CSA_return_code         stat;
569         char                    *user;
570         uint                    access;
571         Uidopt_4                *p_keys;
572         Appt_4                  *h = NULL;
573         Appt_4                  *a;
574         int                     d, n, nf;
575         cms_key                 key;
576         cms_entry               *entry;
577
578         if (debug)
579                 fprintf(stderr, "_DtCm_rtable_delete_4_svc called\n");
580
581         /* clean out left over */
582         if (res.res.Table_Res_List_4_u.a)
583                 _DtCm_free_appt4(res.res.Table_Res_List_4_u.a);
584
585         res.status = access_other_4;
586         res.res.tag = AP_4;
587         res.res.Table_Res_List_4_u.a = NULL;
588
589         /* check arguments */
590         if (args->target == NULL)
591                 return (&res);
592         if ((p_keys = args->args.Args_4_u.uidopt) == NULL)
593                 return (&res);
594
595         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
596             &access, &cal)) == CSA_SUCCESS) {
597                 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
598                     !_DTCMS_HAS_CHANGE_ACCESS(access)) {
599                         res.status = access_failed_4;
600                         return (&res);
601                 }
602         } else {
603                 res.status = csastat2accessstat(stat);
604                 return (&res);
605         }
606
607         nf = d = n = 0;
608         while (p_keys != NULL) {
609                 n++;
610                 if (debug) {
611                         fprintf (stderr, "Delete: (key %ld)%s\n",
612                               p_keys->appt_id.key,
613                               ctime(&p_keys->appt_id.tick));
614                 }
615
616                 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
617                         key.time = p_keys->appt_id.tick;
618                         key.id = p_keys->appt_id.key;
619
620                         if (p_keys->option == do_all_4)
621                                 stat = _DtCmsDeleteEntryAndLog(cal, user,
622                                         access, &key, &entry);
623                         else
624                                 stat = _DtCmsDeleteInstancesAndLog(cal, user,
625                                         access, &key,
626                                         (p_keys->option == CSA_SCOPE_ONE ?
627                                         CSA_SCOPE_ONE : CSA_SCOPE_FORWARD),
628                                         NULL, &entry); 
629
630                         if (stat == CSA_SUCCESS)
631                                 stat = _DtCm_cms_entry_to_appt4(entry, &a);
632
633                         _DtCm_free_cms_entry(entry);
634
635                 } else {
636
637                         /* single or all in a repeating series */
638                         if (p_keys->option == do_all_4)
639                                 stat = _DtCmsDeleteApptAndLog(cal, user,
640                                         access, &p_keys->appt_id, &a);
641                         else {
642                                 stat = _DtCmsDeleteApptInstancesAndLog(cal,
643                                         user, access, &p_keys->appt_id,
644                                         p_keys->option, NULL, &a);
645                         }
646                 }
647
648                 if (stat == CSA_SUCCESS) {
649                         if (p_keys->option != do_all_4)
650                                 APPT_TICK(a) = p_keys->appt_id.tick;
651
652                         d++;
653                         a->next = h;
654                         h = a;
655                 } else if (stat == CSA_X_DT_E_ENTRY_NOT_FOUND)
656                         nf++;
657
658                 p_keys = p_keys->next;
659         }
660
661         if (h != NULL) {
662                 cal->modified = B_TRUE;
663
664                 /* do callback */
665                 cal->rlist = _DtCmsDoV1Callback(cal->rlist, user, args->pid, h);
666                 for (a = h, p_keys = args->args.Args_4_u.uidopt;
667                     a != NULL; a = a->next) {
668                         while (a->appt_id.key != p_keys->appt_id.key)
669                                 p_keys = p_keys->next;
670
671                         cal->rlist = _DtCmsDoDeleteEntryCallback(cal->rlist,
672                                         cal->calendar, user, a->appt_id.key,
673                                         p_keys->option,
674                                         (p_keys->option == do_all_4 ?
675                                         a->appt_id.tick : p_keys->appt_id.tick),
676                                         args->pid);
677                 }
678         }
679
680         if (d == 0) {
681                 if (stat != 0)
682                         res.status = csastat2accessstat(stat);
683                 else
684                         res.status = (nf < n) ? access_failed_4 : access_ok_4;
685         } else if (d < n)
686                 res.status = access_partial_4;
687         else
688                 res.status = access_ok_4;
689
690         res.res.Table_Res_List_4_u.a = h;
691
692         return (&res);
693 }
694
695 extern Table_Res_4 *
696 _DtCm_rtable_delete_instance_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
697 {
698         static Table_Res_4 res;
699
700         if (debug)
701                 fprintf(stderr, "_DtCm_rtable_delete_instance_4_svc called\n");
702
703         res.status = access_notsupported_4;
704         res.res.tag = AP_4;
705         res.res.Table_Res_List_4_u.a = NULL;
706
707         return(&res);
708 }
709
710 extern Table_Res_4 *
711 _DtCm_rtable_change_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
712 {
713         static Table_Res_4      res;
714         _DtCmsCalendar          *cal;
715         CSA_return_code         stat;
716         char                    *user;
717         uint                    access;
718         Id_4                    *p_key;
719         Appt_4                  *newa, *olda;
720         Appt_4                  tmpappt;
721         Options_4               option;
722         cms_entry               *entry, *oldentry, *newentry = NULL;
723         cms_key                 key;
724
725         if (debug)
726                 fprintf(stderr, "_DtCm_rtable_change_4_svc called\n");
727
728         /* clean out left over */
729         res.status = access_other_4;
730         res.res.tag = AP_4;
731         res.res.Table_Res_List_4_u.a = NULL;
732
733         /* check arguments */
734         if (args->target == NULL)
735                 return (&res);
736         if ((p_key = args->args.Args_4_u.apptid.oid) == NULL)
737                 return (&res);
738         if ((newa = args->args.Args_4_u.apptid.new_appt) == NULL)
739                 return (&res);
740
741         /* ntimes should be 0 or positive */
742         if (newa->ntimes < 0 ||
743             (newa->period.period > single_4 && newa->ntimes == 0))
744                 return(&res);
745
746         /* period beyond daysOfWeek is not supported */
747         if (newa->period.period > daysOfWeek_4) {
748                 res.status = access_notsupported_4;
749                 return(&res);
750         }
751
752         /* if weekmask of daysOfWeek appt is not set correctly, return */
753         if (newa->period.period == daysOfWeek_4 &&
754             (newa->period.nth == 0 || newa->period.nth > 127))
755                 return(&res);
756
757         option = args->args.Args_4_u.apptid.option;
758         if (option < do_all_4 || option > do_forward_4)
759                 return (&res); 
760
761         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
762             &access, &cal)) == CSA_SUCCESS) {
763                 if ((cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
764                     !_DTCMS_HAS_CHANGE_ACCESS(access)) ||
765                     (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
766                     !_DTCMS_HAS_V4_WRITE_ACCESS(access))) {
767
768                         res.status = access_failed_4;
769                         return (&res);
770                 }
771         } else {
772                 res.status = csastat2accessstat(stat);
773                 return (&res);
774         }
775
776         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
777                 /* convert to attributes */
778                 if ((stat = _DtCmsAppt4ToCmsentry(args->target, newa, &entry,
779                     B_TRUE)) == CSA_SUCCESS) {
780
781                         key.time = p_key->tick;
782                         key.id = p_key->key;
783
784                         /* null out readonly attributes */
785                         _DtCm_free_cms_attributes(1,
786                                 &entry->attrs[CSA_ENTRY_ATTR_ORGANIZER_I]);
787                         _DtCm_free_cms_attributes(1, &entry->attrs\
788                                 [CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I]);
789                         _DtCm_free_cms_attributes(1,
790                                 &entry->attrs[CSA_ENTRY_ATTR_TYPE_I]);
791
792                         /* update entry */
793                         if (option == do_all_4)
794                                 stat = _DtCmsUpdateEntry(cal, user, access,
795                                         &key, entry->num_attrs,
796                                         &entry->attrs[1], &oldentry, NULL);
797                         else
798                                 stat = _DtCmsUpdateInstances(cal, user,
799                                         access, &key, (option == do_one_4 ?
800                                         CSA_SCOPE_ONE : CSA_SCOPE_FORWARD),
801                                         entry->num_attrs, &entry->attrs[1],
802                                         &oldentry, &newentry);
803
804                         _DtCm_free_cms_entry(entry);
805                 }
806         } else {
807
808                 if (option == do_all_4)
809                         stat = _DtCmsChangeAll(cal, user, access, p_key, newa,
810                                 &olda);
811                 else
812                         stat = _DtCmsChangeSome(cal, user, access,p_key, newa,
813                                 option, &olda);
814         }
815
816         if (stat == CSA_SUCCESS) {
817                 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
818                         tmpappt.appt_id.tick = oldentry->key.time;
819                         tmpappt.appt_id.key = oldentry->key.id;
820                         olda = &tmpappt;
821                         _DtCm_free_cms_entry(oldentry);
822                         if (newentry) {
823                                 newa->appt_id.key = newentry->key.id;
824                                 _DtCm_free_cms_entry(newentry);
825                         }
826                 }
827
828                 /* If the date/time is changed, we do a callback
829                  * with the old and new appointments.  Otherwise,
830                  * we only do callback with the new appointmnt.
831                  */
832                 if (APPT_TICK(newa) == APPT_TICK(olda)) {
833                         cal->rlist = _DtCmsDoV1Callback(cal->rlist, user,
834                                         args->pid, newa);
835                 } else {
836                         olda->next = newa;
837                         cal->rlist = _DtCmsDoV1Callback(cal->rlist, user,
838                                         args->pid, olda);
839                         olda->next = NULL;
840                 }
841
842                 cal->rlist = _DtCmsDoUpdateEntryCallback(cal->rlist,
843                                 cal->calendar, user,
844                                 (newa->appt_id.key == olda->appt_id.key ?
845                                 0 : newa->appt_id.key),
846                                 olda->appt_id.key, option, (option == do_all_4 ?
847                                 olda->appt_id.tick : p_key->tick),
848                                 args->pid);
849
850                 cal->modified = B_TRUE;
851
852                 /* Return the new appointment. */
853                 res.res.Table_Res_List_4_u.a = newa;
854                 res.status = access_ok_4;
855
856                 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION)
857                         _DtCm_free_appt4(olda);
858         } else
859                 res.status = csastat2accessstat(stat);
860
861         return (&res);
862 }
863
864 extern Table_Res_4 *
865 _DtCm_rtable_change_instance_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
866 {
867         static Table_Res_4 res;
868
869         if (debug)
870                 fprintf(stderr, "_DtCm_rtable_change_instance_4_svc called\n");
871
872         res.status = access_notsupported_4;
873         res.res.tag = AP_4;
874         res.res.Table_Res_List_4_u.a = NULL;
875
876         return(&res);
877 }
878
879 extern Table_Res_4 *
880 _DtCm_rtable_lookup_next_reminder_4_svc(
881         Table_Args_4    *args,
882         struct svc_req  *svcrq)
883 {
884         static  Table_Res_4     res;
885         CSA_return_code         stat;
886         char                    *user;
887         uint                    access;
888         _DtCmsCalendar          *cal;
889         Reminder_4              *p_reminder;
890         Rm_que                  *p_node;
891         Rm_que                  *p_prev;
892         Rm_que                  *p_new;
893         Rm_que                  *p_next;
894         time_t                  tick;
895         cms_reminder_ref        *rems;
896
897         if (debug)
898                 fprintf(stderr, "_DtCm_rtable_lookup_next_reminder_4_svc called\n");
899
900         /* clean up left over */
901         if (res.res.Table_Res_List_4_u.r)
902                 _DtCm_free_reminder4(res.res.Table_Res_List_4_u.r);
903
904         res.status = access_other_4;
905         res.res.tag = RM_4;
906         res.res.Table_Res_List_4_u.r = NULL;
907
908         if (args->target == NULL)
909                 return (&res);
910
911         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
912             &access, &cal)) == CSA_SUCCESS) {
913                 /* only user with owner rights can lookup reminders */
914                 if (!(access & CSA_OWNER_RIGHTS)) {
915
916                         res.status = access_failed_4;
917                         return (&res);
918                 }
919         } else {
920                 res.status = csastat2accessstat(stat);
921                 return (&res);
922         }
923
924         tick = args->args.Args_4_u.tick;
925
926         if (debug)
927                 fprintf(stderr, "Next reminder after %s", ctime(&tick));
928
929         if (cal->fversion > 1) {
930                 if ((stat = _DtCmsLookupReminder(cal->remq, tick, 0, NULL,
931                     &rems)) == CSA_SUCCESS) {
932                         stat = _DtCmsReminderRefToReminder(rems,
933                             &res.res.Table_Res_List_4_u.r);
934                         _DtCmsFreeReminderRef(rems);
935                 }
936         } else {
937
938                 stat = _DtCmsGetV4Reminders(cal, tick,
939                         &res.res.Table_Res_List_4_u.r, NULL);
940         }
941
942         res.status =  csastat2accessstat(stat);
943         return (&res);
944 }
945
946 extern Table_Status_4 *
947 _DtCm_rtable_check_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
948 {
949         static  Table_Status_4 s;
950         CSA_return_code stat;
951         Rb_Status rbstat;
952         _DtCmsCalendar  *cal;
953
954         if (debug)
955                 fprintf(stderr, "_DtCm_rtable_check_4_svc called\n");
956
957         if ((stat = _DtCmsGetCalendarByName(args->target, B_TRUE, &cal))
958             != CSA_SUCCESS)
959         {
960                 s = csastat2tablestat(stat);
961                 return (&s);
962         }
963
964         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
965                 s = tbl_notsupported_4;
966         } else {
967
968                 rbstat = rb_check_tree (cal->tree);
969                 if (rbstat == rb_ok)
970                         rbstat = hc_check_list (cal->list);
971
972                 if (rbstat == rb_ok)
973                         s = ok_4;
974                 else
975                         s = other_4;
976         }
977
978         return (&s);
979 }
980
981 extern Table_Status_4 *
982 _DtCm_rtable_flush_table_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
983 {
984         static Table_Status_4 s;
985         Id_4            key;
986         CSA_return_code         stat;
987         _DtCmsCalendar  *cal;
988         int             n = 0;
989         Tree_node       *p_node;
990         List_node       *p_lnode;
991         List_node       *p_next;
992         Appt_4  *p_appt;
993
994         if (!debug) {
995                 s = ok_4;
996                 return (&s);
997         }
998
999         if (debug)
1000                 fprintf (stderr, "rtable_flush_table\n");
1001
1002         if ((stat = _DtCmsGetCalendarByName(args->target, B_TRUE, &cal))
1003             != CSA_SUCCESS) {
1004                 s = csastat2tablestat(stat);
1005                 return (&s);
1006         }
1007
1008         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1009                 s = tbl_notsupported_4;
1010                 return (&s);
1011         }
1012
1013         if (debug)
1014         {
1015                 fprintf(stderr, "%s: before flush.. rbsize= %d\n", pgname,
1016                         rb_size(APPT_TREE(cal))+hc_size(REPT_LIST(cal)));
1017         }
1018         
1019         /* Flushing the single appointment tree. */
1020         key.key = 0;
1021         key.tick = args->args.Args_4_u.tick;
1022         while (p_appt = (Appt_4 *) rb_lookup_next_larger(APPT_TREE(cal),
1023             (caddr_t)&key)) {
1024                 p_node = rb_delete (APPT_TREE(cal),
1025                                 (caddr_t)&(p_appt->appt_id));
1026                 if (p_node != NULL)
1027                 {
1028                         n++;
1029                         _DtCm_free_appt4 ((Appt_4 *) p_node->data);
1030                         free(p_node);
1031                 }
1032         }
1033
1034         /* Flushing the repeating appointment list */
1035         key.key = 0;
1036         key.tick = args->args.Args_4_u.tick;
1037         p_lnode = cal->list->root;
1038         while (p_lnode != NULL)
1039         {
1040                 p_next = hc_lookup_next (p_lnode);
1041                 p_appt = (Appt_4*)p_lnode->data;
1042                 if (APPT_TICK(p_appt) > key.tick)
1043                 {
1044                         n++;
1045                         _DtCm_free_appt4 (p_appt);
1046                         (void) hc_delete_node (REPT_LIST(cal), p_lnode);
1047                         free (p_lnode);
1048                 }
1049                 p_lnode = p_next;
1050         }
1051         s = ok_4;
1052         if (debug)
1053         {
1054                 fprintf (stderr, "%s: entries deleted= %d\n", pgname, n);
1055                 fprintf (stderr, "%s: after flush.. rbsize= %d\n", pgname,
1056                         rb_size(APPT_TREE(cal))+hc_size(REPT_LIST(cal)));
1057         }
1058
1059         return (&s);
1060 }
1061
1062 extern int *
1063 _DtCm_rtable_size_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
1064 {
1065         /* must be static! */
1066         static int size;
1067         CSA_return_code stat;
1068         _DtCmsCalendar  *cal;
1069
1070         if (debug)
1071                 fprintf(stderr, "_DtCm_rtable_size_4_svc called\n");
1072
1073         size = 0;
1074         if ((stat = _DtCmsGetCalendarByName(args->target, B_TRUE, &cal))
1075             != CSA_SUCCESS)
1076                 return(&size);
1077
1078         size = rb_size (APPT_TREE(cal)) + hc_size (REPT_LIST(cal));
1079
1080         return(&size);
1081 }
1082
1083 extern Registration_Status_4 *
1084 _DtCm_register_callback_4_svc(Registration_4 *r, struct svc_req *svcrq)
1085 {
1086         static Registration_Status_4 regstat;
1087         CSA_return_code stat;
1088         char *source;
1089         _DtCmsCalendar *cal = NULL;
1090         _DtCmsRegistrationInfo *copy=NULL;
1091
1092         if (debug)
1093                 fprintf(stderr, "_DtCm_register_callback_4_svc called\n");
1094
1095         /* Error */
1096         if (r->target == NULL) {
1097                 regstat = failed_4;
1098                 return(&regstat);
1099         }
1100
1101         if ((stat = _DtCmsGetClientInfo(svcrq, &source)) != CSA_SUCCESS) {
1102                 regstat = csastat2regstat(stat);
1103                 return (&regstat);
1104         }
1105
1106         /* check if the target exists */
1107         if ((stat = _DtCmsGetCalendarByName(r->target, B_TRUE, &cal))
1108             != CSA_SUCCESS) {
1109                 regstat = csastat2regstat(stat);
1110                 return (&regstat);
1111         }
1112
1113         /* Check for duplicate registrations */
1114         if (_DtCmsGetRegistration(&(cal->rlist), source, r->prognum, r->versnum,
1115             r->procnum, r->pid) == NULL) {
1116                 /* not registered */
1117
1118                 /* Make a copy of the callback info. */
1119
1120                 if ((copy = _DtCmsMakeRegistrationInfo(source, 0, r->prognum,
1121                     r->versnum, r->procnum, r->pid)) == NULL) {
1122                         regstat = failed_4;
1123                         return (&regstat);
1124                 }
1125
1126                 /* Store it away so that it can later be called. */
1127                 copy->next = cal->rlist;
1128                 cal->rlist = copy;
1129
1130                 if (debug) {
1131                         fprintf(stderr, "%s requested registration on %s. registered pid= %d\n",
1132                                 source, r->target, r->pid);
1133                         _DtCmsListRegistration(cal->rlist,
1134                                         cal->calendar);
1135                 }
1136                 regstat = registered_4;
1137                 return(&regstat);
1138         } else {
1139                 /* already registered */
1140                 regstat = registered_4;
1141                 return(&regstat);
1142         }
1143 }
1144
1145 /* de-register an rpc callback proc from the client */
1146 extern Registration_Status_4 *
1147 _DtCm_deregister_callback_4_svc(Registration_4 *r, struct svc_req *svcrq)
1148 {
1149         static Registration_Status_4 regstat;
1150         CSA_return_code stat;
1151         _DtCmsCalendar *cal;
1152         char *source;
1153         _DtCmsRegistrationInfo *p = NULL, *q = NULL;
1154
1155         if (debug)
1156                 fprintf(stderr, "_DtCm_deregister_callback_4_svc called\n");
1157
1158         if (r->target == NULL) {
1159                 regstat = failed_4;
1160                 return(&regstat);
1161         }
1162  
1163         if ((stat = _DtCmsGetClientInfo(svcrq, &source)) != CSA_SUCCESS) {
1164                 regstat = csastat2regstat(stat);
1165                 return (&regstat);
1166         }
1167
1168         if ((stat = _DtCmsGetCalendarByName(r->target, B_FALSE, &cal))
1169             != CSA_SUCCESS) {
1170                 regstat = csastat2regstat(stat);
1171                 return (&regstat);
1172         }
1173
1174         if (cal == NULL) {
1175                 regstat = failed_4;
1176                 return (&regstat);
1177         }
1178
1179         q = p = cal->rlist;
1180         while (p != NULL) {
1181
1182                 /* This says:
1183                  * 1) if the name of the caller requesting deregistration
1184                  * is the same as the original caller who requested
1185                  * requested registration, and
1186                  * 2) if the (transient) program, version, & procnum match
1187                  * the original registration, and
1188                  * 3) if the process id of the client matches the
1189                  *  orignal registration 
1190                  *  
1191                  *  ... only then is it ok to decommission the ticket.
1192                  */
1193
1194
1195                 if ((strcmp(p->client, source)==0) &&
1196                     (p->prognum==r->prognum) &&
1197                     (p->versnum==r->versnum) &&
1198                     (p->procnum==r->procnum) &&
1199                     (p->pid==r->pid)) { /* a match */
1200                         if (debug) {
1201                                 fprintf(stderr, "%s requested deregistration on %s. registered pid= %d\n", source, r->target, r->pid);
1202                         }
1203                         if (p==q)
1204                                 cal->rlist = p->next;
1205                         else
1206                                 q->next = p->next;
1207                         _DtCmsFreeRegistrationInfo(p);
1208                         if (debug) {
1209                                 _DtCmsListRegistration(cal->rlist,
1210                                         cal->calendar);
1211                         }
1212                         regstat = deregistered_4;
1213                         return(&regstat);
1214                 }
1215                 q = p;
1216                 p = p->next;
1217         }
1218
1219         /* not found */
1220         regstat = failed_4;
1221         return(&regstat);
1222 }
1223
1224 extern Access_Status_4 *
1225 _DtCm_rtable_set_access_4_svc(Access_Args_4 *args, struct svc_req *svcrq)
1226 {
1227         /* must be static! */
1228         static Access_Status_4  s;
1229         CSA_return_code         stat;
1230         char                    *user;
1231         uint                    access;
1232         _DtCmsCalendar          *cal = NULL;
1233
1234         if (debug)
1235                 fprintf(stderr, "_DtCm_rtable_set_access_4_svc called\n");
1236
1237         s = access_other_4;
1238
1239         if (args->target == NULL)
1240                 return (&s);
1241
1242         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
1243             &access, &cal)) == CSA_SUCCESS) {
1244                 /* only user with owner rights can lookup reminders */
1245                 if ((cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
1246                     !(access&(CSA_OWNER_RIGHTS|CSA_CHANGE_CALENDAR_ATTRIBUTES)))
1247                     || (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
1248                     !(access & CSA_OWNER_RIGHTS))) {
1249
1250                         s = access_failed_4;
1251                         return (&s);
1252                 }
1253         } else {
1254                 s = csastat2accessstat(stat);
1255                 return(&s);
1256         }
1257
1258         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1259                 cms_attribute           attr;
1260                 cms_attribute_value     attrval;
1261                 cms_access_entry        *alist;
1262
1263                 if (args->access_list && (alist =
1264                     _DtCmsConvertV4AccessList(args->access_list)) == NULL) {
1265                         s = csastat2accessstat(CSA_E_INSUFFICIENT_MEMORY);
1266                         return (&s);
1267                 }
1268
1269                 attr.name.name = CSA_CAL_ATTR_ACCESS_LIST;
1270                 attr.name.num = 0;
1271                 attr.value = &attrval;
1272                 attrval.type = CSA_VALUE_ACCESS_LIST;
1273                 attrval.item.access_list_value = alist;
1274
1275                 stat = _DtCmsUpdateCalAttributesAndLog(cal, 1, &attr, access);
1276         } else {
1277                 stat = _DtCmsSetV4AccessListAndLog(cal, args->access_list);
1278         }
1279
1280         if ((s = csastat2accessstat(stat)) == access_ok_4) {
1281
1282                 cms_attribute   attr;
1283
1284                 attr.name.name = CSA_CAL_ATTR_ACCESS_LIST;
1285                 cal->rlist = _DtCmsDoUpdateCalAttrsCallback(cal->rlist,
1286                                 cal->calendar, user, 1, &attr, -1);
1287         }
1288
1289         return(&s);
1290 }
1291
1292 extern Access_Args_4 *
1293 _DtCm_rtable_get_access_4_svc(Access_Args_4 *args, struct svc_req *svcrq)
1294 {
1295         static Access_Args_4    res;
1296         CSA_return_code         stat;
1297         _DtCmsCalendar          *cal;
1298         char                    *target, *user;
1299         uint                    access;
1300         boolean_t               useronly = B_FALSE;
1301         cms_access_entry        aentry;
1302
1303         if (debug)
1304                 fprintf(stderr, "_DtCm_rtable_get_access_4_svc called\n");
1305
1306         if (res.target != NULL)
1307                 free(res.target);
1308         if (res.access_list)
1309                 _DtCm_free_access_list4(res.access_list);
1310
1311         res.target = NULL;
1312         res.access_list = (Access_Entry_4 *) NULL;
1313
1314         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
1315             &access, &cal)) == CSA_SUCCESS) {
1316                 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
1317                     !_DTCMS_HAS_VIEW_CALENDAR_ATTR_ACCESS(access)) {
1318                         useronly = B_TRUE;
1319                 }
1320         } else {
1321                 return (&res);
1322         }
1323
1324         if (cal->fversion > 1) {
1325                 if (useronly) {
1326                         aentry.user = user;
1327                         aentry.rights = access;
1328                         aentry.next = NULL;
1329                         res.access_list = _DtCmsConvertV5AccessList(&aentry,
1330                                                 B_TRUE);
1331                 } else {
1332                         res.access_list = _DtCmsConvertV5AccessList(
1333                                         cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I].\
1334                                         value->item.access_list_value, B_TRUE);
1335                 }
1336         } else {
1337                 res.access_list = _DtCmsCalendarAccessList(cal);
1338                 if (debug)
1339                         _DtCmsShowAccessList (res.access_list);
1340         }
1341
1342         res.target = strdup(args->target); 
1343
1344         return (&res);
1345 }
1346
1347 extern Table_Res_4 *
1348 _DtCm_rtable_abbreviated_lookup_key_range_4_svc(
1349         Table_Args_4    *args,
1350         struct svc_req  *svcrq)
1351 {
1352         static  Table_Res_4 res;
1353         CSA_return_code stat;
1354         _DtCmsCalendar  *cal;
1355         char            *user;
1356         uint            access;
1357         Keyrange_4      *p_range;
1358         Abb_Appt_4      *abbr_r = NULL;
1359
1360         if (debug)
1361                 fprintf(stderr,
1362                     "_DtCm_rtable_abbreviated_lookup_key_range_4_svc called\n");
1363
1364         if (res.res.Table_Res_List_4_u.b)
1365                 _DtCm_free_abbrev_appt4(res.res.Table_Res_List_4_u.b);
1366
1367         res.res.tag = AB_4;
1368         res.res.Table_Res_List_4_u.b = NULL;
1369
1370         res.status = access_other_4;
1371         if ((p_range = args->args.Args_4_u.keyrange) == NULL)
1372                 return (&res);
1373
1374         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
1375             &access, &cal)) == CSA_SUCCESS) {
1376                 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1377                         if (_DTCMS_HAS_V4_BROWSE_ACCESS(access))
1378                                 res.status = access_ok_4;
1379                         else
1380                                 res.status = access_failed_4;
1381                 }
1382         } else {
1383                 res.status = csastat2accessstat(stat);
1384                 return (&res);
1385         }
1386
1387         while (p_range != NULL)
1388         {
1389
1390                 if ((stat = _DtCmsLookupKeyrangeV4(cal, user, access,
1391                     B_FALSE, B_TRUE, p_range->tick1, p_range->tick2, 0, 0,
1392                     p_range->key, NULL, 0, NULL, NULL, NULL, &abbr_r))
1393                     != CSA_SUCCESS) {
1394                         break;
1395                 }
1396
1397                 p_range = p_range->next;
1398         }
1399
1400         if (stat == CSA_SUCCESS)
1401                 res.res.Table_Res_List_4_u.b = abbr_r;
1402         else
1403                 _DtCm_free_abbrev_appt4(abbr_r);
1404
1405         res.status = csastat2accessstat(stat);
1406         return (&res);
1407 }
1408
1409 extern long *
1410 _DtCm_rtable_gmtoff_4_svc(void *args, struct svc_req *svcrq)
1411 {
1412         static long gmtoff;
1413 #if !defined(CSRG_BASED)
1414         extern long timezone;
1415 #else
1416         struct tm *t;
1417 #endif
1418
1419         if (debug)
1420                 fprintf(stderr, "_DtCm_rtable_gmtoff_4_svc called\n");
1421
1422 #if defined(CSRG_BASED)
1423         t = localtime(time(NULL));
1424         gmtoff = t->tm_gmtoff;
1425 #else
1426         gmtoff = timezone;
1427 #endif
1428         return(&gmtoff);
1429 }
1430
1431 extern Table_Status_4 *
1432 _DtCm_rtable_create_4_svc(Table_Op_Args_4 *args, struct svc_req *svcrq)
1433 {
1434         static  Table_Status_4 res;
1435         CSA_return_code stat;
1436         _DtCmsCalendar  *cal;
1437         char    *source;
1438         char    *calname;
1439         char    *log;
1440         char    *ptr;
1441         char    *id, *user, *domain;
1442         Access_Entry_4 aentry;
1443
1444         if (debug)
1445                 fprintf(stderr, "_DtCm_rtable_create_4_svc called\n");
1446
1447         res = other_4;
1448         if ((stat = _DtCmsGetClientInfo(svcrq, &source)) != CSA_SUCCESS) {
1449                 res = csastat2tablestat(stat);
1450                 return (&res);
1451         }
1452
1453         /* check domain if domain info is available */
1454         /* only user in the local domain can create file */
1455         if (ptr = strchr(source, '.')) {
1456                 if (debug)
1457                         fprintf(stderr, "rpc.cmsd: %s %s(target) and %s(sender)\n",
1458                                 "check domains, comparing",
1459                                 args->target, source);
1460
1461                 if ((domain = _DtCmsTarget2Domain(args->target)) != NULL) {
1462
1463                         if (!_DtCmIsSamePath(domain, ++ptr)) {
1464                                 res = denied_4;
1465                                 free(domain);
1466                                 return(&res);
1467                         }
1468                 }
1469         }
1470
1471         if ((calname = _DtCmsTarget2Name(args->target)) == NULL)
1472                 return(&res);
1473
1474         /* if the file is loaded in memory, the file already exists */
1475         if ((stat = _DtCmsGetCalendarByName(calname, B_FALSE, &cal))
1476             == CSA_SUCCESS && cal != NULL) {
1477                 res = tbl_exist_4;
1478                 free(calname);
1479                 return(&res);
1480         }
1481
1482         /*
1483          * If identifier of the calendar name is a user name,
1484          * make sure it's the same as sender.
1485          * format of calendar name assumed: identifier.name
1486          */
1487         if ((id = _DtCmGetPrefix(calname, '.')) == NULL) {
1488                 free(calname);
1489                 return(&res);
1490         }
1491         if ((user = _DtCmGetPrefix(source, '@')) == NULL) {
1492                 free(calname);
1493                 free(id);
1494                 return(&res);
1495         }
1496
1497         if (getpwnam(id) && strcmp(user, id)) {
1498                 free(calname);
1499                 free(id);
1500                 free(user);
1501                 res = denied_4;
1502                 return(&res);
1503         }
1504         free(id);
1505
1506         if ((log = _DtCmsGetLogFN(calname)) == NULL)
1507         {
1508                 free(calname);
1509                 free(user);
1510                 return(&res);
1511         } else if (debug)
1512                 fprintf(stderr, "new file = '%s'\n", log);
1513
1514         if ((stat = _DtCmsCreateLogV1(user, log)) == CSA_E_CALENDAR_EXISTS)
1515                 res = tbl_exist_4;
1516         else if (stat != CSA_SUCCESS)
1517                 res = other_4;
1518         else
1519                 res = ok_4;
1520
1521         /* initialize the access list to be "WORLD", access_read_4 */
1522         aentry.next = NULL;
1523         aentry.who = WORLD;
1524         aentry.access_type = access_read_4;
1525         if ((stat = _DtCmsAppendAccessByFN(log, access_read_4, &aentry))
1526             != CSA_SUCCESS) {
1527                 unlink(log);
1528         }
1529
1530         free(user);
1531         free(calname);
1532         free(log);
1533         return (&res);
1534 }
1535
1536 extern Table_Status_4 *
1537 _DtCm_rtable_remove_4_svc(Table_Op_Args_4 *args, struct svc_req *svcrq)
1538 {
1539         static  Table_Status_4 res;
1540
1541         res = tbl_notsupported_4;
1542         return (&res);
1543 }
1544
1545 extern Table_Status_4 *
1546 _DtCm_rtable_rename_4_svc(Table_Op_Args_4 *args, struct svc_req *svcrq)
1547 {
1548         static  Table_Status_4 res;
1549
1550         res = tbl_notsupported_4;
1551         return (&res);
1552 }
1553
1554 extern void *
1555 _DtCm_rtable_ping_4_svc(void *args, struct svc_req *svcrq)
1556 {
1557         if (debug)
1558                 fprintf(stderr, "_DtCm_rtable_ping_4_svc called\n");
1559
1560         return(NULL); /* for RPC reply */
1561 }
1562
1563 extern void
1564 initrtable4(program_handle ph)
1565 {
1566         ph->program_num = TABLEPROG;
1567         ph->prog[TABLEVERS_4].vers = &tableprog_4_table[0];
1568         ph->prog[TABLEVERS_4].nproc = sizeof(tableprog_4_table)/sizeof(tableprog_4_table[0]);
1569 }
1570
1571 /******************************************************************************
1572  * static functions used within the file
1573  ******************************************************************************/
1574
1575 static Exception_4
1576 append_exception_list(Appt_4 *p_appt, int ordinal)
1577 {
1578         Exception_4 p_excpt;
1579         Exception_4 p_prev;
1580         Exception_4 p_ex;
1581
1582         if ((p_excpt = (Exception_4)calloc(1, sizeof(*p_excpt))) == NULL)
1583                 return (NULL);
1584         p_excpt->ordinal = ordinal;
1585         p_prev = NULL;
1586         p_ex = p_appt->exception;
1587         while (p_ex != NULL)
1588         {
1589                 /* Exception list is in descending order for faster access */
1590                 if (ordinal > p_ex->ordinal)
1591                         break;
1592                 p_prev = p_ex;
1593                 p_ex = p_ex->next;
1594         }
1595         if (p_prev == NULL)
1596         {
1597                 p_excpt->next = p_appt->exception;
1598                 p_appt->exception = p_excpt;
1599         }
1600         else
1601         {
1602                 p_excpt->next = p_prev->next;
1603                 p_prev->next = p_excpt;
1604         }
1605
1606         return (p_excpt);
1607 }
1608
1609 static Appt_4 *
1610 rtable_lookup_internal(_DtCmsCalendar *cal, char **p_src, Id_4 *key)
1611 {
1612         Appt_4  *p_appt;
1613         Privacy_Level_4 p_level;
1614
1615         /* Check if it hits a single appointment */
1616         p_appt = (Appt_4 *)rb_lookup(APPT_TREE(cal), (caddr_t)key);
1617
1618         if (p_appt != NULL) {
1619                 switch (_DtCmCheckPrivacyLevel(p_src, p_appt)) {
1620                 case public_4:
1621                         p_appt = _DtCm_copy_one_appt4(p_appt);
1622                         return(p_appt);
1623                 case semiprivate_4:
1624                         p_appt = _DtCm_copy_semiprivate_appt4(p_appt);
1625                         return(p_appt);
1626                 case private_4:
1627                 default:
1628                         return(NULL);
1629                 }
1630         }
1631         
1632         /* Check if it hits an event in any repeating appointment */
1633         p_appt = (Appt_4 *) hc_lookup (REPT_LIST(cal), (caddr_t)key);
1634
1635         if (p_appt != NULL) {
1636                 if ((p_level = _DtCmCheckPrivacyLevel(p_src, p_appt)) != private_4)
1637                 {
1638                         if (_DtCms_in_repeater (key, p_appt, B_FALSE)) {
1639                                 if (p_level == public_4)
1640                                         p_appt = _DtCm_copy_one_appt4(p_appt);
1641                                 else
1642                                         p_appt = _DtCm_copy_semiprivate_appt4(p_appt);
1643                                 APPT_TICK(p_appt) = key->tick;
1644                                 return(p_appt);
1645                         }
1646                 }
1647         }
1648
1649         return (NULL);
1650 }
1651
1652 static Appt_4 *
1653 repeater_next_larger(List_node *p_lnode, Id_4 *key)
1654 {
1655         static Appt_4 appt;
1656         Period_4        period;
1657         Appt_4  *p_appt;
1658         Appt_4  *p_save = NULL;
1659         Id_4    id, next_larger_id;
1660         int     ord;
1661         int     ntimes;
1662
1663         next_larger_id.tick = MAXINT;
1664         next_larger_id.key = MAXINT;
1665         while (p_lnode != NULL)
1666         {
1667                 p_appt = (Appt_4*)p_lnode->data;
1668
1669                 /* check last tick: if it's before the lookup range, skip it */
1670                 if (p_lnode->lasttick == 0)
1671                         p_lnode->lasttick = _DtCms_last_tick_v4(APPT_TICK(p_appt),
1672                                 p_appt->period, p_appt->ntimes);
1673
1674                 if ((p_lnode->lasttick < key->tick) ||
1675                     (p_lnode->lasttick == key->tick &&
1676                     APPT_KEY(p_appt) <= key->key)) {
1677                         p_lnode = hc_lookup_next(p_lnode);
1678                         continue;
1679                 }
1680
1681                 period = p_appt->period;
1682                 ntimes = _DtCms_get_ninstance_v4(p_appt);
1683                 id.tick = _DtCms_closest_tick_v4(key->tick, APPT_TICK(p_appt),
1684                                 period, &ord);
1685                 ord--;
1686                 id.key = APPT_KEY(p_appt);
1687                 while (++ord <= ntimes)
1688                 {
1689                         if ((id.tick < key->tick) || (id.tick == key->tick &&
1690                                         id.key <= key->key))
1691                                 id.tick = _DtCms_next_tick_v4 (id.tick, period);
1692                         else if (!_DtCms_marked_4_cancellation (p_appt, ord)) {
1693                                 if ((id.tick < next_larger_id.tick) ||
1694                                     (id.tick == next_larger_id.tick &&
1695                                         id.key < next_larger_id.key))
1696                                 {
1697                                         next_larger_id = id;
1698                                         p_save = p_appt;
1699                                 }
1700                                 break;
1701                         } else
1702                                 id.tick = _DtCms_next_tick_v4(id.tick, period);
1703                 }
1704                 p_lnode = hc_lookup_next (p_lnode);
1705         }
1706
1707         if (p_save != NULL)
1708         {
1709                 appt = *p_save;
1710                 APPT_TICK(&appt) = next_larger_id.tick;
1711                 p_save = &appt;
1712         }
1713
1714         return (p_save);
1715 }
1716
1717 static Appt_4 *
1718 repeater_next_smaller(List_node *p_lnode, Id_4 *key)
1719 {
1720         static Appt_4 appt;
1721         Appt_4  *p_appt;
1722         Period_4        period;
1723         Appt_4  *p_save = NULL;
1724         Id_4    id, next_smaller_id;
1725         int     ord;
1726         int     ntimes;
1727
1728         next_smaller_id.tick = 0;
1729         next_smaller_id.key = 0;
1730         while (p_lnode != NULL)
1731         {
1732                 p_appt = (Appt_4*)p_lnode->data;
1733                 ord = 0;
1734                 ntimes = _DtCms_get_ninstance_v4(p_appt);
1735                 period = p_appt->period;
1736                 id.tick = APPT_TICK(p_appt);
1737                 id.key = APPT_KEY(p_appt);
1738
1739                 /* Very inefficient loop because it has to check if each
1740                  * instance is cancelled.  If there is a function to calculate
1741                  * last tick, this loop can be rewritten in an efficient way.
1742                  */
1743                 while ((++ord <= ntimes) && (id.tick <= key->tick))
1744                 {
1745                         if (id.tick == key->tick && id.key >= key->key)
1746                                 /* this will get us out of the loop */
1747                                 /* faster than continue.            */
1748                                 id.tick = _DtCms_next_tick_v4 (id.tick, period);
1749                         else {
1750                                 if (!_DtCms_marked_4_cancellation (p_appt, ord)) {
1751                                         if ((id.tick > next_smaller_id.tick) ||
1752                                             (id.tick == next_smaller_id.tick &&
1753                                                 id.key > next_smaller_id.key))
1754                                         {
1755                                                 next_smaller_id = id;
1756                                                 p_save = p_appt;
1757                                         }
1758                                 }
1759                                 id.tick = _DtCms_next_tick_v4 (id.tick, period);
1760                         }
1761                 }
1762
1763                 p_lnode = hc_lookup_next (p_lnode);
1764         }
1765
1766         if (p_save != NULL)
1767         {
1768                 appt = *p_save;
1769                 APPT_TICK(&appt) = next_smaller_id.tick;
1770                 p_save = &appt;
1771         }
1772
1773         return (p_save);
1774 }
1775
1776 static Table_Res_4 *
1777 table_lookup_next(
1778         Table_Args_4 *args,
1779         struct svc_req *svcrq,
1780         caddr_t (* rb_func)(),
1781         Appt_4 *(* rp_func)())
1782 {
1783         static  Table_Res_4 res;
1784         CSA_return_code stat;
1785         Privacy_Level_4 p_level;
1786         Id_4    key;
1787         _DtCmsCalendar *cal;
1788         Appt_4  *p_appt;
1789         Appt_4  *p_appt1;
1790         char    *user;
1791         uint    access;
1792
1793         if (res.res.Table_Res_List_4_u.a)
1794                 _DtCm_free_appt4(res.res.Table_Res_List_4_u.a);
1795
1796         res.status = access_other_4;
1797         res.res.tag = AP_4;
1798         res.res.Table_Res_List_4_u.a = NULL;
1799
1800         switch (args->args.tag) {
1801         case TICK_4:
1802                 key.tick = args->args.Args_4_u.tick;
1803                 key.key = 0;
1804                 break;
1805         case UID_4:
1806                 key = args->args.Args_4_u.key->appt_id;
1807                 break;
1808         default:
1809                 return(&res);
1810         }
1811
1812         if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
1813             &access, &cal)) == CSA_SUCCESS) {
1814                 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1815                         if (_DTCMS_HAS_V4_BROWSE_ACCESS(access))
1816                                 res.status = access_ok_4;
1817                         else
1818                                 res.status = access_failed_4;
1819                 }
1820         } else {
1821                 res.status = csastat2accessstat(stat);
1822                 return (&res);
1823         }
1824
1825         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1826                 res.status = access_notsupported_4;
1827                 return (&res);
1828         }
1829
1830         p_appt = (Appt_4 *) (*rb_func) (APPT_TREE(cal), &key);
1831         p_appt1 = (*rp_func) (REPT_LIST(cal)->root, &key);
1832
1833         if (p_appt1 != NULL) {
1834                 if (rb_func == rb_lookup_next_larger) {
1835                         if ((p_appt==NULL) ||
1836                             (APPT_TICK(p_appt) > APPT_TICK(p_appt1)) ||
1837                             ((APPT_TICK(p_appt) == APPT_TICK(p_appt1)) &&
1838                                 (APPT_KEY(p_appt) > APPT_KEY(p_appt1)))) {
1839                                 p_appt = p_appt1;
1840                         }
1841                 } else {
1842                         if ((p_appt==NULL) ||
1843                             (APPT_TICK(p_appt) < APPT_TICK(p_appt1)) ||
1844                             ((APPT_TICK(p_appt) == APPT_TICK(p_appt1)) &&
1845                                 (APPT_KEY(p_appt) < APPT_KEY(p_appt1)))) {
1846                                 p_appt = p_appt1;
1847                         }
1848                 }
1849         }
1850
1851         if (p_appt != NULL) {
1852                 switch (_GetAccessLevel(user, access, p_appt)) {
1853                 case public_4:
1854                         p_appt = _DtCm_copy_one_appt4(p_appt);
1855                         break;
1856                 case semiprivate_4:
1857                         p_appt = _DtCm_copy_semiprivate_appt4(p_appt);
1858                         break;
1859                 default:
1860                         p_appt = NULL;
1861                         break;
1862                 }
1863         }
1864
1865         res.res.Table_Res_List_4_u.a = p_appt;
1866         return (&res);
1867 }
1868
1869 static Access_Status_4
1870 csastat2accessstat(CSA_return_code stat)
1871 {
1872         switch (stat) {
1873         case CSA_SUCCESS:
1874                 return (access_ok_4);
1875         case CSA_E_CALENDAR_EXISTS:
1876                 return (access_exists_4);
1877         case CSA_E_CALENDAR_NOT_EXIST:
1878                 return (access_notable_4);
1879         case CSA_E_INSUFFICIENT_MEMORY:
1880         case CSA_E_NO_AUTHORITY:
1881                 return (access_failed_4);
1882         case CSA_X_DT_E_BACKING_STORE_PROBLEM:
1883         case CSA_E_DISK_FULL:
1884                 return (access_incomplete_4);
1885         case CSA_E_NOT_SUPPORTED:
1886                 return (access_notsupported_4);
1887         case CSA_E_INVALID_PARAMETER:
1888         case CSA_E_FAILURE:
1889         case CSA_X_DT_E_ENTRY_NOT_FOUND:
1890         default:
1891                 return (access_other_4);
1892         }
1893 }
1894
1895 static Table_Status_4
1896 csastat2tablestat(CSA_return_code stat)
1897 {
1898         switch (stat) {
1899         case CSA_SUCCESS:
1900                 return (ok_4);
1901         case CSA_E_CALENDAR_EXISTS:
1902                 return (tbl_exist_4);
1903         case CSA_E_CALENDAR_NOT_EXIST:
1904                 return (notable_4);
1905         case CSA_E_NOT_SUPPORTED:
1906                 return (tbl_notsupported_4);
1907         case CSA_E_FAILURE:
1908         case CSA_E_INSUFFICIENT_MEMORY:
1909         case CSA_E_INVALID_PARAMETER:
1910         default:
1911                 return (other_4);
1912         }
1913 }
1914
1915 static Registration_Status_4
1916 csastat2regstat(CSA_return_code stat)
1917 {
1918         switch (stat) {
1919         case CSA_E_CALENDAR_NOT_EXIST:
1920                 return(reg_notable_4);
1921         default:
1922                 return (failed_4);
1923         }
1924 }
1925