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>
43 #include <sys/systeminfo.h>
45 #include "cmscalendar.h"
49 #include "updateattrs.h"
62 extern char *_DtCm_rule_buf; /* buffer to hold a rule for parser */
63 extern RepeatEvent *_DtCm_repeat_info; /* parsed recurrence info */
65 extern boolean_t RulesMatch(char *rule1, char *rule2);
67 /******************************************************************************
68 * forward declaration of static functions used within the file
69 ******************************************************************************/
70 static boolean_t _SameRecurrenceRule(
71 cms_attribute_value *newval,
72 cms_attribute_value *oldval);
74 static CSA_return_code _SetNewStartDate(
81 static CSA_return_code _AdjustStartEndTimeForUpdateInst(
86 cms_attribute *attrs);
88 static CSA_return_code _AdjustStartEndTimeForUpdateEntry(
93 cms_attribute *attrs);
95 static void _GetStartEndIndex(
101 static void _AdjustExceptionDates(cms_entry *entry, time_t delta);
103 static int _NumberExceptionDates(cms_entry *entry);
105 /*****************************************************************************
106 * extern functions used in the library
107 *****************************************************************************/
109 extern CSA_return_code
116 cms_attribute *attrs,
117 cms_entry **oldentry,
118 cms_entry **newentry)
120 CSA_return_code stat;
121 cms_entry *olde, *newe;
122 List_node *lnode = NULL;
125 /* get the entry from the tree */
126 if ((olde = (cms_entry *)rb_lookup(cal->tree, (caddr_t)key)) == NULL) {
127 /* find entry in the repeating entry list */
128 if ((lnode = hc_lookup_node(cal->list, (caddr_t)key)) == NULL)
129 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
131 olde = (cms_entry *)lnode->data;
135 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
137 /* check access rights */
138 if ((stat = _DtCmsCheckChangeAccess(sender, access, olde))
142 /* copy the entry and apply updates */
143 if ((stat = _DtCm_copy_cms_entry(olde, &newe)) != CSA_SUCCESS)
146 if ((stat = _DtCmUpdateAttributes(num_attrs, attrs, &newe->num_attrs,
147 &newe->attrs, &cal->entry_tbl, B_FALSE, &cal->types, B_FALSE))
149 _DtCm_free_cms_entry(newe);
153 /* update start date */
154 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
155 item.date_time_value, &newe->key.time);
157 if (lnode != NULL && (stat = _AdjustStartEndTimeForUpdateEntry(
158 lnode, newe, key, num_attrs, attrs)) != CSA_SUCCESS) {
159 _DtCm_free_cms_entry(newe);
163 /* make sure end time is not earlier than start time */
164 if ((stat = _DtCmsCheckStartEndTime(newe)) != CSA_SUCCESS) {
165 _DtCm_free_cms_entry(newe);
169 /* set last update */
170 if ((stat = _DtCmsSetLastUpdate(newe)) != CSA_SUCCESS) {
171 _DtCm_free_cms_entry(newe);
175 /* save file size in case we need to roll back */
176 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
178 _DtCm_free_cms_entry(newe);
182 /* remove old entry */
183 if ((stat = _DtCmsDeleteEntryAndLog(cal, NULL, 0, key, &olde))
185 _DtCm_free_cms_entry(newe);
189 /* insert new entry */
190 if ((stat = _DtCmsInsertEntryAndLog(cal, newe)) != CSA_SUCCESS) {
192 _DtCmsTruncateFile(cal->calendar, file_size);
193 _DtCmsInsertEntry(cal, olde);
194 _DtCm_free_cms_entry(newe);
195 _DtCm_free_cms_entry(olde);
201 _DtCm_free_cms_entry(newe);
206 _DtCm_free_cms_entry(olde);
212 extern CSA_return_code
213 _DtCmsUpdateInstances(
220 cms_attribute *attrs,
221 cms_entry **oldentry,
222 cms_entry **newentry)
224 CSA_return_code stat;
225 cms_entry *olde, *newe = NULL, *updatedold;
226 List_node *lnode = NULL;
228 int i, remain, rulei;
229 cms_attribute_value *oaptr, *naptr;
231 /* save file size in case we need to roll back */
232 if ((stat = _DtCmsGetFileSize(cal->calendar, &file_size))
236 /* remove old entry */
237 if ((stat = _DtCmsDeleteInstancesAndLog(cal, sender, access, key, scope,
242 /* copy the entry and apply updates */
243 if ((stat = _DtCm_copy_cms_entry(olde, &newe)) != CSA_SUCCESS)
246 if ((stat = _DtCmUpdateAttributes(num_attrs, attrs, &newe->num_attrs,
247 &newe->attrs, &cal->entry_tbl, B_FALSE, &cal->types, B_FALSE))
251 /* check recurrence rule */
252 for (i = 0, rulei = -1; i < num_attrs; i++) {
253 if (attrs[i].name.num == CSA_ENTRY_ATTR_RECURRENCE_RULE_I) {
259 if (scope == CSA_SCOPE_ONE) {
261 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
262 [CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].value);
263 _DtCmUpdateStringAttrVal(NULL, &newe->attrs\
264 [CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value);
265 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
266 [CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I].value);
267 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
268 [CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I].value);
269 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
270 [CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I].value);
271 _DtCmUpdateSint32AttrVal(NULL, &newe->attrs\
272 [CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I].\
274 _DtCmUpdateStringAttrVal(NULL, &newe->attrs\
275 [CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I].value);
279 _SameRecurrenceRule(attrs[rulei].value, olde->\
280 attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value)) {
283 * if recurrence info is not changed, replace
284 * the deleted part with the new one, i.e.,
285 * duration of new equals to the number of
286 * deleted instances of the old one.
287 * Also, update the exception list.
290 if (newe->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value)
292 _DtCmsCleanupExceptionDates(newe, key->time);
296 [CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].value;
298 naptr = (updatedold == NULL) ? NULL :
300 CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].\
303 if (oaptr->item.uint32_value == 0)
306 remain = oaptr->item.uint32_value -
307 (naptr ? naptr->item.uint32_value : 0) +
308 _DtCmsNumberExceptionDates(newe);
310 if ((stat = _DtCmsUpdateDurationInRule(newe, remain))
316 if ((stat = _AdjustStartEndTimeForUpdateInst(newe, olde, key,
317 num_attrs, attrs)) != CSA_SUCCESS)
320 /* set last update */
321 if ((stat = _DtCmsSetLastUpdate(newe)) != CSA_SUCCESS)
324 /* insert new entry */
326 if ((stat = _DtCmsInsertEntryAndLog(cal, newe)) != CSA_SUCCESS) {
335 _DtCm_free_cms_entry(newe);
340 _DtCm_free_cms_entry(olde);
342 if (updatedold) _DtCm_free_cms_entry(updatedold);
347 _DtCmsTruncateFile(cal->calendar, file_size);
348 if (updatedold == NULL)
349 _DtCmsInsertEntry(cal, olde);
351 _DtCm_free_cms_entry(updatedold);
352 if (lnode = hc_lookup_node(cal->list, (caddr_t)key)) {
353 updatedold = (cms_entry *)lnode->data;
354 lnode->data = (caddr_t)olde;
358 _DtCm_free_cms_entry(olde);
360 if (newe) _DtCm_free_cms_entry(newe);
365 /*****************************************************************************
366 * static functions used within the file
367 *****************************************************************************/
370 _SameRecurrenceRule(cms_attribute_value *newval, cms_attribute_value *oldval)
372 if (newval == NULL || newval->item.string_value == NULL)
375 if (strcmp(newval->item.string_value, oldval->item.string_value))
381 static CSA_return_code
382 _AdjustStartEndTimeForUpdateInst(
387 cms_attribute *attrs)
389 CSA_return_code stat;
390 time_t oldbod, newbod, endtime, delta;
393 /* update start date */
394 _GetStartEndIndex(num_attrs, attrs, &starti, &endi);
396 oldbod = _DtCmsBeginOfDay(olde->key.time);
397 if (starti >= 0 && endi == -1 &&
398 newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
400 /* adjust end date */
402 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
403 value->item.date_time_value, &newe->key.time);
404 newbod = _DtCmsBeginOfDay(newe->key.time);
406 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].\
407 value->item.date_time_value, &endtime);
408 endtime += (newbod - oldbod);
409 _csa_tick_to_iso8601(endtime, newe->attrs\
410 [CSA_ENTRY_ATTR_END_DATE_I].value->item.\
413 } else if (starti == -1 && endi >= 0) {
414 /* ajust start date */
415 if (newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
416 _csa_iso8601_to_tick(newe->attrs\
417 [CSA_ENTRY_ATTR_END_DATE_I].value->\
418 item.date_time_value, &endtime);
419 newbod = _DtCmsBeginOfDay(endtime);
421 newbod = _DtCmsBeginOfDay(key->time);
423 newe->key.time += (newbod - oldbod);
424 _csa_tick_to_iso8601(newe->key.time, newe->attrs\
425 [CSA_ENTRY_ATTR_START_DATE_I].value->item.\
428 } else if (starti == -1 && endi == -1) {
429 /* adjust both start and end date */
431 newe->key.time = key->time;
432 _csa_tick_to_iso8601(key->time, newe->attrs[\
433 CSA_ENTRY_ATTR_START_DATE_I].value->item.\
436 if (newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value) {
437 newbod = _DtCmsBeginOfDay(newe->key.time);
439 _csa_iso8601_to_tick(newe->attrs\
440 [CSA_ENTRY_ATTR_END_DATE_I].value->\
441 item.date_time_value, &endtime);
442 endtime += (newbod - oldbod);
443 _csa_tick_to_iso8601(endtime, newe->attrs\
444 [CSA_ENTRY_ATTR_END_DATE_I].value->\
445 item.date_time_value);
448 _csa_iso8601_to_tick(newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
449 value->item.date_time_value, &newe->key.time);
452 if ((stat = _DtCmsCheckStartEndTime(newe)) != CSA_SUCCESS) {
456 if ((delta = _DtCmsTimeOfDay(newe->key.time) -
457 _DtCmsTimeOfDay(key->time)) != 0)
458 _AdjustExceptionDates(newe, delta);
460 return (CSA_SUCCESS);
463 static CSA_return_code
471 if ((newe->key.time = DeriveNewStartTime(olde->key.time, oldre,
472 key->time, newe->key.time, newre)) == 0)
473 return (CSA_E_FAILURE);
475 if (_csa_tick_to_iso8601(newe->key.time, newe->attrs\
476 [CSA_ENTRY_ATTR_START_DATE_I].value->item.date_time_value))
477 return (CSA_E_FAILURE);
479 return (CSA_SUCCESS);
483 * The assumption is that there's only one instance per day.
484 * When we support more than one instance per day, this
485 * needs to be updated.
488 _AdjustExceptionDates(cms_entry *entry, time_t delta)
491 CSA_date_time_list dt, head;
493 if (entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value == NULL ||
494 entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->item.\
495 date_time_list_value == NULL)
498 head = entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->item.\
499 date_time_list_value;
501 for (dt = head; dt != NULL; dt = dt->next) {
502 _csa_iso8601_to_tick(dt->date_time, &tick);
504 _csa_tick_to_iso8601(tick, dt->date_time);
511 cms_attribute *attrs,
517 for (i = 0, *starti = -1, *endi = -1; i < num_attrs; i++) {
518 if (attrs[i].name.num == CSA_ENTRY_ATTR_START_DATE_I)
520 else if (attrs[i].name.num == CSA_ENTRY_ATTR_END_DATE_I)
525 static CSA_return_code
526 _AdjustStartEndTimeForUpdateEntry(
531 cms_attribute *attrs)
533 CSA_return_code stat;
534 cms_entry *olde = (cms_entry *)lnode->data;
535 time_t newbod, instbod, fstbod, newfstbod, endtime;
536 int starti, endi, enddelta = 0;
537 cms_attribute_value *oldaptr, *newaptr, *endaptr;
540 extern void _DtCm_rule_parser();
542 /* check to make sure repeating type is not changed */
543 oldaptr = olde->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value;
544 newaptr = newe->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value;
545 endaptr = newe->attrs[CSA_ENTRY_ATTR_END_DATE_I].value;
547 _csa_iso8601_to_tick(endaptr->item.date_time_value, &endtime);
549 if (key->time != olde->key.time &&
550 (newaptr == NULL || newaptr->item.string_value == NULL ||
551 RulesMatch(oldaptr->item.string_value, newaptr->item.string_value)
553 return (CSA_E_INVALID_ATTRIBUTE_VALUE);
556 _GetStartEndIndex(num_attrs, attrs, &starti, &endi);
557 newbod = _DtCmsBeginOfDay(newe->key.time);
558 instbod = _DtCmsBeginOfDay(key->time);
559 fstbod = _DtCmsBeginOfDay(olde->key.time);
561 if (starti >= 0 && key->time != olde->key.time) {
563 if (newbod == instbod) {
564 /* keep the same start day */
565 newe->key.time -= (newbod - fstbod);
566 _csa_tick_to_iso8601(newe->key.time,
567 newe->attrs[CSA_ENTRY_ATTR_START_DATE_I].\
568 value->item.date_time_value);
571 enddelta = newbod - fstbod;
574 _DtCm_rule_buf = newaptr->item.string_value;
576 if ((newre = _DtCm_repeat_info) == NULL)
577 return (CSA_E_INVALID_RULE);
579 /* get new start date */
580 if ((stat = _SetNewStartDate(olde, lnode->re,
581 newe, newre, key)) != CSA_SUCCESS) {
582 _DtCm_free_re(newre);
585 _DtCm_free_re(newre);
586 newfstbod = _DtCmsBeginOfDay(newe->key.time);
588 enddelta = fstbod - newfstbod;
590 enddelta = newbod - newfstbod;
592 } else if (starti >= 0 && endi < 0 && newbod != fstbod) {
594 enddelta = fstbod - newbod;
596 } else if (starti < 0 && endi >= 0 && key->time != olde->key.time &&
599 enddelta = _DtCmsBeginOfDay(endtime) - fstbod;
603 if (enddelta && endaptr) {
606 _csa_tick_to_iso8601(endtime, endaptr->item.date_time_value);
609 return (CSA_SUCCESS);