dtcm: Resolve CID 87822
[oweals/cde.git] / cde / programs / dtcm / server / delete.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $XConsortium: delete.c /main/4 1995/11/09 12:43:26 rswiston $ */
24 /*
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.
29  */
30
31 #include <EUSCompat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <sys/stat.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <pwd.h>
40 #include <time.h>
41 #if !defined(CSRG_BASED)
42 #include <values.h>
43 #endif
44 #ifdef SunOS
45 #include <sys/systeminfo.h>
46 #endif
47 #include "cmscalendar.h"
48 #include "delete.h"
49 #include "cm.h"
50 #include "tree.h"
51 #include "list.h"
52 #include "cmsdata.h"
53 #include "log.h"
54 #include "access.h"
55 #include "insert.h"
56 #include "v5ops.h"
57 #include "repeat.h"
58 #include "rerule.h"
59 #include "reutil.h"
60 #include "iso8601.h"
61 #include "attr.h"
62
63 /******************************************************************************
64  * forward declaration of static functions used within the file
65  ******************************************************************************/
66 static boolean_t _InSequence(List_node *node, time_t time);
67 static CSA_return_code _AddException(cms_attribute *attr, time_t time);
68 static CSA_return_code _AddEndDateToRule(cms_attribute *attr, RepeatEvent *re,
69                                         time_t time);
70 static void _TruncateExceptionDates(cms_entry *newe, time_t ltick);
71
72 /*****************************************************************************
73  * extern functions used in the library
74  *****************************************************************************/
75
76 extern CSA_return_code
77 _DtCmsDeleteEntry(
78         _DtCmsCalendar  *cal,
79         char            *sender,
80         uint            access,
81         cms_key         *key,
82         cms_entry       **entry_r)
83 {
84         CSA_return_code stat;
85         cms_entry       *entry;
86         List_node       *lnode = NULL;
87         Tree_node       *tnode;
88
89         if ((entry = (cms_entry *)rb_lookup(cal->tree, (caddr_t)key)) == NULL) {
90                 /* find entry in the repeating entry list */
91                 if ((lnode = hc_lookup_node(cal->list, (caddr_t)key)) == NULL)
92                         return (CSA_X_DT_E_ENTRY_NOT_FOUND);
93                 else
94                         entry = (cms_entry *)lnode->data;
95         }
96
97         if (entry == NULL)
98                 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
99
100         if (sender && (stat = _DtCmsCheckChangeAccess(sender, access, entry))
101             != CSA_SUCCESS)
102                 return (stat);
103
104         if (lnode == NULL) {
105                 if ((tnode = rb_delete(cal->tree, (caddr_t)key)) != NULL) {
106                         _DtCmsObsoleteReminder4Entry(cal->remq, entry, NULL,
107                                 0, B_FALSE);
108                         free(tnode);
109                 } else
110                         return (CSA_X_DT_E_ENTRY_NOT_FOUND);
111         } else {
112                 _DtCmsObsoleteReminder4Entry(cal->remq, entry, lnode,
113                         0, B_FALSE);
114                 hc_delete_node(cal->list, lnode);
115                 free(lnode);
116         }
117
118
119         if (entry_r)
120                 *entry_r = entry;
121         else
122                 _DtCm_free_cms_entry(entry);
123
124         return (CSA_SUCCESS);
125 }
126
127 extern CSA_return_code
128 _DtCmsDeleteEntryAndLog(
129         _DtCmsCalendar  *cal,
130         char            *sender,
131         uint            access,
132         cms_key         *key,
133         cms_entry       **entry_r)
134 {
135         CSA_return_code stat;
136         cms_entry       *entry;
137
138         if ((stat = _DtCmsDeleteEntry(cal, sender, access, key, &entry))
139             == CSA_SUCCESS) {
140                 if ((stat = _DtCmsV5TransactLog(cal, entry, _DtCmsLogRemove))
141                     != CSA_SUCCESS) {
142                         (void)_DtCmsInsertEntry(cal, entry);
143                         _DtCm_free_cms_entry(entry);
144                 } else if (entry_r)
145                         *entry_r = entry;
146                 else
147                         _DtCm_free_cms_entry(entry);
148         }
149
150         return (stat);
151 }
152
153 extern CSA_return_code
154 _DtCmsDeleteInstancesAndLog(
155         _DtCmsCalendar  *cal,
156         char            *sender,
157         uint            access,
158         cms_key         *key,
159         int             scope,
160         cms_entry       **newe,
161         cms_entry       **olde)
162 {
163         CSA_return_code stat;
164         cms_entry       *entry, *nentry;
165         List_node       *lnode;
166         int             fsize, count;
167         uint            tmp_num;
168         cms_attribute   *tmp_attrs, *aptr;
169         boolean_t       delentry = B_FALSE;
170
171         if ((lnode = hc_lookup_node(cal->list, (caddr_t)key)) == NULL)
172                 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
173
174         entry = (cms_entry *)lnode->data;
175
176         if ((stat = _DtCmsCheckChangeAccess(sender, access, entry))
177             != CSA_SUCCESS)
178                 return (stat);
179
180         if (_DtCmsInExceptionList(entry, key->time) ||
181             !_InSequence(lnode, key->time))
182                 return (CSA_X_DT_E_ENTRY_NOT_FOUND);
183
184         if ((stat = _DtCm_copy_cms_entry(entry, &nentry)) != CSA_SUCCESS)
185                 return (stat);
186
187         if (scope == CSA_SCOPE_ONE)
188                 stat = _AddException(
189                         &nentry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I],
190                         key->time);
191         else {
192                 /* check whether we are deleting from fst instance */
193                 if (key->time == nentry->key.time)
194                         delentry = B_TRUE;
195                 else {
196                         stat = _DtCmsAddEndDateToRule(&nentry->attrs\
197                                 [CSA_ENTRY_ATTR_RECURRENCE_RULE_I],
198                                 lnode->re, key->time - 1);
199                         lnode->re->re_end_date = key->time - 1;
200
201                         _TruncateExceptionDates(nentry, key->time);
202                 }
203         }
204
205         if (stat != CSA_SUCCESS) {
206                 _DtCm_free_cms_entry(nentry);
207                 return (stat);
208         }
209
210         if (!delentry) {
211                 if ((stat = _DtCmsSetLastUpdate(nentry)) != SUCCESS) {
212                         _DtCm_free_cms_entry(nentry);
213                         return (stat);
214                 }
215
216                 /* remove original entry from log */
217                 if ((stat = _DtCmsGetFileSize(cal->calendar, &fsize))
218                     != CSA_SUCCESS) {
219                         _DtCm_free_cms_entry(nentry);
220                         return (stat);
221                 }
222
223                 if ((stat = _DtCmsV5TransactLog(cal, entry, _DtCmsLogRemove))
224                     != CSA_SUCCESS) {
225                         _DtCm_free_cms_entry(nentry);
226                         return (stat);
227                 }
228
229                 aptr = &nentry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I];
230                 count = CountEvents(nentry->key.time, lnode->re, (aptr->value ?
231                         aptr->value->item.date_time_list_value : NULL));
232         }
233
234         if (count == 0 || delentry) {
235                 /*
236                  * *** obsolete reminders
237                  */
238                 _DtCmsObsoleteReminder4Entry(cal->remq, entry, lnode,
239                         0, B_FALSE);
240
241                 hc_delete_node(cal->list, lnode);
242                 free(lnode);
243
244                 _DtCm_free_cms_entry(nentry);
245
246                 if (olde)
247                         *olde = entry;
248                 else
249                         _DtCm_free_cms_entry(entry);
250
251                 if (newe)
252                         *newe = NULL;
253
254         } else {
255                 /* add new entry in memory and log in file */
256
257                 /* update the count */
258                 if (count == 1) {
259
260                         _DtCmsConvertToOnetime(nentry, lnode->re);
261                         stat = _DtCmsRbToCsaStat(rb_insert(cal->tree,
262                             (caddr_t)nentry, (caddr_t)&(nentry->key)));
263
264                 } else if (count != RE_INFINITY) {
265                         nentry->attrs[CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].\
266                                 value->item.uint32_value = count;
267                 }
268
269                 /* the new entry should be copied when it's updated
270                  * with all the info
271                  */
272                 if (stat == CSA_SUCCESS && newe)
273                         stat = _DtCm_copy_cms_entry(nentry, newe);
274
275                 if (stat || (stat = _DtCmsV5TransactLog(cal, nentry,
276                     _DtCmsLogAdd)) != CSA_SUCCESS) {
277                         _DtCmsTruncateFile(cal->calendar, fsize);
278                         _DtCm_free_cms_entry(nentry);
279                         if (newe) free(*newe);
280                 } else {
281                         if (count == 1) {
282                                 _DtCmsObsoleteReminder4Entry(cal->remq, entry,
283                                         lnode, 0, B_FALSE);
284                                 hc_delete_node(cal->list, lnode);
285                                 free(lnode);
286                                 _DtCmsAddReminders4Entry(&cal->remq, nentry, NULL);
287                         } else {
288                                 /* need to do the swap since the original entry
289                                  * pointer is stored in the reminder info
290                                  */
291                                 tmp_num = entry->num_attrs;
292                                 tmp_attrs = entry->attrs;
293                                 entry->num_attrs = nentry->num_attrs;
294                                 entry->attrs = nentry->attrs;
295                                 nentry->num_attrs = tmp_num;
296                                 nentry->attrs = tmp_attrs;
297
298                                 _DtCmsObsoleteReminder4Entry(cal->remq, entry,
299                                         lnode, key->time,
300                                         (scope == CSA_SCOPE_ONE ? B_FALSE :
301                                         B_TRUE));
302
303                                 if (scope == CSA_SCOPE_FORWARD ||
304                                     key->time == lnode->lasttick) {
305                                         lnode->lasttick = LastTick(
306                                                                 entry->key.time,
307                                                                 lnode->re);
308                                 }
309                         }
310
311                         if (olde)
312                                 *olde = (count == 1) ? entry : nentry;
313                         else
314                                 _DtCm_free_cms_entry((count==1)?entry:nentry);
315                 }
316         }
317
318         return (stat);
319 }
320
321 /*****************************************************************************
322  * static functions used within the file
323  *****************************************************************************/
324
325 static boolean_t
326 _InSequence(List_node *node, time_t time)
327 {
328         time_t          tick;
329         cms_entry       *entry = (cms_entry *)node->data;
330         RepeatEventState *restate;
331
332         for (tick = ClosestTick(time, entry->key.time, node->re, &restate);
333             tick <= node->lasttick;
334             tick = NextTick(tick, entry->key.time, node->re, restate))
335         {
336                 if (tick <= 0 || tick > node->lasttick)
337                         break;
338
339                 if (tick == time)
340                         return (B_TRUE);
341         }
342
343         return (B_FALSE);
344 }
345
346 static CSA_return_code
347 _AddException(cms_attribute *attr, time_t time)
348 {
349         CSA_date_time_entry     *dt, *dlist, *prev;
350         cms_attribute_value     *val;
351         time_t                  tick;
352         char                    buf[20];
353
354         if ((dt = (CSA_date_time_entry *)calloc(1, sizeof(CSA_date_time_entry)))
355             == NULL)
356                 return (CSA_E_INSUFFICIENT_MEMORY);
357
358         if (_csa_tick_to_iso8601(time, buf)) {
359                 free(dt);
360                 return (CSA_E_INVALID_DATE_TIME);
361         } else if ((dt->date_time = strdup(buf)) == NULL) {
362                 free(dt);
363                 return (CSA_E_INSUFFICIENT_MEMORY);
364         }
365
366         if (attr->value == NULL) {
367                 if ((val = (cms_attribute_value *)calloc(1,
368                     sizeof(cms_attribute_value))) == NULL) {
369                         free(dt->date_time);
370                         free(dt);
371                         return (CSA_E_INSUFFICIENT_MEMORY);
372                 }
373                 attr->value = val;
374                 val->type = CSA_VALUE_DATE_TIME_LIST;
375         }
376
377         if (attr->value->item.date_time_list_value == NULL) {
378                 val->item.date_time_list_value = dt;
379         } else {
380                 for (dlist = attr->value->item.date_time_list_value, prev=NULL;
381                     dlist != NULL;
382                     prev = dlist, dlist = dlist->next) {
383                         _csa_iso8601_to_tick(dlist->date_time, &tick);
384                         if (time <= tick)
385                                 break;
386                 }
387
388                 dt->next = dlist;
389                 if (prev == NULL)
390                         attr->value->item.date_time_list_value = dt;
391                 else
392                         prev->next = dt;
393         }
394
395         return (CSA_SUCCESS);
396 }
397
398 static void
399 _TruncateExceptionDates(cms_entry *newe, time_t ltick)
400 {
401         time_t                  tick;
402         CSA_date_time_list      dt, prev, head;
403
404         if (newe->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value == NULL ||
405             newe->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->item.\
406             date_time_list_value == NULL)
407                 return;
408
409         head = newe->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].value->item.\
410                 date_time_list_value;
411
412         for (dt = head, prev = NULL; dt != NULL; prev = dt, dt = dt->next) {
413                 _csa_iso8601_to_tick(dt->date_time, &tick);
414                 if (ltick < tick) {
415                         if (prev) {
416                                 prev->next = NULL;
417                                 _DtCm_free_date_time_list(dt);
418                         } else {
419                                 free(newe->attrs\
420                                         [CSA_ENTRY_ATTR_EXCEPTION_DATES_I].\
421                                         value);
422                                 newe->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I].\
423                                         value = NULL;
424                         }
425                         break;
426                 }
427         }
428 }
429