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