1 /* $XConsortium: update.c /main/4 1995/11/09 12:53:47 rswiston $ */
3 * (c) Copyright 1993, 1994 Hewlett-Packard Company
4 * (c) Copyright 1993, 1994 International Business Machines Corp.
5 * (c) Copyright 1993, 1994 Novell, Inc.
6 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
21 #include <sys/systeminfo.h>
23 #include "cmscalendar.h"
27 #include "updateattrs.h"
40 extern char *_DtCm_rule_buf; /* buffer to hold a rule for parser */
41 extern RepeatEvent *_DtCm_repeat_info; /* parsed recurrence info */
43 extern boolean_t RulesMatch(char *rule1, char *rule2);
45 /******************************************************************************
46 * forward declaration of static functions used within the file
47 ******************************************************************************/
48 static boolean_t _SameRecurrenceRule(
49 cms_attribute_value *newval,
50 cms_attribute_value *oldval);
52 static CSA_return_code _SetNewStartDate(
59 static CSA_return_code _AdjustStartEndTimeForUpdateInst(
64 cms_attribute *attrs);
66 static CSA_return_code _AdjustStartEndTimeForUpdateEntry(
71 cms_attribute *attrs);
73 static void _GetStartEndIndex(
79 static void _AdjustExceptionDates(cms_entry *entry, time_t delta);
81 static int _NumberExceptionDates(cms_entry *entry);
83 /*****************************************************************************
84 * extern functions used in the library
85 *****************************************************************************/
87 extern CSA_return_code
99 cms_entry *olde, *newe;
100 List_node *lnode = NULL;
103 /* get the entry from the tree */
104 if ((olde = (cms_entry *)rb_lookup(cal->tree, (caddr_t)key)) == NULL) {
105 /* find entry in the repeating entry list */
106 if ((lnode = hc_lookup_node(cal->list, (caddr_t)key)) == NULL)
107 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
109 olde = (cms_entry *)lnode->data;
113 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
115 /* check access rights */
116 if ((stat = _DtCmsCheckChangeAccess(sender, access, olde))
120 /* copy the entry and apply updates */
121 if ((stat = _DtCm_copy_cms_entry(olde, &newe)) != CSA_SUCCESS)
124 if ((stat = _DtCmUpdateAttributes(num_attrs, attrs, &newe->num_attrs,
125 &newe->attrs, &cal->entry_tbl, B_FALSE, &cal->types, B_FALSE))
127 _DtCm_free_cms_entry(newe);
131 /* update start date */
132 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
133 item.date_time_value, &newe->key.time);
135 if (lnode != NULL && (stat = _AdjustStartEndTimeForUpdateEntry(
136 lnode, newe, key, num_attrs, attrs)) != CSA_SUCCESS) {
137 _DtCm_free_cms_entry(newe);
141 /* make sure end time is not earlier than start time */
142 if ((stat = _DtCmsCheckStartEndTime(newe)) != CSA_SUCCESS) {
143 _DtCm_free_cms_entry(newe);
147 /* set last update */
148 if ((stat = _DtCmsSetLastUpdate(newe)) != CSA_SUCCESS) {
149 _DtCm_free_cms_entry(newe);
153 /* save file size in case we need to roll back */
154 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
156 _DtCm_free_cms_entry(newe);
160 /* remove old entry */
161 if ((stat = _DtCmsDeleteEntryAndLog(cal, NULL, 0, key, &olde))
163 _DtCm_free_cms_entry(newe);
167 /* insert new entry */
168 if ((stat = _DtCmsInsertEntryAndLog(cal, newe)) != CSA_SUCCESS) {
170 _DtCmsTruncateFile(cal->calendar, file_size);
171 _DtCmsInsertEntry(cal, olde);
172 _DtCm_free_cms_entry(newe);
173 _DtCm_free_cms_entry(olde);
179 _DtCm_free_cms_entry(newe);
184 _DtCm_free_cms_entry(olde);
190 extern CSA_return_code
191 _DtCmsUpdateInstances(
198 cms_attribute *attrs,
199 cms_entry **oldentry,
200 cms_entry **newentry)
202 CSA_return_code stat;
203 cms_entry *olde, *newe = NULL, *updatedold;
204 List_node *lnode = NULL;
206 int i, remain, rulei;
207 cms_attribute_value *oaptr, *naptr;
209 /* save file size in case we need to roll back */
210 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
214 /* remove old entry */
215 if ((stat = _DtCmsDeleteInstancesAndLog(cal, sender, access, key, scope,
220 /* copy the entry and apply updates */
221 if ((stat = _DtCm_copy_cms_entry(olde, &newe)) != CSA_SUCCESS)
224 if ((stat = _DtCmUpdateAttributes(num_attrs, attrs, &newe->num_attrs,
225 &newe->attrs, &cal->entry_tbl, B_FALSE, &cal->types, B_FALSE))
229 /* check recurrence rule */
230 for (i = 0, rulei = -1; i < num_attrs; i++) {
231 if (attrs[i].name.num == CSA_ENTRY_ATTR_RECURRENCE_RULE_I) {
237 if (scope == CSA_SCOPE_ONE) {
239 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
240 [CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].value);
241 _DtCmUpdateStringAttrVal(NULL, &newe->attrs\
242 [CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value);
243 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
244 [CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I].value);
245 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
246 [CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I].value);
247 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
248 [CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I].value);
249 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
250 [CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I].\
252 _DtCmUpdateStringAttrVal(NULL, &newe->attrs\
253 [CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I].value);
257 _SameRecurrenceRule(attrs[rulei].value, olde->\
258 attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value)) {
261 * if recurrence info is not changed, replace
262 * the deleted part with the new one, i.e.,
263 * duration of new equals to the number of
264 * deleted instances of the old one.
265 * Also, update the exception list.
268 if (newe->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value)
270 _DtCmsCleanupExceptionDates(newe, key->time);
274 [CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].value;
276 naptr = (updatedold == NULL) ? NULL :
278 CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].\
281 if (oaptr->item.uint32_value == 0)
284 remain = oaptr->item.uint32_value -
285 (naptr ? naptr->item.uint32_value : 0) +
286 _DtCmsNumberExceptionDates(newe);
288 if ((stat = _DtCmsUpdateDurationInRule(newe, remain))
294 if ((stat = _AdjustStartEndTimeForUpdateInst(newe, olde, key,
295 num_attrs, attrs)) != CSA_SUCCESS)
298 /* set last update */
299 if ((stat = _DtCmsSetLastUpdate(newe)) != CSA_SUCCESS)
302 /* insert new entry */
304 if ((stat = _DtCmsInsertEntryAndLog(cal, newe)) != CSA_SUCCESS) {
313 _DtCm_free_cms_entry(newe);
318 _DtCm_free_cms_entry(olde);
320 if (updatedold) _DtCm_free_cms_entry(updatedold);
325 _DtCmsTruncateFile(cal->calendar, file_size);
326 if (updatedold == NULL)
327 _DtCmsInsertEntry(cal, olde);
329 _DtCm_free_cms_entry(updatedold);
330 if (lnode = hc_lookup_node(cal->list, (caddr_t)key)) {
331 updatedold = (cms_entry *)lnode->data;
332 lnode->data = (caddr_t)olde;
336 _DtCm_free_cms_entry(olde);
338 if (newe) _DtCm_free_cms_entry(newe);
343 /*****************************************************************************
344 * static functions used within the file
345 *****************************************************************************/
348 _SameRecurrenceRule(cms_attribute_value *newval, cms_attribute_value *oldval)
350 if (newval == NULL || newval->item.string_value == NULL)
353 if (strcmp(newval->item.string_value, oldval->item.string_value))
359 static CSA_return_code
360 _AdjustStartEndTimeForUpdateInst(
365 cms_attribute *attrs)
367 CSA_return_code stat;
368 time_t oldbod, newbod, endtime, delta;
371 /* update start date */
372 _GetStartEndIndex(num_attrs, attrs, &starti, &endi);
374 oldbod = _DtCmsBeginOfDay(olde->key.time);
375 if (starti >= 0 && endi == -1 &&
376 newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
378 /* adjust end date */
380 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
381 value->item.date_time_value, &newe->key.time);
382 newbod = _DtCmsBeginOfDay(newe->key.time);
384 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].\
385 value->item.date_time_value, &endtime);
386 endtime += (newbod - oldbod);
387 _csa_tick_to_iso8601(endtime, newe->attrs\
388 [CSA_ENTRY_ATTR_END_DATE_I].value->item.\
391 } else if (starti == -1 && endi >= 0) {
392 /* ajust start date */
393 if (newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
394 _csa_iso8601_to_tick(newe->attrs\
395 [CSA_ENTRY_ATTR_END_DATE_I].value->\
396 item.date_time_value, &endtime);
397 newbod = _DtCmsBeginOfDay(endtime);
399 newbod = _DtCmsBeginOfDay(key->time);
401 newe->key.time += (newbod - oldbod);
402 _csa_tick_to_iso8601(newe->key.time, newe->attrs\
403 [CSA_ENTRY_ATTR_START_DATE_I].value->item.\
406 } else if (starti == -1 && endi == -1) {
407 /* adjust both start and end date */
409 newe->key.time = key->time;
410 _csa_tick_to_iso8601(key->time, newe->attrs[\
411 CSA_ENTRY_ATTR_START_DATE_I].value->item.\
414 if (newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
415 newbod = _DtCmsBeginOfDay(newe->key.time);
417 _csa_iso8601_to_tick(newe->attrs\
418 [CSA_ENTRY_ATTR_END_DATE_I].value->\
419 item.date_time_value, &endtime);
420 endtime += (newbod - oldbod);
421 _csa_tick_to_iso8601(endtime, newe->attrs\
422 [CSA_ENTRY_ATTR_END_DATE_I].value->\
423 item.date_time_value);
426 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
427 value->item.date_time_value, &newe->key.time);
430 if ((stat = _DtCmsCheckStartEndTime(newe)) != CSA_SUCCESS) {
434 if ((delta = _DtCmsTimeOfDay(newe->key.time) -
435 _DtCmsTimeOfDay(key->time)) != 0)
436 _AdjustExceptionDates(newe, delta);
438 return (CSA_SUCCESS);
441 static CSA_return_code
449 if ((newe->key.time = DeriveNewStartTime(olde->key.time, oldre,
450 key->time, newe->key.time, newre)) == 0)
451 return (CSA_E_FAILURE);
453 if (_csa_tick_to_iso8601(newe->key.time, newe->attrs\
454 [CSA_ENTRY_ATTR_START_DATE_I].value->item.date_time_value))
455 return (CSA_E_FAILURE);
457 return (CSA_SUCCESS);
461 * The assumption is that there's only one instance per day.
462 * When we support more than one instance per day, this
463 * needs to be updated.
466 _AdjustExceptionDates(cms_entry *entry, time_t delta)
469 CSA_date_time_list dt, head;
471 if (entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value == NULL ||
472 entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->item.\
473 date_time_list_value == NULL)
476 head = entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->item.\
477 date_time_list_value;
479 for (dt = head; dt != NULL; dt = dt->next) {
480 _csa_iso8601_to_tick(dt->date_time, &tick);
482 _csa_tick_to_iso8601(tick, dt->date_time);
489 cms_attribute *attrs,
495 for (i = 0, *starti = -1, *endi = -1; i < num_attrs; i++) {
496 if (attrs[i].name.num == CSA_ENTRY_ATTR_START_DATE_I)
498 else if (attrs[i].name.num == CSA_ENTRY_ATTR_END_DATE_I)
503 static CSA_return_code
504 _AdjustStartEndTimeForUpdateEntry(
509 cms_attribute *attrs)
511 CSA_return_code stat;
512 cms_entry *olde = (cms_entry *)lnode->data;
513 time_t newbod, instbod, fstbod, newfstbod, endtime;
514 int starti, endi, enddelta = 0;
515 cms_attribute_value *oldaptr, *newaptr, *endaptr;
518 extern void _DtCm_rule_parser();
520 /* check to make sure repeating type is not changed */
521 oldaptr = olde->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value;
522 newaptr = newe->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value;
523 endaptr = newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value;
525 _csa_iso8601_to_tick(endaptr->item.date_time_value, &endtime);
527 if (key->time != olde->key.time &&
528 (newaptr == NULL || newaptr->item.string_value == NULL ||
529 RulesMatch(oldaptr->item.string_value, newaptr->item.string_value)
531 return (CSA_E_INVALID_ATTRIBUTE_VALUE);
534 _GetStartEndIndex(num_attrs, attrs, &starti, &endi);
535 newbod = _DtCmsBeginOfDay(newe->key.time);
536 instbod = _DtCmsBeginOfDay(key->time);
537 fstbod = _DtCmsBeginOfDay(olde->key.time);
539 if (starti >= 0 && key->time != olde->key.time) {
541 if (newbod == instbod) {
542 /* keep the same start day */
543 newe->key.time -= (newbod - fstbod);
544 _csa_tick_to_iso8601(newe->key.time,
545 newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
546 value->item.date_time_value);
549 enddelta = newbod - fstbod;
552 _DtCm_rule_buf = newaptr->item.string_value;
554 if ((newre = _DtCm_repeat_info) == NULL)
555 return (CSA_E_INVALID_RULE);
557 /* get new start date */
558 if ((stat = _SetNewStartDate(olde, lnode->re,
559 newe, newre, key)) != CSA_SUCCESS) {
560 _DtCm_free_re(newre);
563 _DtCm_free_re(newre);
564 newfstbod = _DtCmsBeginOfDay(newe->key.time);
566 enddelta = fstbod - newfstbod;
568 enddelta = newbod - newfstbod;
570 } else if (starti >= 0 && endi < 0 && newbod != fstbod) {
572 enddelta = fstbod - newbod;
574 } else if (starti < 0 && endi >= 0 && key->time != olde->key.time &&
577 enddelta = _DtCmsBeginOfDay(endtime) - fstbod;
581 if (enddelta && endaptr) {
584 _csa_tick_to_iso8601(endtime, endaptr->item.date_time_value);
587 return (CSA_SUCCESS);