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