Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / server / cmscalendar.c
1 /* $XConsortium: cmscalendar.c /main/4 1995/11/09 12:40:39 rswiston $ */
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 #ifdef SunOS
20 #include <sys/systeminfo.h>
21 #endif
22 #include "cmscalendar.h"
23 #include "access.h"
24 #include "attr.h"
25 #include "cm.h"
26 #include "rtable4.h"
27 #include "tree.h"
28 #include "list.h"
29 #include "log.h"
30 #include "appt4.h"              /* Internal appointment data structure */
31 #include "cmsdata.h"
32 #include "cmsentry.h"
33 #include "callback.h"
34 #include "garbage.h"
35 #include "repeat.h"
36 #include "v4ops.h"
37 #include "v5ops.h"
38 #include "insert.h"
39 #include "updateattrs.h"
40 #include "reminder.h"
41 #include "misc.h"
42 #include "convert4-5.h"
43 #include "lutil.h"
44
45 extern  int     debug;
46 extern  char    *pgname;
47
48 /******************************************************************************
49  * forward declaration of static functions used within the file
50  ******************************************************************************/
51
52 static CSA_return_code get_file_owner(char *log, char **owner);
53 static char * get_calname(char *target);
54 static CSA_return_code init_cal_attrs(_DtCmsCalendar *cal);
55 static CSA_return_code _GetCalendarSize(_DtCmsCalendar *cal, int index,
56                                         cms_attribute *attr);
57 static CSA_return_code _GetNumberEntries(_DtCmsCalendar *cal, int index,
58                                         cms_attribute *attr);
59 static CSA_return_code _GetAccessList(_DtCmsCalendar *cal, int index,
60                                         cms_attribute *attr);
61 static CSA_return_code _GetCalendarName(_DtCmsCalendar *cal, int index,
62                                         cms_attribute *attr);
63 static CSA_return_code _GetCalendarOwner(_DtCmsCalendar *cal, int index,
64                                         cms_attribute *attr);
65 static CSA_return_code _GetServerVersion(_DtCmsCalendar *cal, int index,
66                                         cms_attribute *attr);
67 static CSA_return_code _GetDataVersion(_DtCmsCalendar *cal, int index,
68                                         cms_attribute *attr);
69 static CSA_return_code _GetProductId(_DtCmsCalendar *cal, int index,
70                                         cms_attribute *attr);
71 static CSA_return_code _GetSupportedVersion(_DtCmsCalendar *cal, int index,
72                                         cms_attribute *attr);
73 static CSA_return_code _CopyCalendarAttr(_DtCmsCalendar *cal, int index,
74                                         cms_attribute *attr);
75
76 /* global variable shared with parser.y */
77 _DtCmsCalendar *currentCalendar;
78
79 /* static variables used within the file */
80 static  _DtCmsCalendar  *calendar_list = NULL;
81
82 static _DtCmGetAttrFunc _GetAttrFuncPtrs[] =
83         {       NULL,
84                 _GetAccessList,
85                 _GetCalendarName,
86                 _GetCalendarOwner,
87                 _GetCalendarSize,
88                 _CopyCalendarAttr,
89                 _CopyCalendarAttr,
90                 _CopyCalendarAttr,
91                 _CopyCalendarAttr,
92                 _GetNumberEntries,
93                 _GetProductId,
94                 _CopyCalendarAttr,
95                 _GetSupportedVersion,
96                 _CopyCalendarAttr,
97                 _GetServerVersion,
98                 _GetDataVersion
99         };
100
101 /*****************************************************************************
102  * extern functions
103  *****************************************************************************/
104
105 extern _DtCmsCalendar *
106 _DtCmsMakeCalendar(char *owner, char *name)
107 {
108         _DtCmsCalendar  *cal;
109
110         if ((cal = (_DtCmsCalendar *)calloc(1, sizeof(_DtCmsCalendar)))
111             == NULL) {
112                 return (NULL);
113         }
114
115         cal->fversion = _DtCMS_VERSION4;
116
117         if (init_cal_attrs(cal) != CSA_SUCCESS) {
118                 free(cal);
119                 return (NULL);
120         }
121
122         if (_DtCm_set_string_attrval(owner,
123             &cal->attrs[CSA_CAL_ATTR_CALENDAR_OWNER_I].value,
124             CSA_VALUE_CALENDAR_USER)) {
125                 _DtCmsFreeCalendar(cal);
126                 return (NULL);
127         }
128         if ((cal->owner = strdup(cal->attrs[CSA_CAL_ATTR_CALENDAR_OWNER_I].\
129             value->item.string_value)) == NULL) {
130                 _DtCmsFreeCalendar(cal);
131                 return (NULL);
132         }
133
134         if (_DtCm_set_string_attrval(name,
135             &cal->attrs[CSA_CAL_ATTR_CALENDAR_NAME_I].value, CSA_VALUE_STRING))
136         {
137                 _DtCmsFreeCalendar(cal);
138                 return (NULL);
139         }
140         if ((cal->calendar = get_calname(name)) == NULL) {
141                 _DtCmsFreeCalendar(cal);
142                 return (NULL);
143         }
144
145         if ((cal->types = (int *)calloc(1, sizeof(int) *
146             (_DtCm_entry_name_tbl->size + 1))) == NULL) {
147                 _DtCmsFreeCalendar(cal);
148                 return (NULL);
149         } else
150                 _DtCm_get_attribute_types(_DtCm_entry_name_tbl->size,
151                         cal->types);
152
153         if (!(cal->tree = rb_create(_DtCmsGetEntryKey, _DtCmsCompareEntry))) {
154                 _DtCmsFreeCalendar(cal);
155                 return (NULL);
156         }
157
158         if (!(cal->list = hc_create(_DtCmsGetEntryKey, _DtCmsCompareRptEntry)))
159         {
160                 _DtCmsFreeCalendar(cal);
161                 return (NULL);
162         }
163
164         cal->cal_tbl = _DtCm_cal_name_tbl;
165         cal->entry_tbl = _DtCm_entry_name_tbl;
166         cal->num_entry_attrs = _DtCm_entry_name_tbl->size;
167         cal->getattrfuncs = _GetAttrFuncPtrs;
168
169         return (cal);
170 }
171
172 extern void
173 _DtCmsPutInCalList(_DtCmsCalendar *cal)
174 {
175         /* link with other calendar structures */
176         cal->next = calendar_list;
177         calendar_list = cal;
178 }
179
180 extern void
181 _DtCmsFreeCalendar(_DtCmsCalendar *cal)
182 {
183         _DtCmsCalendar *clist, *prev;
184
185         if (cal == NULL) return;
186
187         for (clist = calendar_list, prev = NULL; clist != NULL;
188             clist = clist->next) {
189
190                 if (clist == cal) {
191                         if (prev == NULL)
192                                 calendar_list = clist->next;
193                         else
194                                 prev->next = clist->next;
195
196                         break;
197                 } else
198                         prev = clist;
199         }
200
201         if (cal->calendar)
202                 free(cal->calendar);
203
204         if (cal->owner)
205                 free(cal->owner);
206
207         if (cal->fversion == 1) {
208                 _DtCm_free_access_list4(GET_R_ACCESS ((cal)));
209                 _DtCm_free_access_list4(GET_W_ACCESS ((cal)));
210                 _DtCm_free_access_list4(GET_D_ACCESS ((cal)));
211                 _DtCm_free_access_list4(GET_X_ACCESS ((cal)));
212                 _DtCm_free_access_list4(cal->alist);
213         } else {
214                 if (cal->cal_tbl != _DtCm_cal_name_tbl)
215                         _DtCm_free_name_table(cal->cal_tbl);
216
217                 if (cal->entry_tbl != _DtCm_entry_name_tbl)
218                         _DtCm_free_name_table(cal->entry_tbl);
219
220                 if (cal->types) free(cal->types);
221
222                 if (cal->num_attrs) {
223                         _DtCm_free_cms_attributes(cal->num_attrs + 1,
224                                 cal->attrs);
225                         free(cal->attrs);
226                 }
227         }
228
229         if (cal->tree)
230                 rb_destroy(cal->tree, NULL);
231
232         if (cal->list)
233                 hc_destroy(cal->list, NULL);
234 }
235
236 /*
237  * Called when loading data from callog file.
238  * Types of data to be stored in the tree and list structures
239  * depends on the version of the callog file.
240  */
241 extern CSA_return_code
242 _DtCmsSetFileVersion(_DtCmsCalendar *cal, int version)
243 {
244         cal->fversion = version;
245
246         if (version == 1) {
247                 if (!(cal->tree = rb_create(_DtCmsGetApptKey,
248                     _DtCmsCompareAppt))) {
249                         return (CSA_E_INSUFFICIENT_MEMORY);
250                 }
251
252                 if (!(cal->list = hc_create(_DtCmsGetApptKey,
253                     _DtCmsCompareRptAppt))) {
254                         return (CSA_E_INSUFFICIENT_MEMORY);
255                 }
256         } else {
257                 if (!(cal->tree = rb_create(_DtCmsGetEntryKey,
258                     _DtCmsCompareEntry))) {
259                         return (CSA_E_INSUFFICIENT_MEMORY);
260                 }
261
262                 if (!(cal->list = hc_create(_DtCmsGetEntryKey,
263                     _DtCmsCompareRptEntry))) {
264                         return (CSA_E_INSUFFICIENT_MEMORY);
265                 }
266
267                 if (init_cal_attrs(cal) != CSA_SUCCESS)
268                         return (CSA_E_INSUFFICIENT_MEMORY);
269         
270                 if ((cal->types = (int *)calloc(1, sizeof(int) *
271                     (_DtCm_entry_name_tbl->size + 1))) == NULL) {
272                         _DtCmsFreeCalendar(cal);
273                         return (NULL);
274                 } else
275                         _DtCm_get_attribute_types(_DtCm_entry_name_tbl->size,
276                                 cal->types);
277
278         }
279
280         cal->cal_tbl = _DtCm_cal_name_tbl;
281         cal->entry_tbl = _DtCm_entry_name_tbl;
282
283         return (CSA_SUCCESS);
284 }
285
286 /* return value:
287  * 0            - file loaded successfully
288  * FILEERROR    - file does not exist
289  * CERROR       - something goes wrong
290  */
291 extern CSA_return_code
292 start_log(_DtCmsCalendar *cal, char *filename)
293 {
294         int     fd;
295         FILE    *f;
296         char    firstline[80], *numptr;
297         int     version;
298         struct stat info;
299         struct passwd *pw;
300         extern void setinput(FILE *);
301         extern int yyyparse();
302         extern int yyywrap(FILE *);
303
304         if (cal == NULL || filename == NULL)
305                 return(CSA_E_FAILURE);
306
307         if ((f = fopen(filename, "r")) == NULL) {
308                 if (errno == ENOENT)
309                         return(CSA_E_CALENDAR_NOT_EXIST);
310                 else
311                         return(CSA_X_DT_E_BACKING_STORE_PROBLEM);
312         }
313
314         setinput(f);
315         currentCalendar = cal;
316         if (yyyparse() == -1) {
317                 fprintf(stderr, "%s: unable to parse %s\n", pgname, filename);
318                 yyywrap(f);
319                 return(CSA_X_DT_E_BACKING_STORE_PROBLEM);
320         }
321         yyywrap(f);
322
323         return(CSA_SUCCESS);
324 }
325
326 /*
327  * Load calendar data into memory from callog file.
328  */
329 extern CSA_return_code
330 _DtCmsLoadCalendar(char *target, _DtCmsCalendar **infoptr)
331 {
332         CSA_return_code stat;
333         char            *calname;
334         char            *log;
335         _DtCmsCalendar  *cal = NULL;
336
337         if (target == NULL || infoptr == NULL)
338                 return (CSA_E_FAILURE);
339
340         *infoptr = NULL;
341
342         if ((calname = get_calname(target)) == NULL)
343                 return(CSA_E_INSUFFICIENT_MEMORY);
344
345         if ((log = _DtCmsGetLogFN(calname)) == NULL)
346         {
347                 free(calname);
348                 return(CSA_E_INSUFFICIENT_MEMORY);
349         }
350
351         if ((cal = (_DtCmsCalendar *)calloc(1, sizeof(_DtCmsCalendar)))
352             == NULL) {
353                 stat = CSA_E_INSUFFICIENT_MEMORY;
354                 goto ERROR;
355         }
356
357         if (!(cal->calendar = (char *)strdup(calname))) {
358                 stat = CSA_E_INSUFFICIENT_MEMORY;
359                 goto ERROR;
360         }
361
362         /* load data from file */
363         if ((stat = start_log(cal, log)) != CSA_SUCCESS) {
364                 goto ERROR;
365         }
366
367         /*
368          * get file owner after the file is loaded since file
369          * ownership might be fixed in start_log()
370          */
371         if (cal->fversion == _DtCMS_VERSION1) {
372                 if ((stat = get_file_owner(calname, &cal->owner))
373                     != CSA_SUCCESS)
374                         goto ERROR;
375
376                 cal->alist = _DtCmsCalendarAccessList(cal);
377         } else {
378                 if (cal->attrs[CSA_CAL_ATTR_CALENDAR_OWNER_I].value)
379                         cal->owner = strdup(cal->\
380                                         attrs[CSA_CAL_ATTR_CALENDAR_OWNER_I].\
381                                         value->item.calendar_user_value);
382                 else {
383                         stat = CSA_X_DT_E_BACKING_STORE_PROBLEM;
384                         fprintf(stderr, "%s: %s\n", pgname,
385                                 "calendar owner attribute is missing from callog file");
386                         goto ERROR;
387                 }
388
389                 if (cal->attrs[CSA_CAL_ATTR_PRODUCT_IDENTIFIER_I].value == NULL)
390                 {
391                         if ((stat = _DtCm_set_string_attrval(
392                             _DtCM_PRODUCT_IDENTIFIER, &cal->\
393                             attrs[CSA_CAL_ATTR_PRODUCT_IDENTIFIER_I].value,
394                             CSA_VALUE_STRING)) != CSA_SUCCESS) {
395                                 goto ERROR;
396                         }
397                 }
398
399                 if (cal->attrs[CSA_CAL_ATTR_VERSION_I].value == NULL) {
400                         if ((stat = _DtCm_set_string_attrval(
401                             _DtCM_SPEC_VERSION_SUPPORTED,
402                             &cal->attrs[CSA_CAL_ATTR_VERSION_I].value,
403                             CSA_VALUE_STRING)) != CSA_SUCCESS) {
404                                 goto ERROR;
405                         }
406                 }
407
408                 cal->num_entry_attrs = cal->entry_tbl->size;
409         }
410
411         cal->getattrfuncs = _GetAttrFuncPtrs;
412
413         /* link with other calendar structures */
414         cal->next = calendar_list;
415         calendar_list = cal;
416
417         free(log);
418         free(calname);
419
420         *infoptr = cal;
421         return (CSA_SUCCESS);
422 ERROR:
423         free(calname);
424         free(log);
425
426         _DtCmsFreeCalendar(cal);
427         return (stat);
428 }
429
430 extern char *
431 _DtCmsGetCalendarOwner(char *target)
432 {
433         char *name;
434         _DtCmsCalendar *clist = calendar_list;
435
436         if ((name = get_calname(target)) == NULL)
437                 return(NULL);
438
439         while (clist != NULL) {
440                 if (strcmp(name, clist->calendar) == 0) {
441                         free(name);
442                         return(clist->owner);
443                 }
444                 clist = clist->next;
445         }
446         free(name);
447         return(NULL);
448 }
449
450 extern CSA_return_code
451 _DtCmsGetCalendarByName(char *target, boolean_t load, _DtCmsCalendar **cal)
452 {
453         char    *name;
454         _DtCmsCalendar *clist = calendar_list;
455
456         if ((name = get_calname(target)) == NULL)
457                 return (NULL);
458
459         while (clist != NULL) {
460                 if (strcmp (name, clist->calendar) == 0) {
461                         free (name);
462                         *cal = clist;
463                         return (CSA_SUCCESS);
464                 }
465                 clist = clist->next;
466         }
467         free (name);
468
469         if (load == B_TRUE)
470                 return (_DtCmsLoadCalendar(target, cal));
471         else {
472                 *cal = NULL;
473                 return (CSA_SUCCESS);
474         }
475 }
476
477 /*
478  * For parser only.
479  */
480 extern CSA_return_code
481 _DtCmsInsertAppt_for_parser(_DtCmsCalendar *cal, Appt_4 *appt)
482 {
483         return (_DtCmsInsertAppt(cal, appt));
484 }
485
486 /*
487  * For parser only.
488  */
489 extern CSA_return_code
490 _DtCmsInsertEntry4Parser(_DtCmsCalendar *cal, cms_entry *entry)
491 {
492         cms_entry       *eptr;
493         CSA_return_code stat;
494
495         if ((stat = _DtCmsMakeHashedEntry(cal, entry->num_attrs,
496             entry->attrs, &eptr)) != CSA_SUCCESS)
497                 return (stat);
498
499         eptr->key = entry->key;
500
501         stat = _DtCmsInsertEntry(cal, eptr);
502
503         _DtCm_free_cms_entry(eptr);
504
505         return(stat);
506 }
507
508 extern void
509 _DtCmsGenerateKey(_DtCmsCalendar *cal, long *key)
510 {
511         if (*key == 0) {
512                 *key = ++(cal->lastkey);
513         } else if (*key > cal->lastkey)
514                 cal->lastkey = *key;
515 }
516
517 extern CSA_return_code
518 _DtCmsEnumerateUp(_DtCmsCalendar *cal, _DtCmsEnumerateProc doit)
519 {
520         if (cal == NULL || doit == NULL)
521                 return (CSA_E_INVALID_PARAMETER);
522         if (rb_enumerate_up (APPT_TREE(cal), doit) != rb_ok ||
523             hc_enumerate_up (REPT_LIST(cal), doit) != rb_ok)
524                 return (CSA_E_FAILURE);
525         else
526                 return (CSA_SUCCESS);
527 }
528
529 extern void
530 _DtCmsEnumerateDown(_DtCmsCalendar *cal, _DtCmsEnumerateProc doit)
531 {
532         if (cal == NULL || doit == NULL)
533                 return;
534         rb_enumerate_down (APPT_TREE(cal), doit);
535         hc_enumerate_down (REPT_LIST(cal), doit);
536 }
537
538 /*
539  * For parser only.
540  */
541 extern void
542 _DtCmsSetAccess4Parser(
543         _DtCmsCalendar *cal,
544         Access_Entry_4 *list,
545         int type)
546 {
547         if (type == access_read_4)
548                 SET_R_ACCESS(cal, list);
549         else if (type == access_write_4)
550                 SET_W_ACCESS(cal, list);
551         else if (type == access_delete_4)
552                 SET_D_ACCESS(cal, list);
553         else if (type == access_exec_4)
554                 SET_X_ACCESS(cal, list);
555 }
556
557 extern void
558 _DtCmsSetCalendarAttrs4Parser(
559         _DtCmsCalendar *cal,
560         int len,
561         cms_attribute *attrs)
562 {
563         cms_attribute_value *val;
564
565         /* we don't want to free the value part of the access list
566          * attribute even it may be an empty list
567          */
568         val = cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I].value;
569         cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I].value = NULL;
570         _DtCm_free_cms_attribute_values(cal->num_attrs, cal->attrs);
571         cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I].value = val;
572
573         (void)_DtCmUpdateAttributes(len, attrs, &cal->num_attrs, &cal->attrs,
574                 &cal->cal_tbl, B_TRUE, NULL, B_FALSE);
575 }
576
577 extern CSA_return_code
578 _DtCmsRbToCsaStat(Rb_Status rb_stat)
579 {
580         switch (rb_stat) {
581         case rb_ok:
582                 return (CSA_SUCCESS);
583         case rb_duplicate:
584         case rb_badtable:
585         case rb_notable:
586         case rb_failed:
587         case rb_other:
588                 return (CSA_E_FAILURE);
589         }
590 }
591
592 extern void
593 garbage_collect()
594 {
595         unsigned remain;
596         _DtCmsCalendar *clist = calendar_list;
597
598         while (clist != NULL) {
599
600                 /* deregister stale client */
601                 clist->rlist = _DtCmsCheckRegistrationList(clist->rlist);
602
603                 if (clist->remq)
604                         _DtCmsUpdateReminders(clist->remq);
605
606                 if (clist->modified == B_TRUE) {
607                         if (debug)
608                                 fprintf(stderr, "rpc.csmd: %s%s\n",
609                                         "do garbage collection on ",
610                                         clist->calendar);
611                         _DtCmsCollectOne(clist);
612                         clist->modified = B_FALSE;
613                 }
614
615                 clist = clist->next;
616         }
617
618         if ((remain = (unsigned) alarm((unsigned) 0)) == 0)
619                 alarm ((unsigned) (3600L * 24L));
620         else
621                 alarm (remain);
622 }
623
624 extern void
625 debug_switch()
626 {
627         _DtCmsCalendar *clist = calendar_list;
628         Access_Entry_4 *l;
629
630         debug = !debug;
631         fprintf (stderr, "Debug Mode is %s\n", debug ? "ON" : "OFF");
632
633         if (debug) {
634                 while (clist != NULL) {
635                         _DtCmsPrintReminderListV4(clist->rm_queue);
636
637                         if ((l = _DtCmsCalendarAccessList(clist)) != NULL) {
638                                 _DtCmsShowAccessList(l);
639                                 _DtCm_free_access_list4(l);
640                         }
641                         clist = clist->next;
642                 }
643         }
644 }
645
646 extern CSA_return_code
647 _DtCmsGetCalAttrsByName(
648         _DtCmsCalendar  *cal,
649         uint            num_names,
650         cms_attr_name   *names,
651         uint            *num_attrs_r,
652         cms_attribute   **attrs_r)
653 {
654         CSA_return_code stat = CSA_SUCCESS;
655         int             i, j, index;
656         cms_attribute   *attrs;
657
658         if ((attrs = calloc(1, sizeof(cms_attribute)*num_names)) == NULL)
659                 return (CSA_E_INSUFFICIENT_MEMORY);
660
661         /* get attributes */
662         for (i = 0, j = 0; i < num_names; i++) {
663                 if (names[i].name == NULL)
664                         continue;
665
666                 if (names[i].num <= 0)
667                         index = names[i].num = _DtCm_get_index_from_table(
668                                         cal->cal_tbl, names[i].name);
669
670                 if (index > 0) {
671                         if (index <= _DtCM_DEFINED_CAL_ATTR_SIZE) {
672                                 if (_CSA_cal_attr_info[index].fst_vers
673                                     <= cal->fversion
674                                     || index == CSA_CAL_ATTR_CALENDAR_SIZE_I) {
675                                         stat = cal->getattrfuncs[index](cal,
676                                                 index, &attrs[j]);
677                                 }
678                         } else if (cal->attrs && cal->attrs[index].value) {
679                                 stat = _DtCm_copy_cms_attribute(&attrs[j],
680                                         &cal->attrs[index], B_TRUE);
681                         }
682
683                         if (stat != CSA_SUCCESS) {
684                                 _DtCm_free_cms_attributes(j, attrs);
685                                 free(attrs);
686                                 return (stat);
687                         } else if (attrs[j].name.name)
688                                 j++;
689                 }
690         }
691
692         if (j > 0) {
693                 *num_attrs_r = j;
694                 *attrs_r = attrs;
695         } else {
696                 *num_attrs_r = 0;
697                 *attrs_r = NULL;
698                 free(attrs);
699         }
700
701         return (CSA_SUCCESS);
702 }
703
704 extern CSA_return_code
705 _DtCmsGetAllCalAttrs(
706         _DtCmsCalendar  *cal,
707         uint            *num_attrs_r,
708         cms_attribute   **attrs_r,
709         boolean_t       returnall)
710 {
711         CSA_return_code stat = CSA_SUCCESS;
712         cms_attribute   *attrs, *cattrs = cal->attrs;
713         int             i, j, num_cal_attrs = cal->num_attrs;
714
715         num_cal_attrs = cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION ?
716                         cal->num_attrs : _DtCM_OLD_CAL_ATTR_SIZE;
717
718         if ((attrs = calloc(1, sizeof(cms_attribute)*num_cal_attrs)) == NULL)
719                 return (CSA_E_INSUFFICIENT_MEMORY);
720
721         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
722                 /* first element is not used */
723                 for (i = 1, j = 0; i <= num_cal_attrs; i++) {
724                         if (i <= _DtCM_DEFINED_CAL_ATTR_SIZE) {
725                                 if ((stat = cal->getattrfuncs[i](cal, i,
726                                     &attrs[j])) != CSA_SUCCESS) {
727                                         _DtCm_free_cms_attributes(j, attrs);
728                                         free(attrs);
729                                         return (stat);
730                                 } else if (attrs[j].name.name)
731                                         j++;
732                         } else if (cattrs[i].value) {
733                                 if (returnall) {
734                                         stat = _DtCm_copy_cms_attribute(
735                                                 &attrs[j], &cal->attrs[i],
736                                                 B_TRUE);
737                                 } else {
738                                         /* just return the attribute name */
739                                         if (attrs[j].name.name = strdup(
740                                             cattrs[i].name.name)) {
741                                                 attrs[j].name.num =
742                                                         cattrs[i].name.num;
743                                         } else
744                                                 stat =CSA_E_INSUFFICIENT_MEMORY;
745                                 }
746
747                                 if (stat == CSA_SUCCESS)
748                                         j++;
749                                 else {
750                                         _DtCm_free_cms_attributes(j, attrs);
751                                         free(attrs);
752                                         return (stat);
753                                 }
754                         }
755                 }
756         } else {
757                 for (i = 1, j = 0; i <= _DtCM_DEFINED_CAL_ATTR_SIZE; i++) {
758                         if (_CSA_cal_attr_info[i].fst_vers <= cal->fversion ||
759                             i == CSA_CAL_ATTR_CALENDAR_SIZE_I)
760                         {
761                                 if ((stat = cal->getattrfuncs[i](cal, i,
762                                     &attrs[j])) != CSA_SUCCESS) {
763                                         _DtCm_free_cms_attributes(j, attrs);
764                                         free(attrs);
765                                         return (stat);
766                                 } else if (attrs[j].name.name)
767                                         j++;
768                         }
769                 }
770         }
771
772         if (j > 0) {
773                 *num_attrs_r = j;
774                 *attrs_r = attrs;
775         } else {
776                 *num_attrs_r = 0;
777                 *attrs_r = NULL;
778                 free(attrs);
779         }
780
781         return (CSA_SUCCESS);
782 }
783
784 extern CSA_return_code
785 _DtCmsGetCalAttrNames(
786         _DtCmsCalendar  *cal,
787         uint            *num_names_r,
788         cms_attr_name   **names_r)
789 {
790         CSA_return_code stat = CSA_SUCCESS;
791         cms_attribute   *attrs = cal->attrs;
792         cms_attr_name   *names;
793         uint            i, j, num_attrs = cal->num_attrs;
794
795         if ((names = calloc(1, sizeof(cms_attr_name)*num_attrs)) == NULL)
796                 return (CSA_E_INSUFFICIENT_MEMORY);
797
798         /* first element is not used */
799         for (i = 1, j = 0; i <= num_attrs; i++) {
800                 if (attrs[i].value || (i == CSA_CAL_ATTR_CALENDAR_SIZE_I ||
801                     i == CSA_CAL_ATTR_NUMBER_ENTRIES_I ||
802                     i == CSA_X_DT_CAL_ATTR_SERVER_VERSION_I ||
803                     i == CSA_X_DT_CAL_ATTR_DATA_VERSION_I ||
804                     i == CSA_CAL_ATTR_ACCESS_LIST_I))
805                 {
806                         if (names[j].name = strdup(attrs[i].name.name)) {
807                                 names[j].num = attrs[i].name.num;
808                                 j++;
809                         } else {
810                                 _DtCmsFreeCmsAttrNames(j, names);
811                                 return (CSA_E_INSUFFICIENT_MEMORY);
812                         }
813                 }
814         }
815
816         if (j > 0) {
817                 *num_names_r = j;
818                 *names_r = names;
819         } else {
820                 *num_names_r = 0;
821                 *names_r = NULL;
822                 free(names);
823         }
824
825         return (CSA_SUCCESS);
826 }
827
828 extern void
829 _DtCmsFreeCmsAttrNames(uint num, cms_attr_name *names)
830 {
831         uint    i;
832
833         for (i = 0; i < num; i++)
834                 if (names[i].name) free(names[i].name);
835
836         free(names);
837 }
838
839 extern CSA_return_code
840 _DtCmsUpdateCalAttributesAndLog(
841         _DtCmsCalendar  *cal,
842         uint            numsrc,
843         cms_attribute   *srcattrs,
844         uint            access)
845 {
846         CSA_return_code stat = CSA_SUCCESS;
847         uint            i, oldnum = 0;
848         cms_attribute   *oldattrs = NULL;
849         char            *log;
850
851         /* we didn't use _DtCmUpdateAttributes because we need
852          * to check access rights here
853          */
854
855         /* copy original attributes for rollback if update fails */
856         if (cal->attrs && (stat = _DtCm_copy_cms_attributes(cal->num_attrs,
857             cal->attrs, &oldnum, &oldattrs)) != CSA_SUCCESS)
858                 return (stat);
859
860         for (i = 0; i < numsrc && stat == CSA_SUCCESS; i++) {
861                 if (srcattrs[i].name.name == NULL)
862                         continue;
863
864                 if (srcattrs[i].name.num <= 0)
865                         srcattrs[i].name.num = _DtCm_get_index_from_table(
866                                                 cal->cal_tbl,
867                                                 srcattrs[i].name.name);
868
869                 if (srcattrs[i].name.num < 0) {
870                         if (!_DTCMS_HAS_INSERT_CALENDAR_ATTR_ACCESS(access))
871                                 stat = CSA_E_NO_AUTHORITY;
872                         else {
873                                 if ((stat = _DtCmExtendNameTable(
874                                     srcattrs[i].name.name, 0, 0,
875                                     _DtCm_cal_name_tbl,
876                                     _DtCM_DEFINED_CAL_ATTR_SIZE,
877                                     _CSA_calendar_attribute_names,
878                                     &cal->cal_tbl, NULL)) == CSA_SUCCESS) {
879                                         srcattrs[i].name.num =
880                                                 cal->cal_tbl->size;
881                                         stat = _DtCmGrowAttrArray(
882                                                 &cal->num_attrs, &cal->attrs,
883                                                 &srcattrs[i]);
884                                 }
885                         }
886
887                 } else if (!_DTCMS_HAS_CHANGE_CALENDAR_ATTR_ACCESS(access)) {
888
889                         stat = CSA_E_NO_AUTHORITY;
890                 } else {
891                         cms_attribute_value val;
892
893                         if (srcattrs[i].name.num == CSA_CAL_ATTR_ACCESS_LIST_I
894                             && srcattrs[i].value == NULL) {
895                                 val.type = CSA_VALUE_ACCESS_LIST;
896                                 val.item.access_list_value = NULL;
897                                 srcattrs[i].value = &val;
898                         }
899                         stat = _DtCmUpdateAttribute(&srcattrs[i],
900                                 &cal->attrs[srcattrs[i].name.num]);
901                 }
902         }
903
904         if (stat == CSA_SUCCESS) {
905                 log = _DtCmsGetLogFN(cal->calendar);
906
907                 /* dump file */
908                 stat = _DtCmsAppendCalAttrsByFN(log, cal->num_attrs,
909                         cal->attrs);
910                 free(log);
911         }
912
913         if (stat == CSA_SUCCESS) {
914                 cal->modified = B_TRUE;
915
916                 _DtCm_free_cms_attributes(oldnum + 1, oldattrs);
917                 free(oldattrs);
918         } else {
919                 _DtCm_free_cms_attributes(cal->num_attrs+1, cal->attrs);
920                 free(cal->attrs);
921                 cal->num_attrs = oldnum;
922                 cal->attrs = oldattrs;
923         }
924
925         return (stat);
926 }
927
928 extern CSA_return_code
929 _DtCmsV5TransactLog(_DtCmsCalendar *cal, cms_entry *e, _DtCmsLogOps op)
930 {
931         CSA_return_code stat;
932         char            *log;
933
934         if ((log = _DtCmsGetLogFN(cal->calendar)) == NULL)
935                  return (CSA_E_INSUFFICIENT_MEMORY);
936
937         if (cal->hashed == B_FALSE ||
938             cal->num_entry_attrs < cal->entry_tbl->size) {
939                 if ((stat = _DtCmsAppendHTableByFN(log, cal->entry_tbl->size,
940                     cal->entry_tbl->names, cal->types)) != CSA_SUCCESS) {
941                         free(log);
942                         return (stat);
943                 } else {
944                         cal->hashed = B_TRUE;
945                         cal->num_entry_attrs = cal->entry_tbl->size;
946                 }
947         }
948         stat = _DtCmsAppendEntryByFN(log, e, op);
949         free(log);
950         return(stat);
951 }
952
953 /*****************************************************************************
954  * static functions used within the file
955  *****************************************************************************/
956
957 /*
958  * return user name of file owner
959  * If the calendar name is the same as a user account name, the
960  * calendar name is return; otherwise, the owner name is derived from
961  * the owner of the calendar file
962  */
963 static CSA_return_code
964 get_file_owner(char *calname, char **owner)
965 {
966         struct stat info;
967         struct passwd *pw;
968         char buf[BUFSIZ];
969         char *log;
970         int res;
971
972         if (calname == NULL || owner == NULL)
973                 return (CSA_E_FAILURE);
974
975         *owner = NULL;
976
977         if (_DtCmIsUserName(calname) == B_TRUE) {
978                 strcpy(buf, calname);
979         } else {
980                 if ((log = _DtCmsGetLogFN(calname)) == NULL)
981                         return (CSA_E_INSUFFICIENT_MEMORY);
982
983                 res = stat(log, &info);
984                 free(log);
985
986                 if (res == 0) {
987
988                         if (pw = getpwuid(info.st_uid))
989                                 strcpy(buf, pw->pw_name);
990                         else
991                                 return (CSA_E_FAILURE);
992                 } else
993                         return(CSA_X_DT_E_BACKING_STORE_PROBLEM);
994         }
995
996         if (((*owner) = (char *)strdup(buf)) == NULL)
997                 return (CSA_E_INSUFFICIENT_MEMORY);
998         else
999                 return (CSA_SUCCESS);
1000 }
1001
1002 static char *
1003 get_calname(char *target)
1004 {
1005         char *ptr, *name;
1006
1007         if (target == NULL)
1008                 return (NULL);
1009
1010         ptr = strchr(target, '@');
1011         if (ptr == NULL) {
1012                 return (strdup(target));
1013         } else {
1014                 *ptr = NULL;
1015                 name = strdup(target);
1016                 *ptr = '@';
1017                 return (name);
1018         }
1019 }
1020
1021 static CSA_return_code
1022 init_cal_attrs(_DtCmsCalendar *cal)
1023 {
1024         int i;
1025
1026         /* initialize the calendar with predefined attribute names */
1027         if ((cal->attrs = (cms_attribute *)calloc(1,
1028             sizeof(cms_attribute)*(_DtCm_cal_name_tbl->size + 1))) == NULL) {
1029                 return (CSA_E_INSUFFICIENT_MEMORY);
1030         }
1031
1032         for (i = 1; i <= _DtCm_cal_name_tbl->size; i++) {
1033                 if ((cal->attrs[i].name.name =
1034                     strdup(_DtCm_cal_name_tbl->names[i])) == NULL) {
1035                         _DtCm_free_cms_attributes(i, cal->attrs);
1036                         free(cal->attrs);
1037                         return (CSA_E_INSUFFICIENT_MEMORY);
1038                 }
1039
1040                 cal->attrs[i].name.num = i;
1041         }
1042         cal->num_attrs = _DtCm_cal_name_tbl->size;
1043
1044         return (CSA_SUCCESS);
1045 }
1046
1047 static CSA_return_code
1048 _CopyCalendarAttr(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1049 {
1050         cms_attribute           tmp;
1051         cms_attribute_value     tmpval;
1052
1053         if (cal->attrs && cal->attrs[index].value)
1054                 return (_DtCm_copy_cms_attribute(attr,
1055                                 &cal->attrs[index], B_TRUE));
1056         else
1057                 return (CSA_SUCCESS);
1058 }
1059
1060 static CSA_return_code
1061 _GetCalendarSize(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1062 {
1063         CSA_return_code stat;
1064         int             size;
1065
1066         if ((stat = _DtCmsGetFileSize(cal->calendar, &size)) == CSA_SUCCESS) {
1067                 attr->name.num = CSA_CAL_ATTR_CALENDAR_SIZE_I;
1068                 if (attr->name.name = strdup(CSA_CAL_ATTR_CALENDAR_SIZE))
1069                         return (_DtCm_set_uint32_attrval((uint)size,
1070                                 &attr->value));
1071                 else
1072                         return (CSA_E_INSUFFICIENT_MEMORY);
1073         }
1074         return (stat);
1075 }
1076
1077 static CSA_return_code
1078 _GetNumberEntries(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1079 {
1080         uint    size;
1081
1082         size = rb_size(cal->tree) + hc_size(cal->list);
1083
1084         attr->name.num = CSA_CAL_ATTR_NUMBER_ENTRIES_I;
1085         if (attr->name.name = strdup(CSA_CAL_ATTR_NUMBER_ENTRIES))
1086                 return (_DtCm_set_uint32_attrval(size, &attr->value));
1087         else
1088                 return (CSA_E_INSUFFICIENT_MEMORY);
1089 }
1090
1091 static CSA_return_code
1092 _GetAccessList(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1093 {
1094         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1095                 return (_DtCm_copy_cms_attribute(attr,
1096                         &cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I], B_TRUE));
1097         } else {
1098                 Access_Entry_4  *alist;
1099                 CSA_return_code stat;
1100                 cms_attribute   tmpattr;
1101                 cms_attribute_value tmpval;
1102
1103                 alist = _DtCmsCalendarAccessList(cal);
1104                 if ((stat = _DtCm_accessentry4_to_cmsaccesslist(alist,
1105                     &tmpval.item.access_list_value)) == CSA_SUCCESS) {
1106                         tmpattr.name.num = CSA_CAL_ATTR_ACCESS_LIST_I;
1107                         tmpattr.name.name = CSA_CAL_ATTR_ACCESS_LIST;
1108                         tmpattr.value = &tmpval;
1109                         tmpval.type = CSA_VALUE_ACCESS_LIST;
1110
1111                         return (_DtCm_copy_cms_attribute(attr, &tmpattr,
1112                                 B_TRUE));
1113                 } else
1114                         return (stat);
1115         }
1116 }
1117
1118 static CSA_return_code
1119 _GetCalendarName(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1120 {
1121         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1122                 return (_DtCm_copy_cms_attribute(attr,
1123                         &cal->attrs[CSA_CAL_ATTR_CALENDAR_NAME_I], B_TRUE));
1124         } else {
1125                 attr->name.num = CSA_CAL_ATTR_CALENDAR_NAME_I;
1126                 if (attr->name.name = strdup(CSA_CAL_ATTR_CALENDAR_NAME)) {
1127                         return (_DtCm_set_string_attrval(cal->calendar,
1128                                 &attr->value, CSA_VALUE_STRING));
1129                 } else {
1130                         return (CSA_E_INSUFFICIENT_MEMORY);
1131                 }
1132         }
1133 }
1134
1135 static CSA_return_code
1136 _GetCalendarOwner(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1137 {
1138         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1139                 return (_DtCm_copy_cms_attribute(attr,
1140                         &cal->attrs[CSA_CAL_ATTR_CALENDAR_OWNER_I], B_TRUE));
1141         } else {
1142                 attr->name.num = CSA_CAL_ATTR_CALENDAR_OWNER_I;
1143                 if (attr->name.name = strdup(CSA_CAL_ATTR_CALENDAR_OWNER)) {
1144                         return (_DtCm_set_user_attrval(cal->owner,
1145                                 &attr->value));
1146                 } else {
1147                         return (CSA_E_INSUFFICIENT_MEMORY);
1148                 }
1149         }
1150 }
1151
1152 static CSA_return_code
1153 _GetServerVersion(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1154 {
1155         attr->name.num = CSA_X_DT_CAL_ATTR_SERVER_VERSION_I;
1156         if (attr->name.name = strdup(CSA_X_DT_CAL_ATTR_SERVER_VERSION))
1157                 return (_DtCm_set_uint32_attrval((uint)TABLEVERS, &attr->value));
1158         else
1159                 return (CSA_E_INSUFFICIENT_MEMORY);
1160 }
1161
1162 static CSA_return_code
1163 _GetDataVersion(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1164 {
1165         uint    version;
1166
1167         version = cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION ?
1168                         cal->fversion : _DtCM_FIRST_EXTENSIBLE_DATA_VERSION - 1;
1169
1170         attr->name.num = CSA_X_DT_CAL_ATTR_DATA_VERSION_I;
1171         if (attr->name.name = strdup(CSA_X_DT_CAL_ATTR_DATA_VERSION))
1172                 return (_DtCm_set_uint32_attrval(version, &attr->value));
1173         else
1174                 return (CSA_E_INSUFFICIENT_MEMORY);
1175 }
1176
1177 static CSA_return_code
1178 _GetProductId(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1179 {
1180         attr->name.num = CSA_CAL_ATTR_PRODUCT_IDENTIFIER_I;
1181         if (attr->name.name = strdup(CSA_CAL_ATTR_PRODUCT_IDENTIFIER)) {
1182                 return (_DtCm_set_string_attrval(_DtCM_PRODUCT_IDENTIFIER,
1183                         &attr->value, CSA_VALUE_STRING));
1184         } else {
1185                 return (CSA_E_INSUFFICIENT_MEMORY);
1186         }
1187 }
1188
1189 static CSA_return_code
1190 _GetSupportedVersion(_DtCmsCalendar *cal, int index, cms_attribute *attr)
1191 {
1192         attr->name.num = CSA_CAL_ATTR_VERSION_I;
1193         if (attr->name.name = strdup(CSA_CAL_ATTR_VERSION)) {
1194                 return (_DtCm_set_string_attrval(_DtCM_SPEC_VERSION_SUPPORTED,
1195                         &attr->value, CSA_VALUE_STRING));
1196         } else {
1197                 return (CSA_E_INSUFFICIENT_MEMORY);
1198         }
1199 }
1200