dtcm: Resolve CID 87822
[oweals/cde.git] / cde / programs / dtcm / server / insert.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: insert.c /main/5 1996/10/03 10:29:24 drk $ */
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 "insert.h"
48 #include "cm.h"
49 #include "cmscalendar.h"
50 #include "cmsdata.h"
51 #include "attr.h"
52 #include "delete.h"
53 #include "log.h"
54 #include "tree.h"
55 #include "list.h"
56 #include "iso8601.h"
57 #include "rerule.h"
58 #include "reutil.h"
59 #include "lutil.h"
60 #include "v5ops.h"
61 #include "repeat.h"
62
63 extern char *_DtCm_rule_buf;            /* buffer to hold a rule for parser */
64 extern RepeatEvent *_DtCm_repeat_info;  /* parsed recurrence info */
65
66 /******************************************************************************
67  * forward declaration of static functions used within the file
68  ******************************************************************************/
69 static boolean_t _IsOnetimeEntry(cms_entry *entry);
70 static CSA_return_code _RuleToRepeatInfo(cms_entry *entry, RepeatEvent *re);
71 static int _RuleToRepeatType(RepeatEvent *re);
72 static int _DailyRuleToRepeatType(RepeatEvent *re);
73 static int _WeeklyRuleToRepeatType(RepeatEvent *re);
74 static int _MonthlyRuleToRepeatType(RepeatEvent *re);
75
76 /*****************************************************************************
77  * extern functions used in the library
78  *****************************************************************************/
79
80 extern CSA_return_code
81 _DtCmsInsertEntry(_DtCmsCalendar *cal, cms_entry *entry)
82 {
83         CSA_return_code stat;
84         Rb_Status       rb_stat;
85         List_node       *lnode = NULL;
86         cms_entry       *newptr;
87         time_t          current_time;
88         time_t          key, tick, endtime;
89         char            *date, buf[80];
90         CSA_opaque_data opq;
91         cms_attribute   *aptr;
92         RepeatEvent     *re = NULL;
93         RepeatEventState *res;
94         extern          void _DtCm_rule_parser();
95         uint            count;
96         int             i;
97
98         if (cal == NULL || entry == NULL)
99                 return (CSA_E_INVALID_PARAMETER);
100
101         /* assign key if this is a new appointment */
102         key = entry->key.id;
103         _DtCmsGenerateKey(cal, &(entry->key.id));
104
105         if (key == 0) {
106                 /* set start date */
107                 date = entry->attrs[CSA_ENTRY_ATTR_START_DATE_I].value->\
108                         item.date_time_value;
109                 _csa_iso8601_to_tick(date, &entry->key.time);
110
111                 /* set reference id */
112                 sprintf(buf, "%ld:%s@%s", entry->key.id, cal->calendar,
113                         _DtCmGetHostAtDomain());
114                 opq.size = strlen(buf);
115                 opq.data = (unsigned char *)buf;
116                 if ((stat = _DtCm_set_opaque_attrval(&opq,
117                     &entry->attrs[CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I].value))                    != CSA_SUCCESS) {
118                         return (stat);
119                 }
120         }
121
122         /* check recurrence rule */
123         if (_IsOnetimeEntry(entry) == B_FALSE) {
124                 /* check recurrence rule */
125                 aptr = &entry->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I];
126                 _DtCm_rule_buf = aptr->value->item.string_value;
127                 _DtCm_rule_parser();
128                 if ((re = _DtCm_repeat_info) == NULL)
129                         return (CSA_E_INVALID_RULE);
130
131                 /* get number of recurrences */
132                 aptr = &entry->attrs[CSA_ENTRY_ATTR_EXCEPTION_DATES_I];
133                 count = CountEvents(entry->key.time, re,
134                         (aptr->value ?
135                         aptr->value->item.date_time_list_value : NULL));
136
137                 if (count == 1) {
138                         /* turn into onetime entry */
139                         _DtCmsConvertToOnetime(entry, re);
140                         re = NULL;
141                 } else {
142
143                         if (count == 0)
144                                 return (CSA_E_INVALID_RULE);
145                         else if (count == RE_INFINITY)
146                                 count = CSA_X_DT_DT_REPEAT_FOREVER;
147
148                         if ((stat = _DtCm_set_uint32_attrval(count,
149                             &entry->attrs[CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I].\
150                             value)) != CSA_SUCCESS)
151                                 return (stat);
152
153                         /* adjust start date */
154                         tick = ClosestTick(entry->key.time, entry->key.time,
155                                 re, &res);
156                         if (tick != entry->key.time &&
157                             !_DtCmsInExceptionList(entry, tick)) {
158
159                                 /* start date */
160                                 _csa_tick_to_iso8601(tick, entry->attrs\
161                                         [CSA_ENTRY_ATTR_START_DATE_I].value->\
162                                         item.date_time_value);
163
164                                 /* end date */
165                                 _csa_iso8601_to_tick(entry->attrs\
166                                         [CSA_ENTRY_ATTR_END_DATE_I].value->\
167                                         item.date_time_value, &endtime);
168                                 endtime += (tick - entry->key.time);
169                                 _csa_tick_to_iso8601(endtime, entry->attrs\
170                                         [CSA_ENTRY_ATTR_END_DATE_I].value->\
171                                         item.date_time_value);
172
173                                 /* start tick */
174                                 entry->key.time = tick;
175                         }
176                 }
177         }
178
179         if ((stat = _DtCmsCheckStartEndTime(entry)) != CSA_SUCCESS)
180                 return (stat);
181
182         if ((stat = _RuleToRepeatInfo(entry, re)) != CSA_SUCCESS)
183                 return (stat);
184  
185         if ((stat = _DtCm_copy_cms_entry(entry, &newptr)) != CSA_SUCCESS)
186                 return (stat);
187
188         /* Add the entry into the data structure */
189         if (re == NULL) {
190                 rb_stat = rb_insert (cal->tree, (caddr_t)newptr,
191                                 (caddr_t)&(newptr->key));
192         } else {
193                 rb_stat = hc_insert (REPT_LIST(cal), (caddr_t)newptr,
194                                 (caddr_t)&(newptr->key), re, &lnode);
195         }
196
197         if (rb_stat == rb_ok) {
198                 /* Add the qualified reminder attrs to the reminder queue */
199                 _DtCmsAddReminders4Entry(&cal->remq, newptr, lnode);
200         }
201
202         return (_DtCmsRbToCsaStat(rb_stat));
203 }
204
205 extern CSA_return_code
206 _DtCmsInsertEntryAndLog(_DtCmsCalendar *cal, cms_entry *entry)
207 {
208         CSA_return_code stat;
209
210         if ((stat = _DtCmsInsertEntry(cal, entry)) == CSA_SUCCESS) {
211                 /* append entry to the log file */
212                 if ((stat = _DtCmsV5TransactLog(cal, entry, _DtCmsLogAdd))
213                     != CSA_SUCCESS) {
214                         (void)_DtCmsDeleteEntry(cal, NULL, 0, &entry->key,
215                                 NULL); 
216                 }
217         }
218         return (stat);
219 }
220
221 /*****************************************************************************
222  * static functions used within the file
223  *****************************************************************************/
224
225 static boolean_t
226 _IsOnetimeEntry(cms_entry *entry)
227 {
228         cms_attribute   *attr;
229
230         if (entry->attrs[CSA_ENTRY_ATTR_RECURRENCE_RULE_I].value == NULL)
231                 return (B_TRUE);
232         else
233                 return (B_FALSE);
234 }
235
236 static CSA_return_code
237 _RuleToRepeatInfo(cms_entry *entry, RepeatEvent *re)
238 {
239         CSA_return_code stat;
240         uint    duration;
241         char    buf[BUFSIZ];
242         int     type;
243
244         if (re == NULL)
245             return (_DtCm_set_sint32_attrval(CSA_X_DT_REPEAT_ONETIME,
246                 &entry->attrs[CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I].value)); 
247
248         if ((stat = _DtCm_set_sint32_attrval(_RuleToRepeatType(re),
249             &entry->attrs[CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I].value))
250             != CSA_SUCCESS)
251                 return (stat);
252
253         type = entry->attrs[CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I].value->\
254                 item.sint32_value;
255
256         if (re->re_duration != RE_NOTSET) {
257                 if (re->re_duration == RE_INFINITY) {
258                         duration = 0;
259                 } else if (type == CSA_X_DT_REPEAT_EVERY_NDAY ||
260                     type == CSA_X_DT_REPEAT_EVERY_NWEEK ||
261                     type == CSA_X_DT_REPEAT_EVERY_NMONTH) {
262
263                         duration = re->re_duration * re->re_interval;
264                 } else
265                         duration = re->re_duration;
266
267                 if ((stat = _DtCm_set_uint32_attrval(duration,
268                     &entry->attrs[CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I].value))
269                     != CSA_SUCCESS)
270                         return (stat);
271         }
272
273         if ((stat = _DtCm_set_uint32_attrval(re->re_interval,
274             &entry->attrs[CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I].value))
275             != CSA_SUCCESS)
276                 return (stat);
277
278         if (_csa_tick_to_iso8601(re->re_end_date, buf) == 0) {
279                 if ((stat = _DtCm_set_string_attrval(buf,
280                     &entry->attrs[CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I].\
281                     value, CSA_VALUE_DATE_TIME)) != CSA_SUCCESS)
282                         return (stat);
283         }
284
285         return (CSA_SUCCESS);
286 }
287
288 static int
289 _RuleToRepeatType(RepeatEvent *re)
290 {
291         switch (re->re_type) {
292         /* not supported in this release
293          * case RT_MINUTE:
294          */
295         case RT_DAILY:
296                 return (_DailyRuleToRepeatType(re));
297
298         case RT_WEEKLY:
299                 return (_WeeklyRuleToRepeatType(re));
300
301         case RT_MONTHLY_POSITION:
302                 return (_MonthlyRuleToRepeatType(re));
303
304         case RT_MONTHLY_DAY:
305                 return (_MonthlyRuleToRepeatType(re));
306
307         case RT_YEARLY_MONTH:
308                 if ((re->re_data.re_yearly->yd_nitems == 1 ||
309                     re->re_data.re_yearly->yd_nitems == 0) &&
310                     re->re_interval == 1)
311                         return (CSA_X_DT_REPEAT_YEARLY);
312                 else
313                         return (CSA_X_DT_REPEAT_OTHER_YEARLY);
314
315         case RT_YEARLY_DAY:
316                 return (CSA_X_DT_REPEAT_YEARLY);
317
318         default:
319                 return (CSA_X_DT_REPEAT_OTHER);
320         }
321 }
322
323 static int
324 _DailyRuleToRepeatType(RepeatEvent *re)
325 {
326         if (re->re_interval == 1)
327                 return (CSA_X_DT_REPEAT_DAILY);
328         else
329                 return (CSA_X_DT_REPEAT_EVERY_NDAY);
330 }
331
332 #define _DtCms_MON_TO_FRI_MASK  0x3e
333 #define _DtCms_MON_WED_FRI_MASK 0x2a
334 #define _DtCms_TUE_THUR_MASK    0x14
335
336 static int
337 _WeeklyRuleToRepeatType(RepeatEvent *re)
338 {
339         int     i, mask, temp;
340
341         if (re->re_data.re_weekly->wd_ndaytime == 1 ||
342             re->re_data.re_weekly->wd_ndaytime == 0) {
343                 if (re->re_interval == 1)
344                         return (CSA_X_DT_REPEAT_WEEKLY);
345                 else if (re->re_interval == 2)
346                         return (CSA_X_DT_REPEAT_BIWEEKLY);
347                 else
348                         return (CSA_X_DT_REPEAT_EVERY_NWEEK);
349         } else if (re->re_interval > 1)
350                 return (CSA_X_DT_REPEAT_OTHER_WEEKLY);
351
352         /* check for MWF, M-F, TuTh */
353         for (i = 0, mask = 0; i < re->re_data.re_weekly->wd_ndaytime; i++) {
354                 temp = re->re_data.re_weekly->wd_daytime[i].dt_day;
355                 temp = 0x1 << re->re_data.re_weekly->wd_daytime[i].dt_day;
356                 mask |= (0x1 << re->re_data.re_weekly->wd_daytime[i].dt_day);
357         }
358
359         if (mask == _DtCms_MON_TO_FRI_MASK)
360                 return (CSA_X_DT_REPEAT_MON_TO_FRI);
361         else if (mask == _DtCms_MON_WED_FRI_MASK)
362                 return (CSA_X_DT_REPEAT_MONWEDFRI);
363         else if (mask == _DtCms_TUE_THUR_MASK)
364                 return (CSA_X_DT_REPEAT_TUETHUR);
365         else
366                 return (CSA_X_DT_REPEAT_WEEKDAYCOMBO);
367 }
368
369 static int
370 _MonthlyRuleToRepeatType(RepeatEvent *re)
371 {
372         if (re->re_data.re_monthly->md_nitems == 1 ||
373             re->re_data.re_monthly->md_nitems == 0) {
374                 if (re->re_interval == 1)
375                         if (re->re_type == RT_MONTHLY_POSITION)
376                                 return (CSA_X_DT_REPEAT_MONTHLY_BY_WEEKDAY);
377                         else
378                                 return (CSA_X_DT_REPEAT_MONTHLY_BY_DATE);
379                 else
380                         return (CSA_X_DT_REPEAT_EVERY_NMONTH);
381         } else
382                 return (CSA_X_DT_REPEAT_OTHER_MONTHLY);
383 }
384
385