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 libraries 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 #if defined(__NetBSD__)
43 #include <sys/limits.h>
45 #define MAXINT INT_MAX
50 #include <sys/systeminfo.h>
54 #include "cmscalendar.h"
58 #include "appt4.h" /* Internal appointment data structure */
63 #include "cmsconvert.h"
72 /*****************************************************************************
73 * forward declaration of static functions used within the file
74 *****************************************************************************/
75 static Exception_4 append_exception_list(Appt_4 *p_appt, int ordinal);
76 static void trunc_exception_list(Appt_4 *p_appt, int ordinal);
77 static int num_exception(Appt_4 *p_appt);
79 /*****************************************************************************
80 * extern functions used in the library
81 *****************************************************************************/
84 * Insert one appointment into the single appointment tree structure
85 * or the repeat appointment list structure.
86 * The passed in appointment is stored in the structure.
88 extern CSA_return_code
89 _DtCmsInsertAppt(_DtCmsCalendar *cal, Appt_4 *appt4)
96 if (cal == NULL || appt4 == NULL)
97 return (CSA_E_INVALID_PARAMETER);
99 /* assign key if this is a new appointment */
100 _DtCmsGenerateKey(cal, &(appt4->appt_id.key));
103 fprintf(stderr, "Insert appt4: (%ld)%s\n",
104 appt4->appt_id.key, ctime(&(appt4->appt_id.tick)));
107 /* Add the appointment into the data structure */
108 if (appt4->period.period == single_4)
109 rb_stat = rb_insert (cal->tree, (caddr_t)appt4,
110 (caddr_t)&(appt4->appt_id));
112 rb_stat = hc_insert (REPT_LIST(cal), (caddr_t)appt4,
113 (caddr_t)&(appt4->appt_id), NULL, NULL);
115 if (rb_stat == rb_ok) {
116 /* Add the qualified reminder attrs to the reminder queue */
117 current_time = time(0);
118 p_attr = appt4->attr;
119 while (p_attr != NULL)
124 tick = appt4->appt_id.tick - atol(p_attr->value);
125 p_reminder = build_reminder (current_time, appt4,
127 if (p_reminder != NULL)
128 _DtCmsAddReminderV4(&cal->rm_queue, p_reminder);
129 p_attr = p_attr->next;
133 return (_DtCmsRbToCsaStat(rb_stat));
137 * If p_auth is null, the initiator is the owner of the calendar. Permission
138 * to delete any appointment is always granted. If p_auth is not null, we need
139 * to check if it matches the author of the deleting appointment. Only the
140 * author can delete his/her appointment.
142 extern CSA_return_code
155 * Before we delete an event from the single appointment tree, we
156 * need to check if the initiator is the author of the appointment.
158 if ((user != NULL) && (p_appt = (Appt_4 *)rb_lookup(APPT_TREE(cal),
159 (caddr_t)p_key)) != NULL) {
160 if (!(access & (access_delete_4|CSA_OWNER_RIGHTS)) &&
161 !_DtCmIsSameUser(user, p_appt->author))
162 return (CSA_E_NO_AUTHORITY);
165 if ((p_node = rb_delete (APPT_TREE(cal), (caddr_t)p_key)) != NULL) {
166 p_appt = (Appt_4*)p_node->data;
167 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0, B_FALSE);
171 fprintf (stderr, "Deleted (%ld)%s\n",
173 ctime(&(p_appt->appt_id.tick)));
178 _DtCm_free_appt4(p_appt);
179 return (CSA_SUCCESS);
182 /* Attempt to delete the event from the repeating appointment list */
183 p_lnode = (List_node *)hc_lookup_node(REPT_LIST(cal),
186 if (p_lnode != NULL) {
187 p_appt = (Appt_4 *)p_lnode->data;
190 !(access & (access_delete_4|CSA_OWNER_RIGHTS)) &&
191 !_DtCmIsSameUser(user, p_appt->author))
192 return (CSA_E_NO_AUTHORITY);
194 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0, B_FALSE);
195 (void) hc_delete_node (REPT_LIST(cal), p_lnode);
199 fprintf (stderr, "Deleted (%ld)%s\n",
201 ctime(&(p_appt->appt_id.tick)));
206 _DtCm_free_appt4(p_appt);
207 return (CSA_SUCCESS);
209 return (CSA_E_USER_NOT_FOUND | CSA_E_INVALID_ENTRY_HANDLE);
212 extern CSA_return_code
213 _DtCmsDeleteApptAndLog(
220 CSA_return_code stat;
223 if ((stat = _DtCmsDeleteAppt(cal, user, access, key, &appt))
226 /* Transact the log */
227 if ((stat = v4_transact_log(cal->calendar, appt,
228 _DtCmsLogRemove)) != CSA_SUCCESS) {
230 (void)_DtCmsInsertAppt(cal, appt);
232 } else if (oldappt) {
235 _DtCm_free_appt4(appt);
242 extern CSA_return_code
243 _DtCmsDeleteApptInstancesAndLog(
253 CSA_return_code stat = CSA_SUCCESS;
254 Appt_4 *p_appt, *oldcopy;
256 int f, file_size, ntimes, ninstance, status = 0;
259 p_lnode = (List_node *)hc_lookup_node (REPT_LIST(cal), (caddr_t)key);
261 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
263 p_appt = (Appt_4*)p_lnode->data;
264 if (!(access & (access_delete_4 | CSA_OWNER_RIGHTS)) &&
265 !_DtCmIsSameUser(source, p_appt->author))
266 return (CSA_E_NO_AUTHORITY);
268 if ((ordinal = _DtCms_in_repeater (key, p_appt, B_TRUE)) == 0)
269 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
272 fprintf(stderr,"Delete instance: Ordinal=%d\n",ordinal);
275 * save file size in case the first log transaction
276 * succeeds but the second log transaction fails.
278 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
282 /* remove from log */
283 if ((stat = v4_transact_log(cal->calendar, p_appt, _DtCmsLogRemove))
287 ninstance = _DtCms_get_ninstance_v4(p_appt);
289 /* calculate the ntimes value for the part
290 * of the sequence that start from the ordinal to the end
293 *remain = _DtCms_get_new_ntimes_v4(p_appt->period, key->tick,
294 (ninstance - ordinal + 1));
297 * make a copy of the original appointment,
298 * in case we need a rollback
300 if ((oldcopy = _DtCm_copy_one_appt4(p_appt)) == NULL) {
301 stat = CSA_E_INSUFFICIENT_MEMORY;
305 /* remove from memory */
306 if (option == do_one_4) {
307 if (!append_exception_list (p_appt, ordinal)) {
308 stat = CSA_E_INSUFFICIENT_MEMORY;
312 ninstance = ordinal - 1;
313 if (ninstance == 1) {
314 /* convert to one-time event */
315 p_appt->period.period = single_4;
316 p_appt->period.nth = 0;
317 p_appt->period.enddate = 0;
319 if (p_appt->exception) {
320 _DtCm_free_excpt4(p_appt->exception);
321 p_appt->exception = NULL;
323 stat = _DtCmsRbToCsaStat(rb_insert(cal->tree,
324 (caddr_t)p_appt, (caddr_t)&(p_appt->appt_id)));
326 p_appt->ntimes = _DtCms_get_new_ntimes_v4(
327 p_appt->period, p_appt->appt_id.tick,
330 /* update enddate just for M-F, MWF, TTh
333 switch (p_appt->period.period) {
338 p_appt->period.enddate = _DtCms_prev_tick_v4(
342 trunc_exception_list(p_appt, ordinal);
346 /* The last one from the series has been deleted, no more left. */
347 if (ninstance == num_exception (p_appt))
351 /* Obsolete the reminders which match the ordinal */
352 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, ordinal,
353 (option == do_one_4 ? B_FALSE : B_TRUE));
354 _DtCm_free_appt4(p_appt);
355 hc_delete_node (REPT_LIST(cal), p_lnode);
358 /* Write out the series with new exception list. */
359 if (stat || (stat = v4_transact_log(cal->calendar, p_appt,
360 _DtCmsLogAdd)) != CSA_SUCCESS) {
361 /* reverse memory update */
362 p_appt->ntimes = oldcopy->ntimes;
363 p_appt->period = oldcopy->period;
364 _DtCm_free_excpt4(p_appt->exception);
365 p_appt->exception = oldcopy->exception;
366 oldcopy->exception = NULL;
370 if (ninstance == 1) {
374 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt, 0,
375 (option == do_one_4 ? B_FALSE : B_TRUE));
376 hc_delete_node(REPT_LIST(cal), p_lnode);
379 /* Add the qualified reminder attrs to
382 current_time = time(0);
383 p_attr = p_appt->attr;
384 while (p_attr != NULL) {
388 tick = p_appt->appt_id.tick-atol(p_attr->value);
389 p_reminder = build_reminder(current_time,
390 p_appt, p_attr, tick, 1);
391 if (p_reminder != NULL)
392 _DtCmsAddReminderV4(&cal->rm_queue,
394 p_attr = p_attr->next;
398 _DtCmsObsoleteReminderV4(&cal->rm_queue, p_appt,
400 (option == do_one_4 ? B_FALSE : B_TRUE));
407 _DtCm_free_appt4(oldcopy);
409 return (CSA_SUCCESS);
412 /* rollback log file */
413 _DtCmsTruncateFile(cal->calendar, file_size);
416 _DtCm_free_appt4(oldcopy);
421 extern CSA_return_code
430 CSA_return_code stat = CSA_SUCCESS;
431 Appt_4 *olda, *newcopy = NULL;
435 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
440 * first, remove the old appointment from internal data structure
441 * and the callog file
443 if ((stat = _DtCmsDeleteApptAndLog(cal, source, access, p_key, &olda))
447 if (is_repeater(olda) && is_repeater(newa)) {
448 if (_DtCmsBeginOfDay(APPT_TICK(newa)) ==
449 _DtCmsBeginOfDay(p_key->tick) &&
450 olda->period.period == newa->period.period)
452 /* keep the start day of the original
453 * appointment if the date of the
454 * key matches that of the new
455 * appointment and the interval
458 APPT_TICK(newa) -= _DtCmsBeginOfDay(APPT_TICK(newa)) -
459 _DtCmsBeginOfDay(APPT_TICK(olda));
461 /* otherwise, calculate new parent */
462 if ((ordinal = _DtCms_in_repeater(p_key, olda, B_TRUE))
464 stat = CSA_X_DT_E_ENTRY_NOT_FOUND;
465 goto change_all_cleanup;
467 APPT_TICK(newa) = _DtCms_first_tick_v4(
469 newa->period, ordinal);
470 /* if enddate exist, adjust it */
471 if (olda->period.enddate &&
472 newa->period.period == olda->period.period
473 && newa->period.nth == olda->period.nth) {
474 newa->period.enddate +=
475 (_DtCmsBeginOfDay(APPT_TICK(newa)) -
476 _DtCmsBeginOfDay(APPT_TICK(olda)));
482 /* We use the same exception list for the
483 * new appt. ?? is this reasonable for
486 newa->exception = _DtCm_copy_excpt4(olda->exception);
489 /* adjust start date */
490 _DtCms_adjust_appt_startdate(newa);
492 /* make copy of new appointment */
493 if ((newcopy = _DtCm_copy_one_appt4(newa)) == NULL) {
494 stat = CSA_E_INSUFFICIENT_MEMORY;
495 goto change_all_cleanup;
499 newcopy->appt_id.key = olda->appt_id.key;
501 /* keep the original author */
502 free(newcopy->author);
503 if ((newcopy->author = strdup(olda->author)) == NULL) {
504 stat = CSA_E_INSUFFICIENT_MEMORY;
505 goto change_all_cleanup;
508 if ((stat = _DtCmsInsertApptAndLog(cal, newcopy)) != CSA_SUCCESS) {
509 goto change_all_cleanup;
511 newa->appt_id.key = newcopy->appt_id.key;
516 _DtCm_free_appt4(olda);
522 _DtCm_free_appt4(newcopy);
523 _DtCmsTruncateFile(cal->calendar, file_size);
524 (void)_DtCmsInsertAppt(cal, olda);
528 extern CSA_return_code
538 CSA_return_code stat;
539 Appt_4 *olda, *newcopy = NULL;
541 Exception_4 *newexcept;
545 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
550 * first, remove the old appointment from internal data structure
551 * and the callog file
553 if ((stat = _DtCmsDeleteApptInstancesAndLog(cal, source, access,
554 p_key, option, &remain, &olda)) != CSA_SUCCESS)
557 /* adjust start date */
558 _DtCms_adjust_appt_startdate(newa);
560 /* make copy of new appointment */
561 newcopy = _DtCm_copy_one_appt4(newa);
563 if (option == do_forward_4) {
564 /* if repeating info is not changed, replace
565 * the deleted part with the new series, i.e.,
566 * ntimes of new series _DtCmsIsEquals to the number
567 * of deleted instances. Also get new
570 if (olda->period.period == newa->period.period &&
571 olda->period.nth == newa->period.nth &&
572 olda->ntimes == newa->ntimes) {
574 newcopy->ntimes = remain;
575 if (olda->exception != NULL) {
576 _DtCm_free_excpt4(newcopy->exception);
577 if ((stat = _DtCmsTruncateElist(olda, remain,
578 &newcopy->exception)) != CSA_SUCCESS) {
579 goto change_some_cleanup;
585 /* keep the original author */
586 free(newcopy->author);
587 if ((newcopy->author = strdup(olda->author)) == NULL) {
588 stat = CSA_E_INSUFFICIENT_MEMORY;
589 goto change_some_cleanup;
592 APPT_KEY(newcopy) = 0;
594 if ((stat = _DtCmsInsertApptAndLog(cal, newcopy)) != CSA_SUCCESS) {
595 goto change_some_cleanup;
597 newa->appt_id.key = newcopy->appt_id.key;
602 _DtCm_free_appt4(olda);
608 _DtCm_free_appt4(newcopy);
609 _DtCmsTruncateFile(cal->calendar, file_size);
610 (void)_DtCmsInsertAppt(cal, olda);
615 * the passed in appt is stored in the internal data structure
617 extern CSA_return_code
618 _DtCmsInsertApptAndLog(_DtCmsCalendar *cal, Appt_4 *appt)
620 CSA_return_code stat;
622 if ((stat = _DtCmsInsertAppt(cal, appt)) == CSA_SUCCESS) {
624 /* Add the new appointment to the log */
625 if ((stat = v4_transact_log(cal->calendar, appt,
626 _DtCmsLogAdd)) != CSA_SUCCESS) {
628 (void)_DtCmsDeleteAppt(cal, NULL, 0, &appt->appt_id,
635 extern _DtCmsComparisonResult
636 _DtCmsCompareAppt(Id_4 *key, caddr_t data)
638 Appt_4 *appt = (Appt_4 *)data;
641 if (key->tick < appt->appt_id.tick)
642 return (_DtCmsIsLess);
643 if (key->tick > appt->appt_id.tick)
644 return (_DtCmsIsGreater);
646 /* tick's are _DtCmsIsEqual */
647 if (key->key < appt->appt_id.key)
648 return (_DtCmsIsLess);
649 if (key->key > appt->appt_id.key)
650 return (_DtCmsIsGreater);
652 return (_DtCmsIsEqual);
655 extern _DtCmsComparisonResult
656 _DtCmsCompareRptAppt(Id_4 *key, caddr_t data)
658 Appt_4 *appt = (Appt_4 *)data;
660 if (key->key < appt->appt_id.key)
661 return (_DtCmsIsLess);
662 if (key->key > appt->appt_id.key)
663 return (_DtCmsIsGreater);
664 return (_DtCmsIsEqual);
668 _DtCmsGetApptKey (caddr_t data)
670 return ((caddr_t) &(((Appt_4 *) data)->appt_id));
673 extern CSA_return_code
674 v4_transact_log(char *calendar, Appt_4 *a, _DtCmsLogOps op)
676 CSA_return_code stat;
679 if ((log = _DtCmsGetLogFN(calendar)) == NULL)
680 return (CSA_E_INSUFFICIENT_MEMORY);
682 stat = _DtCmsAppendAppt4ByFN(log, a, op);
688 extern CSA_return_code
694 boolean_t no_end_time_range,
697 boolean_t (*match_func)(),
699 cms_attribute *attrs,
704 CSA_return_code stat = CSA_SUCCESS;
707 int tmp_tick, endtick;
711 time_t hi_tick, lo_tick;
717 CSA_return_code (*add_list_func)();
719 /* do lookup on new format calendar */
720 if (cal->fversion > 1) {
721 if ((stat = _DtCmsLookupEntries(cal, user, access,
722 p_range->key1, p_range->key2, no_end_time_range, end1, end2,
723 num_attrs, attrs, ops, &entries)) != CSA_SUCCESS) {
728 stat = _DtCmsCmsentriesToAppt4ForClient(entries,
731 stat = _DtCmsCmsentriesToAbbrAppt4ForClient(entries,
734 _DtCm_free_cms_entries(entries);
739 add_list_func = _AddToLinkedAppts;
741 add_list_func = _AddToLinkedAbbrAppts;
743 while (p_range != NULL)
746 lo_key.tick = p_range->key1;
747 hi_tick = p_range->key2;
751 fprintf(stderr,"Range lookup from %s",
752 ctime(&lo_key.tick));
753 fprintf(stderr, " to %s\n", ctime(&hi_tick));
758 /* Get a range of appointments in single appointment tree */
759 while ((p_appt = (Appt_4 *)rb_lookup_next_larger(
760 APPT_TREE(cal),(caddr_t)&lo_key))
761 && (APPT_TICK(p_appt) < hi_tick))
765 endtick = p_appt->appt_id.tick + p_appt->duration;
766 if ((!no_end_time_range && (p_appt->duration == 0 ||
767 endtick <= end1 || endtick >= end2)) ||
768 (match_func && !match_func(p_appt, num_attrs,
770 lo_key.key = APPT_KEY(p_appt);
771 lo_key.tick = APPT_TICK(p_appt);
775 if ((stat = (*add_list_func)(p_appt, user,
776 access,&ilp)) != CSA_SUCCESS) {
779 _DtCm_free_appt4((Appt_4 *)ilp);
781 _DtCm_free_abbrev_appt4(
788 lo_key.key = APPT_KEY(p_appt);
789 lo_key.tick = APPT_TICK(p_appt);
792 /* Get a range of events from repeating appointment list */
793 p_lnode = REPT_LIST(cal)->root;
794 while (p_lnode != NULL)
796 lo_tick = p_range->key1;
797 hi_tick = p_range->key2;
799 p_appt = (Appt_4*)p_lnode->data;
801 /* calculate the last tick */
802 if (p_lnode->lasttick == 0)
803 p_lnode->lasttick = _DtCms_last_tick_v4(
808 if (p_lnode->lasttick <= lo_tick ||
809 APPT_TICK(p_appt) >= hi_tick ||
810 (!no_end_time_range && p_appt->duration == 0) ||
811 (!no_end_time_range &&
812 (p_lnode->lasttick+p_appt->duration) <= end1) ||
813 (!no_end_time_range &&
814 (p_appt->appt_id.tick+p_appt->duration) >= end2) ||
816 !match_func(p_appt, num_attrs, attrs, ops)) ||
817 _GetAccessLevel(user, access, p_appt) == private_4)
819 p_lnode = hc_lookup_next (p_lnode);
823 if (!no_end_time_range &&
824 lo_tick < (end1 - p_appt->duration))
825 lo_tick = end1 - p_appt->duration;
827 if (!no_end_time_range &&
828 ((end2 - p_appt->duration) < hi_tick))
829 hi_tick = end2 - p_appt->duration;
831 ntimes = _DtCms_get_ninstance_v4(p_appt);
832 period = p_appt->period;
833 for (tick = _DtCms_closest_tick_v4(lo_tick,
834 APPT_TICK(p_appt), period, &ordinal), ordinal--;
836 tick = _DtCms_next_tick_v4(tick, period))
838 /* Repeater but beyond the scope */
839 if (++ordinal > ntimes ||
840 tick > p_lnode->lasttick)
843 if (tick <= lo_tick ||
844 _DtCms_marked_4_cancellation(p_appt,
850 /* Replace the parent key by the
851 * current tick for the repeating event
853 tmp_tick = APPT_TICK(p_appt);
854 APPT_TICK(p_appt) = tick;
856 /* Add to list, restore parent key */
857 stat = (*add_list_func)(p_appt, user,
860 APPT_TICK(p_appt) = tmp_tick;
862 if (stat != CSA_SUCCESS) {
868 _DtCm_free_abbrev_appt4(
876 p_lnode = hc_lookup_next (p_lnode);
879 p_range = p_range->next;
883 fprintf (stderr, "Found %d entries in range lookup\n", n);
885 if (stat == CSA_SUCCESS) {
887 *appt_r = (Appt_4 *)ilp;
889 *abbr_r = (Abb_Appt_4 *)ilp;
895 extern CSA_return_code
896 _DtCmsLookupKeyrangeV4(
900 boolean_t no_start_time_range,
901 boolean_t no_end_time_range,
907 boolean_t (*match_func)(),
909 cms_attribute *attrs,
914 CSA_return_code stat = CSA_SUCCESS;
916 long tmp_tick, endtick;
923 Appt_4 *p_appt, *tappt;
926 CSA_return_code (*add_list_func)();
928 /* do lookup on new format calendar */
929 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
930 if ((stat = _DtCmsLookupEntriesById(cal, user, access,
931 no_start_time_range, no_end_time_range, start1, start2,
932 end1, end2, id, num_attrs, attrs, ops, &entries))
938 stat = _DtCmsCmsentriesToAppt4ForClient(entries,
940 *appt_r = _AddApptInOrder(*appt_r, tappt);
942 stat = _DtCmsCmsentriesToAbbrAppt4ForClient(entries,
944 *abbr_r = _AddAbbApptInOrder(*abbr_r, tabbr);
947 _DtCm_free_cms_entries(entries);
952 add_list_func = _AddToLinkedAppts;
954 add_list_func = _AddToLinkedAbbrAppts;
957 lo_key.tick = start1;
959 /* Search from repeating appointments first for optimization */
960 p_lnode = hc_lookup_node (REPT_LIST(cal), (caddr_t)&lo_key);
961 if (p_lnode != NULL) {
962 p_appt = (Appt_4*)p_lnode->data;
963 if ((match_func && !match_func(p_appt, num_attrs, attrs, ops))
964 || _GetAccessLevel(user, access, p_appt) == private_4)
965 return (CSA_SUCCESS);
967 /* just return the first event */
968 if (no_start_time_range && no_end_time_range)
969 return ((*add_list_func)(p_appt, user, access,
970 (appt_r ? (caddr_t)appt_r : (caddr_t)abbr_r)));
972 /* Get the range of events from this appointment. */
973 ntimes = _DtCms_get_ninstance_v4(p_appt);
974 period = p_appt->period;
976 /* calculate the last tick */
977 if (p_lnode->lasttick == 0)
978 p_lnode->lasttick = _DtCms_last_tick_v4(
980 p_appt->period, p_appt->ntimes);
982 if (p_lnode->lasttick <= start1 ||
983 p_appt->appt_id.tick >= start2 ||
984 (!no_end_time_range && p_appt->duration == 0) ||
985 (!no_end_time_range &&
986 (p_lnode->lasttick+p_appt->duration) <= end1) ||
987 (!no_end_time_range &&
988 (p_appt->appt_id.tick+p_appt->duration) >= end2))
991 if (!no_end_time_range && (start1 < (end1 - p_appt->duration)))
992 start1 = end1 - p_appt->duration;
994 if (!no_end_time_range && ((end2 - p_appt->duration) < start2))
995 start2 = end2 - p_appt->duration;
997 for (tick = _DtCms_closest_tick_v4(start1,
998 APPT_TICK(p_appt), period, &ordinal), ordinal--;
999 stat == CSA_SUCCESS && tick < start2;
1000 tick = _DtCms_next_tick_v4(tick, period))
1002 /* Repeater but beyond the scope */
1003 if (++ordinal > ntimes || tick > p_lnode->lasttick)
1009 /* If not cancelled, add to linked list */
1010 if (!_DtCms_marked_4_cancellation (p_appt, ordinal))
1014 /* Replace the parent key by
1015 * the current tick for the
1018 tmp_tick = APPT_TICK(p_appt);
1019 APPT_TICK(p_appt) = tick;
1021 /* Add to list, restore parent key */
1022 stat = (*add_list_func)(p_appt, user, access,
1023 (appt_r ? (caddr_t)appt_r :
1026 APPT_TICK(p_appt) = tmp_tick;
1032 /* Check if it is in single appointment tree */
1033 while ((p_appt = (Appt_4 *)rb_lookup_next_larger(
1034 APPT_TREE(cal), (caddr_t) &lo_key)) &&
1035 (APPT_TICK(p_appt) < start2))
1037 if (p_appt->appt_id.key != lo_key.key) {
1038 lo_key.tick = APPT_TICK(p_appt);
1039 lo_key.key = APPT_KEY(p_appt);
1041 endtick = p_appt->appt_id.tick+p_appt->duration;
1043 if ((!no_end_time_range &&
1044 (p_appt->duration == 0 || endtick <= end1 ||
1045 endtick >= end2)) ||
1046 (match_func && !match_func(p_appt,
1047 num_attrs, attrs, ops))) {
1049 return (CSA_SUCCESS);
1051 return ((*add_list_func)(p_appt, user,
1058 return (CSA_SUCCESS);
1062 extern CSA_return_code
1072 switch (_GetAccessLevel(user, access, p_appt)) {
1074 copy = _DtCm_copy_one_appt4(p_appt);
1077 copy = _DtCm_copy_semiprivate_appt4(p_appt);
1080 return (CSA_SUCCESS);
1084 return(CSA_E_INSUFFICIENT_MEMORY);
1086 *ilp = (caddr_t)_AddApptInOrder((Appt_4 *)*ilp, copy);
1087 return (CSA_SUCCESS);
1091 extern CSA_return_code
1092 _AddToLinkedAbbrAppts(
1100 switch (_GetAccessLevel(user, access, p_appt)) {
1102 copy = _DtCm_appt_to_abbrev4(p_appt);
1105 copy = _DtCm_appt_to_semiprivate_abbrev4(p_appt);
1108 return (CSA_SUCCESS);
1112 return(CSA_E_INSUFFICIENT_MEMORY);
1114 *ilp = (caddr_t)_AddAbbApptInOrder((Abb_Appt_4 *)*ilp, copy);
1115 return (CSA_SUCCESS);
1119 extern Privacy_Level_4
1120 _GetAccessLevel(char *user, uint access, Appt_4 *p_appt)
1122 if (access & CSA_OWNER_RIGHTS ||
1123 ((access & access_read_4) && p_appt->privacy == public_4) ||
1124 _DtCmIsSameUser(user, p_appt->author)) {
1128 } else if (p_appt->privacy == private_4) {
1133 return (semiprivate_4);
1138 _AddApptInOrder(Appt_4 *head, Appt_4 *aptr)
1140 Appt_4 *p_appt, *p_prev, *p_next;
1143 p_next = aptr->next;
1146 /* Add the item to the linked list in ascending order */
1149 while (p_appt != NULL)
1151 if (APPT_TICK(aptr) <= APPT_TICK(p_appt))
1154 p_appt = p_appt->next;
1159 aptr->next = p_appt;
1162 aptr->next = p_prev->next;
1163 p_prev->next = aptr;
1173 _AddAbbApptInOrder(Abb_Appt_4 *head, Abb_Appt_4 *aptr)
1175 Abb_Appt_4 *p_appt, *p_prev, *p_next;
1178 p_next = aptr->next;
1181 /* Add the item to the linked list in ascending order */
1184 while (p_appt != NULL)
1186 if (APPT_TICK(aptr) <= APPT_TICK(p_appt))
1189 p_appt = p_appt->next;
1194 aptr->next = p_appt;
1197 aptr->next = p_prev->next;
1198 p_prev->next = aptr;
1207 extern CSA_return_code
1208 _DtCmsSetV4AccessListAndLog(_DtCmsCalendar *cal, Access_Entry_4 *alist)
1210 CSA_return_code stat;
1214 /* update access list for old format calendar */
1215 if ((name = _DtCmsTarget2Name(cal->calendar)) == NULL)
1216 return (CSA_E_INSUFFICIENT_MEMORY);
1218 if ((log = _DtCmsGetLogFN(name)) == NULL) {
1220 return (CSA_E_INSUFFICIENT_MEMORY);
1224 * save file size in case the first log transaction
1225 * succeeds but the second log transaction fails.
1227 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
1234 /* Set to the data structure */
1235 if ((stat = _DtCmsSetV4AccessListInCal(cal, alist)) == CSA_SUCCESS) {
1237 if (((stat = _DtCmsAppendAccessByFN(log, access_read_4,
1238 GET_R_ACCESS(cal))) != CSA_SUCCESS) ||
1239 ((stat = _DtCmsAppendAccessByFN(log, access_write_4,
1240 GET_W_ACCESS(cal))) != CSA_SUCCESS) ||
1241 ((stat = _DtCmsAppendAccessByFN(log, access_delete_4,
1242 GET_D_ACCESS(cal))) != CSA_SUCCESS) ||
1243 ((stat = _DtCmsAppendAccessByFN(log, access_exec_4,
1244 GET_X_ACCESS(cal))) != CSA_SUCCESS)) {
1246 /* rollback log file */
1247 _DtCmsTruncateFile(cal->calendar, file_size);
1249 cal->modified = B_TRUE;
1257 extern CSA_return_code
1258 _DtCmsGetV4Reminders(
1259 _DtCmsCalendar *cal,
1262 _DtCmsEntryId **ids_r)
1264 Rm_que *p_node, *p_prev, *p_next, *p_new;
1265 Reminder_4 *rptr, *v4rem = NULL;
1266 _DtCmsEntryId *idptr, *ids = NULL;
1268 if (rem_r == NULL) return (CSA_E_INVALID_PARAMETER);
1270 /* do lookup in old format calendar */
1272 p_node = cal->rm_queue;
1273 while (p_node != NULL)
1275 /* It is still a future reminder. */
1276 if (tick < p_node->remind_at)
1279 /* The reminder expired. It either needs to be recalculated
1280 * (repeating appointment) or dropped (non-repeating appt.)
1282 p_next = _DtCmsRemoveReminderV4(&cal->rm_queue, p_prev, p_node);
1284 if (is_repeater(p_node->appt)) {
1285 /* Calculate next reminder for repeating appointment */
1286 p_new = build_reminder(tick+1, p_node->appt,
1287 p_node->attr, p_node->remind_at,
1288 p_node->remind_ord);
1291 _DtCmsAddReminderV4(&cal->rm_queue, p_new);
1292 if (p_new->next == p_next)
1301 /* Pick the first one from the active reminder queue because it is
1302 * always >= the given key.
1304 p_node = cal->rm_queue;
1307 tick = p_node->remind_at;
1310 rptr = _DtCmsGetReminderInfoV4(p_node);
1314 idptr = (_DtCmsEntryId *)calloc(1,
1315 sizeof(_DtCmsEntryId));
1316 idptr->id = p_node->appt->appt_id.key;
1320 p_node = p_node->next;
1321 } while ((p_node != NULL) && (p_node->remind_at == tick));
1325 if (ids_r) *ids_r = ids;
1326 return (CSA_SUCCESS);
1330 _DtCmsFreeEntryIds(_DtCmsEntryId *ids)
1334 while (ids != NULL) {
1341 extern CSA_return_code
1342 _DtCmsTruncateElist(Appt_4 *parent_p, int remain, Except_4 **excpt)
1344 int except_no, ntimes_diff;
1345 Except_4 *e, *p, *last_e = NULL, *head = NULL;
1347 ntimes_diff = _DtCms_get_ninstance_v4(parent_p) - remain;
1348 p = parent_p->exception;
1350 if ((except_no = (p->ordinal - ntimes_diff)) > 0 &&
1351 except_no <= remain) {
1352 if ((e = (Except_4*)calloc(1, sizeof(Except_4)))
1354 _DtCm_free_excpt4(head);
1355 return (CSA_E_INSUFFICIENT_MEMORY);
1357 e->ordinal = except_no;
1369 return (CSA_SUCCESS);
1372 extern CSA_return_code
1373 _DtCmsSetV4AccessListInCal(_DtCmsCalendar *cal, Access_Entry_4 *e)
1377 /* Wipe out the old access lists. */
1378 _DtCm_free_access_list4(GET_R_ACCESS (cal));
1379 _DtCm_free_access_list4(GET_W_ACCESS (cal));
1380 _DtCm_free_access_list4(GET_D_ACCESS (cal));
1381 _DtCm_free_access_list4(GET_X_ACCESS (cal));
1382 SET_R_ACCESS(cal, NULL);
1383 SET_W_ACCESS(cal, NULL);
1384 SET_D_ACCESS(cal, NULL);
1385 SET_X_ACCESS(cal, NULL);
1386 _DtCm_free_access_list4(cal->alist);
1388 /* Split the access list to 3 differnt operation lists */
1391 if (e->access_type & access_read_4) {
1392 q = _DtCm_make_access_entry4(e->who, e->access_type);
1393 q->next = GET_R_ACCESS(cal);
1394 SET_R_ACCESS(cal, q);
1396 if (e->access_type & access_write_4) {
1397 q = _DtCm_make_access_entry4(e->who, e->access_type);
1398 q->next = GET_W_ACCESS(cal);
1399 SET_W_ACCESS(cal, q);
1401 if (e->access_type & access_delete_4) {
1402 q = _DtCm_make_access_entry4(e->who, e->access_type);
1403 q->next = GET_D_ACCESS(cal);
1404 SET_D_ACCESS(cal, q);
1406 if (e->access_type & access_exec_4) {
1407 q = _DtCm_make_access_entry4(e->who, e->access_type);
1408 q->next = GET_X_ACCESS(cal);
1409 SET_X_ACCESS(cal, q);
1414 cal->alist = _DtCmsCalendarAccessList(cal);
1416 return (CSA_SUCCESS);
1419 /******************************************************************************
1420 * static functions used within the file
1421 ******************************************************************************/
1424 append_exception_list(Appt_4 *p_appt, int ordinal)
1426 Exception_4 p_excpt;
1430 if ((p_excpt = (Exception_4)calloc(1, sizeof(*p_excpt))) == NULL)
1432 p_excpt->ordinal = ordinal;
1434 p_ex = p_appt->exception;
1435 while (p_ex != NULL)
1437 /* Exception list is in descending order for faster access */
1438 if (ordinal > p_ex->ordinal)
1445 p_excpt->next = p_appt->exception;
1446 p_appt->exception = p_excpt;
1450 p_excpt->next = p_prev->next;
1451 p_prev->next = p_excpt;
1458 * remove exceptions that are larger than ordinal
1461 trunc_exception_list(Appt_4 *p_appt, int ordinal)
1466 p_ex = p_appt->exception;
1468 /* Exception list is in descending order for faster access */
1469 while ((p_ex != NULL) && (p_ex->ordinal > ordinal))
1471 p_next = p_ex->next;
1475 p_appt->exception = p_ex;
1479 num_exception(Appt_4 *p_appt)
1485 p = p_appt->exception;