Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / server / cmsfunc.c
1 /* $XConsortium: cmsfunc.c /main/4 1995/11/09 12:42:12 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 <errno.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <time.h>
16 #include <sys/resource.h>
17 #include <rpc/rpc.h>
18 #include <dirent.h>
19 #include "csa.h"
20 #include "cm.h"
21 #include "rtable4.h"
22 #include "attr.h"
23 #include "access.h"
24 #include "cmscalendar.h"
25 #include "updateattrs.h"
26 #include "cmsdata.h"
27 #include "cmsentry.h"
28 #include "match.h"
29 #include "rpcextras.h"
30 #include "v5ops.h"
31 #include "v4ops.h"
32 #include "iso8601.h"
33 #include "log.h"
34 #include "lutil.h"
35 #include "cm_tbl.i"
36 #include "callback.h"
37 #include "insert.h"
38 #include "update.h"
39 #include "delete.h"
40 #include "lookup.h"
41 #include "misc.h"
42 #include "convert4-5.h"
43 #include "convert5-4.h"
44 #include "appt4.h"
45 #include "cmsconvert.h"
46
47 extern int debug;
48
49 /******************************************************************************
50  * forward declaration of static functions used within the file
51  ******************************************************************************/
52
53 static CSA_return_code _DtCmsCreateCallog(char *user, cms_create_args *args,
54                                         _DtCmsCalendar **cal);
55 static CSA_return_code _ListCalendarNames(uint *num_names, char ***names);
56 static void * _grow_char_array(void *ptr, uint oldcount, uint newcount);
57 static void _free_char_array(uint num_elem, char **ptr);
58 static CSA_return_code _DtCmsGetOldCalAttrNames(_DtCmsCalendar *cal,
59                                 uint *num_names_r, cms_attr_name **names_r);
60
61 /*****************************************************************************
62  * extern functions used in the library
63  *****************************************************************************/
64
65 extern void *
66 cms_ping_5_svc(void *args, struct svc_req *svcrq)
67 {
68         char dummy;
69
70         if (debug)
71                 fprintf(stderr, "cms_ping_5_svc called\n");
72
73         return((void *)&dummy); /* for RPC reply */
74 }
75
76
77 extern cms_list_calendars_res *
78 cms_list_calendars_5_svc(void *dummy, struct svc_req *svcrq)
79 {
80         static cms_list_calendars_res   res;
81
82         if (debug)
83                 fprintf(stderr, "cms_list_calendars_5_svc called\n");
84
85         if (res.num_names > 0) {
86                 _free_char_array(res.num_names, res.names);
87                 res.num_names = 0;
88         }
89
90         res.stat = _ListCalendarNames(&res.num_names, &res.names);
91
92         return (&res);
93 }
94
95 extern  cms_open_res *
96 cms_open_calendar_5_svc(cms_open_args *args, struct svc_req *svcrq)
97 {
98         static cms_open_res     res;
99         static char             sversion[80];
100         _DtCmsCalendar          *cal;
101         char                    *user;
102
103         if (debug)
104                 fprintf(stderr, "cms_open_calendar_5_svc called\n");
105
106         if (res.num_attrs > 0) {
107                 _DtCm_free_cms_attributes(res.num_attrs, res.attrs);
108                 free(res.attrs);
109                 res.num_attrs = 0;
110         }
111
112         /* check parameter */
113         if (args->cal == NULL) {
114                 res.stat = CSA_E_INVALID_PARAMETER;
115                 return (&res);
116         }
117
118         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
119             &res.user_access, &cal)) == CSA_SUCCESS) {
120
121                 res.svr_vers = TABLEVERS;
122
123                 if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
124
125                         res.file_vers = cal->fversion;
126
127                 } else {
128                         /* old format data */
129                         res.file_vers = _DtCM_FIRST_EXTENSIBLE_DATA_VERSION - 1;
130                 }
131
132                 /* return attribute names */
133                 res.stat = _DtCmsGetAllCalAttrs(cal, &res.num_attrs,
134                                         &res.attrs, B_FALSE);
135         }
136
137         if (res.stat == CSA_SUCCESS) {
138                 /* do callbacks */
139                 cal->rlist = _DtCmsDoOpenCalCallback(cal->rlist,
140                                 cal->calendar, user, args->pid);
141         }
142
143
144         return (&res);
145 }
146
147 extern  CSA_return_code *
148 cms_create_calendar_5_svc(cms_create_args *args, struct svc_req *svcrq)
149 {
150         static CSA_return_code  res;
151         _DtCmsCalendar          *cal;
152         char                    *user;
153
154         if (debug)
155                 fprintf(stderr, "cms_create_calendar_5_svc called\n");
156
157         /* check parameter */
158         if (args->cal == NULL) {
159                 res = CSA_E_INVALID_PARAMETER;
160                 return (&res);
161         }
162
163         /* need to check whether we know about the sender,
164          * if not, fail the request
165          */
166         if ((res = _DtCmsGetClientInfo(svcrq, &user)) != CSA_SUCCESS) {
167                 return (&res);
168         }
169
170         if ((res = _DtCm_check_cal_cms_attributes(_DtCMS_VERSION4,
171             args->num_attrs, args->attrs, user, args->cal, B_TRUE, B_TRUE,
172             B_FALSE)) != CSA_SUCCESS)
173                 return (&res);
174
175         if ((res = _DtCmsGetCalendarByName(args->cal, B_FALSE, &cal))
176             == CSA_SUCCESS && cal != NULL) {
177
178                 res = CSA_E_CALENDAR_EXISTS;
179
180         } else {
181
182                 /* create callog file for new calendar */
183                 res = _DtCmsCreateCallog(user, args, &cal);
184         }
185
186         return (&res);
187 }
188
189 extern  CSA_return_code *
190 cms_remove_calendar_5_svc(cms_remove_args *args, struct svc_req *svcrq)
191 {
192         static CSA_return_code  res;
193         _DtCmsCalendar          *cal;
194         char                    *user;
195         uint                    access;
196
197         if (debug)
198                 fprintf(stderr, "cms_remove_calendar_5_svc called\n");
199
200         if ((res = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
201             &access, &cal)) != CSA_SUCCESS)
202                 return (&res);
203
204         if (!(access & CSA_OWNER_RIGHTS)) {
205
206                 res = CSA_E_NO_AUTHORITY;
207
208         } else {
209
210                 /* move callog.name file to calrm.name */
211                 res = _DtCmsRemoveLog(cal->calendar, user);
212
213                 if (res != CSA_SUCCESS)
214                         return (&res);
215
216                 /* do callbacks */
217                 cal->rlist = _DtCmsDoRemoveCalCallback(cal->rlist,
218                                 cal->calendar, user, args->pid);
219
220                 /* free up internal structures */
221                 _DtCmsFreeCalendar(cal);
222         } 
223
224         return (&res);
225 }
226
227 extern  CSA_return_code *
228 cms_register_5_svc(cms_register_args *args, struct svc_req *svcrq)
229 {
230         static CSA_return_code  res;
231         char                    *user;
232         _DtCmsCalendar          *cal;
233         _DtCmsRegistrationInfo  *rinfo;
234
235         if (debug)
236                 fprintf(stderr, "cms_register_5_svc called\n");
237
238         if (args->cal == NULL ||
239             args->update_type >= (CSA_CB_ENTRY_UPDATED << 1)) {
240                 res = CSA_E_INVALID_PARAMETER;
241                 return (&res);
242         }
243
244         if ((res = _DtCmsGetClientInfo(svcrq, &user)) != CSA_SUCCESS)
245                 return (&res);
246
247         if ((res = _DtCmsGetCalendarByName(args->cal, B_TRUE, &cal))
248             != CSA_SUCCESS)
249                 return (&res);
250
251         if ((rinfo = _DtCmsGetRegistration(&(cal->rlist), user, args->prognum,
252             args->versnum, args->procnum, args->pid)) == NULL) {
253                 /* this client has not registered */
254
255                 if ((rinfo = _DtCmsMakeRegistrationInfo(user,
256                     args->update_type, args->prognum, args->versnum,
257                     args->procnum, args->pid)) == NULL) {
258                         res = CSA_E_INSUFFICIENT_MEMORY;
259                         return (&res);
260                 }
261
262                 /* put in the calendar's registration list */
263                 rinfo->next = cal->rlist;
264                 cal->rlist = rinfo;
265         } else {
266                 if (debug) {
267                         fprintf(stderr, "%s registered on %s, old types = %d\n",
268                                 user, args->cal, rinfo->types);
269                 }
270
271                 /* add new type to the registration */
272                 rinfo->types = rinfo->types | args->update_type;
273         }
274
275         if (debug) {
276                 fprintf(stderr, "%s registered on %s, types = %d\n",
277                         user, args->cal, rinfo->types);
278         }
279
280         res = CSA_SUCCESS;
281         return (&res);
282 }
283
284 extern  CSA_return_code *
285 cms_unregister_5_svc(cms_register_args *args, struct svc_req *svcrq)
286 {
287         static CSA_return_code  res;
288         char                    *user;
289         _DtCmsCalendar          *cal;
290         _DtCmsRegistrationInfo  *rinfo;
291
292         if (debug)
293                 fprintf(stderr, "cms_unregister_5_svc called\n");
294
295         if (args->cal == NULL ||
296             args->update_type >= (CSA_CB_ENTRY_UPDATED << 1)) {
297                 res = CSA_E_INVALID_PARAMETER;
298                 return (&res);
299         }
300
301         if ((res = _DtCmsGetClientInfo(svcrq, &user)) != CSA_SUCCESS)
302                 return (&res);
303
304         if ((res = _DtCmsGetCalendarByName(args->cal, B_FALSE, &cal))
305             != CSA_SUCCESS)
306                 return (&res);
307
308         if (cal == NULL || (rinfo = _DtCmsGetRegistration(&(cal->rlist), user,
309             args->prognum, args->versnum, args->procnum, args->pid)) == NULL) {
310                 res = CSA_E_CALLBACK_NOT_REGISTERED;
311                 return (&res);
312         }
313
314         /* update registration info */
315         if (debug) {
316                 fprintf(stderr, "%s registered on %s, old types = %d\n",
317                         user, args->cal, rinfo->types);
318         }
319
320         /* registered bits are cleared, unregistered bits are ignored */
321         rinfo->types = (rinfo->types | args->update_type) ^ args->update_type;
322
323         if (debug) {
324                 fprintf(stderr, "%s unregistered types %d on %s, new types = %d\n",
325                         user, args->update_type, args->cal, rinfo->types);
326         }
327
328         if (rinfo->types == 0) {
329                 cal->rlist = _DtCmsRemoveRegistration(cal->rlist, rinfo);
330         }
331
332         res = CSA_SUCCESS;
333         return (&res);
334 }
335
336 extern  cms_enumerate_calendar_attr_res *
337 cms_enumerate_calendar_attr_5_svc(buffer *args, struct svc_req *svcrq)
338 {
339         static cms_enumerate_calendar_attr_res  res;
340         _DtCmsCalendar          *cal;
341         char                    *user;
342         uint                    access;
343
344
345         if (debug)
346                 fprintf(stderr, "cms_enumerate_calendar_attr_5_svc called\n");
347
348         if (res.num_names > 0) {
349                 _DtCmsFreeCmsAttrNames(res.num_names, res.names);
350                 res.num_names = 0;
351         }
352
353         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, *args, &user,
354             &access, &cal)) != CSA_SUCCESS)
355                 return (&res);
356
357         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
358                 if (!_DTCMS_HAS_VIEW_CALENDAR_ATTR_ACCESS(access)) {
359                         res.stat = CSA_E_NO_AUTHORITY;
360                         return (&res);
361                 }
362
363                 res.stat = _DtCmsGetCalAttrNames(cal, &res.num_names,
364                                 &res.names);
365         } else {
366                 res.stat = _DtCmsGetOldCalAttrNames(cal, &res.num_names,
367                                 &res.names);
368         }
369
370         return (&res);
371 }
372
373 extern  cms_get_cal_attr_res *
374 cms_get_calendar_attr_5_svc(cms_get_cal_attr_args *args, struct svc_req *svcrq)
375 {
376         static cms_get_cal_attr_res     res;
377         _DtCmsCalendar          *cal;
378         char                    *user;
379         uint                    access;
380
381         if (debug)
382                 fprintf(stderr, "cms_get_calendar_attr_5_svc called\n");
383
384         if (res.num_attrs > 0) {
385                 _DtCm_free_cms_attributes(res.num_attrs, res.attrs);
386                 free(res.attrs);
387                 res.num_attrs = 0;
388         }
389
390         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
391             &access, &cal)) != CSA_SUCCESS)
392                 return (&res);
393
394         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
395             !_DTCMS_HAS_VIEW_CALENDAR_ATTR_ACCESS(access)) {
396                 res.stat = CSA_E_NO_AUTHORITY;
397                 return (&res);
398         }
399
400         if (args->num_names > 0)
401                 res.stat = _DtCmsGetCalAttrsByName(cal, args->num_names,
402                                 args->names, &res.num_attrs, &res.attrs);
403         else
404                 res.stat = _DtCmsGetAllCalAttrs(cal, &res.num_attrs,
405                                 &res.attrs, B_TRUE);
406
407         return (&res);
408 }
409
410 extern  CSA_return_code *
411 cms_set_calendar_attr_5_svc(cms_set_cal_attr_args *args, struct svc_req *svcrq)
412 {
413         static CSA_return_code  res;
414         _DtCmsCalendar          *cal;
415         char                    *user;
416         uint                    access;
417
418         if (debug)
419                 fprintf(stderr, "cms_set_calendar_attr_5_svc called\n");
420
421         if ((res = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
422             &access, &cal)) != CSA_SUCCESS)
423                 return (&res);
424
425         if ((cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
426             !(access & CSA_OWNER_RIGHTS)) ||
427             (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
428             !(access & (CSA_OWNER_RIGHTS | CSA_INSERT_CALENDAR_ATTRIBUTES |
429             CSA_CHANGE_CALENDAR_ATTRIBUTES)))) {
430                 res = CSA_E_NO_AUTHORITY;
431                 return (&res);
432         }
433
434         /* check argument */
435         if (args->cal == NULL || args->num_attrs == 0) {
436                 res = CSA_E_INVALID_PARAMETER;
437                 return (&res);
438         }
439
440         /* check validity of attribute values */
441         if ((res = _DtCm_check_cal_cms_attributes(
442             (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION ?
443             cal->fversion : _DtCM_FIRST_EXTENSIBLE_DATA_VERSION - 1),
444             args->num_attrs, args->attrs, NULL, NULL, B_TRUE, B_FALSE, B_TRUE))
445             != CSA_SUCCESS)
446                 return (&res);
447
448         if (cal->fversion >=_DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
449                 if ((res = _DtCmsUpdateCalAttributesAndLog(cal, args->num_attrs,
450                     args->attrs, access)) != CSA_SUCCESS)
451                 {
452                         return (&res);
453                 }
454         } else {
455                 int             i;
456                 Access_Entry_4  *v4list;
457
458                 /* for old format file, the only settable calendar attribute
459                  * is access list
460                  */
461                 for (i = args->num_attrs - 1; i >= 0; i--) {
462                         if (args->attrs[i].name.name)
463                                 break;
464                 }
465
466                 if (args->attrs[i].value == NULL ||
467                     args->attrs[i].value->item.access_list_value == NULL) {
468                         res = _DtCmsSetV4AccessListAndLog(cal, NULL);
469                 } else {
470                         if ((res = _DtCmsCmsAccessToV4Access(
471                             args->attrs[i].value->item.access_list_value,
472                             &v4list)) == CSA_SUCCESS)
473                                 res = _DtCmsSetV4AccessListAndLog(cal, v4list);
474                 }
475
476                 if (res != CSA_SUCCESS)
477                         return (&res);
478         }
479
480         /* do callback */
481         cal->rlist = _DtCmsDoUpdateCalAttrsCallback(cal->rlist, cal->calendar,
482                         user, args->num_attrs, args->attrs, args->pid);
483
484         /* reply */
485         res = CSA_SUCCESS;
486
487         return (&res);
488 }
489
490 extern  cms_archive_res *
491 cms_archive_5_svc(cms_archive_args *args, struct svc_req *svcrq)
492 {
493         static cms_archive_res res;
494
495         if (debug)
496                 fprintf(stderr, "cms_archive_5_svc called\n");
497
498         res.stat = CSA_E_NOT_SUPPORTED;
499         return (&res);
500 }
501
502 extern  CSA_return_code *
503 cms_restore_5_svc(cms_restore_args *args, struct svc_req *svcrq)
504 {
505         static CSA_return_code res;
506
507         if (debug)
508                 fprintf(stderr, "cms_restore_5_svc called\n");
509
510         res = CSA_E_NOT_SUPPORTED;
511         return (&res);
512 }
513
514 extern  cms_reminder_res *
515 cms_lookup_reminder_5_svc(cms_reminder_args *args, struct svc_req *svcrq)
516 {
517         static cms_reminder_res res;
518         _DtCmsCalendar          *cal;
519         char                    *user;
520         uint                    access;
521
522         if (debug)
523                 fprintf(stderr, "cms_lookup_reminder_5_svc called\n");
524
525         if (res.rems != NULL) {
526                 _DtCmsFreeReminderRef(res.rems);
527                 res.rems = NULL;
528         }
529
530         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
531             &access, &cal)) != CSA_SUCCESS)
532                 return (&res);
533
534         if ((access & CSA_OWNER_RIGHTS) == 0) {
535                 res.stat = CSA_E_NO_AUTHORITY;
536                 return (&res);
537         }
538
539         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
540                 res.stat = _DtCmsLookupReminder(cal->remq, args->tick,
541                                 args->num_names, args->names, &res.rems);
542         } else {
543                 Reminder_4      *v4rem;
544                 _DtCmsEntryId   *ids;
545
546                 if ((res.stat = _DtCmsGetV4Reminders(cal, time(0), &v4rem,
547                     &ids)) == CSA_SUCCESS) {
548                         res.stat = _DtCmsV4ReminderToReminderRef(cal->calendar,
549                                         v4rem, ids, &res.rems);
550                         _DtCm_free_reminder4(v4rem);
551                         _DtCmsFreeEntryIds(ids);
552                 }
553         }
554
555         return (&res);
556 }
557
558 extern  cms_entries_res *
559 cms_lookup_entries_5_svc(cms_lookup_entries_args *args, struct svc_req *svcrq)
560 {
561         static cms_entries_res  res;
562         _DtCmsCalendar          *cal;
563         char                    *user;
564         uint                    access;
565         time_t                  start1, start2, end1, end2;
566         long                    id = 0;
567         boolean_t               no_match;
568         boolean_t               no_start_time_range, no_end_time_range;
569         CSA_uint32              hnum;
570         cms_attribute           *hattrs;
571         CSA_enum                *hops;
572
573         if (debug)
574                 fprintf(stderr, "cms_lookup_entries_5_svc called\n");
575
576         if (res.entries) {
577                 _DtCm_free_cms_entries(res.entries);
578                 res.entries = NULL;
579         }
580
581         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
582             &access, &cal)) != CSA_SUCCESS)
583                 return (&res);
584
585         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
586             !_DTCMS_HAS_VIEW_ACCESS(access)) {
587                 res.stat = CSA_E_NO_AUTHORITY;
588                 return (&res);
589         }
590
591         /* check operator */
592         if ((res.stat = _DtCm_check_operator(args->num_attrs, NULL,
593             args->attrs, args->ops)) != CSA_SUCCESS)
594                 return (&res);
595
596         /* get time range */
597         if ((res.stat = _DtCmHashCriteria(
598             cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION ?
599             _DtCm_entry_name_tbl : cal->entry_tbl, args->num_attrs,
600             NULL, args->attrs, args->ops, &no_match, &no_start_time_range,
601             &no_end_time_range, &start1, &start2, &end1, &end2, &id,
602             &hnum, &hattrs, &hops)) == CSA_E_INVALID_ATTRIBUTE) {
603
604                 /* attribute not defined in this calendar specified,
605                  * return NULL list
606                  */
607                 res.stat = CSA_SUCCESS;
608                 return (&res);
609
610         } else if (res.stat != CSA_SUCCESS || no_match == B_TRUE)
611                 return (&res);
612
613         /* do lookup */
614         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
615                 if (id > 0)
616                         res.stat = _DtCmsLookupEntriesById(cal, user, access,
617                                         no_start_time_range, no_end_time_range,
618                                         start1, start2, end1, end2, id, hnum,
619                                         hattrs, hops, &res.entries);
620                 else
621                         res.stat = _DtCmsLookupEntries(cal, user, access,
622                                         start1, start2, no_end_time_range,
623                                         end1, end2, hnum, hattrs, hops,
624                                         &res.entries);
625         } else {
626                 Range_4 prange;
627                 Appt_4  *appt = NULL;;
628
629                 if (id > 0) {
630                         res.stat = _DtCmsLookupKeyrangeV4(cal, user, access,
631                                         no_start_time_range, no_end_time_range,
632                                         start1, start2, end1, end2, id,
633                                         _DtCm_match_one_appt, hnum, hattrs,
634                                         hops, &appt, NULL);
635                 } else {
636                         prange.key1 = start1;
637                         prange.key2 = start2;
638                         prange.next = NULL;
639                         res.stat = _DtCmsLookupRangeV4(cal, user, access,
640                                         &prange, no_end_time_range, end1, end2,
641                                         _DtCm_match_one_appt, hnum,
642                                         hattrs, hops, &appt, NULL);
643                 }
644
645                 if (res.stat == CSA_SUCCESS && appt) {
646                         res.stat = _DtCmsAppt4ToCmsentriesForClient(args->cal,
647                                         appt, &res.entries);
648                         _DtCm_free_appt4(appt);
649                 }
650         }
651
652         _DtCmFreeHashedArrays(hnum, hattrs, hops);
653
654         return (&res);
655 }
656
657 extern  cms_entries_res *
658 cms_enumerate_sequence_5_svc(cms_enumerate_args *args, struct svc_req *svcrq)
659 {
660         static cms_entries_res  res;
661         _DtCmsCalendar          *cal;
662         char                    *user;
663         uint                    access;
664
665         if (debug)
666                 fprintf(stderr, "cms_enumerate_sequence_5_svc called\n");
667
668         if (res.entries) {
669                 _DtCm_free_cms_entries(res.entries);
670                 res.entries = NULL;
671         }
672
673         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
674             &access, &cal)) != CSA_SUCCESS)
675                 return (&res);
676
677         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
678             !_DTCMS_HAS_VIEW_ACCESS(access)) {
679                 res.stat = CSA_E_NO_AUTHORITY;
680                 return (&res);
681         }
682
683         /* do lookup */
684         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
685                 res.stat = _DtCmsEnumerateSequenceById(cal, user, access,
686                                 B_FALSE, B_TRUE, args->start, args->end,
687                                 0, 0, args->id, 0, NULL, NULL, &res.entries);
688         } else {
689                 Range_4 prange;
690                 Appt_4 *appt = NULL;
691                 res.stat = _DtCmsLookupKeyrangeV4(cal, user, access,
692                                 B_FALSE, B_TRUE, args->start, args->end,
693                                 0, 0, args->id, NULL, 0, NULL, NULL, &appt,
694                                 NULL);
695
696                 if (res.stat == CSA_SUCCESS && appt) {
697                         res.stat = _DtCmsAppt4ToCmsentriesForClient(args->cal,
698                                         appt, &res.entries);
699                         _DtCm_free_appt4(appt);
700                 }
701         }
702
703         return (&res);
704 }
705
706 extern  cms_get_entry_attr_res *
707 cms_get_entry_attr_5_svc(cms_get_entry_attr_args *args, struct svc_req *svcrq)
708 {
709         static cms_get_entry_attr_res   res;
710         _DtCmsCalendar          *cal;
711         char                    *user;
712         uint                    access;
713
714         if (debug)
715                 fprintf(stderr, "cms_get_entry_attr_5_svc called\n");
716
717         if (res.entries) {
718                 _DtCmsFreeEntryAttrResItem(res.entries);
719                 res.entries = NULL;
720         }
721
722         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
723             &access, &cal)) != CSA_SUCCESS)
724                 return (&res);
725
726         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
727             !_DTCMS_HAS_VIEW_ACCESS(access)) {
728                 res.stat = CSA_E_NO_AUTHORITY;
729                 return (&res);
730         }
731
732         /* check operator */
733         if (args->num_keys == 0) {
734                 res.stat = CSA_E_INVALID_PARAMETER;
735                 return (&res);
736         }
737
738         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
739                 res.stat = _DtCmsLookupEntriesByKey(cal, user, access,
740                         args->num_keys, args->keys, args->num_names,
741                         args->names, &res.entries);
742         } else {
743                 res.stat = CSA_E_NOT_SUPPORTED;
744         }
745
746         return (&res);
747 }
748
749 extern  cms_entry_res *
750 cms_insert_entry_5_svc(cms_insert_args *args, struct svc_req *svcrq)
751 {
752         static cms_entry_res    res;
753         _DtCmsCalendar          *cal;
754         cms_entry               *entry;
755         cms_key                 key;
756         char                    *user;
757         uint                    access, needaccess;
758         Appt_4                  *appt;
759
760         if (debug)
761                 fprintf(stderr, "cms_insert_entry_5_svc called\n");
762
763         if (res.entry != NULL) {
764                 res.entry->num_attrs--;
765                 _DtCm_free_cms_entry(res.entry);
766                 res.entry = NULL;
767         }
768
769         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
770             &access, &cal)) != CSA_SUCCESS)
771                 return (&res);
772
773         if ((cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
774             !_DTCMS_HAS_INSERT_ACCESS(access)) ||
775             (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
776             !_DTCMS_HAS_V4_WRITE_ACCESS(access))) {
777                 res.stat = CSA_E_NO_AUTHORITY;
778                 return (&res);
779         }
780
781         /* check argument */
782         if (args->cal == NULL || args->num_attrs == 0) {
783                 res.stat = CSA_E_INVALID_PARAMETER;
784                 return (&res);
785         }
786
787         /* check validity of attribute values */
788         if ((res.stat = _DtCm_check_entry_cms_attributes(
789             (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION ?
790             cal->fversion : _DtCM_FIRST_EXTENSIBLE_DATA_VERSION - 1),
791             args->num_attrs, args->attrs, CSA_CB_ENTRY_ADDED, B_TRUE))
792             != CSA_SUCCESS)
793                 return (&res);
794
795         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
796                 if ((res.stat = _DtCmsMakeHashedEntry(cal, args->num_attrs,
797                     args->attrs, &entry)) != CSA_SUCCESS)
798                         return (&res);
799
800                 if ((res.stat = _DtCmsCheckInitialAttributes(entry))
801                     != CSA_SUCCESS) {
802                         _DtCm_free_cms_entry(entry);
803                         return (&res);
804                 }
805
806                 /* check access rights */
807                 needaccess = _DtCmsClassToInsertAccess(entry);
808                 if ((access & (CSA_OWNER_RIGHTS | needaccess)) == 0) {
809                         _DtCm_free_cms_entry(entry);
810                         res.stat = CSA_E_NO_AUTHORITY;
811                         return (&res);
812                 }
813
814                 /* set organizer */
815                 if ((res.stat = _DtCm_set_string_attrval(user,
816                     &entry->attrs[CSA_ENTRY_ATTR_ORGANIZER_I].value,
817                     CSA_VALUE_CALENDAR_USER)) != CSA_SUCCESS) {
818                         _DtCm_free_cms_entry(entry);
819                         return (&res);
820                 }
821
822                 /* insert entry and log it */
823                 if ((res.stat = _DtCmsInsertEntryAndLog(cal, entry))
824                     != CSA_SUCCESS) {
825                         _DtCm_free_cms_entry(entry);
826                         return (&res);
827                 }
828
829                 key = entry->key;
830         } else {
831                 if ((appt = _DtCm_make_appt4(B_TRUE)) == NULL) {
832                         res.stat = CSA_E_INSUFFICIENT_MEMORY;
833                         return (&res);
834                 }
835  
836                 if ((res.stat = _DtCmsAttrsToAppt4(args->num_attrs,
837                     args->attrs, appt, B_TRUE)) != CSA_SUCCESS) {
838                         _DtCm_free_appt4(appt);
839                         return (&res);
840                 }
841
842                 if (appt->author) free(appt->author);
843                 if ((appt->author = strdup(user)) == NULL) {
844                         _DtCm_free_appt4(appt);
845                         return (&res);
846                 }
847
848                 /*
849                  * calculate the correct start day,
850                  */
851                 _DtCms_adjust_appt_startdate(appt);
852
853                 if ((res.stat = _DtCmsInsertApptAndLog(cal, appt))
854                     != CSA_SUCCESS) {
855                         _DtCm_free_appt4(appt);
856                         return (&res);
857                 }
858
859                 key.id = appt->appt_id.key;
860                 key.time = appt->appt_id.tick;
861         }
862
863         if (res.stat == CSA_SUCCESS)
864                 cal->modified = B_TRUE;
865         else
866                 return (&res);
867
868         /* do callback */
869         cal->rlist = _DtCmsDoV1CbForV4Data(cal->rlist, user, args->pid,
870                         &key, NULL);
871
872         cal->rlist = _DtCmsDoInsertEntryCallback(cal->rlist, cal->calendar,
873                         user, key.id, args->pid);
874
875         /* reply */
876         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION ||
877             (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
878             (res.stat = _DtCmsAppt4ToCmsentriesForClient(cal->calendar, appt,
879             &entry)) == CSA_SUCCESS)) {
880
881                 res.stat = _DtCmsGetCmsEntryForClient(entry, &res.entry, B_FALSE);
882
883                 _DtCm_free_cms_entry(entry);
884         }
885
886         return (&res);
887 }
888
889 extern  cms_entry_res *
890 cms_update_entry_5_svc(cms_update_args *args, struct svc_req *svcrq)
891 {
892         static cms_entry_res    res;
893         _DtCmsCalendar          *cal;
894         cms_entry               *newentry;
895         caddr_t                 event;
896         char                    *user;
897         uint                    access, needaccess;
898         Appt_4                  *appt = NULL;
899
900         if (debug)
901                 fprintf(stderr, "cms_update_entry_5_svc called\n");
902
903         if (res.entry != NULL) {
904                 res.entry->num_attrs--;
905                 _DtCm_free_cms_entry(res.entry);
906                 res.entry = NULL;
907         }
908
909         if ((res.stat = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
910             &access, &cal)) != CSA_SUCCESS)
911                 return (&res);
912
913         if ((cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
914             !_DTCMS_HAS_CHANGE_ACCESS(access)) ||
915             (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
916             !_DTCMS_HAS_V4_WRITE_ACCESS(access))) {
917                 res.stat = CSA_E_NO_AUTHORITY;
918                 return (&res);
919         }
920
921         /* check argument */
922         if (args->cal == NULL || args->entry.id <= 0 || args->num_attrs == 0) {
923                 res.stat = CSA_E_INVALID_PARAMETER;
924                 return (&res);
925         }
926
927         if (args->scope < CSA_SCOPE_ALL || args->scope > CSA_SCOPE_FORWARD) {
928                 res.stat = CSA_E_INVALID_ENUM;
929                 return (&res);
930         }
931
932         /* check validity of attribute values */
933         if ((res.stat = _DtCm_check_entry_cms_attributes(
934             (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION ?
935             cal->fversion : _DtCM_FIRST_EXTENSIBLE_DATA_VERSION - 1),
936             args->num_attrs, args->attrs, CSA_CB_ENTRY_UPDATED, B_TRUE))
937             != CSA_SUCCESS)
938                 return (&res);
939
940         /* get event from one-time event tree */
941         event = (caddr_t)rb_lookup(cal->tree, (caddr_t)&args->entry);
942
943         /* update entry and log it */
944         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
945                 if (event != NULL || args->scope == CSA_SCOPE_ALL) {
946                         res.stat = _DtCmsUpdateEntry(cal, user, access,
947                                         &args->entry, args->num_attrs,
948                                         args->attrs, NULL, &newentry);
949                 } else {
950                         res.stat = _DtCmsUpdateInstances(cal, user, access,
951                                         &args->entry, args->scope,
952                                         args->num_attrs, args->attrs, NULL,
953                                         &newentry);
954                 }
955         } else {
956                 Options_4       opt;
957
958                 if (event != NULL || args->scope == CSA_SCOPE_ALL)
959                         opt = do_all_4;
960                 else
961                         opt = (args->scope == CSA_SCOPE_ONE) ?
962                                 do_one_4 : do_forward_4;
963
964                 if (event == NULL && (event = hc_lookup(cal->list,
965                     (caddr_t)&args->entry)) == NULL) {
966
967                         res.stat = CSA_X_DT_E_ENTRY_NOT_FOUND;
968
969                 } else if ((appt = _DtCm_copy_one_appt4((Appt_4 *)event))
970                     == NULL) {
971
972                         res.stat = CSA_E_INSUFFICIENT_MEMORY; 
973
974                 } else {
975                         /* get rid of exceptions */
976                         _DtCm_free_excpt4(appt->exception);
977                         appt->exception = NULL;
978
979                         if ((res.stat = _DtCmsAttrsToAppt4(args->num_attrs,
980                             args->attrs, appt, B_TRUE)) == CSA_SUCCESS) {
981
982                                 if (opt == do_all_4)
983                                         res.stat = _DtCmsChangeAll(cal, user,
984                                                 access, (Id_4 *)&args->entry,
985                                                 appt, NULL);
986                                 else
987                                         res.stat = _DtCmsChangeSome(cal, user,
988                                                 access, (Id_4 *)&args->entry,
989                                                 appt, opt, NULL);
990
991                         }
992                 }
993         }
994
995         if (res.stat == CSA_SUCCESS)
996                 cal->modified = B_TRUE;
997         else
998                 return (&res);
999
1000         /* do callback */
1001         cal->rlist = _DtCmsDoV1CbForV4Data(cal->rlist, user, args->pid,
1002                         &args->entry,
1003                         (appt ? (cms_key *)&appt->appt_id : &newentry->key));
1004
1005         cal->rlist = _DtCmsDoUpdateEntryCallback(cal->rlist, cal->calendar,
1006                         user, (appt ? appt->appt_id.key : newentry->key.id),
1007                         args->entry.id, args->scope, args->entry.time,
1008                         args->pid);
1009
1010         /* reply */
1011         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION ||
1012             (cal->fversion < _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
1013             (res.stat = _DtCmsAppt4ToCmsentriesForClient(cal->calendar, appt,
1014             &newentry)) == CSA_SUCCESS)) {
1015
1016                 res.stat = _DtCmsGetCmsEntryForClient(newentry, &res.entry, B_FALSE);
1017
1018                 _DtCm_free_cms_entry(newentry);
1019         }
1020
1021         return (&res);
1022 }
1023
1024 extern  CSA_return_code *
1025 cms_delete_entry_5_svc(cms_delete_args *args, struct svc_req *svcrq)
1026 {
1027         static CSA_return_code  res;
1028         _DtCmsCalendar          *cal;
1029         caddr_t                 event;
1030         char                    *user;
1031         uint                    access, needaccess;
1032
1033         if (debug)
1034                 fprintf(stderr, "cms_delete_entry_5_svc called\n");
1035
1036         if ((res = _DtCmsV5LoadAndCheckAccess(svcrq, args->cal, &user,
1037             &access, &cal)) != CSA_SUCCESS)
1038                 return (&res);
1039
1040         /* for v3 data, authority check is done in the routines doing the
1041          * deletion since we may need to check the organizer
1042          */
1043         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION &&
1044             !_DTCMS_HAS_CHANGE_ACCESS(access)) {
1045                 res = CSA_E_NO_AUTHORITY;
1046                 return (&res);
1047         }
1048
1049         /* check argument */
1050         if (args->cal == NULL || args->entry.id <= 0) {
1051                 res = CSA_E_INVALID_PARAMETER;
1052                 return (&res);
1053         }
1054
1055         if (args->scope < CSA_SCOPE_ALL || args->scope > CSA_SCOPE_FORWARD) {
1056                 res = CSA_E_INVALID_ENUM;
1057                 return (&res);
1058         }
1059
1060
1061         /* get event from one-time event tree */
1062         event = (caddr_t)rb_lookup(cal->tree, (caddr_t)&args->entry);
1063
1064         /* delete entry and log it */
1065         if (cal->fversion >= _DtCM_FIRST_EXTENSIBLE_DATA_VERSION) {
1066                 if (event != NULL || args->scope == CSA_SCOPE_ALL) {
1067                         res = _DtCmsDeleteEntryAndLog(cal, user, access,
1068                                 &args->entry, NULL);
1069                 } else {
1070                         res = _DtCmsDeleteInstancesAndLog(cal, user, access,
1071                                 &args->entry, args->scope, NULL, NULL);
1072                 }
1073         } else {
1074                 if (event != NULL || args->scope == CSA_SCOPE_ALL) {
1075                         res = _DtCmsDeleteApptAndLog(cal, user, access,
1076                                 (Id_4 *)&args->entry, NULL);
1077                 } else {
1078                         res = _DtCmsDeleteApptInstancesAndLog(cal, user, access,
1079                                 (Id_4 *)&args->entry,
1080                                 ((args->scope == CSA_SCOPE_ONE) ? do_one_4 :
1081                                 do_forward_4), NULL, NULL);
1082                 }
1083         }
1084
1085         if (res == CSA_SUCCESS)
1086                 cal->modified = B_TRUE;
1087         else
1088                 return (&res);
1089
1090         /* do callback */
1091         cal->rlist = _DtCmsDoV1CbForV4Data(cal->rlist, user, args->pid,
1092                         &args->entry, NULL);
1093
1094         cal->rlist = _DtCmsDoDeleteEntryCallback(cal->rlist, cal->calendar,
1095                         user, args->entry.id, args->scope, args->entry.time,
1096                         args->pid);
1097
1098
1099         return (&res);
1100 }
1101
1102 void initfunctable(program_handle ph)
1103 {
1104         ph->program_num = TABLEPROG;
1105         ph->prog[TABLEVERS].vers = &tableprog_5_table[0];
1106         ph->prog[TABLEVERS].nproc = sizeof(tableprog_5_table)/sizeof(tableprog_5_table[0]);
1107 }
1108
1109 /*****************************************************************************
1110  * static functions used within the file
1111  *****************************************************************************/
1112
1113 static CSA_return_code
1114 _DtCmsCreateCallog(char *user, cms_create_args *args, _DtCmsCalendar **newcal)
1115 {
1116         CSA_return_code stat;
1117         _DtCmsCalendar  *cal;
1118         int             i, index;
1119         char            datestr[80];
1120         char            *calname;
1121         char            *log;
1122         char            *username;
1123         cms_attribute_value val;
1124         cms_access_entry aentry;
1125         int             nidx = 0, oidx = 0;
1126         char            *name, *owner;
1127
1128         /*
1129          * if calendar name is a user name, make sure that
1130          * it's the same as the sender.
1131          */
1132         calname = _DtCmGetPrefix(args->cal, '@');
1133         username = _DtCmGetPrefix(user, '@');
1134
1135         if (_DtCmIsUserName(calname) && strcmp(calname, username)) {
1136                 free(calname);
1137                 free(username);
1138                 return (CSA_E_NO_AUTHORITY);
1139         }
1140         log = _DtCmsGetLogFN(calname);
1141         free(calname);
1142         free(username);
1143
1144         /* create internal calendar data structure */
1145         if ((cal = _DtCmsMakeCalendar(user, args->cal)) == NULL) {
1146                 free(log);
1147                 return (CSA_E_INSUFFICIENT_MEMORY);
1148         }
1149
1150         /* fill in information */
1151         _csa_tick_to_iso8601(time(0), datestr);
1152
1153         if ((stat = _DtCm_set_string_attrval(datestr,
1154             &cal->attrs[CSA_CAL_ATTR_DATE_CREATED_I].value,
1155             CSA_VALUE_DATE_TIME)) != CSA_SUCCESS) {
1156                 _DtCmsFreeCalendar(cal);
1157                 free(log);
1158                 return (stat);
1159         }
1160
1161         /* initialize access list to be "WORLD", VIEW_PUBLIC */
1162         aentry.user = WORLD;
1163         aentry.rights = CSA_VIEW_PUBLIC_ENTRIES;
1164         aentry.next = NULL;
1165         val.item.access_list_value = &aentry;
1166         val.type = CSA_VALUE_ACCESS_LIST;
1167
1168         if ((stat = _DtCmUpdateAccessListAttrVal(&val,
1169             &cal->attrs[CSA_CAL_ATTR_ACCESS_LIST_I].value)) != CSA_SUCCESS) {
1170                 _DtCmsFreeCalendar(cal);
1171                 free(log);
1172                 return (stat);
1173         }
1174
1175         /* set product identifier */
1176         if ((stat = _DtCm_set_string_attrval(_DtCM_PRODUCT_IDENTIFIER,
1177             &cal->attrs[CSA_CAL_ATTR_PRODUCT_IDENTIFIER_I].value,
1178             CSA_VALUE_STRING)) != CSA_SUCCESS) {
1179                 _DtCmsFreeCalendar(cal);
1180                 free(log);
1181                 return (stat);
1182         }
1183
1184         /* set CSA version */
1185         if ((stat = _DtCm_set_string_attrval(_DtCM_SPEC_VERSION_SUPPORTED,
1186             &cal->attrs[CSA_CAL_ATTR_VERSION_I].value, CSA_VALUE_STRING))
1187             != CSA_SUCCESS) {
1188                 _DtCmsFreeCalendar(cal);
1189                 free(log);
1190                 return (stat);
1191         }
1192
1193         /* we dont use the values specified by client */
1194         for (i = 0; i < args->num_attrs; i++) {
1195                 if (strcmp(args->attrs[i].name.name,
1196                     CSA_CAL_ATTR_CALENDAR_NAME) == 0) {
1197                         nidx = i;
1198                         name = args->attrs[i].name.name;
1199                         args->attrs[i].name.name = NULL;
1200                 } else if (strcmp(args->attrs[i].name.name,
1201                     CSA_CAL_ATTR_CALENDAR_OWNER) == 0) {
1202                         oidx = i;
1203                         owner = args->attrs[i].name.name;
1204                         args->attrs[i].name.name = NULL;
1205                 }
1206         }
1207
1208         /* initialize calendar attribute with info provided by caller */
1209         if ((stat = _DtCmUpdateAttributes(args->num_attrs, args->attrs,
1210             &cal->num_attrs, &cal->attrs, &cal->cal_tbl, B_TRUE,
1211             NULL, B_FALSE)) != CSA_SUCCESS) {
1212                 _DtCmsFreeCalendar(cal);
1213                 free(log);
1214                 return (stat);
1215         }
1216
1217         if (nidx) args->attrs[nidx].name.name = name;
1218         if (oidx) args->attrs[oidx].name.name = owner;
1219
1220         /* use passed in char set if client does not supply one */
1221         if (cal->attrs[CSA_CAL_ATTR_CHARACTER_SET_I].value == NULL &&
1222              args->char_set && *args->char_set != NULL) {
1223                 if ((stat = _DtCm_set_string_attrval(args->char_set,
1224                     &cal->attrs[CSA_CAL_ATTR_CHARACTER_SET_I].value,
1225                     CSA_VALUE_STRING)) != CSA_SUCCESS) {
1226                         _DtCmsFreeCalendar(cal);
1227                         free(log);
1228                         return (stat);
1229                 }
1230         }
1231
1232         /* create file */
1233         if ((stat = _DtCmsCreateLogV2(user, log)) != CSA_SUCCESS) {
1234                 _DtCmsFreeCalendar(cal);
1235                 free(log);
1236                 return (stat);
1237         }
1238
1239         /* dump file */
1240         if ((stat = _DtCmsAppendCalAttrsByFN(log, cal->num_attrs, cal->attrs))
1241             != CSA_SUCCESS) {
1242                 free(log);
1243                 unlink(log);
1244                 _DtCmsFreeCalendar(cal);
1245                 return (stat);
1246         }
1247         free(log);
1248
1249         _DtCmsPutInCalList(cal);
1250
1251         *newcal = cal;
1252
1253         return (stat);
1254 }
1255
1256 #define _NAME_INCREMENT 10
1257
1258 static CSA_return_code
1259 _ListCalendarNames(uint *num_names, char ***names)
1260 {
1261         uint    num = 0, count = 0;
1262         char    **names_r = NULL;
1263         DIR     *dirp;
1264         struct  dirent *dp;
1265
1266         if ((dirp = opendir(".")) == NULL)
1267                 return (CSA_E_FAILURE);
1268
1269 #ifdef SunOS
1270         if ((dp = (struct dirent *)malloc(sizeof(struct dirent) + FILENAME_MAX))
1271             == NULL) {
1272                 closedir(dirp);
1273                 return (CSA_E_INSUFFICIENT_MEMORY);
1274         }
1275
1276         while (dp = readdir_r(dirp, dp)) {
1277 #else
1278         while (dp = readdir(dirp)) {
1279 #endif
1280                 if (strncmp(dp->d_name, "callog.", strlen("callog.")) == 0) {
1281                         if (count == num) {
1282                                 count += _NAME_INCREMENT;
1283                                 if ((names_r = (char **)_grow_char_array(
1284                                     names_r, sizeof(char *) * count,
1285                                     sizeof(char *) * (count + _NAME_INCREMENT)))
1286                                     == NULL) {
1287                                         if (num > 0) {
1288                                                 _free_char_array(
1289                                                         num, names_r);
1290                                         }
1291                                         closedir(dirp);
1292                                         return (CSA_E_INSUFFICIENT_MEMORY);
1293                                 }
1294                         }
1295                         if ((names_r[num++] = strdup(dp->d_name)) == NULL) {
1296                                 _free_char_array(num, names_r);
1297                                 closedir(dirp);
1298                                 return (CSA_E_INSUFFICIENT_MEMORY);
1299                         }
1300                 }
1301         }
1302
1303         if (num > 0) {
1304                 *num_names = num;
1305                 *names = names_r;
1306         } else if (count > 0)
1307                 free(names_r);
1308
1309         return (CSA_SUCCESS);
1310 }
1311
1312 static void *
1313 _grow_char_array(void *ptr, uint oldcount, uint newcount)
1314 {
1315         void *nptr;
1316
1317         if (nptr = realloc(ptr, newcount)) {
1318                 memset((void *)((char *)nptr + oldcount), NULL,
1319                         newcount - oldcount);
1320                 return (nptr);
1321         } else
1322                 return (NULL);
1323 }
1324
1325 static void
1326 _free_char_array(uint num_elem, char **ptr)
1327 {
1328         int i;
1329
1330         if (num_elem == 0)
1331                 return;
1332
1333         for (i = 0; i < num_elem; i++) {
1334                 if (ptr[i])
1335                         free(ptr[i]);
1336                 else
1337                         break;
1338         }
1339
1340         free(ptr);
1341 }
1342
1343 /*
1344  * This routine assumes that the attributes are hashed already
1345  */
1346 static CSA_return_code
1347 _DtCmsGetOldCalAttrNames(
1348         _DtCmsCalendar  *cal,
1349         uint            *num_names_r,
1350         cms_attr_name   **names_r)
1351 {
1352         CSA_return_code stat = CSA_SUCCESS;
1353         cms_attr_name   *names;
1354         uint            i, j;
1355
1356         if ((names = (cms_attr_name *)calloc(1,
1357             sizeof(cms_attr_name)*_DtCM_OLD_CAL_ATTR_SIZE)) == NULL)
1358                 return (CSA_E_INSUFFICIENT_MEMORY);
1359
1360         for (i = 1, j = 0; i <= _DtCM_DEFINED_CAL_ATTR_SIZE; i++) {
1361                 if ((_CSA_cal_attr_info[i].fst_vers > 0 &&
1362                     _CSA_cal_attr_info[i].fst_vers <= cal->fversion)
1363                     || i == CSA_CAL_ATTR_CALENDAR_SIZE_I) {
1364                         if ((names[j].name =
1365                             strdup(_CSA_calendar_attribute_names[i])) == NULL)
1366                         {
1367                                 _DtCmsFreeCmsAttrNames(j, names);
1368                                 return (CSA_E_INSUFFICIENT_MEMORY);
1369                         } else {
1370                                 names[j].num = i;
1371                                 j++;
1372                         }
1373                 }
1374         }
1375
1376         *num_names_r = j;
1377         *names_r = names;
1378
1379         return (CSA_SUCCESS);
1380 }
1381