2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $XConsortium: rtable4.c /main/5 1996/10/02 17:31:51 drk $ */
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.
32 * version 4 of calendar manager rpc protocol functions.
35 #include <EUSCompat.h>
44 #include <sys/param.h>
46 #include <sys/signal.h>
48 #if defined(CSRG_BASED)
49 #define MAXINT INT_MAX
58 #include <sys/socket.h>
69 #include "cmscalendar.h"
76 #include "rpcextras.h"
77 #include "rtable4_tbl.i"
81 #include "convert5-4.h"
82 #include "convert4-5.h"
83 #include "cmsconvert.h"
93 /*****************************************************************************
94 * forward declaration of static functions used within the file
95 *****************************************************************************/
97 static Appt_4 * rtable_lookup_internal(_DtCmsCalendar *cal, char **p_src,
100 static Access_Status_4 csastat2accessstat(CSA_return_code stat);
102 static Registration_Status_4 csastat2regstat(CSA_return_code stat);
104 static Table_Status_4 csastat2tablestat(CSA_return_code stat);
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)());
110 static Appt_4 * repeater_next_smaller(List_node *p_lnode, Id_4 *key);
112 static Appt_4 * repeater_next_larger(List_node *p_lnode, Id_4 *key);
114 /*****************************************************************************
115 * extern functions used in the library
116 *****************************************************************************/
119 * supports both data format
122 _DtCm_rtable_lookup_4_svc (Table_Args_4 *args, struct svc_req *svcrq)
124 static Table_Res_4 res;
125 CSA_return_code stat;
138 fprintf(stderr, "_DtCm_rtable_lookup_4_svc called\n");
140 if (res.res.Table_Res_List_4_u.a)
141 _DtCm_free_appt4(res.res.Table_Res_List_4_u.a);
143 res.status = access_other_4;
145 res.res.Table_Res_List_4_u.a = NULL;
146 if ((p_keys = args->args.Args_4_u.key) == NULL)
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;
155 res.status = access_failed_4;
156 } else if (!_DTCMS_HAS_VIEW_ACCESS(access)) {
157 res.status = access_failed_4;
160 res.status = access_ok_4;
162 res.status = csastat2accessstat(stat);
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;
171 if ((stat = _DtCmsGetEntryAttrByKey(cal, user, access,
172 cmskey, 0, NULL, &entries, NULL))
175 if ((stat = _DtCmsCmsentriesToAppt4ForClient(
176 entries, &p_appt)) == CSA_SUCCESS) {
177 /* link to appt list */
178 h = _AddApptInOrder(h, p_appt);
180 _DtCm_free_cms_entries(entries);
183 if (stat != CSA_SUCCESS) {
184 res.status = csastat2accessstat(stat);
191 p_keys = p_keys->next;
194 res.res.Table_Res_List_4_u.a = h;
198 /* do lookup on old format calendar */
199 while (p_keys != NULL)
201 key = &p_keys->appt_id;
205 "_DtCm_rtable_lookup_4_svc at (key %ld)%s\n",
206 key->key, ctime(&key->tick));
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))
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;
224 stat = _AddToLinkedAppts(p_appt, user, access,
227 if (tmptick) p_appt->appt_id.tick = tmptick;
229 if (stat != CSA_SUCCESS) {
234 res.status = csastat2accessstat(stat);
239 p_keys = p_keys->next;
242 res.res.Table_Res_List_4_u.a = h;
247 * supports old data format only
250 _DtCm_rtable_lookup_next_larger_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
255 fprintf(stderr, "_DtCm_rtable_lookup_next_larger_4_svc called\n");
257 res = table_lookup_next(args, svcrq, rb_lookup_next_larger,
258 repeater_next_larger);
263 * supports old data format only
266 _DtCm_rtable_lookup_next_smaller_4_svc(
268 struct svc_req *svcrq)
273 fprintf(stderr, "_DtCm_rtable_lookup_next_smaller_4_svc called\n");
275 res = table_lookup_next(args, svcrq, rb_lookup_next_smaller,
276 repeater_next_smaller);
281 * supports both data format
284 _DtCm_rtable_lookup_range_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
286 static Table_Res_4 res;
287 CSA_return_code stat;
293 fprintf(stderr, "_DtCm_rtable_lookup_range_4_svc called\n");
295 if (res.res.Table_Res_List_4_u.a)
296 _DtCm_free_appt4(res.res.Table_Res_List_4_u.a);
299 res.res.Table_Res_List_4_u.a = NULL;
301 res.status = access_other_4;
302 if (args->args.Args_4_u.range == NULL)
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;
311 res.status = access_failed_4;
314 res.status = csastat2accessstat(stat);
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);
322 res.status = csastat2accessstat(stat);
327 * supports both data format
330 _DtCm_rtable_abbreviated_lookup_range_4_svc(
332 struct svc_req *svcrq)
334 static Table_Res_4 res;
335 CSA_return_code stat;
342 "_DtCm_rtable_abbreviated_lookup_range_4_svc called\n");
344 if (res.res.Table_Res_List_4_u.b)
345 _DtCm_free_abbrev_appt4(res.res.Table_Res_List_4_u.b);
348 res.res.Table_Res_List_4_u.b = NULL;
350 res.status = access_other_4;
351 if (args->args.Args_4_u.range == NULL)
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;
360 res.status = access_failed_4;
363 res.status = csastat2accessstat(stat);
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);
371 res.status = csastat2accessstat(stat);
376 _DtCm_rtable_insert_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
378 static Table_Res_4 res;
380 CSA_return_code stat;
384 Appt_4 *ap, *appt, *prev=NULL, *a;
388 fprintf(stderr, "_DtCm_rtable_insert_4_svc called\n");
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);
394 res.status = access_other_4;
396 res.res.Table_Res_List_4_u.a = NULL;
398 /* check arguments */
399 if (args->target == NULL)
401 if ((ap = args->args.Args_4_u.appt) == NULL)
404 /* do some sanity checks before inserting : check appt data */
405 for (appt = args->args.Args_4_u.appt; appt != NULL; appt = appt->next)
407 /* ntimes should be 0 or positive */
408 if (appt->ntimes < 0 ||
409 (appt->period.period > single_4 && appt->ntimes == 0))
412 /* period beyond daysOfWeek is not supported */
413 if (appt->period.period > daysOfWeek_4) {
414 res.status = access_notsupported_4;
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))
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;
431 } else if (!_DTCMS_HAS_INSERT_ACCESS(access)) {
432 res.status = access_failed_4;
435 res.status = access_ok_4;
437 res.status = csastat2accessstat(stat);
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
445 if ((appt = _DtCm_copy_appt4(args->args.Args_4_u.appt)) == NULL) {
451 while (appt != NULL) {
454 * we used to calculate the correct start day,
455 * but we should return an error instead
457 _DtCms_adjust_appt_startdate(appt);
459 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
460 /* convert to attributes */
461 if (_DtCmsAppt4ToCmsentry(args->target, appt, &entry,
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].\
474 if (_DtCmsCheckInitialAttributes(entry)) {
475 _DtCm_free_cms_entry(entry);
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);
487 /* insert entry and log it */
488 if (_DtCmsInsertEntryAndLog(cal, entry)) {
489 _DtCm_free_cms_entry(entry);
493 appt->appt_id.key = entry->key.id;
494 _DtCm_free_cms_entry(entry);
497 if ((a = _DtCm_copy_one_appt4(appt)) == NULL)
500 /* We don't trust the author field; we set our own. */
502 if ((a->author = strdup(user)) == NULL) {
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);
513 /* get the new key */
514 appt->appt_id.key = a->appt_id.key;
521 cal->modified = B_TRUE;
524 cal->rlist = _DtCmsDoV1Callback(cal->rlist, user, args->pid, ap);
526 for (appt = ap; appt != NULL; appt = appt->next) {
527 cal->rlist = _DtCmsDoInsertEntryCallback(cal->rlist,
528 cal->calendar, user, appt->appt_id.key,
532 res.status = access_ok_4;
533 res.res.Table_Res_List_4_u.a = ap;
539 cal->modified = B_TRUE;
540 /* some appts were inserted successfully */
541 res.status = access_partial_4;
543 res.res.Table_Res_List_4_u.a = ap;
546 cal->rlist = _DtCmsDoV1Callback(cal->rlist, user, args->pid,
548 for (appt = ap; appt != NULL; appt = appt->next) {
549 cal->rlist = _DtCmsDoInsertEntryCallback(cal->rlist,
551 appt->appt_id.key, args->pid);
555 /* first appt in bunch that failed */
556 res.status = csastat2accessstat(stat);
558 _DtCm_free_appt4(appt);
564 _DtCm_rtable_delete_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
566 static Table_Res_4 res;
568 CSA_return_code stat;
579 fprintf(stderr, "_DtCm_rtable_delete_4_svc called\n");
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);
585 res.status = access_other_4;
587 res.res.Table_Res_List_4_u.a = NULL;
589 /* check arguments */
590 if (args->target == NULL)
592 if ((p_keys = args->args.Args_4_u.uidopt) == NULL)
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;
603 res.status = csastat2accessstat(stat);
608 while (p_keys != NULL) {
611 fprintf (stderr, "Delete: (key %ld)%s\n",
613 ctime(&p_keys->appt_id.tick));
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;
620 if (p_keys->option == do_all_4)
621 stat = _DtCmsDeleteEntryAndLog(cal, user,
622 access, &key, &entry);
624 stat = _DtCmsDeleteInstancesAndLog(cal, user,
626 (p_keys->option == CSA_SCOPE_ONE ?
627 CSA_SCOPE_ONE : CSA_SCOPE_FORWARD),
630 if (stat == CSA_SUCCESS)
631 stat = _DtCm_cms_entry_to_appt4(entry, &a);
633 _DtCm_free_cms_entry(entry);
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);
642 stat = _DtCmsDeleteApptInstancesAndLog(cal,
643 user, access, &p_keys->appt_id,
644 p_keys->option, NULL, &a);
648 if (stat == CSA_SUCCESS) {
649 if (p_keys->option != do_all_4)
650 APPT_TICK(a) = p_keys->appt_id.tick;
655 } else if (stat == CSA_X_DT_E_ENTRY_NOT_FOUND)
658 p_keys = p_keys->next;
662 cal->modified = B_TRUE;
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;
671 cal->rlist = _DtCmsDoDeleteEntryCallback(cal->rlist,
672 cal->calendar, user, a->appt_id.key,
674 (p_keys->option == do_all_4 ?
675 a->appt_id.tick : p_keys->appt_id.tick),
682 res.status = csastat2accessstat(stat);
684 res.status = (nf < n) ? access_failed_4 : access_ok_4;
686 res.status = access_partial_4;
688 res.status = access_ok_4;
690 res.res.Table_Res_List_4_u.a = h;
696 _DtCm_rtable_delete_instance_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
698 static Table_Res_4 res;
701 fprintf(stderr, "_DtCm_rtable_delete_instance_4_svc called\n");
703 res.status = access_notsupported_4;
705 res.res.Table_Res_List_4_u.a = NULL;
711 _DtCm_rtable_change_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
713 static Table_Res_4 res;
715 CSA_return_code stat;
722 cms_entry *entry, *oldentry, *newentry = NULL;
726 fprintf(stderr, "_DtCm_rtable_change_4_svc called\n");
728 /* clean out left over */
729 res.status = access_other_4;
731 res.res.Table_Res_List_4_u.a = NULL;
733 /* check arguments */
734 if (args->target == NULL)
736 if ((p_key = args->args.Args_4_u.apptid.oid) == NULL)
738 if ((newa = args->args.Args_4_u.apptid.new_appt) == NULL)
741 /* ntimes should be 0 or positive */
742 if (newa->ntimes < 0 ||
743 (newa->period.period > single_4 && newa->ntimes == 0))
746 /* period beyond daysOfWeek is not supported */
747 if (newa->period.period > daysOfWeek_4) {
748 res.status = access_notsupported_4;
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))
757 option = args->args.Args_4_u.apptid.option;
758 if (option < do_all_4 || option > do_forward_4)
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))) {
768 res.status = access_failed_4;
772 res.status = csastat2accessstat(stat);
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) {
781 key.time = p_key->tick;
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]);
793 if (option == do_all_4)
794 stat = _DtCmsUpdateEntry(cal, user, access,
795 &key, entry->num_attrs,
796 &entry->attrs[1], &oldentry, NULL);
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);
804 _DtCm_free_cms_entry(entry);
808 if (option == do_all_4)
809 stat = _DtCmsChangeAll(cal, user, access, p_key, newa,
812 stat = _DtCmsChangeSome(cal, user, access,p_key, newa,
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;
821 _DtCm_free_cms_entry(oldentry);
823 newa->appt_id.key = newentry->key.id;
824 _DtCm_free_cms_entry(newentry);
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.
832 if (APPT_TICK(newa) == APPT_TICK(olda)) {
833 cal->rlist = _DtCmsDoV1Callback(cal->rlist, user,
837 cal->rlist = _DtCmsDoV1Callback(cal->rlist, user,
842 cal->rlist = _DtCmsDoUpdateEntryCallback(cal->rlist,
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),
850 cal->modified = B_TRUE;
852 /* Return the new appointment. */
853 res.res.Table_Res_List_4_u.a = newa;
854 res.status = access_ok_4;
856 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION)
857 _DtCm_free_appt4(olda);
859 res.status = csastat2accessstat(stat);
865 _DtCm_rtable_change_instance_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
867 static Table_Res_4 res;
870 fprintf(stderr, "_DtCm_rtable_change_instance_4_svc called\n");
872 res.status = access_notsupported_4;
874 res.res.Table_Res_List_4_u.a = NULL;
880 _DtCm_rtable_lookup_next_reminder_4_svc(
882 struct svc_req *svcrq)
884 static Table_Res_4 res;
885 CSA_return_code stat;
889 Reminder_4 *p_reminder;
895 cms_reminder_ref *rems;
898 fprintf(stderr, "_DtCm_rtable_lookup_next_reminder_4_svc called\n");
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);
904 res.status = access_other_4;
906 res.res.Table_Res_List_4_u.r = NULL;
908 if (args->target == NULL)
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)) {
916 res.status = access_failed_4;
920 res.status = csastat2accessstat(stat);
924 tick = args->args.Args_4_u.tick;
927 fprintf(stderr, "Next reminder after %s", ctime(&tick));
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);
938 stat = _DtCmsGetV4Reminders(cal, tick,
939 &res.res.Table_Res_List_4_u.r, NULL);
942 res.status = csastat2accessstat(stat);
946 extern Table_Status_4 *
947 _DtCm_rtable_check_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
949 static Table_Status_4 s;
950 CSA_return_code stat;
955 fprintf(stderr, "_DtCm_rtable_check_4_svc called\n");
957 if ((stat = _DtCmsGetCalendarByName(args->target, B_TRUE, &cal))
960 s = csastat2tablestat(stat);
964 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
965 s = tbl_notsupported_4;
968 rbstat = rb_check_tree (cal->tree);
970 rbstat = hc_check_list (cal->list);
981 extern Table_Status_4 *
982 _DtCm_rtable_flush_table_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
984 static Table_Status_4 s;
986 CSA_return_code stat;
1000 fprintf (stderr, "rtable_flush_table\n");
1002 if ((stat = _DtCmsGetCalendarByName(args->target, B_TRUE, &cal))
1004 s = csastat2tablestat(stat);
1008 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1009 s = tbl_notsupported_4;
1015 fprintf(stderr, "%s: before flush.. rbsize= %d\n", pgname,
1016 rb_size(APPT_TREE(cal))+hc_size(REPT_LIST(cal)));
1019 /* Flushing the single appointment tree. */
1021 key.tick = args->args.Args_4_u.tick;
1022 while (p_appt = (Appt_4 *) rb_lookup_next_larger(APPT_TREE(cal),
1024 p_node = rb_delete (APPT_TREE(cal),
1025 (caddr_t)&(p_appt->appt_id));
1029 _DtCm_free_appt4 ((Appt_4 *) p_node->data);
1034 /* Flushing the repeating appointment list */
1036 key.tick = args->args.Args_4_u.tick;
1037 p_lnode = cal->list->root;
1038 while (p_lnode != NULL)
1040 p_next = hc_lookup_next (p_lnode);
1041 p_appt = (Appt_4*)p_lnode->data;
1042 if (APPT_TICK(p_appt) > key.tick)
1045 _DtCm_free_appt4 (p_appt);
1046 (void) hc_delete_node (REPT_LIST(cal), p_lnode);
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)));
1063 _DtCm_rtable_size_4_svc(Table_Args_4 *args, struct svc_req *svcrq)
1065 /* must be static! */
1067 CSA_return_code stat;
1068 _DtCmsCalendar *cal;
1071 fprintf(stderr, "_DtCm_rtable_size_4_svc called\n");
1074 if ((stat = _DtCmsGetCalendarByName(args->target, B_TRUE, &cal))
1078 size = rb_size (APPT_TREE(cal)) + hc_size (REPT_LIST(cal));
1083 extern Registration_Status_4 *
1084 _DtCm_register_callback_4_svc(Registration_4 *r, struct svc_req *svcrq)
1086 static Registration_Status_4 regstat;
1087 CSA_return_code stat;
1089 _DtCmsCalendar *cal = NULL;
1090 _DtCmsRegistrationInfo *copy=NULL;
1093 fprintf(stderr, "_DtCm_register_callback_4_svc called\n");
1096 if (r->target == NULL) {
1101 if ((stat = _DtCmsGetClientInfo(svcrq, &source)) != CSA_SUCCESS) {
1102 regstat = csastat2regstat(stat);
1106 /* check if the target exists */
1107 if ((stat = _DtCmsGetCalendarByName(r->target, B_TRUE, &cal))
1109 regstat = csastat2regstat(stat);
1113 /* Check for duplicate registrations */
1114 if (_DtCmsGetRegistration(&(cal->rlist), source, r->prognum, r->versnum,
1115 r->procnum, r->pid) == NULL) {
1116 /* not registered */
1118 /* Make a copy of the callback info. */
1120 if ((copy = _DtCmsMakeRegistrationInfo(source, 0, r->prognum,
1121 r->versnum, r->procnum, r->pid)) == NULL) {
1126 /* Store it away so that it can later be called. */
1127 copy->next = cal->rlist;
1131 fprintf(stderr, "%s requested registration on %s. registered pid= %d\n",
1132 source, r->target, r->pid);
1133 _DtCmsListRegistration(cal->rlist,
1136 regstat = registered_4;
1139 /* already registered */
1140 regstat = registered_4;
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)
1149 static Registration_Status_4 regstat;
1150 CSA_return_code stat;
1151 _DtCmsCalendar *cal;
1153 _DtCmsRegistrationInfo *p = NULL, *q = NULL;
1156 fprintf(stderr, "_DtCm_deregister_callback_4_svc called\n");
1158 if (r->target == NULL) {
1163 if ((stat = _DtCmsGetClientInfo(svcrq, &source)) != CSA_SUCCESS) {
1164 regstat = csastat2regstat(stat);
1168 if ((stat = _DtCmsGetCalendarByName(r->target, B_FALSE, &cal))
1170 regstat = csastat2regstat(stat);
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
1191 * ... only then is it ok to decommission the ticket.
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 */
1201 fprintf(stderr, "%s requested deregistration on %s. registered pid= %d\n", source, r->target, r->pid);
1204 cal->rlist = p->next;
1207 _DtCmsFreeRegistrationInfo(p);
1209 _DtCmsListRegistration(cal->rlist,
1212 regstat = deregistered_4;
1224 extern Access_Status_4 *
1225 _DtCm_rtable_set_access_4_svc(Access_Args_4 *args, struct svc_req *svcrq)
1227 /* must be static! */
1228 static Access_Status_4 s;
1229 CSA_return_code stat;
1232 _DtCmsCalendar *cal = NULL;
1235 fprintf(stderr, "_DtCm_rtable_set_access_4_svc called\n");
1239 if (args->target == NULL)
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))) {
1250 s = access_failed_4;
1254 s = csastat2accessstat(stat);
1258 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1260 cms_attribute_value attrval;
1261 cms_access_entry *alist;
1263 if (args->access_list && (alist =
1264 _DtCmsConvertV4AccessList(args->access_list)) == NULL) {
1265 s = csastat2accessstat(CSA_E_INSUFFICIENT_MEMORY);
1269 attr.name.name = CSA_CAL_ATTR_ACCESS_LIST;
1271 attr.value = &attrval;
1272 attrval.type = CSA_VALUE_ACCESS_LIST;
1273 attrval.item.access_list_value = alist;
1275 stat = _DtCmsUpdateCalAttributesAndLog(cal, 1, &attr, access);
1277 stat = _DtCmsSetV4AccessListAndLog(cal, args->access_list);
1280 if ((s = csastat2accessstat(stat)) == access_ok_4) {
1284 attr.name.name = CSA_CAL_ATTR_ACCESS_LIST;
1285 cal->rlist = _DtCmsDoUpdateCalAttrsCallback(cal->rlist,
1286 cal->calendar, user, 1, &attr, -1);
1292 extern Access_Args_4 *
1293 _DtCm_rtable_get_access_4_svc(Access_Args_4 *args, struct svc_req *svcrq)
1295 static Access_Args_4 res;
1296 CSA_return_code stat;
1297 _DtCmsCalendar *cal;
1298 char *target, *user;
1300 boolean_t useronly = B_FALSE;
1301 cms_access_entry aentry;
1304 fprintf(stderr, "_DtCm_rtable_get_access_4_svc called\n");
1306 if (res.target != NULL)
1308 if (res.access_list)
1309 _DtCm_free_access_list4(res.access_list);
1312 res.access_list = (Access_Entry_4 *) NULL;
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)) {
1324 if (cal->fversion > 1) {
1327 aentry.rights = access;
1329 res.access_list = _DtCmsConvertV5AccessList(&aentry,
1332 res.access_list = _DtCmsConvertV5AccessList(
1333 cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I].\
1334 value->item.access_list_value, B_TRUE);
1337 res.access_list = _DtCmsCalendarAccessList(cal);
1339 _DtCmsShowAccessList (res.access_list);
1342 res.target = strdup(args->target);
1347 extern Table_Res_4 *
1348 _DtCm_rtable_abbreviated_lookup_key_range_4_svc(
1350 struct svc_req *svcrq)
1352 static Table_Res_4 res;
1353 CSA_return_code stat;
1354 _DtCmsCalendar *cal;
1357 Keyrange_4 *p_range;
1358 Abb_Appt_4 *abbr_r = NULL;
1362 "_DtCm_rtable_abbreviated_lookup_key_range_4_svc called\n");
1364 if (res.res.Table_Res_List_4_u.b)
1365 _DtCm_free_abbrev_appt4(res.res.Table_Res_List_4_u.b);
1368 res.res.Table_Res_List_4_u.b = NULL;
1370 res.status = access_other_4;
1371 if ((p_range = args->args.Args_4_u.keyrange) == NULL)
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;
1380 res.status = access_failed_4;
1383 res.status = csastat2accessstat(stat);
1387 while (p_range != NULL)
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))
1397 p_range = p_range->next;
1400 if (stat == CSA_SUCCESS)
1401 res.res.Table_Res_List_4_u.b = abbr_r;
1403 _DtCm_free_abbrev_appt4(abbr_r);
1405 res.status = csastat2accessstat(stat);
1410 _DtCm_rtable_gmtoff_4_svc(void *args, struct svc_req *svcrq)
1413 #if !defined(CSRG_BASED)
1414 extern long timezone;
1420 fprintf(stderr, "_DtCm_rtable_gmtoff_4_svc called\n");
1422 #if defined(CSRG_BASED)
1423 t = localtime(time(NULL));
1424 gmtoff = t->tm_gmtoff;
1431 extern Table_Status_4 *
1432 _DtCm_rtable_create_4_svc(Table_Op_Args_4 *args, struct svc_req *svcrq)
1434 static Table_Status_4 res;
1435 CSA_return_code stat;
1436 _DtCmsCalendar *cal;
1441 char *id, *user, *domain;
1442 Access_Entry_4 aentry;
1445 fprintf(stderr, "_DtCm_rtable_create_4_svc called\n");
1448 if ((stat = _DtCmsGetClientInfo(svcrq, &source)) != CSA_SUCCESS) {
1449 res = csastat2tablestat(stat);
1453 /* check domain if domain info is available */
1454 /* only user in the local domain can create file */
1455 if (ptr = strchr(source, '.')) {
1457 fprintf(stderr, "rpc.cmsd: %s %s(target) and %s(sender)\n",
1458 "check domains, comparing",
1459 args->target, source);
1461 if ((domain = _DtCmsTarget2Domain(args->target)) != NULL) {
1463 if (!_DtCmIsSamePath(domain, ++ptr)) {
1471 if ((calname = _DtCmsTarget2Name(args->target)) == NULL)
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) {
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
1487 if ((id = _DtCmGetPrefix(calname, '.')) == NULL) {
1491 if ((user = _DtCmGetPrefix(source, '@')) == NULL) {
1497 if (getpwnam(id) && strcmp(user, id)) {
1506 if ((log = _DtCmsGetLogFN(calname)) == NULL)
1512 fprintf(stderr, "new file = '%s'\n", log);
1514 if ((stat = _DtCmsCreateLogV1(user, log)) == CSA_E_CALENDAR_EXISTS)
1516 else if (stat != CSA_SUCCESS)
1521 /* initialize the access list to be "WORLD", access_read_4 */
1524 aentry.access_type = access_read_4;
1525 if ((stat = _DtCmsAppendAccessByFN(log, access_read_4, &aentry))
1536 extern Table_Status_4 *
1537 _DtCm_rtable_remove_4_svc(Table_Op_Args_4 *args, struct svc_req *svcrq)
1539 static Table_Status_4 res;
1541 res = tbl_notsupported_4;
1545 extern Table_Status_4 *
1546 _DtCm_rtable_rename_4_svc(Table_Op_Args_4 *args, struct svc_req *svcrq)
1548 static Table_Status_4 res;
1550 res = tbl_notsupported_4;
1555 _DtCm_rtable_ping_4_svc(void *args, struct svc_req *svcrq)
1560 fprintf(stderr, "_DtCm_rtable_ping_4_svc called\n");
1562 return((void *)&dummy); /* for RPC reply */
1566 initrtable4(program_handle ph)
1568 ph->program_num = TABLEPROG;
1569 ph->prog[TABLEVERS_4].vers = &tableprog_4_table[0];
1570 ph->prog[TABLEVERS_4].nproc = sizeof(tableprog_4_table)/sizeof(tableprog_4_table[0]);
1573 /******************************************************************************
1574 * static functions used within the file
1575 ******************************************************************************/
1578 append_exception_list(Appt_4 *p_appt, int ordinal)
1580 Exception_4 p_excpt;
1584 if ((p_excpt = (Exception_4)calloc(1, sizeof(*p_excpt))) == NULL)
1586 p_excpt->ordinal = ordinal;
1588 p_ex = p_appt->exception;
1589 while (p_ex != NULL)
1591 /* Exception list is in descending order for faster access */
1592 if (ordinal > p_ex->ordinal)
1599 p_excpt->next = p_appt->exception;
1600 p_appt->exception = p_excpt;
1604 p_excpt->next = p_prev->next;
1605 p_prev->next = p_excpt;
1612 rtable_lookup_internal(_DtCmsCalendar *cal, char **p_src, Id_4 *key)
1615 Privacy_Level_4 p_level;
1617 /* Check if it hits a single appointment */
1618 p_appt = (Appt_4 *)rb_lookup(APPT_TREE(cal), (caddr_t)key);
1620 if (p_appt != NULL) {
1621 switch (_DtCmCheckPrivacyLevel(p_src, p_appt)) {
1623 p_appt = _DtCm_copy_one_appt4(p_appt);
1626 p_appt = _DtCm_copy_semiprivate_appt4(p_appt);
1634 /* Check if it hits an event in any repeating appointment */
1635 p_appt = (Appt_4 *) hc_lookup (REPT_LIST(cal), (caddr_t)key);
1637 if (p_appt != NULL) {
1638 if ((p_level = _DtCmCheckPrivacyLevel(p_src, p_appt)) != private_4)
1640 if (_DtCms_in_repeater (key, p_appt, B_FALSE)) {
1641 if (p_level == public_4)
1642 p_appt = _DtCm_copy_one_appt4(p_appt);
1644 p_appt = _DtCm_copy_semiprivate_appt4(p_appt);
1645 APPT_TICK(p_appt) = key->tick;
1655 repeater_next_larger(List_node *p_lnode, Id_4 *key)
1660 Appt_4 *p_save = NULL;
1661 Id_4 id, next_larger_id;
1665 next_larger_id.tick = MAXINT;
1666 next_larger_id.key = MAXINT;
1667 while (p_lnode != NULL)
1669 p_appt = (Appt_4*)p_lnode->data;
1671 /* check last tick: if it's before the lookup range, skip it */
1672 if (p_lnode->lasttick == 0)
1673 p_lnode->lasttick = _DtCms_last_tick_v4(APPT_TICK(p_appt),
1674 p_appt->period, p_appt->ntimes);
1676 if ((p_lnode->lasttick < key->tick) ||
1677 (p_lnode->lasttick == key->tick &&
1678 APPT_KEY(p_appt) <= key->key)) {
1679 p_lnode = hc_lookup_next(p_lnode);
1683 period = p_appt->period;
1684 ntimes = _DtCms_get_ninstance_v4(p_appt);
1685 id.tick = _DtCms_closest_tick_v4(key->tick, APPT_TICK(p_appt),
1688 id.key = APPT_KEY(p_appt);
1689 while (++ord <= ntimes)
1691 if ((id.tick < key->tick) || (id.tick == key->tick &&
1692 id.key <= key->key))
1693 id.tick = _DtCms_next_tick_v4 (id.tick, period);
1694 else if (!_DtCms_marked_4_cancellation (p_appt, ord)) {
1695 if ((id.tick < next_larger_id.tick) ||
1696 (id.tick == next_larger_id.tick &&
1697 id.key < next_larger_id.key))
1699 next_larger_id = id;
1704 id.tick = _DtCms_next_tick_v4(id.tick, period);
1706 p_lnode = hc_lookup_next (p_lnode);
1712 APPT_TICK(&appt) = next_larger_id.tick;
1720 repeater_next_smaller(List_node *p_lnode, Id_4 *key)
1725 Appt_4 *p_save = NULL;
1726 Id_4 id, next_smaller_id;
1730 next_smaller_id.tick = 0;
1731 next_smaller_id.key = 0;
1732 while (p_lnode != NULL)
1734 p_appt = (Appt_4*)p_lnode->data;
1736 ntimes = _DtCms_get_ninstance_v4(p_appt);
1737 period = p_appt->period;
1738 id.tick = APPT_TICK(p_appt);
1739 id.key = APPT_KEY(p_appt);
1741 /* Very inefficient loop because it has to check if each
1742 * instance is cancelled. If there is a function to calculate
1743 * last tick, this loop can be rewritten in an efficient way.
1745 while ((++ord <= ntimes) && (id.tick <= key->tick))
1747 if (id.tick == key->tick && id.key >= key->key)
1748 /* this will get us out of the loop */
1749 /* faster than continue. */
1750 id.tick = _DtCms_next_tick_v4 (id.tick, period);
1752 if (!_DtCms_marked_4_cancellation (p_appt, ord)) {
1753 if ((id.tick > next_smaller_id.tick) ||
1754 (id.tick == next_smaller_id.tick &&
1755 id.key > next_smaller_id.key))
1757 next_smaller_id = id;
1761 id.tick = _DtCms_next_tick_v4 (id.tick, period);
1765 p_lnode = hc_lookup_next (p_lnode);
1771 APPT_TICK(&appt) = next_smaller_id.tick;
1778 static Table_Res_4 *
1781 struct svc_req *svcrq,
1782 caddr_t (* rb_func)(),
1783 Appt_4 *(* rp_func)())
1785 static Table_Res_4 res;
1786 CSA_return_code stat;
1787 Privacy_Level_4 p_level;
1789 _DtCmsCalendar *cal;
1795 if (res.res.Table_Res_List_4_u.a)
1796 _DtCm_free_appt4(res.res.Table_Res_List_4_u.a);
1798 res.status = access_other_4;
1800 res.res.Table_Res_List_4_u.a = NULL;
1802 switch (args->args.tag) {
1804 key.tick = args->args.Args_4_u.tick;
1808 key = args->args.Args_4_u.key->appt_id;
1814 if ((stat = _DtCmsV4LoadAndCheckAccess(svcrq, args->target, &user,
1815 &access, &cal)) == CSA_SUCCESS) {
1816 if (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1817 if (_DTCMS_HAS_V4_BROWSE_ACCESS(access))
1818 res.status = access_ok_4;
1820 res.status = access_failed_4;
1823 res.status = csastat2accessstat(stat);
1827 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1828 res.status = access_notsupported_4;
1832 p_appt = (Appt_4 *) (*rb_func) (APPT_TREE(cal), &key);
1833 p_appt1 = (*rp_func) (REPT_LIST(cal)->root, &key);
1835 if (p_appt1 != NULL) {
1836 if (rb_func == rb_lookup_next_larger) {
1837 if ((p_appt==NULL) ||
1838 (APPT_TICK(p_appt) > APPT_TICK(p_appt1)) ||
1839 ((APPT_TICK(p_appt) == APPT_TICK(p_appt1)) &&
1840 (APPT_KEY(p_appt) > APPT_KEY(p_appt1)))) {
1844 if ((p_appt==NULL) ||
1845 (APPT_TICK(p_appt) < APPT_TICK(p_appt1)) ||
1846 ((APPT_TICK(p_appt) == APPT_TICK(p_appt1)) &&
1847 (APPT_KEY(p_appt) < APPT_KEY(p_appt1)))) {
1853 if (p_appt != NULL) {
1854 switch (_GetAccessLevel(user, access, p_appt)) {
1856 p_appt = _DtCm_copy_one_appt4(p_appt);
1859 p_appt = _DtCm_copy_semiprivate_appt4(p_appt);
1867 res.res.Table_Res_List_4_u.a = p_appt;
1871 static Access_Status_4
1872 csastat2accessstat(CSA_return_code stat)
1876 return (access_ok_4);
1877 case CSA_E_CALENDAR_EXISTS:
1878 return (access_exists_4);
1879 case CSA_E_CALENDAR_NOT_EXIST:
1880 return (access_notable_4);
1881 case CSA_E_INSUFFICIENT_MEMORY:
1882 case CSA_E_NO_AUTHORITY:
1883 return (access_failed_4);
1884 case CSA_X_DT_E_BACKING_STORE_PROBLEM:
1885 case CSA_E_DISK_FULL:
1886 return (access_incomplete_4);
1887 case CSA_E_NOT_SUPPORTED:
1888 return (access_notsupported_4);
1889 case CSA_E_INVALID_PARAMETER:
1891 case CSA_X_DT_E_ENTRY_NOT_FOUND:
1893 return (access_other_4);
1897 static Table_Status_4
1898 csastat2tablestat(CSA_return_code stat)
1903 case CSA_E_CALENDAR_EXISTS:
1904 return (tbl_exist_4);
1905 case CSA_E_CALENDAR_NOT_EXIST:
1907 case CSA_E_NOT_SUPPORTED:
1908 return (tbl_notsupported_4);
1910 case CSA_E_INSUFFICIENT_MEMORY:
1911 case CSA_E_INVALID_PARAMETER:
1917 static Registration_Status_4
1918 csastat2regstat(CSA_return_code stat)
1921 case CSA_E_CALENDAR_NOT_EXIST:
1922 return(reg_notable_4);