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