Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtcm / server / log.c
1 /* $XConsortium: log.c /main/8 1996/11/21 19:45:13 drk $ */
2 /*
3  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
4  *  (c) Copyright 1993, 1994 International Business Machines Corp.
5  *  (c) Copyright 1993, 1994 Novell, Inc.
6  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
7  */
8
9 #include <EUSCompat.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <pwd.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <sys/file.h>
18 #define XOS_USE_NO_LOCKING
19 #define X_INCLUDE_TIME_H
20 #include <X11/Xos_r.h>
21 #include "cm.h"
22 #include "rtable4.h"
23 #include "log.h"
24 #include "iso8601.h"
25
26 extern uid_t    daemon_uid;
27 extern gid_t    daemon_gid;
28 extern char     *pgname;
29 extern int      debug;
30 static char     *spool_dir = _DtCMS_DEFAULT_DIR;
31
32 char *tag_string[] = {
33         "0:boolean",
34         "1:enum",
35         "2:flags",
36         "3:sint32",
37         "4:uint32",
38         "5:string",
39         "6:user",
40         "7:date_time",
41         "8:date_time_range",
42         "9:time_duration",
43         "10:access_list",
44         "11:attendees",
45         "12:date_time_list",
46         "13:reminder",
47         "14:opaque_data",
48         NULL
49 };
50
51 /*
52  * forward declaration of functions used within this file
53  */
54 static char * cr_to_str(char *s, int size);
55 static void periodtostr(Interval_4 i, char *q);
56 static void privacytostr(Privacy_Level_4 p, char *q);
57 static void apptstatustostr(Appt_Status_4 p, char *q);
58 static void apptstatustostr(Appt_Status_4 p, char *q);
59 static void tagstostr(Event_Type_4 p, char *q);
60 static char * get_fname (char *dir, char *fname, char *who);
61 static CSA_return_code append_log(int f, char *buf);
62 static CSA_return_code create_log(char *owner, char *file, int version);
63 static char *attrs_to_attrliststr(int len, cms_attribute *attrs,
64                                 boolean_t write_hash, boolean_t entryattrs);
65 static char *grow_n_concat(char *base, char *newstr, int newcount);
66 static char *get_access_list_string(cms_access_entry *list);
67 static char *get_date_time_list_string(CSA_date_time_list list);
68
69
70 /*
71  * extern functions
72  */
73
74 extern char *
75 _DtCmsGetLogFN(char *who)
76 {
77         return (get_fname (spool_dir, _DtCMS_DEFAULT_LOG, who));
78 }
79  
80 extern char *
81 _DtCmsGetBakFN(char *who)
82 {
83         return (get_fname (spool_dir, _DtCMS_DEFAULT_BAK, who));
84 }
85  
86 extern char *
87 _DtCmsGetTmpFN(char *who)
88 {
89         return (get_fname (spool_dir, _DtCMS_DEFAULT_TMP, who));
90 }
91
92 extern char *
93 _DtCmsGetDelFN(char *who)
94 {
95         return (get_fname (spool_dir, _DtCMS_DEFAULT_DEL, who));
96 }
97
98 extern CSA_return_code
99 _DtCmsCreateLogV1(char *owner, char *file)
100 {
101         return (create_log(owner, file, _DtCMS_VERSION1));
102 }
103
104
105 extern CSA_return_code
106 _DtCmsAppendHTableByFN(char *file, uint size, char **names, int *types)
107 {
108         int     f;
109         CSA_return_code stat;
110
111         if ((f = open(file, O_WRONLY | O_APPEND | O_SYNC)) < 0) {
112                 perror(pgname);
113                 return (CSA_X_DT_E_BACKING_STORE_PROBLEM);
114         }
115
116         stat = _DtCmsAppendHTableByFD(f, size, names, types);
117
118         close(f);
119         return (stat);
120 }
121
122 /*
123  * the first element of the arrays is not used
124  */
125 extern CSA_return_code
126 _DtCmsAppendHTableByFD(int fd, uint size, char **names, int *types)
127 {
128         CSA_return_code stat;
129         char    *tptr, *buf, tmpbuf[BUFSIZ/4];
130         int     i, tcount, count = 15;  /* strlen("(entrytable )\n") + 1 */
131
132         if ((buf = malloc(BUFSIZ)) == NULL) return (CSA_E_INSUFFICIENT_MEMORY);
133         tcount = BUFSIZ;
134         strcpy(buf, "(entrytable ");
135
136         for (i = 1; i <= size; i++) {
137                 sprintf(tmpbuf, "(%d \"%s\" \"%s\")\n", i, names[i],
138                         tag_string[types[i]]);
139
140                 count += strlen(tmpbuf);
141                 if (tcount < count) {
142                         if ((tptr = grow_n_concat(buf, tmpbuf, tcount + BUFSIZ))
143                             == NULL) {
144                                 free(buf);
145                                 return (CSA_E_INSUFFICIENT_MEMORY);
146                         }
147                         buf = tptr;
148                         tcount += BUFSIZ;
149                 } else
150                         strcat(buf, tmpbuf);
151         }
152
153         strcat(buf, ")\n");
154
155         stat = append_log(fd, buf);
156
157         free(buf);
158         return (stat);
159 }
160
161 extern CSA_return_code
162 _DtCmsAppendEntryByFN(char *file, cms_entry *entry, _DtCmsLogOps op)
163 {
164         int     f;
165         CSA_return_code stat;
166
167         if ((f = open(file, O_WRONLY | O_APPEND | O_SYNC)) < 0) {
168                 perror(pgname);
169                 return (CSA_X_DT_E_BACKING_STORE_PROBLEM);
170         }
171
172         stat = _DtCmsAppendEntryByFD(f, entry, op);
173
174         close(f);
175         return (stat);
176 }
177
178 extern CSA_return_code
179 _DtCmsAppendEntryByFD(int f, cms_entry *entry, _DtCmsLogOps op)
180 {
181         CSA_return_code stat;
182         int     count;
183         char    *cptr, *tptr, *buf;
184         char    isotime[25];
185
186         if ((buf = malloc(100)) == NULL) return (CSA_E_INSUFFICIENT_MEMORY);
187
188         _csa_tick_to_iso8601(entry->key.time, isotime);
189         sprintf(buf, "(%s \"%s\" key: %ld%s",
190                 (op == _DtCmsLogAdd ? "add" : "remove"),
191                 isotime, entry->key.id,
192                 (op == _DtCmsLogAdd ? "\nhashedattributes: (" : ""));
193         count = strlen(buf) + 4;
194
195         if (op == _DtCmsLogAdd && entry->num_attrs > 0) {
196                 if ((cptr = attrs_to_attrliststr(entry->num_attrs,
197                     entry->attrs, B_TRUE, B_TRUE)) == NULL) {
198                         free(buf);
199                         return (CSA_E_INSUFFICIENT_MEMORY);
200                 }
201                 count += strlen(cptr);
202                 if ((tptr = grow_n_concat(buf, cptr, count)) == NULL) {
203                         free(cptr);
204                         free(buf);
205                         return (CSA_E_INSUFFICIENT_MEMORY);
206                 }
207                 free(cptr);
208                 buf = tptr;
209         }
210
211         /* closing for attr list and closing for entry */
212         if (op == _DtCmsLogAdd)
213                 strcat(buf, "))\n");
214         else
215                 strcat(buf, ")\n");
216
217         stat = append_log(f, buf);
218
219         free(buf);
220         return (stat);
221 }
222
223 extern CSA_return_code
224 _DtCmsAppendCalAttrsByFN(char *file, int size, cms_attribute * attrs)
225 {
226         int     f;
227         CSA_return_code stat;
228
229         if (file == NULL || size <= 0)
230                 return (CSA_E_INVALID_PARAMETER);
231
232         if ((f = open(file, O_WRONLY | O_APPEND | O_SYNC)) < 0) {
233                 perror(pgname);
234                 return (CSA_X_DT_E_BACKING_STORE_PROBLEM);
235         }
236
237         stat = _DtCmsAppendCalAttrsByFD(f, size, attrs);
238
239         close(f);
240         return (stat);
241 }
242
243 extern CSA_return_code
244 _DtCmsAppendCalAttrsByFD(int f, int size, cms_attribute * attrs)
245 {
246         CSA_return_code stat;
247         char    *buf, *attrstr;
248         char    *prefix = "(calendarattributes ";
249         char    *subfix = ")\n";
250         int     count;
251
252         if ((attrstr = attrs_to_attrliststr(size, attrs, B_FALSE, B_FALSE))
253             == NULL)
254                 return (CSA_E_INSUFFICIENT_MEMORY);
255
256         count = strlen(prefix) + strlen(attrstr) + strlen(subfix) + 1;
257         if ((buf = malloc(count)) == NULL) {
258                 free(attrstr);
259                 return (CSA_E_INSUFFICIENT_MEMORY);
260         }
261         sprintf(buf, "%s%s%s", prefix, attrstr, subfix);
262
263         stat = append_log(f, buf);
264
265         free(attrstr);
266         free(buf);
267         return (stat);
268 }
269
270 extern CSA_return_code
271 _DtCmsAppendAppt4ByFN(char *file, Appt_4 *appt, _DtCmsLogOps op)
272 {
273         int     f;
274         CSA_return_code stat;
275
276         if ((f = open(file, O_WRONLY | O_APPEND | O_SYNC)) < 0) {
277                 perror(pgname);
278                 return (CSA_X_DT_E_BACKING_STORE_PROBLEM);
279         }
280
281         stat = _DtCmsAppendAppt4ByFD(f, appt, op);
282
283         close(f);
284         return (stat);
285 }
286
287 extern CSA_return_code
288 _DtCmsAppendAppt4ByFD(int f, Appt_4 *appt, _DtCmsLogOps op)
289 {
290         char *cptr;
291         char tmpbuf[BUFSIZ];
292         char buf[BUFSIZ*3], buf2[BUFSIZ*2]; /* 1 BUFSIZ for what fields, 
293                                                1 BUFSIZ for mailto field,
294                                                and 1 BUFSIZ for the rest */
295
296         cptr = ctime (&appt->appt_id.tick);
297         cptr[24] = NULL;                /* strip off CR */
298
299         buf[0] = NULL;
300         switch (op) {
301         case _DtCmsLogAdd:
302                 sprintf(buf, "(add \"%s\" key: %ld ", cptr, appt->appt_id.key);
303                 if (appt->what) {
304                         cptr = cr_to_str(appt->what, strlen(appt->what));
305                         if (cptr != NULL) {
306                                 sprintf(buf2, "what: \"%s\" ", cptr);
307                                 strcat(buf, buf2);
308                                 free(cptr);
309                         } else {
310                                 return (CSA_E_INSUFFICIENT_MEMORY);
311                         }
312                 }
313                 if (appt->client_data) {
314                         sprintf(buf2, "details: \"%s\" ", appt->client_data);
315                         strcat(buf, buf2);
316                 }
317                 if (appt->duration) {
318                         sprintf(buf2, "duration: %d ", appt->duration);
319                         strcat(buf, buf2);
320                 }
321
322                 periodtostr (appt->period.period, tmpbuf);
323                 sprintf(buf2, "period: %s ", tmpbuf);
324                 strcat(buf, buf2);
325
326                 if (appt->period.nth != 0) {
327                         sprintf (buf2, "nth: %d ", appt->period.nth);
328                         strcat(buf, buf2);
329                 }
330                 if (appt->period.enddate != 0) {
331                         cptr = ctime (&(appt->period.enddate));
332                         cptr[24] = NULL; /* strip off CR */
333                         sprintf(buf2, "enddate: \"%s\" ", cptr);
334                         strcat(buf, buf2);
335                 }
336
337                 sprintf(buf2, "ntimes: %d ", appt->ntimes);
338                 strcat(buf, buf2);
339
340                 if (appt->exception != NULL) {
341                         struct Except_4 *e = appt->exception;
342                         strcat(buf, "exceptions: (");
343                         while(e != NULL) {
344                                 sprintf(buf2, "%d ", e->ordinal);
345                                 strcat(buf, buf2);
346                                 e = e->next;
347                         }
348                         strcat(buf, ") ");
349                 }
350
351                 if (appt->author != NULL) {
352                         sprintf(buf2, "author: \"%s\" ", appt->author);
353                         strcat(buf, buf2);
354                 }
355                 if (appt->attr != NULL) {
356                         struct Attribute_4 *item = appt->attr;
357                         strcat(buf, "attributes: (");
358                         while(item != NULL) {
359                                 sprintf(buf2, "(\"%s\",\"%s\",\"%s\")",
360                                         item->attr, item->value,
361                                         item->clientdata);
362                                 strcat(buf, buf2);
363                                 item = item->next;
364                         }
365                         strcat(buf, ") ");
366                 }
367                 if (appt->tag != NULL) {
368                         struct Tag_4 *item = appt->tag;
369                         strcat(buf, "tags: (");
370                         while(item != NULL) {
371                                 tagstostr(item->tag, tmpbuf);
372                                 sprintf(buf2, "(%s , %d)", tmpbuf,
373                                         item->showtime);
374                                 strcat(buf, buf2);
375                                 item = item->next;
376                         }
377                         strcat(buf, ") ");
378                 }
379
380                 apptstatustostr(appt->appt_status, tmpbuf);
381                 sprintf(buf2, "apptstat: %s ", tmpbuf);
382                 strcat(buf, buf2);
383
384                 privacytostr(appt->privacy, tmpbuf);
385                 sprintf(buf2, "privacy: %s )\n", tmpbuf);
386                 strcat(buf, buf2);
387
388                 break;    
389
390         case _DtCmsLogRemove:
391                 sprintf(buf, "(remove \"%s\" key: %ld)\n", cptr,
392                         appt->appt_id.key);
393                 break;
394         }
395
396         return (append_log(f, buf));
397 }
398
399 extern CSA_return_code
400 _DtCmsAppendAccessByFN(char *file, int type, Access_Entry_4 *p)
401 {
402         int     f;
403         CSA_return_code stat;
404
405         if ((f = open(file, O_WRONLY | O_APPEND | O_SYNC)) < 0) {
406                 perror(pgname);
407                 return (CSA_X_DT_E_BACKING_STORE_PROBLEM);
408         }
409
410         stat = _DtCmsAppendAccessByFD(f, type, p);
411
412         close(f);
413         return (stat);
414 }
415
416 extern CSA_return_code
417 _DtCmsAppendAccessByFD(int f, int type, Access_Entry_4 *p)
418 {
419         CSA_return_code stat;
420         int     count = 12; /* (access  )\n */
421         char    *p_type;
422         char    *buf;
423
424         if (type == access_read_4)
425                 p_type = "read";
426         else if (type == access_write_4)
427                 p_type = "write";
428         else if (type == access_delete_4)
429                 p_type = "delete";
430         else if (type == access_exec_4)
431                 p_type = "exec";
432         else
433                 return (CSA_E_INVALID_PARAMETER);
434
435         count = count + strlen(p_type);
436         if ((buf = malloc(count)) == NULL)
437                 return (CSA_E_INSUFFICIENT_MEMORY);
438
439         sprintf(buf, "(access %s ", p_type);
440
441         while(p != NULL) {
442                 if (p->who != NULL) {
443                         count = count + strlen(p->who) + 3;
444                         if ((buf = realloc(buf, count)) == NULL)
445                                 return (CSA_E_INSUFFICIENT_MEMORY);
446                         else {
447                                 strcat(buf, "\"");
448                                 strcat(buf, p->who);
449                                 strcat(buf, "\" ");
450                         }
451                 }
452                 p = p->next;
453         }
454         strcat(buf, ")\n");
455
456         stat = append_log(f, buf);
457
458         free(buf);
459         return(stat);
460 }
461
462 extern boolean_t
463 _DtCmsPrintAppt4(caddr_t data)
464 {
465         Appt_4 *appt = (Appt_4 *)data;
466         char *tmstr;
467         char buf[BUFSIZ];
468
469         fprintf(stderr, "*** V4 appointement: ***\n\n");
470
471         tmstr = ctime (&appt->appt_id.tick);
472         tmstr[24] = NULL;               /* strip off CR */
473
474         if (fprintf(stderr, "(add \"%s\" ", tmstr)==EOF) {
475                 return (B_TRUE);
476         }
477         if (fprintf(stderr, "key: %ld ", appt->appt_id.key)==EOF) {
478                 return (B_TRUE);
479         }
480         if (appt->what) {
481                 tmstr = cr_to_str(appt->what, strlen(appt->what));
482                 if (fprintf(stderr, "what: \"%s\" ", tmstr) == EOF) {
483                         free(tmstr);
484                         return (1);
485                 } else
486                         free(tmstr);
487         }
488         if (appt->client_data) {
489                 if (fprintf(stderr, "details: \"%s\" ", appt->client_data)
490                     == EOF)
491                         return (B_TRUE);
492         }
493         if (appt->duration) {
494                 if (fprintf(stderr, "duration: %d ", appt->duration) == EOF)
495                         return (B_TRUE);
496         }
497
498         buf[0]=NULL;  
499         periodtostr (appt->period.period, buf);
500         if (fprintf(stderr, "period: %s ", buf) == EOF)
501                 return (B_TRUE);
502
503         if (appt->period.nth != 0) {
504                 if (fprintf (stderr, "nth: %d ", appt->period.nth) == EOF)
505                         return (B_TRUE);
506         }
507         if (appt->period.enddate != 0) {
508                 tmstr = ctime (&(appt->period.enddate));
509                 tmstr[24] = NULL; /* strip off CR */
510                 if (fprintf(stderr, "enddate: \"%s\" ", tmstr) == EOF)
511                         return (B_TRUE);
512         }
513
514         if (fprintf(stderr, "ntimes: %d ", appt->ntimes) == EOF)
515                 return (B_TRUE);
516
517         if (appt->exception != NULL) {
518                 struct Except_4 *e = appt->exception;
519                 if (fprintf(stderr, "exceptions: (") == EOF)
520                         return (B_TRUE);
521                 while(e != NULL) {
522                         if (fprintf(stderr, "%d ", e->ordinal) == EOF)
523                                 return (B_TRUE);
524                         e = e->next;
525                 }
526                 if (fprintf(stderr, ") ") == EOF)
527                         return (B_TRUE);
528         }
529         if (appt->author != NULL) {
530                 if (fprintf(stderr, "author: \"%s\" ", appt->author) == EOF)
531                         return (B_TRUE);
532         }
533         if (appt->attr != NULL) {
534                 struct Attribute_4 *item = appt->attr;
535                 if (fprintf(stderr, "attributes: (") == EOF)
536                         return (B_TRUE);
537                 while(item != NULL) {
538                         if (fprintf(stderr, "(\"%s\",\"%s\",\"%s\")",
539                             item->attr, item->value, item->clientdata) == EOF)
540                                 return (B_TRUE);
541                         item = item->next;
542                 }
543                 if (fprintf(stderr, ") ") == EOF)
544                         return (B_TRUE);
545         }
546         if (appt->tag != NULL) {
547                 struct Tag_4 *item = appt->tag;
548                 if (fprintf(stderr, "tags: (") == EOF)
549                         return (B_TRUE);
550                 while(item != NULL) {
551                         buf[0]=NULL;
552                         tagstostr(item->tag, buf);
553                         if (fprintf(stderr, "(%s , %d)", buf, item->showtime)
554                             == EOF)
555                                 return (B_TRUE);
556                         item = item->next;
557                 }
558                 if (fprintf(stderr, ") ") == EOF)
559                         return (B_TRUE);
560         }
561
562
563         buf[0]=NULL;
564         apptstatustostr(appt->appt_status, buf);
565         if (fprintf(stderr, "apptstat: %s ", buf) == EOF)
566                 return (B_TRUE);
567
568         buf[0]=NULL;
569         privacytostr(appt->privacy, buf);
570         if (fprintf(stderr, "privacy: %s )\n", buf) == EOF)
571                 return (B_TRUE);
572
573         return (B_FALSE);
574 }
575
576 extern void
577 _DtCmsPrintExceptions(int len, int *exceptions)
578 {
579         int i;
580
581         fprintf(stderr, "\nexception part:\n");
582         fprintf(stderr, "number of exception = %d\n", len);
583         fprintf(stderr, "exceptions:");
584         for (i = 0; i < len; i++) {
585                 fprintf(stderr, " %d", exceptions[i]);
586         }
587         fprintf(stderr, "\n");
588 }
589
590 extern CSA_return_code
591 _DtCmsCreateLogV2(char *owner, char *file)
592 {
593         return (create_log(owner, file, _DtCMS_VERSION4));
594 }
595
596 extern CSA_return_code
597 _DtCmsGetFileSize(char *calendar, int *size)
598 {
599         char            *log;
600         struct stat     info;
601
602         if ((log = _DtCmsGetLogFN(calendar)) == NULL)
603                 return (CSA_E_INSUFFICIENT_MEMORY);
604
605         if (stat(log, &info) != 0) {
606                 free(log);
607                 return (CSA_X_DT_E_BACKING_STORE_PROBLEM);
608         } else {
609                 *size = info.st_size;
610                 free(log);
611                 return (CSA_SUCCESS);
612         }
613 }
614
615 extern void
616 _DtCmsTruncateFile(char *calendar, int size)
617 {
618         char    *log;
619         int     f;
620
621         if ((log = _DtCmsGetLogFN(calendar)) == NULL)
622                 return;
623
624         /* truncate log file to specified size */
625         if ((f = open(log, O_RDWR | O_APPEND | O_SYNC)) >= 0)
626                 ftruncate(f, size);
627
628         free(log);
629 }
630
631 extern CSA_return_code
632 _DtCmsRemoveLog(char *calendar, char *user)
633 {
634         CSA_return_code stat = CSA_SUCCESS;
635         char            *log, *dlog;
636
637         if ((log = _DtCmsGetLogFN(calendar)) == NULL)
638                 return (CSA_E_INSUFFICIENT_MEMORY);
639
640         if ((dlog = _DtCmsGetDelFN(calendar)) == NULL) {
641                 free(log);
642                 return (CSA_E_INSUFFICIENT_MEMORY);
643         }
644
645         if (rename(log, dlog) < 0)
646                 stat = CSA_X_DT_E_BACKING_STORE_PROBLEM;
647
648         free(log);
649         free(dlog);
650
651         return (stat);
652 }
653
654 extern CSA_return_code
655 _DtCmsWriteVersionString(char *file, int version)
656 {
657         struct  tm *tm;
658         time_t  tmval;
659         char    *tmstr;
660         int     fd, len;
661         char    buf[BUFSIZ];
662         CSA_return_code stat = CSA_SUCCESS;
663         _Xltimeparams   localtime_buf;
664         _Xatimeparams   asctime_buf;
665
666         tmval = time((time_t *) 0);
667         tm = _XLocaltime(&tmval, localtime_buf);
668         tmstr  = _XAsctime(tm, asctime_buf);
669         tmstr[24] = NULL;               /* strip off CR */
670
671         if ((fd = open(file, O_WRONLY|O_TRUNC|O_SYNC)) < 0) {
672                 if (debug)
673                         fprintf(stderr, "%s: failed to open %s in %s\n",
674                                 pgname, file, _DtCmsWriteVersionString);
675                 return (CSA_X_DT_E_BACKING_STORE_PROBLEM);
676         }
677
678         sprintf(buf, "Version: %d\n**** start of log on %s ****\n\n",
679                 version, tmstr);
680
681         len = strlen(buf);
682         if (write(fd, buf, len) != len) {
683                 perror(pgname);
684                 stat = CSA_X_DT_E_BACKING_STORE_PROBLEM;
685         }
686         close(fd);
687
688         return (stat);
689 }
690
691 /*
692  * if everything works fine, return 0; otherwise, return -1
693  */
694 extern int
695 _DtCmsSetFileMode(
696         char *file,
697         uid_t uid,
698         gid_t gid,
699         mode_t mode,
700         boolean_t changeeuid,
701         boolean_t printerr)
702 {
703         int     error;
704         char    buff[BUFSIZ];
705
706         if (changeeuid == B_TRUE) {
707 #ifndef AIX
708 #ifdef HPUX
709                 setuid (0);
710 #else
711                 seteuid (0);
712 #endif
713 #endif
714         }
715
716         if (chmod (file, mode) < 0) {
717                 if (printerr == B_TRUE) {
718                         error = errno;
719                         sprintf (buff, "%s: chmod %s to %lo failed.\n%s: System error",
720                                 pgname, file, (long)mode, pgname);
721                         errno = error;
722                         perror (buff);
723                 }
724                 return(-1);
725         }
726
727         if (chown (file, uid, gid) < 0) {
728                 if (printerr == B_TRUE) {
729                         error = errno;
730                         sprintf (buff, "%s: chown %s to (uid=%ld,gid=%ld) failed.\n%s%s",
731                                 pgname, file, (long)uid, (long)gid, pgname, ": System error");
732                         errno = error;
733                         perror (buff);
734                 }
735                 return(-1);
736         }
737
738 #ifndef AIX
739 #ifdef HPUX
740         if (changeeuid == B_TRUE && setuid (daemon_uid) < 0)
741 #else
742         if (changeeuid == B_TRUE && seteuid (daemon_uid) < 0)
743 #endif
744         {
745                 if (printerr == B_TRUE) {
746                         error = errno;
747                         sprintf (buff, "%s: Can't switch process uid back to daemon.\n%s%s",
748                                 pgname, pgname, ": System error");
749                         errno = error;
750                         perror (buff);
751                 }
752         }
753 #endif /* AIX */
754
755         return(0);
756 }
757
758 static void
759 periodtostr(Interval_4 i, char *q)
760 {
761         if (q==NULL) return;
762         q[0]=NULL;
763         switch (i) {
764                 case single_4:
765                         strcpy (q, "single");
766                         break;
767                 case daily_4:
768                         strcpy (q, "daily");
769                         break;
770                 case weekly_4:
771                         strcpy (q, "weekly");
772                         break;
773                 case biweekly_4:
774                         strcpy (q, "biweekly");
775                         break;
776                 case monthly_4:
777                         strcpy (q, "monthly");
778                         break;
779                 case yearly_4:
780                         strcpy (q, "yearly");
781                         break;
782                 case nthWeekday_4:
783                         strcpy (q, "nthWeekday");
784                         break;
785                 case everyNthDay_4:
786                         strcpy (q, "everyNthDay");
787                         break;
788                 case everyNthWeek_4:
789                         strcpy (q, "everyNthWeek");
790                         break;
791                 case everyNthMonth_4:
792                         strcpy (q, "everyNthMonth");
793                         break;
794                 case monThruFri_4:
795                         strcpy (q, "monThruFri");
796                         break;
797                 case monWedFri_4:
798                         strcpy (q, "monWedFri");
799                         break;
800                 case tueThur_4:
801                         strcpy (q, "tueThur");
802                         break;
803                 case daysOfWeek_4:
804                         strcpy (q, "daysOfWeek");
805                         break;
806                 default:
807                         strcpy (q, "single");
808                         break;
809         }
810 }
811
812 static void
813 privacytostr(Privacy_Level_4 p, char *q)
814 {
815         if (q==NULL) return;
816         q[0]=NULL;
817         switch(p) {
818         case public_4:
819                 strcpy(q, "public");
820                 break;
821         case private_4:
822                 strcpy(q, "private");
823                 break;
824         case semiprivate_4:
825                 strcpy(q, "semiprivate");
826                 break;
827         default:
828                 strcpy(q, "public");
829                 break;
830         }
831 }
832
833 static void
834 apptstatustostr(Appt_Status_4 p, char *q)
835 {
836         if (q==NULL) return;
837         q[0]=NULL;
838         switch(p) {
839         case active_4:
840                 strcpy(q, "active");
841                 break;
842         case pendingAdd_4:
843                 strcpy(q, "pendingAdd");
844                 break;
845         case pendingDelete_4:
846                 strcpy(q, "pendingDelete");
847                 break;
848         case committed_4:
849                 strcpy(q, "committed");
850                 break;
851         case cancelled_4:
852                 strcpy(q, "cancelled");
853                 break;
854         case completed_4:
855                 strcpy(q, "completed");
856                 break;
857         default:
858                 strcpy(q, "active");
859                 break;
860         }
861 }
862
863 static void
864 tagstostr(Event_Type_4 p, char *q)
865 {
866         if (q==NULL) return;
867         q[0]=NULL;
868         switch(p) {
869         case appointment_4:
870                 strcpy(q, "appointment");
871                 break;
872         case reminder_4:
873                 strcpy(q, "reminder");
874                 break;
875         case otherTag_4:
876                 strcpy(q, "otherTag");
877                 break;
878         case holiday_4:
879                 strcpy(q, "holiday");
880                 break;
881         case toDo_4:
882                 strcpy(q, "toDo");
883                 break;
884         default:
885                 strcpy(q, "appointment");
886                 break;
887         }
888 }
889
890 static char *
891 get_fname (char *dir, char *fname, char *who)
892 {
893         char *buf;
894
895         buf = (char *)malloc(strlen(dir) + strlen(fname) + strlen(who) + 3);
896         if (buf != NULL)
897                 sprintf (buf, "%s/%s.%s", dir, fname, who);
898         return (buf);
899 }
900
901 static CSA_return_code
902 create_log(char *owner, char *file, int version)
903 {
904         uid_t   uid;
905         struct  passwd *pw;
906         int     fd;
907         char    *ptr;
908         CSA_return_code stat;
909
910         ptr = strchr(owner, '@');
911         if (ptr) *ptr = NULL;
912         pw = getpwnam (owner);
913         if (ptr) *ptr = '@';
914         if (pw == NULL)
915                 return(CSA_E_FAILURE);
916         else
917                 uid = pw->pw_uid;
918
919         /* Read by owner and Read/Write by group (gid must be daemon) */
920         fd = open(file, O_WRONLY|O_CREAT|O_EXCL, _DtCMS_DEFAULT_MODE);
921         if (fd < 0) {
922                 if (debug)
923                         fprintf(stderr, "%s: can't create %s\n", pgname, file);
924
925                 if (errno == EEXIST)
926                         return(CSA_E_CALENDAR_EXISTS);
927                 else
928                         return(CSA_X_DT_E_BACKING_STORE_PROBLEM);
929         }
930
931         if (_DtCmsSetFileMode(file, uid, daemon_gid, _DtCMS_DEFAULT_MODE,
932             B_TRUE, B_TRUE) < 0) {
933                 close(fd);
934                 unlink(file);
935                 return(CSA_X_DT_E_BACKING_STORE_PROBLEM);
936         }
937         close(fd);
938
939         if ((stat = _DtCmsWriteVersionString(file, version)) != CSA_SUCCESS) {
940                 unlink(file);
941         }
942
943         return (stat);
944 }
945
946 static CSA_return_code
947 append_log(int f, char *buf)
948 {
949         CSA_return_code status;
950         struct stat finfo;
951         int file_size = 0, nbytes_written = 0, nbytes_towrite = 0;
952
953         if (buf == NULL)
954                 return (CSA_E_INVALID_PARAMETER);
955
956         if (fstat(f, &finfo) < 0) {
957                 perror(pgname);
958                 return (CSA_X_DT_E_BACKING_STORE_PROBLEM);
959         } else
960                 file_size = finfo.st_size;
961
962         nbytes_towrite = strlen(buf);
963         nbytes_written = write(f, buf, nbytes_towrite);
964         if (nbytes_written != nbytes_towrite) {
965                 if (errno == ENOSPC)
966                         status = CSA_E_DISK_FULL;
967                 else
968                         status = CSA_X_DT_E_BACKING_STORE_PROBLEM;
969
970                 perror(pgname);
971                 ftruncate(f, file_size);
972                 return (status);        
973         }
974
975         return(CSA_SUCCESS);
976 }
977
978 static char *
979 grow_n_concat(char *base, char *newstr, int newcount)
980 {
981         char *ptr;
982
983         if ((ptr = realloc(base, newcount)) == NULL)
984                 return (NULL);
985
986         if (base)
987                 strcat(ptr, newstr);
988         else
989                 strcpy(ptr, newstr);
990
991         return (ptr);
992 }
993
994 /*
995  * format of attributes:
996  * CSA_VALUE_BOOLEAN:           ("name","type","number")
997  * CSA_VALUE_ENUMERATED:        ("name","type","number")
998  * CSA_VALUE_FLAGS:             ("name","type","number")
999  * CSA_VALUE_SINT32:            ("name","type","number")
1000  * CSA_VALUE_UINT32:            ("name","type","number")
1001  * CSA_VALUE_STRING:            ("name","type","string")
1002  * CSA_VALUE_ACCESS_LIST:       ("name","type","user:rights [user:rights]")
1003  * CSA_VALUE_CALENDAR_USER:     ("name","type","string")
1004  * CSA_VALUE_DATE_TIME:         ("name","type","datetime")
1005  * CSA_VALUE_DATE_TIME_RANGE:   ("name","type","datetimerange")
1006  * CSA_VALUE_TIME_DURATION:     ("name","type","timeduration")
1007  * CSA_VALUE_DATE_TIME_LIST:    ("name","type","datetime [datetime]")
1008  * CSA_VALUE_REMINDER:          ("name","type","string:number:string") or
1009  *                              ("name","type","string:string:number:number:string")
1010  * CSA_VALUE_OPAQUE_DATA:       ("name","type","number:string")
1011  *
1012  * format of attributes (when only hashed number is written):
1013  * CSA_VALUE_BOOLEAN:           (hash_number "number")
1014  * CSA_VALUE_ENUMERATED:        (hash_number "number")
1015  * CSA_VALUE_FLAGS:             (hash_number "number")
1016  * CSA_VALUE_SINT32:            (hash_number "number")
1017  * CSA_VALUE_UINT32:            (hash_number "number")
1018  * CSA_VALUE_STRING:            (hash_number "string")
1019  * CSA_VALUE_ACCESS_LIST:       (hash_number "user:rights [user:rights]")
1020  * CSA_VALUE_CALENDAR_USER:     (hash_number "string")
1021  * CSA_VALUE_DATE_TIME:         (hash_number "datetime")
1022  * CSA_VALUE_DATE_TIME_RANGE:   (hash_number "datetimerange")
1023  * CSA_VALUE_TIME_DURATION:     (hash_number "timeduration")
1024  * CSA_VALUE_DATE_TIME_LIST:    (hash_number "datetime [datetime]")
1025  * CSA_VALUE_REMINDER:          (hash_number "string:number:string") or
1026  *                              (hash_number "string:string:number:number:string")
1027  * CSA_VALUE_OPAQUE_DATA:       (hash_number "number:string")
1028  *
1029  * Note: element 0 of the array is not used
1030  */
1031 static char *
1032 attrs_to_attrliststr(
1033         int             num_attr,
1034         cms_attribute   *attrs,
1035         boolean_t       write_hash,
1036         boolean_t       entryattrs)
1037 {
1038         int     i, count, tcount;
1039         char    *ptr, *buf = NULL;
1040         char    tmpbuf[BUFSIZ/2], tmpbuf2[BUFSIZ/2], *body;
1041         CSA_opaque_data *opq;
1042
1043         if ((buf = malloc(BUFSIZ+1)) == NULL) return (NULL);
1044         tcount = BUFSIZ;
1045
1046         for (i = 1, count = 0, *buf = NULL; i <= num_attr; i++) {
1047
1048                 if (attrs[i].value == NULL || (entryattrs &&
1049                     (i == CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I ||
1050                     i == CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I ||
1051                     i == CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I ||
1052                     i == CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I ||
1053                     i == CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I ||
1054                     i == CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I)))
1055                         continue;
1056
1057                 if (write_hash)
1058                         /* open_bracket hash_number open quote for value */
1059                         sprintf(tmpbuf, "(%d \"", attrs[i].name.num);
1060                 else
1061                         /* open bracket name, type, open quote for value */
1062                         sprintf(tmpbuf, "(\"%s\",\"%s\",\"", attrs[i].name.name,
1063                                 tag_string[attrs[i].value->type]);
1064
1065                 /* value string */
1066                 body = NULL;
1067                 *tmpbuf2 = NULL;
1068                 switch (attrs[i].value->type) {
1069                 case CSA_VALUE_ENUMERATED:
1070                 case CSA_VALUE_SINT32:
1071                         sprintf(tmpbuf2, "%ld",
1072                                 attrs[i].value->item.sint32_value);
1073                         break;
1074
1075                 case CSA_VALUE_BOOLEAN:
1076                 case CSA_VALUE_FLAGS:
1077                 case CSA_VALUE_UINT32:
1078                         sprintf(tmpbuf2, "%lu",
1079                                 attrs[i].value->item.uint32_value);
1080                         break;
1081
1082                 case CSA_VALUE_STRING:
1083                 case CSA_VALUE_DATE_TIME:
1084                 case CSA_VALUE_DATE_TIME_RANGE:
1085                 case CSA_VALUE_TIME_DURATION:
1086                 case CSA_VALUE_CALENDAR_USER:
1087                         if (attrs[i].value->item.string_value) {
1088                                 if ((ptr = cr_to_str(attrs[i].value->\
1089                                     item.string_value,
1090                                     strlen(attrs[i].value->item.string_value)))
1091                                     == NULL) {
1092                                         free(buf);
1093                                         return (NULL);
1094                                 }
1095                         } else
1096                                 ptr = NULL;
1097
1098                         body = ptr;
1099                         break;
1100
1101                 case CSA_VALUE_REMINDER:
1102                         opq = &attrs[i].value->item.reminder_value->\
1103                                 reminder_data;
1104                         if (attrs[i].value->item.reminder_value->repeat_count
1105                             > 1)
1106                         {
1107                             sprintf(tmpbuf2, "%s:%s:%lu:%lu:",
1108                                 attrs[i].value->item.reminder_value->lead_time,
1109                                 (attrs[i].value->item.reminder_value->snooze_time ?
1110                                 attrs[i].value->item.reminder_value->snooze_time:""),
1111                                 attrs[i].value->item.reminder_value->repeat_count,
1112                                 opq->size);
1113                         } else {
1114                             sprintf(tmpbuf2, "%s:%lu:",
1115                                 attrs[i].value->item.reminder_value->lead_time,
1116                                 opq->size);
1117                         }
1118
1119                         if (opq->size > 0) {
1120                                 if ((ptr = cr_to_str((char *)opq->data,
1121                                     opq->size)) == NULL) {
1122                                         free(buf);
1123                                         return (NULL);
1124                                 }
1125                         } else
1126                                 ptr = NULL;
1127                         body = ptr;
1128
1129                         break;
1130
1131                 case CSA_VALUE_OPAQUE_DATA:
1132                         opq = attrs[i].value->item.opaque_data_value;
1133                         sprintf(tmpbuf2, "%lu:", opq->size);
1134
1135                         if (opq->size > 0) {
1136                                 if ((ptr = cr_to_str((char *)opq->data,
1137                                     opq->size)) == NULL) {
1138                                         free(buf);
1139                                         return (NULL);
1140                                 }
1141                         } else
1142                                 ptr = NULL;
1143                         body = ptr;
1144                         break;
1145
1146                 case CSA_VALUE_ACCESS_LIST:
1147                         if (attrs[i].value->item.access_list_value) {
1148                                 if ((ptr = get_access_list_string(
1149                                     attrs[i].value->item.access_list_value))
1150                                     == NULL) {
1151                                         free(buf);
1152                                         return (NULL);
1153                                 }
1154                         } else
1155                                 ptr = NULL;
1156                         body = ptr;
1157                         break;
1158
1159                 case CSA_VALUE_DATE_TIME_LIST:
1160                         if (attrs[i].value->item.date_time_list_value) {
1161                                 if ((ptr = get_date_time_list_string(
1162                                     attrs[i].value->item.date_time_list_value))
1163                                     == NULL) {
1164                                         free(buf);
1165                                         return (NULL);
1166                                 }
1167                         } else
1168                                 ptr = NULL;
1169                         body = ptr;
1170                         break;
1171                 }
1172
1173                 count += strlen(tmpbuf) + strlen(tmpbuf2) +
1174                                 (body ? strlen(body) : 0) + 3; /* closing */
1175                 if (tcount < count) {
1176                         if ((ptr = realloc(buf, tcount+BUFSIZ)) == NULL) {
1177                                 if (body) free(body);
1178                                 free(buf);
1179                                 return NULL;
1180                         }
1181                         buf = ptr;
1182                         tcount += BUFSIZ;
1183                 }
1184                 strcat(buf, tmpbuf);
1185                 if (*tmpbuf2 != NULL) strcat(buf, tmpbuf2);
1186                 if (body) strcat(buf, body);
1187                 strcat(buf, "\")\n");
1188                 if (body) free(body);
1189         }
1190
1191         return (buf);
1192 }
1193
1194 static char *
1195 get_access_list_string(cms_access_entry *list)
1196 {
1197         char *ptr = NULL, *tptr, buf[BUFSIZ/4];
1198         int count, tcount;
1199
1200         /* do the first one */
1201         if ((ptr = malloc(BUFSIZ+1)) == NULL) return (NULL);
1202         tcount = BUFSIZ;
1203         sprintf(ptr, "%s:%u", list->user, list->rights);
1204         count = strlen(ptr);
1205
1206         while (list->next) {
1207                 list = list->next;
1208                 sprintf(buf, " %s:%u", list->user, list->rights);
1209
1210                 count += strlen(buf);
1211                 if (tcount < count) {
1212                         if ((tptr = grow_n_concat(ptr, buf, tcount+BUFSIZ))
1213                             == NULL) {
1214                                 free(ptr);
1215                                 return (NULL);
1216                         }
1217                         ptr = tptr;
1218                         tcount += BUFSIZ;
1219                 } else
1220                         strcat(ptr, buf);
1221         }
1222         return (ptr);
1223 }
1224
1225 static char *
1226 cr_to_str(char *s, int size)
1227 {
1228         int j, k;
1229         char *newstr;
1230
1231         if (s==NULL)
1232                 return(NULL);
1233
1234         if ((newstr = (char *) calloc(1, (unsigned)((2 * size) + 2))) == NULL)
1235                 return (NULL);
1236         k = 0;
1237         for (j=0; j<size; j++) {
1238                 if (s[j]=='\n') {
1239                         newstr[k] = '\\';
1240                         newstr[k+1] = 'n';
1241                         k+=2;
1242                 }
1243                 else if (s[j]=='\\') {
1244                         newstr[k] = '\\';
1245                         newstr[k+1] = '\\';
1246                         k+=2;
1247                 }
1248                 else if (s[j]=='\"') {
1249                         newstr[k] = '\\';
1250                         newstr[k+1] = '\"';
1251                         k+=2;
1252                 }
1253                 else {
1254                         newstr[k] = s[j];
1255                         k++;
1256                 }
1257         }
1258         newstr[k] = NULL;
1259         return(newstr);
1260 }
1261
1262 static char *
1263 get_date_time_list_string(CSA_date_time_list list)
1264 {
1265         char *ptr = NULL, *tptr, buf[80];
1266         int count, datestrlen, tcount;
1267
1268         /* do the first one */
1269         sprintf(buf, "%s", list->date_time);
1270         if ((ptr = strdup(buf)) == NULL)
1271                 return (NULL);
1272
1273         if ((ptr = malloc(BUFSIZ+1)) == NULL) return (NULL);
1274         tcount = BUFSIZ;
1275         strcpy(ptr, list->date_time);
1276         count = strlen(ptr);
1277
1278         datestrlen = count + 1;
1279         while (list->next) {
1280                 list = list->next;
1281                 sprintf(buf, " %s", list->date_time);
1282
1283                 count += datestrlen;
1284                 if (tcount < count) {
1285                         if ((tptr = grow_n_concat(ptr, buf, tcount+BUFSIZ))
1286                             == NULL) {
1287                                 free(ptr);
1288                                 return (NULL);
1289                         }
1290                         ptr = tptr;
1291                         tcount += BUFSIZ;
1292                 } else
1293                         strcat(ptr, buf);
1294         }
1295         return (ptr);
1296 }
1297