1 /* $XConsortium: v4ops.c /main/5 1996/10/02 17:21:09 drk $ */
3 * (c) Copyright 1993, 1994 Hewlett-Packard Company
4 * (c) Copyright 1993, 1994 International Business Machines Corp.
5 * (c) Copyright 1993, 1994 Novell, Inc.
6 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
19 #include <sys/systeminfo.h>
23 #include "cmscalendar.h"
27 #include "appt4.h" /* Internal appointment data structure */
32 #include "cmsconvert.h"
41 /*****************************************************************************
42 * forward declaration of static functions used within the file
43 *****************************************************************************/
44 static Exception_4 append_exception_list(Appt_4 *p_appt, int ordinal);
45 static void trunc_exception_list(Appt_4 *p_appt, int ordinal);
46 static int num_exception(Appt_4 *p_appt);
48 /*****************************************************************************
49 * extern functions used in the library
50 *****************************************************************************/
53 * Insert one appointment into the single appointment tree structure
54 * or the repeat appointment list structure.
55 * The passed in appointment is stored in the structure.
57 extern CSA_return_code
58 _DtCmsInsertAppt(_DtCmsCalendar *cal, Appt_4 *appt4)
65 if (cal == NULL || appt4 == NULL)
66 return (CSA_E_INVALID_PARAMETER);
68 /* assign key if this is a new appointment */
69 _DtCmsGenerateKey(cal, &(appt4->appt_id.key));
72 fprintf(stderr, "Insert appt4: (%ld)%s\n",
73 appt4->appt_id.key, ctime(&(appt4->appt_id.tick)));
76 /* Add the appointment into the data structure */
77 if (appt4->period.period == single_4)
78 rb_stat = rb_insert (cal->tree, (caddr_t)appt4,
79 (caddr_t)&(appt4->appt_id));
81 rb_stat = hc_insert (REPT_LIST(cal), (caddr_t)appt4,
82 (caddr_t)&(appt4->appt_id), NULL, NULL);
84 if (rb_stat == rb_ok) {
85 /* Add the qualified reminder attrs to the reminder queue */
86 current_time = time(0);
88 while (p_attr != NULL)
93 tick = appt4->appt_id.tick - atol(p_attr->value);
94 p_reminder = build_reminder (current_time, appt4,
96 if (p_reminder != NULL)
97 _DtCmsAddReminderV4(&cal->rm_queue, p_reminder);
98 p_attr = p_attr->next;
102 return (_DtCmsRbToCsaStat(rb_stat));
106 * If p_auth is null, the initiator is the owner of the calendar. Permission
107 * to delete any appointment is always granted. If p_auth is not null, we need
108 * to check if it matches the author of the deleting appointment. Only the
109 * author can delete his/her appointment.
111 extern CSA_return_code
124 * Before we delete an event from the single appointment tree, we
125 * need to check if the initiator is the author of the appointment.
127 if ((user != NULL) && (p_appt = (Appt_4 *)rb_lookup(APPT_TREE(cal),
128 (caddr_t)p_key)) != NULL) {
129 if (!(access & (access_delete_4|CSA_OWNER_RIGHTS)) &&
130 !_DtCmIsSameUser(user, p_appt->author))
131 return (CSA_E_NO_AUTHORITY);
134 if ((p_node = rb_delete (APPT_TREE(cal), (caddr_t)p_key)) != NULL) {
135 p_appt = (Appt_4*)p_node->data;
136 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0, B_FALSE);
140 fprintf (stderr, "Deleted (%ld)%s\n",
142 ctime(&(p_appt->appt_id.tick)));
147 _DtCm_free_appt4(p_appt);
148 return (CSA_SUCCESS);
151 /* Attempt to delete the event from the repeating appointment list */
152 p_lnode = (List_node *)hc_lookup_node(REPT_LIST(cal),
155 if (p_lnode != NULL) {
156 p_appt = (Appt_4 *)p_lnode->data;
159 !(access & (access_delete_4|CSA_OWNER_RIGHTS)) &&
160 !_DtCmIsSameUser(user, p_appt->author))
161 return (CSA_E_NO_AUTHORITY);
163 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0, B_FALSE);
164 (void) hc_delete_node (REPT_LIST(cal), p_lnode);
168 fprintf (stderr, "Deleted (%ld)%s\n",
170 ctime(&(p_appt->appt_id.tick)));
175 _DtCm_free_appt4(p_appt);
176 return (CSA_SUCCESS);
178 return (CSA_E_USER_NOT_FOUND | CSA_E_INVALID_ENTRY_HANDLE);
181 extern CSA_return_code
182 _DtCmsDeleteApptAndLog(
189 CSA_return_code stat;
192 if ((stat = _DtCmsDeleteAppt(cal, user, access, key, &appt))
195 /* Transact the log */
196 if ((stat = v4_transact_log(cal->calendar, appt,
197 _DtCmsLogRemove)) != CSA_SUCCESS) {
199 (void)_DtCmsInsertAppt(cal, appt);
201 } else if (oldappt) {
204 _DtCm_free_appt4(appt);
211 extern CSA_return_code
212 _DtCmsDeleteApptInstancesAndLog(
222 CSA_return_code stat = CSA_SUCCESS;
223 Appt_4 *p_appt, *oldcopy;
225 int f, file_size, ntimes, ninstance, status = 0;
228 p_lnode = (List_node *)hc_lookup_node (REPT_LIST(cal), (caddr_t)key);
230 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
232 p_appt = (Appt_4*)p_lnode->data;
233 if (!(access & (access_delete_4 | CSA_OWNER_RIGHTS)) &&
234 !_DtCmIsSameUser(source, p_appt->author))
235 return (CSA_E_NO_AUTHORITY);
237 if ((ordinal = _DtCms_in_repeater (key, p_appt, B_TRUE)) == 0)
238 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
241 fprintf(stderr,"Delete instance: Ordinal=%d\n",ordinal);
244 * save file size in case the first log transaction
245 * succeeds but the second log transaction fails.
247 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
251 /* remove from log */
252 if ((stat = v4_transact_log(cal->calendar, p_appt, _DtCmsLogRemove))
256 ninstance = _DtCms_get_ninstance_v4(p_appt);
258 /* calculate the ntimes value for the part
259 * of the sequence that start from the ordinal to the end
262 *remain = _DtCms_get_new_ntimes_v4(p_appt->period, key->tick,
263 (ninstance - ordinal + 1));
266 * make a copy of the original appointment,
267 * in case we need a rollback
269 if ((oldcopy = _DtCm_copy_one_appt4(p_appt)) == NULL) {
270 stat = CSA_E_INSUFFICIENT_MEMORY;
274 /* remove from memory */
275 if (option == do_one_4) {
276 if (!append_exception_list (p_appt, ordinal)) {
277 stat = CSA_E_INSUFFICIENT_MEMORY;
281 ninstance = ordinal - 1;
282 if (ninstance == 1) {
283 /* convert to one-time event */
284 p_appt->period.period = single_4;
285 p_appt->period.nth = 0;
286 p_appt->period.enddate = 0;
288 if (p_appt->exception) {
289 _DtCm_free_excpt4(p_appt->exception);
290 p_appt->exception = NULL;
292 stat = _DtCmsRbToCsaStat(rb_insert(cal->tree,
293 (caddr_t)p_appt, (caddr_t)&(p_appt->appt_id)));
295 p_appt->ntimes = _DtCms_get_new_ntimes_v4(
296 p_appt->period, p_appt->appt_id.tick,
299 /* update enddate just for M-F, MWF, TTh
302 switch (p_appt->period.period) {
307 p_appt->period.enddate = _DtCms_prev_tick_v4(
311 trunc_exception_list(p_appt, ordinal);
315 /* The last one from the series has been deleted, no more left. */
316 if (ninstance == num_exception (p_appt))
320 /* Obsolete the reminders which match the ordinal */
321 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, ordinal,
322 (option == do_one_4 ? B_FALSE : B_TRUE));
323 _DtCm_free_appt4(p_appt);
324 hc_delete_node (REPT_LIST(cal), p_lnode);
327 /* Write out the series with new exception list. */
328 if (stat || (stat = v4_transact_log(cal->calendar, p_appt,
329 _DtCmsLogAdd)) != CSA_SUCCESS) {
330 /* reverse memory update */
331 p_appt->ntimes = oldcopy->ntimes;
332 p_appt->period = oldcopy->period;
333 _DtCm_free_excpt4(p_appt->exception);
334 p_appt->exception = oldcopy->exception;
335 oldcopy->exception = NULL;
339 if (ninstance == 1) {
343 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0,
344 (option == do_one_4 ? B_FALSE : B_TRUE));
345 hc_delete_node(REPT_LIST(cal), p_lnode);
348 /* Add the qualified reminder attrs to
351 current_time = time(0);
352 p_attr = p_appt->attr;
353 while (p_attr != NULL) {
357 tick = p_appt->appt_id.tick-atol(p_attr->value);
358 p_reminder = build_reminder(current_time,
359 p_appt, p_attr, tick, 1);
360 if (p_reminder != NULL)
361 _DtCmsAddReminderV4(&cal->rm_queue,
363 p_attr = p_attr->next;
367 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt,
369 (option == do_one_4 ? B_FALSE : B_TRUE));
376 _DtCm_free_appt4(oldcopy);
378 return (CSA_SUCCESS);
381 /* rollback log file */
382 _DtCmsTruncateFile(cal->calendar, file_size);
385 _DtCm_free_appt4(oldcopy);
390 extern CSA_return_code
399 CSA_return_code stat = CSA_SUCCESS;
400 Appt_4 *olda, *newcopy = NULL;
404 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
409 * first, remove the old appointment from internal data structure
410 * and the callog file
412 if ((stat = _DtCmsDeleteApptAndLog(cal, source, access, p_key, &olda))
416 if (is_repeater(olda) && is_repeater(newa)) {
417 if (_DtCmsBeginOfDay(APPT_TICK(newa)) ==
418 _DtCmsBeginOfDay(p_key->tick) &&
419 olda->period.period == newa->period.period)
421 /* keep the start day of the original
422 * appointment if the date of the
423 * key matches that of the new
424 * appointment and the interval
427 APPT_TICK(newa) -= _DtCmsBeginOfDay(APPT_TICK(newa)) -
428 _DtCmsBeginOfDay(APPT_TICK(olda));
430 /* otherwise, calculate new parent */
431 if ((ordinal = _DtCms_in_repeater(p_key, olda, B_TRUE))
433 stat = CSA_X_DT_E_ENTRY_NOT_FOUND;
434 goto change_all_cleanup;
436 APPT_TICK(newa) = _DtCms_first_tick_v4(
438 newa->period, ordinal);
439 /* if enddate exist, adjust it */
440 if (olda->period.enddate &&
441 newa->period.period == olda->period.period
442 && newa->period.nth == olda->period.nth) {
443 newa->period.enddate +=
444 (_DtCmsBeginOfDay(APPT_TICK(newa)) -
445 _DtCmsBeginOfDay(APPT_TICK(olda)));
451 /* We use the same exception list for the
452 * new appt. ?? is this reasonable for
455 newa->exception = _DtCm_copy_excpt4(olda->exception);
458 /* adjust start date */
459 _DtCms_adjust_appt_startdate(newa);
461 /* make copy of new appointment */
462 if ((newcopy = _DtCm_copy_one_appt4(newa)) == NULL) {
463 stat = CSA_E_INSUFFICIENT_MEMORY;
464 goto change_all_cleanup;
468 newcopy->appt_id.key = olda->appt_id.key;
470 /* keep the original author */
471 free(newcopy->author);
472 if ((newcopy->author = strdup(olda->author)) == NULL) {
473 stat = CSA_E_INSUFFICIENT_MEMORY;
474 goto change_all_cleanup;
477 if ((stat = _DtCmsInsertApptAndLog(cal, newcopy)) != CSA_SUCCESS) {
478 goto change_all_cleanup;
480 newa->appt_id.key = newcopy->appt_id.key;
485 _DtCm_free_appt4(olda);
491 _DtCm_free_appt4(newcopy);
492 _DtCmsTruncateFile(cal->calendar, file_size);
493 (void)_DtCmsInsertAppt(cal, olda);
497 extern CSA_return_code
507 CSA_return_code stat;
508 Appt_4 *olda, *newcopy = NULL;
510 Exception_4 *newexcept;
514 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
519 * first, remove the old appointment from internal data structure
520 * and the callog file
522 if ((stat = _DtCmsDeleteApptInstancesAndLog(cal, source, access,
523 p_key, option, &remain, &olda)) != CSA_SUCCESS)
526 /* adjust start date */
527 _DtCms_adjust_appt_startdate(newa);
529 /* make copy of new appointment */
530 newcopy = _DtCm_copy_one_appt4(newa);
532 if (option == do_forward_4) {
533 /* if repeating info is not changed, replace
534 * the deleted part with the new series, i.e.,
535 * ntimes of new series _DtCmsIsEquals to the number
536 * of deleted instances. Also get new
539 if (olda->period.period == newa->period.period &&
540 olda->period.nth == newa->period.nth &&
541 olda->ntimes == newa->ntimes) {
543 newcopy->ntimes = remain;
544 if (olda->exception != NULL) {
545 _DtCm_free_excpt4(newcopy->exception);
546 if ((stat = _DtCmsTruncateElist(olda, remain,
547 &newcopy->exception)) != CSA_SUCCESS) {
548 goto change_some_cleanup;
554 /* keep the original author */
555 free(newcopy->author);
556 if ((newcopy->author = strdup(olda->author)) == NULL) {
557 stat = CSA_E_INSUFFICIENT_MEMORY;
558 goto change_some_cleanup;
561 APPT_KEY(newcopy) = 0;
563 if ((stat = _DtCmsInsertApptAndLog(cal, newcopy)) != CSA_SUCCESS) {
564 goto change_some_cleanup;
566 newa->appt_id.key = newcopy->appt_id.key;
571 _DtCm_free_appt4(olda);
577 _DtCm_free_appt4(newcopy);
578 _DtCmsTruncateFile(cal->calendar, file_size);
579 (void)_DtCmsInsertAppt(cal, olda);
584 * the passed in appt is stored in the internal data structure
586 extern CSA_return_code
587 _DtCmsInsertApptAndLog(_DtCmsCalendar *cal, Appt_4 *appt)
589 CSA_return_code stat;
591 if ((stat = _DtCmsInsertAppt(cal, appt)) == CSA_SUCCESS) {
593 /* Add the new appointment to the log */
594 if ((stat = v4_transact_log(cal->calendar, appt,
595 _DtCmsLogAdd)) != CSA_SUCCESS) {
597 (void)_DtCmsDeleteAppt(cal, NULL, 0, &appt->appt_id,
604 extern _DtCmsComparisonResult
605 _DtCmsCompareAppt(Id_4 *key, caddr_t data)
607 Appt_4 *appt = (Appt_4 *)data;
610 if (key->tick < appt->appt_id.tick)
611 return (_DtCmsIsLess);
612 if (key->tick > appt->appt_id.tick)
613 return (_DtCmsIsGreater);
615 /* tick's are _DtCmsIsEqual */
616 if (key->key < appt->appt_id.key)
617 return (_DtCmsIsLess);
618 if (key->key > appt->appt_id.key)
619 return (_DtCmsIsGreater);
621 return (_DtCmsIsEqual);
624 extern _DtCmsComparisonResult
625 _DtCmsCompareRptAppt(Id_4 *key, caddr_t data)
627 Appt_4 *appt = (Appt_4 *)data;
629 if (key->key < appt->appt_id.key)
630 return (_DtCmsIsLess);
631 if (key->key > appt->appt_id.key)
632 return (_DtCmsIsGreater);
633 return (_DtCmsIsEqual);
637 _DtCmsGetApptKey (caddr_t data)
639 return ((caddr_t) &(((Appt_4 *) data)->appt_id));
642 extern CSA_return_code
643 v4_transact_log(char *calendar, Appt_4 *a, _DtCmsLogOps op)
645 CSA_return_code stat;
648 if ((log = _DtCmsGetLogFN(calendar)) == NULL)
649 return (CSA_E_INSUFFICIENT_MEMORY);
651 stat = _DtCmsAppendAppt4ByFN(log, a, op);
657 extern CSA_return_code
663 boolean_t no_end_time_range,
666 boolean_t (*match_func)(),
668 cms_attribute *attrs,
673 CSA_return_code stat = CSA_SUCCESS;
676 int tmp_tick, endtick;
680 time_t hi_tick, lo_tick;
686 CSA_return_code (*add_list_func)();
688 /* do lookup on new format calendar */
689 if (cal->fversion > 1) {
690 if ((stat = _DtCmsLookupEntries(cal, user, access,
691 p_range->key1, p_range->key2, no_end_time_range, end1, end2,
692 num_attrs, attrs, ops, &entries)) != CSA_SUCCESS) {
697 stat = _DtCmsCmsentriesToAppt4ForClient(entries,
700 stat = _DtCmsCmsentriesToAbbrAppt4ForClient(entries,
703 _DtCm_free_cms_entries(entries);
708 add_list_func = _AddToLinkedAppts;
710 add_list_func = _AddToLinkedAbbrAppts;
712 while (p_range != NULL)
715 lo_key.tick = p_range->key1;
716 hi_tick = p_range->key2;
720 fprintf(stderr,"Range lookup from %s",
721 ctime(&lo_key.tick));
722 fprintf(stderr, " to %s\n", ctime(&hi_tick));
727 /* Get a range of appointments in single appointment tree */
728 while ((p_appt = (Appt_4 *)rb_lookup_next_larger(
729 APPT_TREE(cal),(caddr_t)&lo_key))
730 && (APPT_TICK(p_appt) < hi_tick))
734 endtick = p_appt->appt_id.tick + p_appt->duration;
735 if ((!no_end_time_range && (p_appt->duration == 0 ||
736 endtick <= end1 || endtick >= end2)) ||
737 (match_func && !match_func(p_appt, num_attrs,
739 lo_key.key = APPT_KEY(p_appt);
740 lo_key.tick = APPT_TICK(p_appt);
744 if ((stat = (*add_list_func)(p_appt, user,
745 access,&ilp)) != CSA_SUCCESS) {
748 _DtCm_free_appt4((Appt_4 *)ilp);
750 _DtCm_free_abbrev_appt4(
757 lo_key.key = APPT_KEY(p_appt);
758 lo_key.tick = APPT_TICK(p_appt);
761 /* Get a range of events from repeating appointment list */
762 p_lnode = REPT_LIST(cal)->root;
763 while (p_lnode != NULL)
765 lo_tick = p_range->key1;
766 hi_tick = p_range->key2;
768 p_appt = (Appt_4*)p_lnode->data;
770 /* calculate the last tick */
771 if (p_lnode->lasttick == 0)
772 p_lnode->lasttick = _DtCms_last_tick_v4(
777 if (p_lnode->lasttick <= lo_tick ||
778 APPT_TICK(p_appt) >= hi_tick ||
779 (!no_end_time_range && p_appt->duration == 0) ||
780 (!no_end_time_range &&
781 (p_lnode->lasttick+p_appt->duration) <= end1) ||
782 (!no_end_time_range &&
783 (p_appt->appt_id.tick+p_appt->duration) >= end2) ||
785 !match_func(p_appt, num_attrs, attrs, ops)) ||
786 _GetAccessLevel(user, access, p_appt) == private_4)
788 p_lnode = hc_lookup_next (p_lnode);
792 if (!no_end_time_range &&
793 lo_tick < (end1 - p_appt->duration))
794 lo_tick = end1 - p_appt->duration;
796 if (!no_end_time_range &&
797 ((end2 - p_appt->duration) < hi_tick))
798 hi_tick = end2 - p_appt->duration;
800 ntimes = _DtCms_get_ninstance_v4(p_appt);
801 period = p_appt->period;
802 for (tick = _DtCms_closest_tick_v4(lo_tick,
803 APPT_TICK(p_appt), period, &ordinal), ordinal--;
805 tick = _DtCms_next_tick_v4(tick, period))
807 /* Repeater but beyond the scope */
808 if (++ordinal > ntimes ||
809 tick > p_lnode->lasttick)
812 if (tick <= lo_tick ||
813 _DtCms_marked_4_cancellation(p_appt,
819 /* Replace the parent key by the
820 * current tick for the repeating event
822 tmp_tick = APPT_TICK(p_appt);
823 APPT_TICK(p_appt) = tick;
825 /* Add to list, restore parent key */
826 stat = (*add_list_func)(p_appt, user,
829 APPT_TICK(p_appt) = tmp_tick;
831 if (stat != CSA_SUCCESS) {
837 _DtCm_free_abbrev_appt4(
845 p_lnode = hc_lookup_next (p_lnode);
848 p_range = p_range->next;
852 fprintf (stderr, "Found %d entries in range lookup\n", n);
854 if (stat == CSA_SUCCESS) {
856 *appt_r = (Appt_4 *)ilp;
858 *abbr_r = (Abb_Appt_4 *)ilp;
864 extern CSA_return_code
865 _DtCmsLookupKeyrangeV4(
869 boolean_t no_start_time_range,
870 boolean_t no_end_time_range,
876 boolean_t (*match_func)(),
878 cms_attribute *attrs,
883 CSA_return_code stat = CSA_SUCCESS;
885 long tmp_tick, endtick;
892 Appt_4 *p_appt, *tappt;
895 CSA_return_code (*add_list_func)();
897 /* do lookup on new format calendar */
898 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
899 if ((stat = _DtCmsLookupEntriesById(cal, user, access,
900 no_start_time_range, no_end_time_range, start1, start2,
901 end1, end2, id, num_attrs, attrs, ops, &entries))
907 stat = _DtCmsCmsentriesToAppt4ForClient(entries,
909 *appt_r = _AddApptInOrder(*appt_r, tappt);
911 stat = _DtCmsCmsentriesToAbbrAppt4ForClient(entries,
913 *abbr_r = _AddAbbApptInOrder(*abbr_r, tabbr);
916 _DtCm_free_cms_entries(entries);
921 add_list_func = _AddToLinkedAppts;
923 add_list_func = _AddToLinkedAbbrAppts;
926 lo_key.tick = start1;
928 /* Search from repeating appointments first for optimization */
929 p_lnode = hc_lookup_node (REPT_LIST(cal), (caddr_t)&lo_key);
930 if (p_lnode != NULL) {
931 p_appt = (Appt_4*)p_lnode->data;
932 if ((match_func && !match_func(p_appt, num_attrs, attrs, ops))
933 || _GetAccessLevel(user, access, p_appt) == private_4)
934 return (CSA_SUCCESS);
936 /* just return the first event */
937 if (no_start_time_range && no_end_time_range)
938 return ((*add_list_func)(p_appt, user, access,
939 (appt_r ? (caddr_t)appt_r : (caddr_t)abbr_r)));
941 /* Get the range of events from this appointment. */
942 ntimes = _DtCms_get_ninstance_v4(p_appt);
943 period = p_appt->period;
945 /* calculate the last tick */
946 if (p_lnode->lasttick == 0)
947 p_lnode->lasttick = _DtCms_last_tick_v4(
949 p_appt->period, p_appt->ntimes);
951 if (p_lnode->lasttick <= start1 ||
952 p_appt->appt_id.tick >= start2 ||
953 (!no_end_time_range && p_appt->duration == 0) ||
954 (!no_end_time_range &&
955 (p_lnode->lasttick+p_appt->duration) <= end1) ||
956 (!no_end_time_range &&
957 (p_appt->appt_id.tick+p_appt->duration) >= end2))
960 if (!no_end_time_range && (start1 < (end1 - p_appt->duration)))
961 start1 = end1 - p_appt->duration;
963 if (!no_end_time_range && ((end2 - p_appt->duration) < start2))
964 start2 = end2 - p_appt->duration;
966 for (tick = _DtCms_closest_tick_v4(start1,
967 APPT_TICK(p_appt), period, &ordinal), ordinal--;
968 stat == CSA_SUCCESS && tick < start2;
969 tick = _DtCms_next_tick_v4(tick, period))
971 /* Repeater but beyond the scope */
972 if (++ordinal > ntimes || tick > p_lnode->lasttick)
978 /* If not cancelled, add to linked list */
979 if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
983 /* Replace the parent key by
984 * the current tick for the
987 tmp_tick = APPT_TICK(p_appt);
988 APPT_TICK(p_appt) = tick;
990 /* Add to list, restore parent key */
991 stat = (*add_list_func)(p_appt, user, access,
992 (appt_r ? (caddr_t)appt_r :
995 APPT_TICK(p_appt) = tmp_tick;
1001 /* Check if it is in single appointment tree */
1002 while ((p_appt = (Appt_4 *)rb_lookup_next_larger(
1003 APPT_TREE(cal), (caddr_t) &lo_key)) &&
1004 (APPT_TICK(p_appt) < start2))
1006 if (p_appt->appt_id.key != lo_key.key) {
1007 lo_key.tick = APPT_TICK(p_appt);
1008 lo_key.key = APPT_KEY(p_appt);
1010 endtick = p_appt->appt_id.tick+p_appt->duration;
1012 if ((!no_end_time_range &&
1013 (p_appt->duration == 0 || endtick <= end1 ||
1014 endtick >= end2)) ||
1015 (match_func && !match_func(p_appt,
1016 num_attrs, attrs, ops))) {
1018 return (CSA_SUCCESS);
1020 return ((*add_list_func)(p_appt, user,
1027 return (CSA_SUCCESS);
1031 extern CSA_return_code
1041 switch (_GetAccessLevel(user, access, p_appt)) {
1043 copy = _DtCm_copy_one_appt4(p_appt);
1046 copy = _DtCm_copy_semiprivate_appt4(p_appt);
1049 return (CSA_SUCCESS);
1053 return(CSA_E_INSUFFICIENT_MEMORY);
1055 *ilp = (caddr_t)_AddApptInOrder((Appt_4 *)*ilp, copy);
1056 return (CSA_SUCCESS);
1060 extern CSA_return_code
1061 _AddToLinkedAbbrAppts(
1069 switch (_GetAccessLevel(user, access, p_appt)) {
1071 copy = _DtCm_appt_to_abbrev4(p_appt);
1074 copy = _DtCm_appt_to_semiprivate_abbrev4(p_appt);
1077 return (CSA_SUCCESS);
1081 return(CSA_E_INSUFFICIENT_MEMORY);
1083 *ilp = (caddr_t)_AddAbbApptInOrder((Abb_Appt_4 *)*ilp, copy);
1084 return (CSA_SUCCESS);
1088 extern Privacy_Level_4
1089 _GetAccessLevel(char *user, uint access, Appt_4 *p_appt)
1091 if (access & CSA_OWNER_RIGHTS ||
1092 ((access & access_read_4) && p_appt->privacy == public_4) ||
1093 _DtCmIsSameUser(user, p_appt->author)) {
1097 } else if (p_appt->privacy == private_4) {
1102 return (semiprivate_4);
1107 _AddApptInOrder(Appt_4 *head, Appt_4 *aptr)
1109 Appt_4 *p_appt, *p_prev, *p_next;
1112 p_next = aptr->next;
1115 /* Add the item to the linked list in ascending order */
1118 while (p_appt != NULL)
1120 if (APPT_TICK(aptr) <= APPT_TICK(p_appt))
1123 p_appt = p_appt->next;
1128 aptr->next = p_appt;
1131 aptr->next = p_prev->next;
1132 p_prev->next = aptr;
1142 _AddAbbApptInOrder(Abb_Appt_4 *head, Abb_Appt_4 *aptr)
1144 Abb_Appt_4 *p_appt, *p_prev, *p_next;
1147 p_next = aptr->next;
1150 /* Add the item to the linked list in ascending order */
1153 while (p_appt != NULL)
1155 if (APPT_TICK(aptr) <= APPT_TICK(p_appt))
1158 p_appt = p_appt->next;
1163 aptr->next = p_appt;
1166 aptr->next = p_prev->next;
1167 p_prev->next = aptr;
1176 extern CSA_return_code
1177 _DtCmsSetV4AccessListAndLog(_DtCmsCalendar *cal, Access_Entry_4 *alist)
1179 CSA_return_code stat;
1183 /* update access list for old format calendar */
1184 if ((name = _DtCmsTarget2Name(cal->calendar)) == NULL)
1185 return (CSA_E_INSUFFICIENT_MEMORY);
1187 if ((log = _DtCmsGetLogFN(name)) == NULL) {
1189 return (CSA_E_INSUFFICIENT_MEMORY);
1193 * save file size in case the first log transaction
1194 * succeeds but the second log transaction fails.
1196 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
1203 /* Set to the data structure */
1204 if ((stat = _DtCmsSetV4AccessListInCal(cal, alist)) == CSA_SUCCESS) {
1206 if (((stat = _DtCmsAppendAccessByFN(log, access_read_4,
1207 GET_R_ACCESS(cal))) != CSA_SUCCESS) ||
1208 ((stat = _DtCmsAppendAccessByFN(log, access_write_4,
1209 GET_W_ACCESS(cal))) != CSA_SUCCESS) ||
1210 ((stat = _DtCmsAppendAccessByFN(log, access_delete_4,
1211 GET_D_ACCESS(cal))) != CSA_SUCCESS) ||
1212 ((stat = _DtCmsAppendAccessByFN(log, access_exec_4,
1213 GET_X_ACCESS(cal))) != CSA_SUCCESS)) {
1215 /* rollback log file */
1216 _DtCmsTruncateFile(cal->calendar, file_size);
1218 cal->modified = B_TRUE;
1226 extern CSA_return_code
1227 _DtCmsGetV4Reminders(
1228 _DtCmsCalendar *cal,
1231 _DtCmsEntryId **ids_r)
1233 Rm_que *p_node, *p_prev, *p_next, *p_new;
1234 Reminder_4 *rptr, *v4rem = NULL;
1235 _DtCmsEntryId *idptr, *ids = NULL;
1237 if (rem_r == NULL) return (CSA_E_INVALID_PARAMETER);
1239 /* do lookup in old format calendar */
1241 p_node = cal->rm_queue;
1242 while (p_node != NULL)
1244 /* It is still a future reminder. */
1245 if (tick < p_node->remind_at)
1248 /* The reminder expired. It either needs to be recalculated
1249 * (repeating appointment) or dropped (non-repeating appt.)
1251 p_next = _DtCmsRemoveReminderV4(&cal->rm_queue, p_prev, p_node);
1253 if (is_repeater(p_node->appt)) {
1254 /* Calculate next reminder for repeating appointment */
1255 p_new = build_reminder(tick+1, p_node->appt,
1256 p_node->attr, p_node->remind_at,
1257 p_node->remind_ord);
1260 _DtCmsAddReminderV4(&cal->rm_queue, p_new);
1261 if (p_new->next == p_next)
1270 /* Pick the first one from the active reminder queue because it is
1271 * always >= the given key.
1273 p_node = cal->rm_queue;
1276 tick = p_node->remind_at;
1279 rptr = _DtCmsGetReminderInfoV4(p_node);
1283 idptr = (_DtCmsEntryId *)calloc(1,
1284 sizeof(_DtCmsEntryId));
1285 idptr->id = p_node->appt->appt_id.key;
1289 p_node = p_node->next;
1290 } while ((p_node != NULL) && (p_node->remind_at == tick));
1294 if (ids_r) *ids_r = ids;
1295 return (CSA_SUCCESS);
1299 _DtCmsFreeEntryIds(_DtCmsEntryId *ids)
1303 while (ids != NULL) {
1310 extern CSA_return_code
1311 _DtCmsTruncateElist(Appt_4 *parent_p, int remain, Except_4 **excpt)
1313 int except_no, ntimes_diff;
1314 Except_4 *e, *p, *last_e = NULL, *head = NULL;
1316 ntimes_diff = _DtCms_get_ninstance_v4(parent_p) - remain;
1317 p = parent_p->exception;
1319 if ((except_no = (p->ordinal - ntimes_diff)) > 0 &&
1320 except_no <= remain) {
1321 if ((e = (Except_4*)calloc(1, sizeof(Except_4)))
1323 _DtCm_free_excpt4(head);
1324 return (CSA_E_INSUFFICIENT_MEMORY);
1326 e->ordinal = except_no;
1338 return (CSA_SUCCESS);
1341 extern CSA_return_code
1342 _DtCmsSetV4AccessListInCal(_DtCmsCalendar *cal, Access_Entry_4 *e)
1346 /* Wipe out the old access lists. */
1347 _DtCm_free_access_list4(GET_R_ACCESS (cal));
1348 _DtCm_free_access_list4(GET_W_ACCESS (cal));
1349 _DtCm_free_access_list4(GET_D_ACCESS (cal));
1350 _DtCm_free_access_list4(GET_X_ACCESS (cal));
1351 SET_R_ACCESS(cal, NULL);
1352 SET_W_ACCESS(cal, NULL);
1353 SET_D_ACCESS(cal, NULL);
1354 SET_X_ACCESS(cal, NULL);
1355 _DtCm_free_access_list4(cal->alist);
1357 /* Split the access list to 3 differnt operation lists */
1360 if (e->access_type & access_read_4) {
1361 q = _DtCm_make_access_entry4(e->who, e->access_type);
1362 q->next = GET_R_ACCESS(cal);
1363 SET_R_ACCESS(cal, q);
1365 if (e->access_type & access_write_4) {
1366 q = _DtCm_make_access_entry4(e->who, e->access_type);
1367 q->next = GET_W_ACCESS(cal);
1368 SET_W_ACCESS(cal, q);
1370 if (e->access_type & access_delete_4) {
1371 q = _DtCm_make_access_entry4(e->who, e->access_type);
1372 q->next = GET_D_ACCESS(cal);
1373 SET_D_ACCESS(cal, q);
1375 if (e->access_type & access_exec_4) {
1376 q = _DtCm_make_access_entry4(e->who, e->access_type);
1377 q->next = GET_X_ACCESS(cal);
1378 SET_X_ACCESS(cal, q);
1383 cal->alist = _DtCmsCalendarAccessList(cal);
1385 return (CSA_SUCCESS);
1388 /******************************************************************************
1389 * static functions used within the file
1390 ******************************************************************************/
1393 append_exception_list(Appt_4 *p_appt, int ordinal)
1395 Exception_4 p_excpt;
1399 if ((p_excpt = (Exception_4)calloc(1, sizeof(*p_excpt))) == NULL)
1401 p_excpt->ordinal = ordinal;
1403 p_ex = p_appt->exception;
1404 while (p_ex != NULL)
1406 /* Exception list is in descending order for faster access */
1407 if (ordinal > p_ex->ordinal)
1414 p_excpt->next = p_appt->exception;
1415 p_appt->exception = p_excpt;
1419 p_excpt->next = p_prev->next;
1420 p_prev->next = p_excpt;
1427 * remove exceptions that are larger than ordinal
1430 trunc_exception_list(Appt_4 *p_appt, int ordinal)
1435 p_ex = p_appt->exception;
1437 /* Exception list is in descending order for faster access */
1438 while ((p_ex != NULL) && (p_ex->ordinal > ordinal))
1440 p_next = p_ex->next;
1444 p_appt->exception = p_ex;
1448 num_exception(Appt_4 *p_appt)
1454 p = p_appt->exception;