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: update.c /main/4 1995/11/09 12:53:47 rswiston $ */
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 #if !defined(CSRG_BASED)
45 #include <sys/systeminfo.h>
47 #include "cmscalendar.h"
51 #include "updateattrs.h"
64 extern char *_DtCm_rule_buf; /* buffer to hold a rule for parser */
65 extern RepeatEvent *_DtCm_repeat_info; /* parsed recurrence info */
67 extern boolean_t RulesMatch(char *rule1, char *rule2);
69 /******************************************************************************
70 * forward declaration of static functions used within the file
71 ******************************************************************************/
72 static boolean_t _SameRecurrenceRule(
73 cms_attribute_value *newval,
74 cms_attribute_value *oldval);
76 static CSA_return_code _SetNewStartDate(
83 static CSA_return_code _AdjustStartEndTimeForUpdateInst(
88 cms_attribute *attrs);
90 static CSA_return_code _AdjustStartEndTimeForUpdateEntry(
95 cms_attribute *attrs);
97 static void _GetStartEndIndex(
103 static void _AdjustExceptionDates(cms_entry *entry, time_t delta);
105 static int _NumberExceptionDates(cms_entry *entry);
107 /*****************************************************************************
108 * extern functions used in the library
109 *****************************************************************************/
111 extern CSA_return_code
118 cms_attribute *attrs,
119 cms_entry **oldentry,
120 cms_entry **newentry)
122 CSA_return_code stat;
123 cms_entry *olde, *newe;
124 List_node *lnode = NULL;
127 /* get the entry from the tree */
128 if ((olde = (cms_entry *)rb_lookup(cal->tree, (caddr_t)key)) == NULL) {
129 /* find entry in the repeating entry list */
130 if ((lnode = hc_lookup_node(cal->list, (caddr_t)key)) == NULL)
131 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
133 olde = (cms_entry *)lnode->data;
137 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
139 /* check access rights */
140 if ((stat = _DtCmsCheckChangeAccess(sender, access, olde))
144 /* copy the entry and apply updates */
145 if ((stat = _DtCm_copy_cms_entry(olde, &newe)) != CSA_SUCCESS)
148 if ((stat = _DtCmUpdateAttributes(num_attrs, attrs, &newe->num_attrs,
149 &newe->attrs, &cal->entry_tbl, B_FALSE, &cal->types, B_FALSE))
151 _DtCm_free_cms_entry(newe);
155 /* update start date */
156 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
157 item.date_time_value, &newe->key.time);
159 if (lnode != NULL && (stat = _AdjustStartEndTimeForUpdateEntry(
160 lnode, newe, key, num_attrs, attrs)) != CSA_SUCCESS) {
161 _DtCm_free_cms_entry(newe);
165 /* make sure end time is not earlier than start time */
166 if ((stat = _DtCmsCheckStartEndTime(newe)) != CSA_SUCCESS) {
167 _DtCm_free_cms_entry(newe);
171 /* set last update */
172 if ((stat = _DtCmsSetLastUpdate(newe)) != CSA_SUCCESS) {
173 _DtCm_free_cms_entry(newe);
177 /* save file size in case we need to roll back */
178 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
180 _DtCm_free_cms_entry(newe);
184 /* remove old entry */
185 if ((stat = _DtCmsDeleteEntryAndLog(cal, NULL, 0, key, &olde))
187 _DtCm_free_cms_entry(newe);
191 /* insert new entry */
192 if ((stat = _DtCmsInsertEntryAndLog(cal, newe)) != CSA_SUCCESS) {
194 _DtCmsTruncateFile(cal->calendar, file_size);
195 _DtCmsInsertEntry(cal, olde);
196 _DtCm_free_cms_entry(newe);
197 _DtCm_free_cms_entry(olde);
203 _DtCm_free_cms_entry(newe);
208 _DtCm_free_cms_entry(olde);
214 extern CSA_return_code
215 _DtCmsUpdateInstances(
222 cms_attribute *attrs,
223 cms_entry **oldentry,
224 cms_entry **newentry)
226 CSA_return_code stat;
227 cms_entry *olde, *newe = NULL, *updatedold;
228 List_node *lnode = NULL;
230 int i, remain, rulei;
231 cms_attribute_value *oaptr, *naptr;
233 /* save file size in case we need to roll back */
234 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
238 /* remove old entry */
239 if ((stat = _DtCmsDeleteInstancesAndLog(cal, sender, access, key, scope,
244 /* copy the entry and apply updates */
245 if ((stat = _DtCm_copy_cms_entry(olde, &newe)) != CSA_SUCCESS)
248 if ((stat = _DtCmUpdateAttributes(num_attrs, attrs, &newe->num_attrs,
249 &newe->attrs, &cal->entry_tbl, B_FALSE, &cal->types, B_FALSE))
253 /* check recurrence rule */
254 for (i = 0, rulei = -1; i < num_attrs; i++) {
255 if (attrs[i].name.num == CSA_ENTRY_ATTR_RECURRENCE_RULE_I) {
261 if (scope == CSA_SCOPE_ONE) {
263 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
264 [CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].value);
265 _DtCmUpdateStringAttrVal(NULL, &newe->attrs\
266 [CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value);
267 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
268 [CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I].value);
269 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
270 [CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I].value);
271 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
272 [CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I].value);
273 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
274 [CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I].\
276 _DtCmUpdateStringAttrVal(NULL, &newe->attrs\
277 [CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I].value);
281 _SameRecurrenceRule(attrs[rulei].value, olde->\
282 attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value)) {
285 * if recurrence info is not changed, replace
286 * the deleted part with the new one, i.e.,
287 * duration of new equals to the number of
288 * deleted instances of the old one.
289 * Also, update the exception list.
292 if (newe->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value)
294 _DtCmsCleanupExceptionDates(newe, key->time);
298 [CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].value;
300 naptr = (updatedold == NULL) ? NULL :
302 CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].\
305 if (oaptr->item.uint32_value == 0)
308 remain = oaptr->item.uint32_value -
309 (naptr ? naptr->item.uint32_value : 0) +
310 _DtCmsNumberExceptionDates(newe);
312 if ((stat = _DtCmsUpdateDurationInRule(newe, remain))
318 if ((stat = _AdjustStartEndTimeForUpdateInst(newe, olde, key,
319 num_attrs, attrs)) != CSA_SUCCESS)
322 /* set last update */
323 if ((stat = _DtCmsSetLastUpdate(newe)) != CSA_SUCCESS)
326 /* insert new entry */
328 if ((stat = _DtCmsInsertEntryAndLog(cal, newe)) != CSA_SUCCESS) {
337 _DtCm_free_cms_entry(newe);
342 _DtCm_free_cms_entry(olde);
344 if (updatedold) _DtCm_free_cms_entry(updatedold);
349 _DtCmsTruncateFile(cal->calendar, file_size);
350 if (updatedold == NULL)
351 _DtCmsInsertEntry(cal, olde);
353 _DtCm_free_cms_entry(updatedold);
354 if (lnode = hc_lookup_node(cal->list, (caddr_t)key)) {
355 updatedold = (cms_entry *)lnode->data;
356 lnode->data = (caddr_t)olde;
360 _DtCm_free_cms_entry(olde);
362 if (newe) _DtCm_free_cms_entry(newe);
367 /*****************************************************************************
368 * static functions used within the file
369 *****************************************************************************/
372 _SameRecurrenceRule(cms_attribute_value *newval, cms_attribute_value *oldval)
374 if (newval == NULL || newval->item.string_value == NULL)
377 if (strcmp(newval->item.string_value, oldval->item.string_value))
383 static CSA_return_code
384 _AdjustStartEndTimeForUpdateInst(
389 cms_attribute *attrs)
391 CSA_return_code stat;
392 time_t oldbod, newbod, endtime, delta;
395 /* update start date */
396 _GetStartEndIndex(num_attrs, attrs, &starti, &endi);
398 oldbod = _DtCmsBeginOfDay(olde->key.time);
399 if (starti >= 0 && endi == -1 &&
400 newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
402 /* adjust end date */
404 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
405 value->item.date_time_value, &newe->key.time);
406 newbod = _DtCmsBeginOfDay(newe->key.time);
408 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].\
409 value->item.date_time_value, &endtime);
410 endtime += (newbod - oldbod);
411 _csa_tick_to_iso8601(endtime, newe->attrs\
412 [CSA_ENTRY_ATTR_END_DATE_I].value->item.\
415 } else if (starti == -1 && endi >= 0) {
416 /* ajust start date */
417 if (newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
418 _csa_iso8601_to_tick(newe->attrs\
419 [CSA_ENTRY_ATTR_END_DATE_I].value->\
420 item.date_time_value, &endtime);
421 newbod = _DtCmsBeginOfDay(endtime);
423 newbod = _DtCmsBeginOfDay(key->time);
425 newe->key.time += (newbod - oldbod);
426 _csa_tick_to_iso8601(newe->key.time, newe->attrs\
427 [CSA_ENTRY_ATTR_START_DATE_I].value->item.\
430 } else if (starti == -1 && endi == -1) {
431 /* adjust both start and end date */
433 newe->key.time = key->time;
434 _csa_tick_to_iso8601(key->time, newe->attrs[\
435 CSA_ENTRY_ATTR_START_DATE_I].value->item.\
438 if (newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
439 newbod = _DtCmsBeginOfDay(newe->key.time);
441 _csa_iso8601_to_tick(newe->attrs\
442 [CSA_ENTRY_ATTR_END_DATE_I].value->\
443 item.date_time_value, &endtime);
444 endtime += (newbod - oldbod);
445 _csa_tick_to_iso8601(endtime, newe->attrs\
446 [CSA_ENTRY_ATTR_END_DATE_I].value->\
447 item.date_time_value);
450 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
451 value->item.date_time_value, &newe->key.time);
454 if ((stat = _DtCmsCheckStartEndTime(newe)) != CSA_SUCCESS) {
458 if ((delta = _DtCmsTimeOfDay(newe->key.time) -
459 _DtCmsTimeOfDay(key->time)) != 0)
460 _AdjustExceptionDates(newe, delta);
462 return (CSA_SUCCESS);
465 static CSA_return_code
473 if ((newe->key.time = DeriveNewStartTime(olde->key.time, oldre,
474 key->time, newe->key.time, newre)) == 0)
475 return (CSA_E_FAILURE);
477 if (_csa_tick_to_iso8601(newe->key.time, newe->attrs\
478 [CSA_ENTRY_ATTR_START_DATE_I].value->item.date_time_value))
479 return (CSA_E_FAILURE);
481 return (CSA_SUCCESS);
485 * The assumption is that there's only one instance per day.
486 * When we support more than one instance per day, this
487 * needs to be updated.
490 _AdjustExceptionDates(cms_entry *entry, time_t delta)
493 CSA_date_time_list dt, head;
495 if (entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value == NULL ||
496 entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->item.\
497 date_time_list_value == NULL)
500 head = entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->item.\
501 date_time_list_value;
503 for (dt = head; dt != NULL; dt = dt->next) {
504 _csa_iso8601_to_tick(dt->date_time, &tick);
506 _csa_tick_to_iso8601(tick, dt->date_time);
513 cms_attribute *attrs,
519 for (i = 0, *starti = -1, *endi = -1; i < num_attrs; i++) {
520 if (attrs[i].name.num == CSA_ENTRY_ATTR_START_DATE_I)
522 else if (attrs[i].name.num == CSA_ENTRY_ATTR_END_DATE_I)
527 static CSA_return_code
528 _AdjustStartEndTimeForUpdateEntry(
533 cms_attribute *attrs)
535 CSA_return_code stat;
536 cms_entry *olde = (cms_entry *)lnode->data;
537 time_t newbod, instbod, fstbod, newfstbod, endtime;
538 int starti, endi, enddelta = 0;
539 cms_attribute_value *oldaptr, *newaptr, *endaptr;
542 extern void _DtCm_rule_parser();
544 /* check to make sure repeating type is not changed */
545 oldaptr = olde->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value;
546 newaptr = newe->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value;
547 endaptr = newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value;
549 _csa_iso8601_to_tick(endaptr->item.date_time_value, &endtime);
551 if (key->time != olde->key.time &&
552 (newaptr == NULL || newaptr->item.string_value == NULL ||
553 RulesMatch(oldaptr->item.string_value, newaptr->item.string_value)
555 return (CSA_E_INVALID_ATTRIBUTE_VALUE);
558 _GetStartEndIndex(num_attrs, attrs, &starti, &endi);
559 newbod = _DtCmsBeginOfDay(newe->key.time);
560 instbod = _DtCmsBeginOfDay(key->time);
561 fstbod = _DtCmsBeginOfDay(olde->key.time);
563 if (starti >= 0 && key->time != olde->key.time) {
565 if (newbod == instbod) {
566 /* keep the same start day */
567 newe->key.time -= (newbod - fstbod);
568 _csa_tick_to_iso8601(newe->key.time,
569 newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
570 value->item.date_time_value);
573 enddelta = newbod - fstbod;
576 _DtCm_rule_buf = newaptr->item.string_value;
578 if ((newre = _DtCm_repeat_info) == NULL)
579 return (CSA_E_INVALID_RULE);
581 /* get new start date */
582 if ((stat = _SetNewStartDate(olde, lnode->re,
583 newe, newre, key)) != CSA_SUCCESS) {
584 _DtCm_free_re(newre);
587 _DtCm_free_re(newre);
588 newfstbod = _DtCmsBeginOfDay(newe->key.time);
590 enddelta = fstbod - newfstbod;
592 enddelta = newbod - newfstbod;
594 } else if (starti >= 0 && endi < 0 && newbod != fstbod) {
596 enddelta = fstbod - newbod;
598 } else if (starti < 0 && endi >= 0 && key->time != olde->key.time &&
601 enddelta = _DtCmsBeginOfDay(endtime) - fstbod;
605 if (enddelta && endaptr) {
608 _csa_tick_to_iso8601(endtime, endaptr->item.date_time_value);
611 return (CSA_SUCCESS);