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>
39 #if defined(CSRG_BASED)
40 #include <sys/limits.h>
41 #define MAXINT INT_MAX
46 #include <sys/systeminfo.h>
50 #include "cmscalendar.h"
54 #include "appt4.h" /* Internal appointment data structure */
59 #include "cmsconvert.h"
68 /*****************************************************************************
69 * forward declaration of static functions used within the file
70 *****************************************************************************/
71 static Exception_4 append_exception_list(Appt_4 *p_appt, int ordinal);
72 static void trunc_exception_list(Appt_4 *p_appt, int ordinal);
73 static int num_exception(Appt_4 *p_appt);
75 /*****************************************************************************
76 * extern functions used in the library
77 *****************************************************************************/
80 * Insert one appointment into the single appointment tree structure
81 * or the repeat appointment list structure.
82 * The passed in appointment is stored in the structure.
84 extern CSA_return_code
85 _DtCmsInsertAppt(_DtCmsCalendar *cal, Appt_4 *appt4)
92 if (cal == NULL || appt4 == NULL)
93 return (CSA_E_INVALID_PARAMETER);
95 /* assign key if this is a new appointment */
96 _DtCmsGenerateKey(cal, &(appt4->appt_id.key));
99 fprintf(stderr, "Insert appt4: (%ld)%s\n",
100 appt4->appt_id.key, ctime(&(appt4->appt_id.tick)));
103 /* Add the appointment into the data structure */
104 if (appt4->period.period == single_4)
105 rb_stat = rb_insert (cal->tree, (caddr_t)appt4,
106 (caddr_t)&(appt4->appt_id));
108 rb_stat = hc_insert (REPT_LIST(cal), (caddr_t)appt4,
109 (caddr_t)&(appt4->appt_id), NULL, NULL);
111 if (rb_stat == rb_ok) {
112 /* Add the qualified reminder attrs to the reminder queue */
113 current_time = time(0);
114 p_attr = appt4->attr;
115 while (p_attr != NULL)
120 tick = appt4->appt_id.tick - atol(p_attr->value);
121 p_reminder = build_reminder (current_time, appt4,
123 if (p_reminder != NULL)
124 _DtCmsAddReminderV4(&cal->rm_queue, p_reminder);
125 p_attr = p_attr->next;
129 return (_DtCmsRbToCsaStat(rb_stat));
133 * If p_auth is null, the initiator is the owner of the calendar. Permission
134 * to delete any appointment is always granted. If p_auth is not null, we need
135 * to check if it matches the author of the deleting appointment. Only the
136 * author can delete his/her appointment.
138 extern CSA_return_code
151 * Before we delete an event from the single appointment tree, we
152 * need to check if the initiator is the author of the appointment.
154 if ((user != NULL) && (p_appt = (Appt_4 *)rb_lookup(APPT_TREE(cal),
155 (caddr_t)p_key)) != NULL) {
156 if (!(access & (access_delete_4|CSA_OWNER_RIGHTS)) &&
157 !_DtCmIsSameUser(user, p_appt->author))
158 return (CSA_E_NO_AUTHORITY);
161 if ((p_node = rb_delete (APPT_TREE(cal), (caddr_t)p_key)) != NULL) {
162 p_appt = (Appt_4*)p_node->data;
163 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0, B_FALSE);
167 fprintf (stderr, "Deleted (%ld)%s\n",
169 ctime(&(p_appt->appt_id.tick)));
174 _DtCm_free_appt4(p_appt);
175 return (CSA_SUCCESS);
178 /* Attempt to delete the event from the repeating appointment list */
179 p_lnode = (List_node *)hc_lookup_node(REPT_LIST(cal),
182 if (p_lnode != NULL) {
183 p_appt = (Appt_4 *)p_lnode->data;
186 !(access & (access_delete_4|CSA_OWNER_RIGHTS)) &&
187 !_DtCmIsSameUser(user, p_appt->author))
188 return (CSA_E_NO_AUTHORITY);
190 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0, B_FALSE);
191 (void) hc_delete_node (REPT_LIST(cal), p_lnode);
195 fprintf (stderr, "Deleted (%ld)%s\n",
197 ctime(&(p_appt->appt_id.tick)));
202 _DtCm_free_appt4(p_appt);
203 return (CSA_SUCCESS);
205 return (CSA_E_USER_NOT_FOUND | CSA_E_INVALID_ENTRY_HANDLE);
208 extern CSA_return_code
209 _DtCmsDeleteApptAndLog(
216 CSA_return_code stat;
219 if ((stat = _DtCmsDeleteAppt(cal, user, access, key, &appt))
222 /* Transact the log */
223 if ((stat = v4_transact_log(cal->calendar, appt,
224 _DtCmsLogRemove)) != CSA_SUCCESS) {
226 (void)_DtCmsInsertAppt(cal, appt);
228 } else if (oldappt) {
231 _DtCm_free_appt4(appt);
238 extern CSA_return_code
239 _DtCmsDeleteApptInstancesAndLog(
249 CSA_return_code stat = CSA_SUCCESS;
250 Appt_4 *p_appt, *oldcopy;
252 int f, file_size, ntimes, ninstance, status = 0;
255 p_lnode = (List_node *)hc_lookup_node (REPT_LIST(cal), (caddr_t)key);
257 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
259 p_appt = (Appt_4*)p_lnode->data;
260 if (!(access & (access_delete_4 | CSA_OWNER_RIGHTS)) &&
261 !_DtCmIsSameUser(source, p_appt->author))
262 return (CSA_E_NO_AUTHORITY);
264 if ((ordinal = _DtCms_in_repeater (key, p_appt, B_TRUE)) == 0)
265 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
268 fprintf(stderr,"Delete instance: Ordinal=%d\n",ordinal);
271 * save file size in case the first log transaction
272 * succeeds but the second log transaction fails.
274 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
278 /* remove from log */
279 if ((stat = v4_transact_log(cal->calendar, p_appt, _DtCmsLogRemove))
283 ninstance = _DtCms_get_ninstance_v4(p_appt);
285 /* calculate the ntimes value for the part
286 * of the sequence that start from the ordinal to the end
289 *remain = _DtCms_get_new_ntimes_v4(p_appt->period, key->tick,
290 (ninstance - ordinal + 1));
293 * make a copy of the original appointment,
294 * in case we need a rollback
296 if ((oldcopy = _DtCm_copy_one_appt4(p_appt)) == NULL) {
297 stat = CSA_E_INSUFFICIENT_MEMORY;
301 /* remove from memory */
302 if (option == do_one_4) {
303 if (!append_exception_list (p_appt, ordinal)) {
304 stat = CSA_E_INSUFFICIENT_MEMORY;
308 ninstance = ordinal - 1;
309 if (ninstance == 1) {
310 /* convert to one-time event */
311 p_appt->period.period = single_4;
312 p_appt->period.nth = 0;
313 p_appt->period.enddate = 0;
315 if (p_appt->exception) {
316 _DtCm_free_excpt4(p_appt->exception);
317 p_appt->exception = NULL;
319 stat = _DtCmsRbToCsaStat(rb_insert(cal->tree,
320 (caddr_t)p_appt, (caddr_t)&(p_appt->appt_id)));
322 p_appt->ntimes = _DtCms_get_new_ntimes_v4(
323 p_appt->period, p_appt->appt_id.tick,
326 /* update enddate just for M-F, MWF, TTh
329 switch (p_appt->period.period) {
334 p_appt->period.enddate = _DtCms_prev_tick_v4(
338 trunc_exception_list(p_appt, ordinal);
342 /* The last one from the series has been deleted, no more left. */
343 if (ninstance == num_exception (p_appt))
347 /* Obsolete the reminders which match the ordinal */
348 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, ordinal,
349 (option == do_one_4 ? B_FALSE : B_TRUE));
350 _DtCm_free_appt4(p_appt);
351 hc_delete_node (REPT_LIST(cal), p_lnode);
354 /* Write out the series with new exception list. */
355 if (stat || (stat = v4_transact_log(cal->calendar, p_appt,
356 _DtCmsLogAdd)) != CSA_SUCCESS) {
357 /* reverse memory update */
358 p_appt->ntimes = oldcopy->ntimes;
359 p_appt->period = oldcopy->period;
360 _DtCm_free_excpt4(p_appt->exception);
361 p_appt->exception = oldcopy->exception;
362 oldcopy->exception = NULL;
366 if (ninstance == 1) {
370 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0,
371 (option == do_one_4 ? B_FALSE : B_TRUE));
372 hc_delete_node(REPT_LIST(cal), p_lnode);
375 /* Add the qualified reminder attrs to
378 current_time = time(0);
379 p_attr = p_appt->attr;
380 while (p_attr != NULL) {
384 tick = p_appt->appt_id.tick-atol(p_attr->value);
385 p_reminder = build_reminder(current_time,
386 p_appt, p_attr, tick, 1);
387 if (p_reminder != NULL)
388 _DtCmsAddReminderV4(&cal->rm_queue,
390 p_attr = p_attr->next;
394 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt,
396 (option == do_one_4 ? B_FALSE : B_TRUE));
403 _DtCm_free_appt4(oldcopy);
405 return (CSA_SUCCESS);
408 /* rollback log file */
409 _DtCmsTruncateFile(cal->calendar, file_size);
412 _DtCm_free_appt4(oldcopy);
417 extern CSA_return_code
426 CSA_return_code stat = CSA_SUCCESS;
427 Appt_4 *olda, *newcopy = NULL;
431 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
436 * first, remove the old appointment from internal data structure
437 * and the callog file
439 if ((stat = _DtCmsDeleteApptAndLog(cal, source, access, p_key, &olda))
443 if (is_repeater(olda) && is_repeater(newa)) {
444 if (_DtCmsBeginOfDay(APPT_TICK(newa)) ==
445 _DtCmsBeginOfDay(p_key->tick) &&
446 olda->period.period == newa->period.period)
448 /* keep the start day of the original
449 * appointment if the date of the
450 * key matches that of the new
451 * appointment and the interval
454 APPT_TICK(newa) -= _DtCmsBeginOfDay(APPT_TICK(newa)) -
455 _DtCmsBeginOfDay(APPT_TICK(olda));
457 /* otherwise, calculate new parent */
458 if ((ordinal = _DtCms_in_repeater(p_key, olda, B_TRUE))
460 stat = CSA_X_DT_E_ENTRY_NOT_FOUND;
461 goto change_all_cleanup;
463 APPT_TICK(newa) = _DtCms_first_tick_v4(
465 newa->period, ordinal);
466 /* if enddate exist, adjust it */
467 if (olda->period.enddate &&
468 newa->period.period == olda->period.period
469 && newa->period.nth == olda->period.nth) {
470 newa->period.enddate +=
471 (_DtCmsBeginOfDay(APPT_TICK(newa)) -
472 _DtCmsBeginOfDay(APPT_TICK(olda)));
478 /* We use the same exception list for the
479 * new appt. ?? is this reasonable for
482 newa->exception = _DtCm_copy_excpt4(olda->exception);
485 /* adjust start date */
486 _DtCms_adjust_appt_startdate(newa);
488 /* make copy of new appointment */
489 if ((newcopy = _DtCm_copy_one_appt4(newa)) == NULL) {
490 stat = CSA_E_INSUFFICIENT_MEMORY;
491 goto change_all_cleanup;
495 newcopy->appt_id.key = olda->appt_id.key;
497 /* keep the original author */
498 free(newcopy->author);
499 if ((newcopy->author = strdup(olda->author)) == NULL) {
500 stat = CSA_E_INSUFFICIENT_MEMORY;
501 goto change_all_cleanup;
504 if ((stat = _DtCmsInsertApptAndLog(cal, newcopy)) != CSA_SUCCESS) {
505 goto change_all_cleanup;
507 newa->appt_id.key = newcopy->appt_id.key;
512 _DtCm_free_appt4(olda);
518 _DtCm_free_appt4(newcopy);
519 _DtCmsTruncateFile(cal->calendar, file_size);
520 (void)_DtCmsInsertAppt(cal, olda);
524 extern CSA_return_code
534 CSA_return_code stat;
535 Appt_4 *olda, *newcopy = NULL;
537 Exception_4 *newexcept;
541 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
546 * first, remove the old appointment from internal data structure
547 * and the callog file
549 if ((stat = _DtCmsDeleteApptInstancesAndLog(cal, source, access,
550 p_key, option, &remain, &olda)) != CSA_SUCCESS)
553 /* adjust start date */
554 _DtCms_adjust_appt_startdate(newa);
556 /* make copy of new appointment */
557 newcopy = _DtCm_copy_one_appt4(newa);
559 if (option == do_forward_4) {
560 /* if repeating info is not changed, replace
561 * the deleted part with the new series, i.e.,
562 * ntimes of new series _DtCmsIsEquals to the number
563 * of deleted instances. Also get new
566 if (olda->period.period == newa->period.period &&
567 olda->period.nth == newa->period.nth &&
568 olda->ntimes == newa->ntimes) {
570 newcopy->ntimes = remain;
571 if (olda->exception != NULL) {
572 _DtCm_free_excpt4(newcopy->exception);
573 if ((stat = _DtCmsTruncateElist(olda, remain,
574 &newcopy->exception)) != CSA_SUCCESS) {
575 goto change_some_cleanup;
581 /* keep the original author */
582 free(newcopy->author);
583 if ((newcopy->author = strdup(olda->author)) == NULL) {
584 stat = CSA_E_INSUFFICIENT_MEMORY;
585 goto change_some_cleanup;
588 APPT_KEY(newcopy) = 0;
590 if ((stat = _DtCmsInsertApptAndLog(cal, newcopy)) != CSA_SUCCESS) {
591 goto change_some_cleanup;
593 newa->appt_id.key = newcopy->appt_id.key;
598 _DtCm_free_appt4(olda);
604 _DtCm_free_appt4(newcopy);
605 _DtCmsTruncateFile(cal->calendar, file_size);
606 (void)_DtCmsInsertAppt(cal, olda);
611 * the passed in appt is stored in the internal data structure
613 extern CSA_return_code
614 _DtCmsInsertApptAndLog(_DtCmsCalendar *cal, Appt_4 *appt)
616 CSA_return_code stat;
618 if ((stat = _DtCmsInsertAppt(cal, appt)) == CSA_SUCCESS) {
620 /* Add the new appointment to the log */
621 if ((stat = v4_transact_log(cal->calendar, appt,
622 _DtCmsLogAdd)) != CSA_SUCCESS) {
624 (void)_DtCmsDeleteAppt(cal, NULL, 0, &appt->appt_id,
631 extern _DtCmsComparisonResult
632 _DtCmsCompareAppt(Id_4 *key, caddr_t data)
634 Appt_4 *appt = (Appt_4 *)data;
637 if (key->tick < appt->appt_id.tick)
638 return (_DtCmsIsLess);
639 if (key->tick > appt->appt_id.tick)
640 return (_DtCmsIsGreater);
642 /* tick's are _DtCmsIsEqual */
643 if (key->key < appt->appt_id.key)
644 return (_DtCmsIsLess);
645 if (key->key > appt->appt_id.key)
646 return (_DtCmsIsGreater);
648 return (_DtCmsIsEqual);
651 extern _DtCmsComparisonResult
652 _DtCmsCompareRptAppt(Id_4 *key, caddr_t data)
654 Appt_4 *appt = (Appt_4 *)data;
656 if (key->key < appt->appt_id.key)
657 return (_DtCmsIsLess);
658 if (key->key > appt->appt_id.key)
659 return (_DtCmsIsGreater);
660 return (_DtCmsIsEqual);
664 _DtCmsGetApptKey (caddr_t data)
666 return ((caddr_t) &(((Appt_4 *) data)->appt_id));
669 extern CSA_return_code
670 v4_transact_log(char *calendar, Appt_4 *a, _DtCmsLogOps op)
672 CSA_return_code stat;
675 if ((log = _DtCmsGetLogFN(calendar)) == NULL)
676 return (CSA_E_INSUFFICIENT_MEMORY);
678 stat = _DtCmsAppendAppt4ByFN(log, a, op);
684 extern CSA_return_code
690 boolean_t no_end_time_range,
693 boolean_t (*match_func)(),
695 cms_attribute *attrs,
700 CSA_return_code stat = CSA_SUCCESS;
703 int tmp_tick, endtick;
707 time_t hi_tick, lo_tick;
713 CSA_return_code (*add_list_func)();
715 /* do lookup on new format calendar */
716 if (cal->fversion > 1) {
717 if ((stat = _DtCmsLookupEntries(cal, user, access,
718 p_range->key1, p_range->key2, no_end_time_range, end1, end2,
719 num_attrs, attrs, ops, &entries)) != CSA_SUCCESS) {
724 stat = _DtCmsCmsentriesToAppt4ForClient(entries,
727 stat = _DtCmsCmsentriesToAbbrAppt4ForClient(entries,
730 _DtCm_free_cms_entries(entries);
735 add_list_func = _AddToLinkedAppts;
737 add_list_func = _AddToLinkedAbbrAppts;
739 while (p_range != NULL)
742 lo_key.tick = p_range->key1;
743 hi_tick = p_range->key2;
747 fprintf(stderr,"Range lookup from %s",
748 ctime(&lo_key.tick));
749 fprintf(stderr, " to %s\n", ctime(&hi_tick));
754 /* Get a range of appointments in single appointment tree */
755 while ((p_appt = (Appt_4 *)rb_lookup_next_larger(
756 APPT_TREE(cal),(caddr_t)&lo_key))
757 && (APPT_TICK(p_appt) < hi_tick))
761 endtick = p_appt->appt_id.tick + p_appt->duration;
762 if ((!no_end_time_range && (p_appt->duration == 0 ||
763 endtick <= end1 || endtick >= end2)) ||
764 (match_func && !match_func(p_appt, num_attrs,
766 lo_key.key = APPT_KEY(p_appt);
767 lo_key.tick = APPT_TICK(p_appt);
771 if ((stat = (*add_list_func)(p_appt, user,
772 access,&ilp)) != CSA_SUCCESS) {
775 _DtCm_free_appt4((Appt_4 *)ilp);
777 _DtCm_free_abbrev_appt4(
784 lo_key.key = APPT_KEY(p_appt);
785 lo_key.tick = APPT_TICK(p_appt);
788 /* Get a range of events from repeating appointment list */
789 p_lnode = REPT_LIST(cal)->root;
790 while (p_lnode != NULL)
792 lo_tick = p_range->key1;
793 hi_tick = p_range->key2;
795 p_appt = (Appt_4*)p_lnode->data;
797 /* calculate the last tick */
798 if (p_lnode->lasttick == 0)
799 p_lnode->lasttick = _DtCms_last_tick_v4(
804 if (p_lnode->lasttick <= lo_tick ||
805 APPT_TICK(p_appt) >= hi_tick ||
806 (!no_end_time_range && p_appt->duration == 0) ||
807 (!no_end_time_range &&
808 (p_lnode->lasttick+p_appt->duration) <= end1) ||
809 (!no_end_time_range &&
810 (p_appt->appt_id.tick+p_appt->duration) >= end2) ||
812 !match_func(p_appt, num_attrs, attrs, ops)) ||
813 _GetAccessLevel(user, access, p_appt) == private_4)
815 p_lnode = hc_lookup_next (p_lnode);
819 if (!no_end_time_range &&
820 lo_tick < (end1 - p_appt->duration))
821 lo_tick = end1 - p_appt->duration;
823 if (!no_end_time_range &&
824 ((end2 - p_appt->duration) < hi_tick))
825 hi_tick = end2 - p_appt->duration;
827 ntimes = _DtCms_get_ninstance_v4(p_appt);
828 period = p_appt->period;
829 for (tick = _DtCms_closest_tick_v4(lo_tick,
830 APPT_TICK(p_appt), period, &ordinal), ordinal--;
832 tick = _DtCms_next_tick_v4(tick, period))
834 /* Repeater but beyond the scope */
835 if (++ordinal > ntimes ||
836 tick > p_lnode->lasttick)
839 if (tick <= lo_tick ||
840 _DtCms_marked_4_cancellation(p_appt,
846 /* Replace the parent key by the
847 * current tick for the repeating event
849 tmp_tick = APPT_TICK(p_appt);
850 APPT_TICK(p_appt) = tick;
852 /* Add to list, restore parent key */
853 stat = (*add_list_func)(p_appt, user,
856 APPT_TICK(p_appt) = tmp_tick;
858 if (stat != CSA_SUCCESS) {
864 _DtCm_free_abbrev_appt4(
872 p_lnode = hc_lookup_next (p_lnode);
875 p_range = p_range->next;
879 fprintf (stderr, "Found %d entries in range lookup\n", n);
881 if (stat == CSA_SUCCESS) {
883 *appt_r = (Appt_4 *)ilp;
885 *abbr_r = (Abb_Appt_4 *)ilp;
891 extern CSA_return_code
892 _DtCmsLookupKeyrangeV4(
896 boolean_t no_start_time_range,
897 boolean_t no_end_time_range,
903 boolean_t (*match_func)(),
905 cms_attribute *attrs,
910 CSA_return_code stat = CSA_SUCCESS;
912 long tmp_tick, endtick;
919 Appt_4 *p_appt, *tappt;
922 CSA_return_code (*add_list_func)();
924 /* do lookup on new format calendar */
925 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
926 if ((stat = _DtCmsLookupEntriesById(cal, user, access,
927 no_start_time_range, no_end_time_range, start1, start2,
928 end1, end2, id, num_attrs, attrs, ops, &entries))
934 stat = _DtCmsCmsentriesToAppt4ForClient(entries,
936 *appt_r = _AddApptInOrder(*appt_r, tappt);
938 stat = _DtCmsCmsentriesToAbbrAppt4ForClient(entries,
940 *abbr_r = _AddAbbApptInOrder(*abbr_r, tabbr);
943 _DtCm_free_cms_entries(entries);
948 add_list_func = _AddToLinkedAppts;
950 add_list_func = _AddToLinkedAbbrAppts;
953 lo_key.tick = start1;
955 /* Search from repeating appointments first for optimization */
956 p_lnode = hc_lookup_node (REPT_LIST(cal), (caddr_t)&lo_key);
957 if (p_lnode != NULL) {
958 p_appt = (Appt_4*)p_lnode->data;
959 if ((match_func && !match_func(p_appt, num_attrs, attrs, ops))
960 || _GetAccessLevel(user, access, p_appt) == private_4)
961 return (CSA_SUCCESS);
963 /* just return the first event */
964 if (no_start_time_range && no_end_time_range)
965 return ((*add_list_func)(p_appt, user, access,
966 (appt_r ? (caddr_t)appt_r : (caddr_t)abbr_r)));
968 /* Get the range of events from this appointment. */
969 ntimes = _DtCms_get_ninstance_v4(p_appt);
970 period = p_appt->period;
972 /* calculate the last tick */
973 if (p_lnode->lasttick == 0)
974 p_lnode->lasttick = _DtCms_last_tick_v4(
976 p_appt->period, p_appt->ntimes);
978 if (p_lnode->lasttick <= start1 ||
979 p_appt->appt_id.tick >= start2 ||
980 (!no_end_time_range && p_appt->duration == 0) ||
981 (!no_end_time_range &&
982 (p_lnode->lasttick+p_appt->duration) <= end1) ||
983 (!no_end_time_range &&
984 (p_appt->appt_id.tick+p_appt->duration) >= end2))
987 if (!no_end_time_range && (start1 < (end1 - p_appt->duration)))
988 start1 = end1 - p_appt->duration;
990 if (!no_end_time_range && ((end2 - p_appt->duration) < start2))
991 start2 = end2 - p_appt->duration;
993 for (tick = _DtCms_closest_tick_v4(start1,
994 APPT_TICK(p_appt), period, &ordinal), ordinal--;
995 stat == CSA_SUCCESS && tick < start2;
996 tick = _DtCms_next_tick_v4(tick, period))
998 /* Repeater but beyond the scope */
999 if (++ordinal > ntimes || tick > p_lnode->lasttick)
1005 /* If not cancelled, add to linked list */
1006 if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
1010 /* Replace the parent key by
1011 * the current tick for the
1014 tmp_tick = APPT_TICK(p_appt);
1015 APPT_TICK(p_appt) = tick;
1017 /* Add to list, restore parent key */
1018 stat = (*add_list_func)(p_appt, user, access,
1019 (appt_r ? (caddr_t)appt_r :
1022 APPT_TICK(p_appt) = tmp_tick;
1028 /* Check if it is in single appointment tree */
1029 while ((p_appt = (Appt_4 *)rb_lookup_next_larger(
1030 APPT_TREE(cal), (caddr_t) &lo_key)) &&
1031 (APPT_TICK(p_appt) < start2))
1033 if (p_appt->appt_id.key != lo_key.key) {
1034 lo_key.tick = APPT_TICK(p_appt);
1035 lo_key.key = APPT_KEY(p_appt);
1037 endtick = p_appt->appt_id.tick+p_appt->duration;
1039 if ((!no_end_time_range &&
1040 (p_appt->duration == 0 || endtick <= end1 ||
1041 endtick >= end2)) ||
1042 (match_func && !match_func(p_appt,
1043 num_attrs, attrs, ops))) {
1045 return (CSA_SUCCESS);
1047 return ((*add_list_func)(p_appt, user,
1054 return (CSA_SUCCESS);
1058 extern CSA_return_code
1068 switch (_GetAccessLevel(user, access, p_appt)) {
1070 copy = _DtCm_copy_one_appt4(p_appt);
1073 copy = _DtCm_copy_semiprivate_appt4(p_appt);
1076 return (CSA_SUCCESS);
1080 return(CSA_E_INSUFFICIENT_MEMORY);
1082 *ilp = (caddr_t)_AddApptInOrder((Appt_4 *)*ilp, copy);
1083 return (CSA_SUCCESS);
1087 extern CSA_return_code
1088 _AddToLinkedAbbrAppts(
1096 switch (_GetAccessLevel(user, access, p_appt)) {
1098 copy = _DtCm_appt_to_abbrev4(p_appt);
1101 copy = _DtCm_appt_to_semiprivate_abbrev4(p_appt);
1104 return (CSA_SUCCESS);
1108 return(CSA_E_INSUFFICIENT_MEMORY);
1110 *ilp = (caddr_t)_AddAbbApptInOrder((Abb_Appt_4 *)*ilp, copy);
1111 return (CSA_SUCCESS);
1115 extern Privacy_Level_4
1116 _GetAccessLevel(char *user, uint access, Appt_4 *p_appt)
1118 if (access & CSA_OWNER_RIGHTS ||
1119 ((access & access_read_4) && p_appt->privacy == public_4) ||
1120 _DtCmIsSameUser(user, p_appt->author)) {
1124 } else if (p_appt->privacy == private_4) {
1129 return (semiprivate_4);
1134 _AddApptInOrder(Appt_4 *head, Appt_4 *aptr)
1136 Appt_4 *p_appt, *p_prev, *p_next;
1139 p_next = aptr->next;
1142 /* Add the item to the linked list in ascending order */
1145 while (p_appt != NULL)
1147 if (APPT_TICK(aptr) <= APPT_TICK(p_appt))
1150 p_appt = p_appt->next;
1155 aptr->next = p_appt;
1158 aptr->next = p_prev->next;
1159 p_prev->next = aptr;
1169 _AddAbbApptInOrder(Abb_Appt_4 *head, Abb_Appt_4 *aptr)
1171 Abb_Appt_4 *p_appt, *p_prev, *p_next;
1174 p_next = aptr->next;
1177 /* Add the item to the linked list in ascending order */
1180 while (p_appt != NULL)
1182 if (APPT_TICK(aptr) <= APPT_TICK(p_appt))
1185 p_appt = p_appt->next;
1190 aptr->next = p_appt;
1193 aptr->next = p_prev->next;
1194 p_prev->next = aptr;
1203 extern CSA_return_code
1204 _DtCmsSetV4AccessListAndLog(_DtCmsCalendar *cal, Access_Entry_4 *alist)
1206 CSA_return_code stat;
1210 /* update access list for old format calendar */
1211 if ((name = _DtCmsTarget2Name(cal->calendar)) == NULL)
1212 return (CSA_E_INSUFFICIENT_MEMORY);
1214 if ((log = _DtCmsGetLogFN(name)) == NULL) {
1216 return (CSA_E_INSUFFICIENT_MEMORY);
1220 * save file size in case the first log transaction
1221 * succeeds but the second log transaction fails.
1223 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
1230 /* Set to the data structure */
1231 if ((stat = _DtCmsSetV4AccessListInCal(cal, alist)) == CSA_SUCCESS) {
1233 if (((stat = _DtCmsAppendAccessByFN(log, access_read_4,
1234 GET_R_ACCESS(cal))) != CSA_SUCCESS) ||
1235 ((stat = _DtCmsAppendAccessByFN(log, access_write_4,
1236 GET_W_ACCESS(cal))) != CSA_SUCCESS) ||
1237 ((stat = _DtCmsAppendAccessByFN(log, access_delete_4,
1238 GET_D_ACCESS(cal))) != CSA_SUCCESS) ||
1239 ((stat = _DtCmsAppendAccessByFN(log, access_exec_4,
1240 GET_X_ACCESS(cal))) != CSA_SUCCESS)) {
1242 /* rollback log file */
1243 _DtCmsTruncateFile(cal->calendar, file_size);
1245 cal->modified = B_TRUE;
1253 extern CSA_return_code
1254 _DtCmsGetV4Reminders(
1255 _DtCmsCalendar *cal,
1258 _DtCmsEntryId **ids_r)
1260 Rm_que *p_node, *p_prev, *p_next, *p_new;
1261 Reminder_4 *rptr, *v4rem = NULL;
1262 _DtCmsEntryId *idptr, *ids = NULL;
1264 if (rem_r == NULL) return (CSA_E_INVALID_PARAMETER);
1266 /* do lookup in old format calendar */
1268 p_node = cal->rm_queue;
1269 while (p_node != NULL)
1271 /* It is still a future reminder. */
1272 if (tick < p_node->remind_at)
1275 /* The reminder expired. It either needs to be recalculated
1276 * (repeating appointment) or dropped (non-repeating appt.)
1278 p_next = _DtCmsRemoveReminderV4(&cal->rm_queue, p_prev, p_node);
1280 if (is_repeater(p_node->appt)) {
1281 /* Calculate next reminder for repeating appointment */
1282 p_new = build_reminder(tick+1, p_node->appt,
1283 p_node->attr, p_node->remind_at,
1284 p_node->remind_ord);
1287 _DtCmsAddReminderV4(&cal->rm_queue, p_new);
1288 if (p_new->next == p_next)
1297 /* Pick the first one from the active reminder queue because it is
1298 * always >= the given key.
1300 p_node = cal->rm_queue;
1303 tick = p_node->remind_at;
1306 rptr = _DtCmsGetReminderInfoV4(p_node);
1310 idptr = (_DtCmsEntryId *)calloc(1,
1311 sizeof(_DtCmsEntryId));
1312 idptr->id = p_node->appt->appt_id.key;
1316 p_node = p_node->next;
1317 } while ((p_node != NULL) && (p_node->remind_at == tick));
1321 if (ids_r) *ids_r = ids;
1322 return (CSA_SUCCESS);
1326 _DtCmsFreeEntryIds(_DtCmsEntryId *ids)
1330 while (ids != NULL) {
1337 extern CSA_return_code
1338 _DtCmsTruncateElist(Appt_4 *parent_p, int remain, Except_4 **excpt)
1340 int except_no, ntimes_diff;
1341 Except_4 *e, *p, *last_e = NULL, *head = NULL;
1343 ntimes_diff = _DtCms_get_ninstance_v4(parent_p) - remain;
1344 p = parent_p->exception;
1346 if ((except_no = (p->ordinal - ntimes_diff)) > 0 &&
1347 except_no <= remain) {
1348 if ((e = (Except_4*)calloc(1, sizeof(Except_4)))
1350 _DtCm_free_excpt4(head);
1351 return (CSA_E_INSUFFICIENT_MEMORY);
1353 e->ordinal = except_no;
1365 return (CSA_SUCCESS);
1368 extern CSA_return_code
1369 _DtCmsSetV4AccessListInCal(_DtCmsCalendar *cal, Access_Entry_4 *e)
1373 /* Wipe out the old access lists. */
1374 _DtCm_free_access_list4(GET_R_ACCESS (cal));
1375 _DtCm_free_access_list4(GET_W_ACCESS (cal));
1376 _DtCm_free_access_list4(GET_D_ACCESS (cal));
1377 _DtCm_free_access_list4(GET_X_ACCESS (cal));
1378 SET_R_ACCESS(cal, NULL);
1379 SET_W_ACCESS(cal, NULL);
1380 SET_D_ACCESS(cal, NULL);
1381 SET_X_ACCESS(cal, NULL);
1382 _DtCm_free_access_list4(cal->alist);
1384 /* Split the access list to 3 differnt operation lists */
1387 if (e->access_type & access_read_4) {
1388 q = _DtCm_make_access_entry4(e->who, e->access_type);
1389 q->next = GET_R_ACCESS(cal);
1390 SET_R_ACCESS(cal, q);
1392 if (e->access_type & access_write_4) {
1393 q = _DtCm_make_access_entry4(e->who, e->access_type);
1394 q->next = GET_W_ACCESS(cal);
1395 SET_W_ACCESS(cal, q);
1397 if (e->access_type & access_delete_4) {
1398 q = _DtCm_make_access_entry4(e->who, e->access_type);
1399 q->next = GET_D_ACCESS(cal);
1400 SET_D_ACCESS(cal, q);
1402 if (e->access_type & access_exec_4) {
1403 q = _DtCm_make_access_entry4(e->who, e->access_type);
1404 q->next = GET_X_ACCESS(cal);
1405 SET_X_ACCESS(cal, q);
1410 cal->alist = _DtCmsCalendarAccessList(cal);
1412 return (CSA_SUCCESS);
1415 /******************************************************************************
1416 * static functions used within the file
1417 ******************************************************************************/
1420 append_exception_list(Appt_4 *p_appt, int ordinal)
1422 Exception_4 p_excpt;
1426 if ((p_excpt = (Exception_4)calloc(1, sizeof(*p_excpt))) == NULL)
1428 p_excpt->ordinal = ordinal;
1430 p_ex = p_appt->exception;
1431 while (p_ex != NULL)
1433 /* Exception list is in descending order for faster access */
1434 if (ordinal > p_ex->ordinal)
1441 p_excpt->next = p_appt->exception;
1442 p_appt->exception = p_excpt;
1446 p_excpt->next = p_prev->next;
1447 p_prev->next = p_excpt;
1454 * remove exceptions that are larger than ordinal
1457 trunc_exception_list(Appt_4 *p_appt, int ordinal)
1462 p_ex = p_appt->exception;
1464 /* Exception list is in descending order for faster access */
1465 while ((p_ex != NULL) && (p_ex->ordinal > ordinal))
1467 p_next = p_ex->next;
1471 p_appt->exception = p_ex;
1475 num_exception(Appt_4 *p_appt)
1481 p = p_appt->exception;