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: v4ops.c /main/5 1996/10/02 17:21:09 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.
31 #include <EUSCompat.h>
41 #include <sys/systeminfo.h>
45 #include "cmscalendar.h"
49 #include "appt4.h" /* Internal appointment data structure */
54 #include "cmsconvert.h"
63 /*****************************************************************************
64 * forward declaration of static functions used within the file
65 *****************************************************************************/
66 static Exception_4 append_exception_list(Appt_4 *p_appt, int ordinal);
67 static void trunc_exception_list(Appt_4 *p_appt, int ordinal);
68 static int num_exception(Appt_4 *p_appt);
70 /*****************************************************************************
71 * extern functions used in the library
72 *****************************************************************************/
75 * Insert one appointment into the single appointment tree structure
76 * or the repeat appointment list structure.
77 * The passed in appointment is stored in the structure.
79 extern CSA_return_code
80 _DtCmsInsertAppt(_DtCmsCalendar *cal, Appt_4 *appt4)
87 if (cal == NULL || appt4 == NULL)
88 return (CSA_E_INVALID_PARAMETER);
90 /* assign key if this is a new appointment */
91 _DtCmsGenerateKey(cal, &(appt4->appt_id.key));
94 fprintf(stderr, "Insert appt4: (%ld)%s\n",
95 appt4->appt_id.key, ctime(&(appt4->appt_id.tick)));
98 /* Add the appointment into the data structure */
99 if (appt4->period.period == single_4)
100 rb_stat = rb_insert (cal->tree, (caddr_t)appt4,
101 (caddr_t)&(appt4->appt_id));
103 rb_stat = hc_insert (REPT_LIST(cal), (caddr_t)appt4,
104 (caddr_t)&(appt4->appt_id), NULL, NULL);
106 if (rb_stat == rb_ok) {
107 /* Add the qualified reminder attrs to the reminder queue */
108 current_time = time(0);
109 p_attr = appt4->attr;
110 while (p_attr != NULL)
115 tick = appt4->appt_id.tick - atol(p_attr->value);
116 p_reminder = build_reminder (current_time, appt4,
118 if (p_reminder != NULL)
119 _DtCmsAddReminderV4(&cal->rm_queue, p_reminder);
120 p_attr = p_attr->next;
124 return (_DtCmsRbToCsaStat(rb_stat));
128 * If p_auth is null, the initiator is the owner of the calendar. Permission
129 * to delete any appointment is always granted. If p_auth is not null, we need
130 * to check if it matches the author of the deleting appointment. Only the
131 * author can delete his/her appointment.
133 extern CSA_return_code
146 * Before we delete an event from the single appointment tree, we
147 * need to check if the initiator is the author of the appointment.
149 if ((user != NULL) && (p_appt = (Appt_4 *)rb_lookup(APPT_TREE(cal),
150 (caddr_t)p_key)) != NULL) {
151 if (!(access & (access_delete_4|CSA_OWNER_RIGHTS)) &&
152 !_DtCmIsSameUser(user, p_appt->author))
153 return (CSA_E_NO_AUTHORITY);
156 if ((p_node = rb_delete (APPT_TREE(cal), (caddr_t)p_key)) != NULL) {
157 p_appt = (Appt_4*)p_node->data;
158 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0, B_FALSE);
162 fprintf (stderr, "Deleted (%ld)%s\n",
164 ctime(&(p_appt->appt_id.tick)));
169 _DtCm_free_appt4(p_appt);
170 return (CSA_SUCCESS);
173 /* Attempt to delete the event from the repeating appointment list */
174 p_lnode = (List_node *)hc_lookup_node(REPT_LIST(cal),
177 if (p_lnode != NULL) {
178 p_appt = (Appt_4 *)p_lnode->data;
181 !(access & (access_delete_4|CSA_OWNER_RIGHTS)) &&
182 !_DtCmIsSameUser(user, p_appt->author))
183 return (CSA_E_NO_AUTHORITY);
185 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0, B_FALSE);
186 (void) hc_delete_node (REPT_LIST(cal), p_lnode);
190 fprintf (stderr, "Deleted (%ld)%s\n",
192 ctime(&(p_appt->appt_id.tick)));
197 _DtCm_free_appt4(p_appt);
198 return (CSA_SUCCESS);
200 return (CSA_E_USER_NOT_FOUND | CSA_E_INVALID_ENTRY_HANDLE);
203 extern CSA_return_code
204 _DtCmsDeleteApptAndLog(
211 CSA_return_code stat;
214 if ((stat = _DtCmsDeleteAppt(cal, user, access, key, &appt))
217 /* Transact the log */
218 if ((stat = v4_transact_log(cal->calendar, appt,
219 _DtCmsLogRemove)) != CSA_SUCCESS) {
221 (void)_DtCmsInsertAppt(cal, appt);
223 } else if (oldappt) {
226 _DtCm_free_appt4(appt);
233 extern CSA_return_code
234 _DtCmsDeleteApptInstancesAndLog(
244 CSA_return_code stat = CSA_SUCCESS;
245 Appt_4 *p_appt, *oldcopy;
247 int f, file_size, ntimes, ninstance, status = 0;
250 p_lnode = (List_node *)hc_lookup_node (REPT_LIST(cal), (caddr_t)key);
252 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
254 p_appt = (Appt_4*)p_lnode->data;
255 if (!(access & (access_delete_4 | CSA_OWNER_RIGHTS)) &&
256 !_DtCmIsSameUser(source, p_appt->author))
257 return (CSA_E_NO_AUTHORITY);
259 if ((ordinal = _DtCms_in_repeater (key, p_appt, B_TRUE)) == 0)
260 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
263 fprintf(stderr,"Delete instance: Ordinal=%d\n",ordinal);
266 * save file size in case the first log transaction
267 * succeeds but the second log transaction fails.
269 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
273 /* remove from log */
274 if ((stat = v4_transact_log(cal->calendar, p_appt, _DtCmsLogRemove))
278 ninstance = _DtCms_get_ninstance_v4(p_appt);
280 /* calculate the ntimes value for the part
281 * of the sequence that start from the ordinal to the end
284 *remain = _DtCms_get_new_ntimes_v4(p_appt->period, key->tick,
285 (ninstance - ordinal + 1));
288 * make a copy of the original appointment,
289 * in case we need a rollback
291 if ((oldcopy = _DtCm_copy_one_appt4(p_appt)) == NULL) {
292 stat = CSA_E_INSUFFICIENT_MEMORY;
296 /* remove from memory */
297 if (option == do_one_4) {
298 if (!append_exception_list (p_appt, ordinal)) {
299 stat = CSA_E_INSUFFICIENT_MEMORY;
303 ninstance = ordinal - 1;
304 if (ninstance == 1) {
305 /* convert to one-time event */
306 p_appt->period.period = single_4;
307 p_appt->period.nth = 0;
308 p_appt->period.enddate = 0;
310 if (p_appt->exception) {
311 _DtCm_free_excpt4(p_appt->exception);
312 p_appt->exception = NULL;
314 stat = _DtCmsRbToCsaStat(rb_insert(cal->tree,
315 (caddr_t)p_appt, (caddr_t)&(p_appt->appt_id)));
317 p_appt->ntimes = _DtCms_get_new_ntimes_v4(
318 p_appt->period, p_appt->appt_id.tick,
321 /* update enddate just for M-F, MWF, TTh
324 switch (p_appt->period.period) {
329 p_appt->period.enddate = _DtCms_prev_tick_v4(
333 trunc_exception_list(p_appt, ordinal);
337 /* The last one from the series has been deleted, no more left. */
338 if (ninstance == num_exception (p_appt))
342 /* Obsolete the reminders which match the ordinal */
343 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, ordinal,
344 (option == do_one_4 ? B_FALSE : B_TRUE));
345 _DtCm_free_appt4(p_appt);
346 hc_delete_node (REPT_LIST(cal), p_lnode);
349 /* Write out the series with new exception list. */
350 if (stat || (stat = v4_transact_log(cal->calendar, p_appt,
351 _DtCmsLogAdd)) != CSA_SUCCESS) {
352 /* reverse memory update */
353 p_appt->ntimes = oldcopy->ntimes;
354 p_appt->period = oldcopy->period;
355 _DtCm_free_excpt4(p_appt->exception);
356 p_appt->exception = oldcopy->exception;
357 oldcopy->exception = NULL;
361 if (ninstance == 1) {
365 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0,
366 (option == do_one_4 ? B_FALSE : B_TRUE));
367 hc_delete_node(REPT_LIST(cal), p_lnode);
370 /* Add the qualified reminder attrs to
373 current_time = time(0);
374 p_attr = p_appt->attr;
375 while (p_attr != NULL) {
379 tick = p_appt->appt_id.tick-atol(p_attr->value);
380 p_reminder = build_reminder(current_time,
381 p_appt, p_attr, tick, 1);
382 if (p_reminder != NULL)
383 _DtCmsAddReminderV4(&cal->rm_queue,
385 p_attr = p_attr->next;
389 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt,
391 (option == do_one_4 ? B_FALSE : B_TRUE));
398 _DtCm_free_appt4(oldcopy);
400 return (CSA_SUCCESS);
403 /* rollback log file */
404 _DtCmsTruncateFile(cal->calendar, file_size);
407 _DtCm_free_appt4(oldcopy);
412 extern CSA_return_code
421 CSA_return_code stat = CSA_SUCCESS;
422 Appt_4 *olda, *newcopy = NULL;
426 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
431 * first, remove the old appointment from internal data structure
432 * and the callog file
434 if ((stat = _DtCmsDeleteApptAndLog(cal, source, access, p_key, &olda))
438 if (is_repeater(olda) && is_repeater(newa)) {
439 if (_DtCmsBeginOfDay(APPT_TICK(newa)) ==
440 _DtCmsBeginOfDay(p_key->tick) &&
441 olda->period.period == newa->period.period)
443 /* keep the start day of the original
444 * appointment if the date of the
445 * key matches that of the new
446 * appointment and the interval
449 APPT_TICK(newa) -= _DtCmsBeginOfDay(APPT_TICK(newa)) -
450 _DtCmsBeginOfDay(APPT_TICK(olda));
452 /* otherwise, calculate new parent */
453 if ((ordinal = _DtCms_in_repeater(p_key, olda, B_TRUE))
455 stat = CSA_X_DT_E_ENTRY_NOT_FOUND;
456 goto change_all_cleanup;
458 APPT_TICK(newa) = _DtCms_first_tick_v4(
460 newa->period, ordinal);
461 /* if enddate exist, adjust it */
462 if (olda->period.enddate &&
463 newa->period.period == olda->period.period
464 && newa->period.nth == olda->period.nth) {
465 newa->period.enddate +=
466 (_DtCmsBeginOfDay(APPT_TICK(newa)) -
467 _DtCmsBeginOfDay(APPT_TICK(olda)));
473 /* We use the same exception list for the
474 * new appt. ?? is this reasonable for
477 newa->exception = _DtCm_copy_excpt4(olda->exception);
480 /* adjust start date */
481 _DtCms_adjust_appt_startdate(newa);
483 /* make copy of new appointment */
484 if ((newcopy = _DtCm_copy_one_appt4(newa)) == NULL) {
485 stat = CSA_E_INSUFFICIENT_MEMORY;
486 goto change_all_cleanup;
490 newcopy->appt_id.key = olda->appt_id.key;
492 /* keep the original author */
493 free(newcopy->author);
494 if ((newcopy->author = strdup(olda->author)) == NULL) {
495 stat = CSA_E_INSUFFICIENT_MEMORY;
496 goto change_all_cleanup;
499 if ((stat = _DtCmsInsertApptAndLog(cal, newcopy)) != CSA_SUCCESS) {
500 goto change_all_cleanup;
502 newa->appt_id.key = newcopy->appt_id.key;
507 _DtCm_free_appt4(olda);
513 _DtCm_free_appt4(newcopy);
514 _DtCmsTruncateFile(cal->calendar, file_size);
515 (void)_DtCmsInsertAppt(cal, olda);
519 extern CSA_return_code
529 CSA_return_code stat;
530 Appt_4 *olda, *newcopy = NULL;
532 Exception_4 *newexcept;
536 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
541 * first, remove the old appointment from internal data structure
542 * and the callog file
544 if ((stat = _DtCmsDeleteApptInstancesAndLog(cal, source, access,
545 p_key, option, &remain, &olda)) != CSA_SUCCESS)
548 /* adjust start date */
549 _DtCms_adjust_appt_startdate(newa);
551 /* make copy of new appointment */
552 newcopy = _DtCm_copy_one_appt4(newa);
554 if (option == do_forward_4) {
555 /* if repeating info is not changed, replace
556 * the deleted part with the new series, i.e.,
557 * ntimes of new series _DtCmsIsEquals to the number
558 * of deleted instances. Also get new
561 if (olda->period.period == newa->period.period &&
562 olda->period.nth == newa->period.nth &&
563 olda->ntimes == newa->ntimes) {
565 newcopy->ntimes = remain;
566 if (olda->exception != NULL) {
567 _DtCm_free_excpt4(newcopy->exception);
568 if ((stat = _DtCmsTruncateElist(olda, remain,
569 &newcopy->exception)) != CSA_SUCCESS) {
570 goto change_some_cleanup;
576 /* keep the original author */
577 free(newcopy->author);
578 if ((newcopy->author = strdup(olda->author)) == NULL) {
579 stat = CSA_E_INSUFFICIENT_MEMORY;
580 goto change_some_cleanup;
583 APPT_KEY(newcopy) = 0;
585 if ((stat = _DtCmsInsertApptAndLog(cal, newcopy)) != CSA_SUCCESS) {
586 goto change_some_cleanup;
588 newa->appt_id.key = newcopy->appt_id.key;
593 _DtCm_free_appt4(olda);
599 _DtCm_free_appt4(newcopy);
600 _DtCmsTruncateFile(cal->calendar, file_size);
601 (void)_DtCmsInsertAppt(cal, olda);
606 * the passed in appt is stored in the internal data structure
608 extern CSA_return_code
609 _DtCmsInsertApptAndLog(_DtCmsCalendar *cal, Appt_4 *appt)
611 CSA_return_code stat;
613 if ((stat = _DtCmsInsertAppt(cal, appt)) == CSA_SUCCESS) {
615 /* Add the new appointment to the log */
616 if ((stat = v4_transact_log(cal->calendar, appt,
617 _DtCmsLogAdd)) != CSA_SUCCESS) {
619 (void)_DtCmsDeleteAppt(cal, NULL, 0, &appt->appt_id,
626 extern _DtCmsComparisonResult
627 _DtCmsCompareAppt(Id_4 *key, caddr_t data)
629 Appt_4 *appt = (Appt_4 *)data;
632 if (key->tick < appt->appt_id.tick)
633 return (_DtCmsIsLess);
634 if (key->tick > appt->appt_id.tick)
635 return (_DtCmsIsGreater);
637 /* tick's are _DtCmsIsEqual */
638 if (key->key < appt->appt_id.key)
639 return (_DtCmsIsLess);
640 if (key->key > appt->appt_id.key)
641 return (_DtCmsIsGreater);
643 return (_DtCmsIsEqual);
646 extern _DtCmsComparisonResult
647 _DtCmsCompareRptAppt(Id_4 *key, caddr_t data)
649 Appt_4 *appt = (Appt_4 *)data;
651 if (key->key < appt->appt_id.key)
652 return (_DtCmsIsLess);
653 if (key->key > appt->appt_id.key)
654 return (_DtCmsIsGreater);
655 return (_DtCmsIsEqual);
659 _DtCmsGetApptKey (caddr_t data)
661 return ((caddr_t) &(((Appt_4 *) data)->appt_id));
664 extern CSA_return_code
665 v4_transact_log(char *calendar, Appt_4 *a, _DtCmsLogOps op)
667 CSA_return_code stat;
670 if ((log = _DtCmsGetLogFN(calendar)) == NULL)
671 return (CSA_E_INSUFFICIENT_MEMORY);
673 stat = _DtCmsAppendAppt4ByFN(log, a, op);
679 extern CSA_return_code
685 boolean_t no_end_time_range,
688 boolean_t (*match_func)(),
690 cms_attribute *attrs,
695 CSA_return_code stat = CSA_SUCCESS;
698 int tmp_tick, endtick;
702 time_t hi_tick, lo_tick;
708 CSA_return_code (*add_list_func)();
710 /* do lookup on new format calendar */
711 if (cal->fversion > 1) {
712 if ((stat = _DtCmsLookupEntries(cal, user, access,
713 p_range->key1, p_range->key2, no_end_time_range, end1, end2,
714 num_attrs, attrs, ops, &entries)) != CSA_SUCCESS) {
719 stat = _DtCmsCmsentriesToAppt4ForClient(entries,
722 stat = _DtCmsCmsentriesToAbbrAppt4ForClient(entries,
725 _DtCm_free_cms_entries(entries);
730 add_list_func = _AddToLinkedAppts;
732 add_list_func = _AddToLinkedAbbrAppts;
734 while (p_range != NULL)
737 lo_key.tick = p_range->key1;
738 hi_tick = p_range->key2;
742 fprintf(stderr,"Range lookup from %s",
743 ctime(&lo_key.tick));
744 fprintf(stderr, " to %s\n", ctime(&hi_tick));
749 /* Get a range of appointments in single appointment tree */
750 while ((p_appt = (Appt_4 *)rb_lookup_next_larger(
751 APPT_TREE(cal),(caddr_t)&lo_key))
752 && (APPT_TICK(p_appt) < hi_tick))
756 endtick = p_appt->appt_id.tick + p_appt->duration;
757 if ((!no_end_time_range && (p_appt->duration == 0 ||
758 endtick <= end1 || endtick >= end2)) ||
759 (match_func && !match_func(p_appt, num_attrs,
761 lo_key.key = APPT_KEY(p_appt);
762 lo_key.tick = APPT_TICK(p_appt);
766 if ((stat = (*add_list_func)(p_appt, user,
767 access,&ilp)) != CSA_SUCCESS) {
770 _DtCm_free_appt4((Appt_4 *)ilp);
772 _DtCm_free_abbrev_appt4(
779 lo_key.key = APPT_KEY(p_appt);
780 lo_key.tick = APPT_TICK(p_appt);
783 /* Get a range of events from repeating appointment list */
784 p_lnode = REPT_LIST(cal)->root;
785 while (p_lnode != NULL)
787 lo_tick = p_range->key1;
788 hi_tick = p_range->key2;
790 p_appt = (Appt_4*)p_lnode->data;
792 /* calculate the last tick */
793 if (p_lnode->lasttick == 0)
794 p_lnode->lasttick = _DtCms_last_tick_v4(
799 if (p_lnode->lasttick <= lo_tick ||
800 APPT_TICK(p_appt) >= hi_tick ||
801 (!no_end_time_range && p_appt->duration == 0) ||
802 (!no_end_time_range &&
803 (p_lnode->lasttick+p_appt->duration) <= end1) ||
804 (!no_end_time_range &&
805 (p_appt->appt_id.tick+p_appt->duration) >= end2) ||
807 !match_func(p_appt, num_attrs, attrs, ops)) ||
808 _GetAccessLevel(user, access, p_appt) == private_4)
810 p_lnode = hc_lookup_next (p_lnode);
814 if (!no_end_time_range &&
815 lo_tick < (end1 - p_appt->duration))
816 lo_tick = end1 - p_appt->duration;
818 if (!no_end_time_range &&
819 ((end2 - p_appt->duration) < hi_tick))
820 hi_tick = end2 - p_appt->duration;
822 ntimes = _DtCms_get_ninstance_v4(p_appt);
823 period = p_appt->period;
824 for (tick = _DtCms_closest_tick_v4(lo_tick,
825 APPT_TICK(p_appt), period, &ordinal), ordinal--;
827 tick = _DtCms_next_tick_v4(tick, period))
829 /* Repeater but beyond the scope */
830 if (++ordinal > ntimes ||
831 tick > p_lnode->lasttick)
834 if (tick <= lo_tick ||
835 _DtCms_marked_4_cancellation(p_appt,
841 /* Replace the parent key by the
842 * current tick for the repeating event
844 tmp_tick = APPT_TICK(p_appt);
845 APPT_TICK(p_appt) = tick;
847 /* Add to list, restore parent key */
848 stat = (*add_list_func)(p_appt, user,
851 APPT_TICK(p_appt) = tmp_tick;
853 if (stat != CSA_SUCCESS) {
859 _DtCm_free_abbrev_appt4(
867 p_lnode = hc_lookup_next (p_lnode);
870 p_range = p_range->next;
874 fprintf (stderr, "Found %d entries in range lookup\n", n);
876 if (stat == CSA_SUCCESS) {
878 *appt_r = (Appt_4 *)ilp;
880 *abbr_r = (Abb_Appt_4 *)ilp;
886 extern CSA_return_code
887 _DtCmsLookupKeyrangeV4(
891 boolean_t no_start_time_range,
892 boolean_t no_end_time_range,
898 boolean_t (*match_func)(),
900 cms_attribute *attrs,
905 CSA_return_code stat = CSA_SUCCESS;
907 long tmp_tick, endtick;
914 Appt_4 *p_appt, *tappt;
917 CSA_return_code (*add_list_func)();
919 /* do lookup on new format calendar */
920 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
921 if ((stat = _DtCmsLookupEntriesById(cal, user, access,
922 no_start_time_range, no_end_time_range, start1, start2,
923 end1, end2, id, num_attrs, attrs, ops, &entries))
929 stat = _DtCmsCmsentriesToAppt4ForClient(entries,
931 *appt_r = _AddApptInOrder(*appt_r, tappt);
933 stat = _DtCmsCmsentriesToAbbrAppt4ForClient(entries,
935 *abbr_r = _AddAbbApptInOrder(*abbr_r, tabbr);
938 _DtCm_free_cms_entries(entries);
943 add_list_func = _AddToLinkedAppts;
945 add_list_func = _AddToLinkedAbbrAppts;
948 lo_key.tick = start1;
950 /* Search from repeating appointments first for optimization */
951 p_lnode = hc_lookup_node (REPT_LIST(cal), (caddr_t)&lo_key);
952 if (p_lnode != NULL) {
953 p_appt = (Appt_4*)p_lnode->data;
954 if ((match_func && !match_func(p_appt, num_attrs, attrs, ops))
955 || _GetAccessLevel(user, access, p_appt) == private_4)
956 return (CSA_SUCCESS);
958 /* just return the first event */
959 if (no_start_time_range && no_end_time_range)
960 return ((*add_list_func)(p_appt, user, access,
961 (appt_r ? (caddr_t)appt_r : (caddr_t)abbr_r)));
963 /* Get the range of events from this appointment. */
964 ntimes = _DtCms_get_ninstance_v4(p_appt);
965 period = p_appt->period;
967 /* calculate the last tick */
968 if (p_lnode->lasttick == 0)
969 p_lnode->lasttick = _DtCms_last_tick_v4(
971 p_appt->period, p_appt->ntimes);
973 if (p_lnode->lasttick <= start1 ||
974 p_appt->appt_id.tick >= start2 ||
975 (!no_end_time_range && p_appt->duration == 0) ||
976 (!no_end_time_range &&
977 (p_lnode->lasttick+p_appt->duration) <= end1) ||
978 (!no_end_time_range &&
979 (p_appt->appt_id.tick+p_appt->duration) >= end2))
982 if (!no_end_time_range && (start1 < (end1 - p_appt->duration)))
983 start1 = end1 - p_appt->duration;
985 if (!no_end_time_range && ((end2 - p_appt->duration) < start2))
986 start2 = end2 - p_appt->duration;
988 for (tick = _DtCms_closest_tick_v4(start1,
989 APPT_TICK(p_appt), period, &ordinal), ordinal--;
990 stat == CSA_SUCCESS && tick < start2;
991 tick = _DtCms_next_tick_v4(tick, period))
993 /* Repeater but beyond the scope */
994 if (++ordinal > ntimes || tick > p_lnode->lasttick)
1000 /* If not cancelled, add to linked list */
1001 if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
1005 /* Replace the parent key by
1006 * the current tick for the
1009 tmp_tick = APPT_TICK(p_appt);
1010 APPT_TICK(p_appt) = tick;
1012 /* Add to list, restore parent key */
1013 stat = (*add_list_func)(p_appt, user, access,
1014 (appt_r ? (caddr_t)appt_r :
1017 APPT_TICK(p_appt) = tmp_tick;
1023 /* Check if it is in single appointment tree */
1024 while ((p_appt = (Appt_4 *)rb_lookup_next_larger(
1025 APPT_TREE(cal), (caddr_t) &lo_key)) &&
1026 (APPT_TICK(p_appt) < start2))
1028 if (p_appt->appt_id.key != lo_key.key) {
1029 lo_key.tick = APPT_TICK(p_appt);
1030 lo_key.key = APPT_KEY(p_appt);
1032 endtick = p_appt->appt_id.tick+p_appt->duration;
1034 if ((!no_end_time_range &&
1035 (p_appt->duration == 0 || endtick <= end1 ||
1036 endtick >= end2)) ||
1037 (match_func && !match_func(p_appt,
1038 num_attrs, attrs, ops))) {
1040 return (CSA_SUCCESS);
1042 return ((*add_list_func)(p_appt, user,
1049 return (CSA_SUCCESS);
1053 extern CSA_return_code
1063 switch (_GetAccessLevel(user, access, p_appt)) {
1065 copy = _DtCm_copy_one_appt4(p_appt);
1068 copy = _DtCm_copy_semiprivate_appt4(p_appt);
1071 return (CSA_SUCCESS);
1075 return(CSA_E_INSUFFICIENT_MEMORY);
1077 *ilp = (caddr_t)_AddApptInOrder((Appt_4 *)*ilp, copy);
1078 return (CSA_SUCCESS);
1082 extern CSA_return_code
1083 _AddToLinkedAbbrAppts(
1091 switch (_GetAccessLevel(user, access, p_appt)) {
1093 copy = _DtCm_appt_to_abbrev4(p_appt);
1096 copy = _DtCm_appt_to_semiprivate_abbrev4(p_appt);
1099 return (CSA_SUCCESS);
1103 return(CSA_E_INSUFFICIENT_MEMORY);
1105 *ilp = (caddr_t)_AddAbbApptInOrder((Abb_Appt_4 *)*ilp, copy);
1106 return (CSA_SUCCESS);
1110 extern Privacy_Level_4
1111 _GetAccessLevel(char *user, uint access, Appt_4 *p_appt)
1113 if (access & CSA_OWNER_RIGHTS ||
1114 ((access & access_read_4) && p_appt->privacy == public_4) ||
1115 _DtCmIsSameUser(user, p_appt->author)) {
1119 } else if (p_appt->privacy == private_4) {
1124 return (semiprivate_4);
1129 _AddApptInOrder(Appt_4 *head, Appt_4 *aptr)
1131 Appt_4 *p_appt, *p_prev, *p_next;
1134 p_next = aptr->next;
1137 /* Add the item to the linked list in ascending order */
1140 while (p_appt != NULL)
1142 if (APPT_TICK(aptr) <= APPT_TICK(p_appt))
1145 p_appt = p_appt->next;
1150 aptr->next = p_appt;
1153 aptr->next = p_prev->next;
1154 p_prev->next = aptr;
1164 _AddAbbApptInOrder(Abb_Appt_4 *head, Abb_Appt_4 *aptr)
1166 Abb_Appt_4 *p_appt, *p_prev, *p_next;
1169 p_next = aptr->next;
1172 /* Add the item to the linked list in ascending order */
1175 while (p_appt != NULL)
1177 if (APPT_TICK(aptr) <= APPT_TICK(p_appt))
1180 p_appt = p_appt->next;
1185 aptr->next = p_appt;
1188 aptr->next = p_prev->next;
1189 p_prev->next = aptr;
1198 extern CSA_return_code
1199 _DtCmsSetV4AccessListAndLog(_DtCmsCalendar *cal, Access_Entry_4 *alist)
1201 CSA_return_code stat;
1205 /* update access list for old format calendar */
1206 if ((name = _DtCmsTarget2Name(cal->calendar)) == NULL)
1207 return (CSA_E_INSUFFICIENT_MEMORY);
1209 if ((log = _DtCmsGetLogFN(name)) == NULL) {
1211 return (CSA_E_INSUFFICIENT_MEMORY);
1215 * save file size in case the first log transaction
1216 * succeeds but the second log transaction fails.
1218 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
1225 /* Set to the data structure */
1226 if ((stat = _DtCmsSetV4AccessListInCal(cal, alist)) == CSA_SUCCESS) {
1228 if (((stat = _DtCmsAppendAccessByFN(log, access_read_4,
1229 GET_R_ACCESS(cal))) != CSA_SUCCESS) ||
1230 ((stat = _DtCmsAppendAccessByFN(log, access_write_4,
1231 GET_W_ACCESS(cal))) != CSA_SUCCESS) ||
1232 ((stat = _DtCmsAppendAccessByFN(log, access_delete_4,
1233 GET_D_ACCESS(cal))) != CSA_SUCCESS) ||
1234 ((stat = _DtCmsAppendAccessByFN(log, access_exec_4,
1235 GET_X_ACCESS(cal))) != CSA_SUCCESS)) {
1237 /* rollback log file */
1238 _DtCmsTruncateFile(cal->calendar, file_size);
1240 cal->modified = B_TRUE;
1248 extern CSA_return_code
1249 _DtCmsGetV4Reminders(
1250 _DtCmsCalendar *cal,
1253 _DtCmsEntryId **ids_r)
1255 Rm_que *p_node, *p_prev, *p_next, *p_new;
1256 Reminder_4 *rptr, *v4rem = NULL;
1257 _DtCmsEntryId *idptr, *ids = NULL;
1259 if (rem_r == NULL) return (CSA_E_INVALID_PARAMETER);
1261 /* do lookup in old format calendar */
1263 p_node = cal->rm_queue;
1264 while (p_node != NULL)
1266 /* It is still a future reminder. */
1267 if (tick < p_node->remind_at)
1270 /* The reminder expired. It either needs to be recalculated
1271 * (repeating appointment) or dropped (non-repeating appt.)
1273 p_next = _DtCmsRemoveReminderV4(&cal->rm_queue, p_prev, p_node);
1275 if (is_repeater(p_node->appt)) {
1276 /* Calculate next reminder for repeating appointment */
1277 p_new = build_reminder(tick+1, p_node->appt,
1278 p_node->attr, p_node->remind_at,
1279 p_node->remind_ord);
1282 _DtCmsAddReminderV4(&cal->rm_queue, p_new);
1283 if (p_new->next == p_next)
1292 /* Pick the first one from the active reminder queue because it is
1293 * always >= the given key.
1295 p_node = cal->rm_queue;
1298 tick = p_node->remind_at;
1301 rptr = _DtCmsGetReminderInfoV4(p_node);
1305 idptr = (_DtCmsEntryId *)calloc(1,
1306 sizeof(_DtCmsEntryId));
1307 idptr->id = p_node->appt->appt_id.key;
1311 p_node = p_node->next;
1312 } while ((p_node != NULL) && (p_node->remind_at == tick));
1316 if (ids_r) *ids_r = ids;
1317 return (CSA_SUCCESS);
1321 _DtCmsFreeEntryIds(_DtCmsEntryId *ids)
1325 while (ids != NULL) {
1332 extern CSA_return_code
1333 _DtCmsTruncateElist(Appt_4 *parent_p, int remain, Except_4 **excpt)
1335 int except_no, ntimes_diff;
1336 Except_4 *e, *p, *last_e = NULL, *head = NULL;
1338 ntimes_diff = _DtCms_get_ninstance_v4(parent_p) - remain;
1339 p = parent_p->exception;
1341 if ((except_no = (p->ordinal - ntimes_diff)) > 0 &&
1342 except_no <= remain) {
1343 if ((e = (Except_4*)calloc(1, sizeof(Except_4)))
1345 _DtCm_free_excpt4(head);
1346 return (CSA_E_INSUFFICIENT_MEMORY);
1348 e->ordinal = except_no;
1360 return (CSA_SUCCESS);
1363 extern CSA_return_code
1364 _DtCmsSetV4AccessListInCal(_DtCmsCalendar *cal, Access_Entry_4 *e)
1368 /* Wipe out the old access lists. */
1369 _DtCm_free_access_list4(GET_R_ACCESS (cal));
1370 _DtCm_free_access_list4(GET_W_ACCESS (cal));
1371 _DtCm_free_access_list4(GET_D_ACCESS (cal));
1372 _DtCm_free_access_list4(GET_X_ACCESS (cal));
1373 SET_R_ACCESS(cal, NULL);
1374 SET_W_ACCESS(cal, NULL);
1375 SET_D_ACCESS(cal, NULL);
1376 SET_X_ACCESS(cal, NULL);
1377 _DtCm_free_access_list4(cal->alist);
1379 /* Split the access list to 3 differnt operation lists */
1382 if (e->access_type & access_read_4) {
1383 q = _DtCm_make_access_entry4(e->who, e->access_type);
1384 q->next = GET_R_ACCESS(cal);
1385 SET_R_ACCESS(cal, q);
1387 if (e->access_type & access_write_4) {
1388 q = _DtCm_make_access_entry4(e->who, e->access_type);
1389 q->next = GET_W_ACCESS(cal);
1390 SET_W_ACCESS(cal, q);
1392 if (e->access_type & access_delete_4) {
1393 q = _DtCm_make_access_entry4(e->who, e->access_type);
1394 q->next = GET_D_ACCESS(cal);
1395 SET_D_ACCESS(cal, q);
1397 if (e->access_type & access_exec_4) {
1398 q = _DtCm_make_access_entry4(e->who, e->access_type);
1399 q->next = GET_X_ACCESS(cal);
1400 SET_X_ACCESS(cal, q);
1405 cal->alist = _DtCmsCalendarAccessList(cal);
1407 return (CSA_SUCCESS);
1410 /******************************************************************************
1411 * static functions used within the file
1412 ******************************************************************************/
1415 append_exception_list(Appt_4 *p_appt, int ordinal)
1417 Exception_4 p_excpt;
1421 if ((p_excpt = (Exception_4)calloc(1, sizeof(*p_excpt))) == NULL)
1423 p_excpt->ordinal = ordinal;
1425 p_ex = p_appt->exception;
1426 while (p_ex != NULL)
1428 /* Exception list is in descending order for faster access */
1429 if (ordinal > p_ex->ordinal)
1436 p_excpt->next = p_appt->exception;
1437 p_appt->exception = p_excpt;
1441 p_excpt->next = p_prev->next;
1442 p_prev->next = p_excpt;
1449 * remove exceptions that are larger than ordinal
1452 trunc_exception_list(Appt_4 *p_appt, int ordinal)
1457 p_ex = p_appt->exception;
1459 /* Exception list is in descending order for faster access */
1460 while ((p_ex != NULL) && (p_ex->ordinal > ordinal))
1462 p_next = p_ex->next;
1466 p_appt->exception = p_ex;
1470 num_exception(Appt_4 *p_appt)
1476 p = p_appt->exception;