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