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