c68e603b0c1e81100c58da8d37ce5de7ee88c1c0
[oweals/cde.git] / cde / programs / dtcm / libDtCmP / util.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 libraries 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 /*******************************************************************************
24 **
25 **  util.c
26 **
27 **  $XConsortium: util.c /main/12 1996/11/21 19:44:40 drk $
28 **
29 **  RESTRICTED CONFIDENTIAL INFORMATION:
30 **
31 **  The information in this document is subject to special
32 **  restrictions in a confidential disclosure agreement between
33 **  HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34 **  document outside HP, IBM, Sun, USL, SCO, or Univel without
35 **  Sun's specific written approval.  This document and all copies
36 **  and derivative works thereof must be returned or destroyed at
37 **  Sun's request.
38 **
39 **  Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
40 **
41 *******************************************************************************/
42
43 /*                                                                      *
44  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
45  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
46  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
47  * (c) Copyright 1993, 1994 Novell, Inc.                                *
48  */
49
50 #ifndef lint
51 #endif
52
53 #include <EUSCompat.h>
54 #include <stdio.h>
55 #include <stdarg.h>
56 #include <stdlib.h>
57 #include <stdint.h>
58 #include <unistd.h>
59 #include <pwd.h> 
60 #include <netdb.h> 
61 #include <sys/utsname.h> /* SYS_NMLN */
62 #if defined(sun) || defined(USL) || defined(__uxp__)
63 #include <sys/systeminfo.h>
64 #else
65 #include <sys/dir.h>
66 #endif /* sun || USL || __uxp__ */
67 #include <sys/param.h>
68
69 #if (defined(USL) || defined(__uxp__)) && !defined(DOM_NM_LN)
70 #define DOM_NM_LN  BUFSIZ
71 #endif
72
73 #define X_INCLUDE_STRING_H
74 #define X_INCLUDE_TIME_H
75 #define XOS_USE_NO_LOCKING
76 #if defined(linux)
77 #undef SVR4
78 #endif
79 #include <X11/Xos_r.h>
80
81 #include <errno.h>
82 #ifdef X_NOT_STDC_ENV
83 extern int errno;
84 #endif
85
86 #include "util.h"
87 #include "cm_tty.h"
88
89 extern int _csa_tick_to_iso8601(time_t, char *);
90 extern int _csa_iso8601_to_tick(char *, time_t*);
91
92 extern FILE     *popen(const char *, const char *);
93 extern int      pclose(FILE *);
94
95 /*
96  *
97  *  Function:   cm_def_printer
98  *
99  *  Purpose:    get the default printer name for SVR4   
100  *
101  *  Parameters: none     
102  *
103  *  Returns:    char* (printer name)        
104  *
105  */
106 extern char*
107 cm_def_printer()
108 {
109         FILE *fp;
110         char message[257];
111         char *tmp=NULL;
112         char *printer_name=NULL;
113
114 #ifdef SVR4
115         tmp = (char*)getenv("LPDEST");
116         if (tmp != NULL && *tmp != NULL) {
117                 printer_name = (char*)malloc(strlen(tmp)+1);
118                 strcpy(printer_name, tmp);
119         }
120         else {
121         
122         /* This is really nasty.  lpstat -d does *not* work on the AIX
123            machines.  Just fall back to "lp" here */
124
125 #ifndef AIX
126                 _Xstrtokparams strtok_buf;
127
128                 fp = (FILE *)popen("lpstat -d", "r");
129                 fread(message, 256, 1, fp);
130                 tmp = (char *)_XStrtok(message, ":", strtok_buf);
131                 tmp = (char *)_XStrtok((char *)NULL, "\n", strtok_buf);
132                 if (tmp != NULL && *tmp != NULL) {
133                         printer_name = (char*)malloc(strlen(tmp)+1);
134                         strcpy(printer_name, tmp);
135                 }
136                 else {
137                         printer_name = (char*)malloc(3);
138                         strcpy(printer_name, "lp");
139                 }
140
141                 /* close the process connection */
142                 pclose(fp);
143 #else
144                 printer_name = (char*)malloc(3);
145                 strcpy(printer_name, "lp");
146 #endif
147         }
148 #else
149         tmp = (char*)getenv("PRINTER");
150         if (tmp != NULL && *tmp != '\0') {
151                 printer_name = (char*)malloc(strlen(tmp)+1);
152                 strcpy(printer_name, tmp);
153         }
154         else {
155                 printer_name = (char*)malloc(3);
156                 strcpy(printer_name, "lw");
157         }
158 #endif
159         return printer_name;
160 }
161
162 /*--------------------------------------------------------------------------
163  * THE FOLLOWING STRING FUNCTION redefinitions are a HACK !
164  * 
165  * The cm code should be changed so that
166  *   a) the redefined functions use the same headers as in <string.h>
167  *   b) no redefinition of these library function is necessary
168  *
169  * The cm definitions use different function headers than in <string.h>
170  * Prefixing the functions will get rid of the resulting compiler error.
171  * Now cm functions will use the cm_ string functions, but library functions, 
172  * e.g. fprintf, will use strlen etc. which leads to core dumps. 
173  * As part of the bootstrapping process, I am including the below redefinitions
174  * of the system functions. This should be fixed later.
175  * [vmh - 5/31/90]
176  *--------------------------------------------------------------------------*/
177
178 extern char *
179 cm_strcpy(register char *s1, register char *s2)
180 {
181         if (s1==NULL || s2==NULL) return(NULL);
182         strcpy(s1, s2); 
183         return (s1);
184 }
185
186 extern int 
187 cm_strlen(register char *s)
188 {
189         register int n;
190  
191         if (s==NULL) return 0;
192         return (strlen(s));
193 }
194
195 extern char *
196 cm_strdup (char *s1)
197 {
198         char *s2;
199         if (s1 == NULL) return NULL;
200         s2 = (char *) strdup(s1);
201         return (s2);
202 }
203
204 extern char *
205 cm_strcat(char *s1, char *s2)
206 {
207         if (s1==NULL || s2==NULL) return(s1);
208         strcat(s1, s2);
209         return s1;
210 }
211
212 /*      transform string patterns of \\ into \
213         \n into carriage returns and
214         \" into "       */
215
216 extern char *
217 str_to_cr(char *s)
218 {
219         int i, j, k;
220         char *newstr;
221
222         if (s==NULL) return(NULL);
223         i = cm_strlen(s);
224
225         newstr= (char *) ckalloc((unsigned)i + 1);
226         k = 0;
227         for (j=0; j<i; j++) {
228                 if (s[j]=='\\') {
229                         if (s[j+1]=='n') {
230                                 newstr[k] = '\n';
231                                 j++;
232                         }
233                         else if (s[j+1]=='\\') {
234                                 newstr[k] = '\\';
235                                 j++;
236                         }
237                         else if (s[j+1]=='\"') {
238                                 newstr[k] = '\"';
239                                 j++;
240                         }
241                         else {
242                                 newstr[k] = s[j];
243                         }
244                 }
245                 else {
246                         newstr[k] = s[j];
247                 }
248                 k++;
249         }
250         newstr[k] = '\0';
251         return(newstr);
252 }
253
254 /*      transform string patterns of \ into \\
255         carriage returns into \n, and
256         " into \"       */
257
258 extern char *
259 cr_to_str(char *s)
260 {
261         int i, j, k;
262         char *newstr;
263
264         if (s==NULL) return(NULL);
265         i = cm_strlen(s);
266
267         newstr = (char *) ckalloc((unsigned)((2 * i) + 1));
268         k = 0;
269         for (j=0; j<i; j++) {
270                 if (s[j]=='\n') {
271                         newstr[k] = '\\';
272                         newstr[k+1] = 'n';
273                         k+=2;
274                 }
275                 else if (s[j]=='\\') {
276                         newstr[k] = '\\';
277                         newstr[k+1] = '\\';
278                         k+=2;
279                 }
280                 else if (s[j]=='\"') {
281                         newstr[k] = '\\';
282                         newstr[k+1] = '\"';
283                         k+=2;
284                 }
285                 else {
286                         newstr[k] = s[j];
287                         k++;
288                 }
289         }
290         newstr[k] = '\0';
291         return(newstr);
292 }
293
294 /* VARARGS1 */
295 extern void
296 syserr(msg, a1, a2, a3)
297         char *msg;
298 {
299         /* Taken from Unix World, July 1989, p. 66 */
300         int saveerr;
301
302         /* save the error number so fprintf doesn't step on it */
303         saveerr = errno;
304
305         (void) fprintf(stderr, "cm: ");
306         /* print the actual message itself */
307         (void) fprintf(stderr, msg, a1, a2, a3);
308
309 #if 0
310         /* print the error, if any */
311         if (saveerr != 0) {
312                 if (saveerr < 0 || saveerr > sys_nerr) 
313                         (void) fprintf(stderr, ":Unknown error %d", saveerr);
314                 else 
315                         (void) fprintf(stderr, ":%s", sys_errlist[saveerr]);
316         }
317 #endif
318
319         /* thow a newline on the end */
320         (void) fprintf(stderr, "\n");
321
322         /* exit with an error */
323         if (saveerr==0)
324                 saveerr = -1;
325         exit(saveerr);
326 }
327
328
329 /*      Wrapper around standard storage allocation, to localize errors.
330         Taken from Unix World, July 1989, p. 66                         */
331 extern char *
332 ckalloc(unsigned int size)
333 {
334         register char *p;
335
336         /* try to get the memory */
337         p = (char *)calloc(1, size);
338
339         /* if it worked, return the memory directly */
340         if (p != NULL) return(p);
341
342         /* try allocation again */
343         p = (char *)calloc(1, size);
344
345         /* see if it worked the second time */
346         if (p != NULL) return(p);
347
348         /* no recovery available */
349         syserr("ckalloc: cannot allocate %d bytes", size, 0, 0);
350         return((char *)NULL);
351 }
352
353         
354 extern void
355 print_tick(Tick t)
356 {
357         char *a;
358         _Xctimeparams ctime_buf;
359  
360         a = _XCtime(&t, ctime_buf);
361         (void) fprintf (stderr, "%ld %s\n", (long)t, a);
362 }
363
364 int
365 min(int i1, int i2)
366 {
367         if (i1 > i2) return(i2);
368         if (i1 < i2) return(i1);
369         return(i1);
370 }
371
372 int
373 max(int i1, int i2)
374 {
375         if (i1 > i2) return(i1);
376         if (i1 < i2) return(i2);
377         return(i1);
378 }
379         
380 extern Lines *
381 text_to_lines(char *s, int n)
382 {
383         char *string, *line;
384         Lines *prev_l = NULL, *l = NULL, *head= NULL;
385         int i = 0;
386         char *_p;
387         int clen;
388
389         if (s == NULL || n <= 0) return NULL;
390
391         string = cm_strdup(s);
392         /*
393          * Here, look for \n, which is (in)famous character in IBM-932.
394          * Therefore, don't use strtok(). It is not i18n'ed.
395          */
396         for ( _p = string; *_p != '\0'; _p += clen ) {
397             clen = mblen( _p, MB_CUR_MAX );
398             if ( clen <= 0 ) {
399                 *_p = '\0';
400                 break;
401             }
402             if ( ( clen == 1 ) && ( *_p == '\n' ) ) {
403                 *_p = '\0';
404                 _p++;
405                 break;
406             }
407         }
408         line = string;
409         do {
410                 if (line == NULL) break;
411                 l = (Lines*)ckalloc(sizeof(Lines));
412                 if (head == NULL) head = l;
413                 if (prev_l != NULL) prev_l->next = l;
414                 l->s = cm_strdup(line);
415                 prev_l = l;
416                 i++;
417                 if ( ( *_p == '\0' ) || ( clen == -1 ) )
418                     break;
419                 line = _p;
420                 for ( ; *_p != '\0'; _p += clen ) {
421                     clen = mblen( _p, MB_CUR_MAX );
422                     if ( clen <= 0 ) {
423                         *_p = '\0';
424                         break;
425                     }
426                     if ( ( clen == 1 ) && ( *_p == '\n' ) ) {
427                         *_p = '\0';
428                         _p++;
429                         break;
430                     }
431                 }
432
433         } while (i < n);
434                 
435         free(string);
436         return head;
437 }
438  
439 extern void
440 destroy_lines(Lines *l)
441 {
442         Lines *p;
443
444         while (l != NULL) {
445                 free(l->s); l->s=NULL;
446                 p = l;
447                 l = l->next;
448                 free((char *)p); p=NULL;
449         }
450 }
451
452 /*
453  * Expand any escape characters in passed string
454  */
455 extern void
456 expand_esc_chars(char *string) {
457         char    *from, *to;
458
459         from = to = string;
460         while (from && *from) {
461                 int     len = mblen(from, MB_CUR_MAX);
462
463                 if (len <= 0) break; /* invalid char */
464                 if (len > 1) {  /* move over multibyte char */
465                         from += len;
466                         to += len;
467                         continue;
468                 }
469
470                 switch (*from++) {
471                 case '\\':
472                         switch (*from++) {
473                         case 'n':
474                                 *to++ = '\n';
475                                 break;
476                         case 't':
477                                 *to++ = '\t';
478                                 break;
479                         default:
480                                 *to++ = *(from-2);
481                                 *to++ = *(from-1);
482                                 break;
483                         }
484                         break;
485                 default:
486                         *to++ = *(from-1);
487                         break;
488                 }
489         }
490         *to = '\0';
491 }
492
493 extern char *
494 get_head(char *str, char sep)
495 {
496         static char buf[BUFSIZ];
497         char *ptr;
498
499         if (str == NULL)
500                 return(NULL);
501
502         ptr = buf;
503         while (*str && *str != sep)
504                 *ptr++ = *str++;
505         if (ptr == buf)
506                 return(NULL);
507         else {
508                 *ptr = '\0';
509                 return(cm_strdup(buf));
510         }
511 }
512
513 extern char *
514 get_tail(char *str, char sep)
515 {
516         char *ptr;
517  
518         if (str == NULL)
519                 return(NULL);
520  
521         while (*str && *str != sep)
522                 str++;
523         if (*str)
524                 return(cm_strdup(++str));
525         else
526                 return(NULL);
527 }
528
529 extern char *
530 cm_get_credentials()
531 {
532         char *name, *host;
533         static char *login = NULL;
534
535         if (login==NULL)
536         {
537                 name = (char*)cm_get_uname();
538                 host = (char*)cm_get_local_host();
539                 login = (char *) ckalloc (cm_strlen(name) + cm_strlen(host) + 2);
540                 sprintf(login, "%s@%s", name, host);
541         }
542         return (login);
543 }
544
545 extern char *
546 cm_get_local_host()
547 {
548         static char *local_host;
549
550         if (local_host == NULL) {
551 #if defined(sun) || defined(USL) || defined(__uxp__)
552                 local_host = (char *)ckalloc(MAXHOSTNAMELEN);
553                 (void) sysinfo(SI_HOSTNAME, local_host, MAXHOSTNAMELEN);
554 #else
555                 local_host = (char *)ckalloc(MAXHOSTNAMELEN);
556                 (void) gethostname(local_host, MAXHOSTNAMELEN);
557 #endif /* sun || USL || __uxp__ */
558         }
559         return local_host;
560 }
561
562 extern char *
563 cm_get_uname()
564 {
565         static char *name;
566         struct passwd *pw; 
567
568         if (name == NULL) {
569                 if ((pw = (struct passwd *)getpwuid(geteuid())) == NULL)
570                          name = (char *) cm_strdup("nobody");
571                 else
572                         name = (char *) cm_strdup(pw->pw_name);
573         }
574         return name;
575     
576 }
577
578 extern char *
579 cm_get_local_domain()
580 {
581         static char *local_domain;
582
583         if (local_domain == NULL) {
584                 local_domain = ckalloc(BUFSIZ);
585 #if defined(sun) || defined(USL) || defined(__uxp__)
586                 sysinfo(SI_SRPC_DOMAIN, local_domain, DOM_NM_LN);
587 #else
588                 if(-1 == getdomainname(local_domain, BUFSIZ)) {
589                         fprintf(stderr, "getdomainname() failed %d '%s'\n", errno, strerror(errno));
590                 }
591                 
592 #endif /* sun || USL || __uxp__ */
593         }
594         return(local_domain);
595 }
596
597 /* partially qualified target */
598 extern char*
599 cm_pqtarget(char *name)
600 {
601         char *host, *target=NULL;
602  
603         host = (char*)strchr(name, '@');
604         if (host == NULL) {
605                 host = (char*)cm_get_local_host();
606                 target = (char *)ckalloc(cm_strlen(name) +
607                                 cm_strlen(host) + 2);
608                 sprintf(target, "%s@%s", name, host);
609         }
610         else
611                 target = (char *) cm_strdup(name);
612  
613         return target;
614 }
615 /*
616  * calendar_name@host[.domain] -> calendar_name
617  */
618 extern char *
619 cm_target2name(char *target)
620 {
621         return(get_head(target, '@'));
622 }
623  
624 /*
625  * calendar_name@host[.domain] -> host[.domain]
626  */
627 extern char *
628 cm_target2location(char *target)
629 {
630         return(get_tail(target, '@'));
631 }
632  
633 /*
634  * calendar_name@host[.domain] -> host
635  */
636 extern char *
637 cm_target2host(char *target)
638 {
639         char *location, *host;
640  
641         location = get_tail(target, '@');
642         if (location != NULL) {
643                 host = get_head(location, '.');
644                 free(location);
645                 return(host);
646         } else
647                 return(NULL);
648 }
649 /*
650  * calendar_name@host[.domain] -> domain
651  */
652 extern char *
653 cm_target2domain(char *target)
654 {
655         char *location, *domain;
656  
657         location = get_tail(target, '@');
658         if (location != NULL) {
659                 domain = get_tail(location, '.');
660                 free(location);
661                 return(domain);
662         } else
663                 return(NULL);
664 }
665
666 /*
667  * str consists of components separated by token
668  * get and copy the first component into comp and
669  * strip it out of str, so str would point to the first
670  * token or the null terminator.
671  */
672 static void
673 get_component(char **str, char *comp, char token)
674 {
675         char *ptr;
676
677         *comp = 0;
678
679         if (str == NULL)
680                 return;
681         else
682                 ptr = *str;
683
684         while (ptr && *ptr != 0 && *ptr != token)
685                 *comp++ = *ptr++;
686
687         *str = ptr;
688
689         *comp = 0;
690 }
691
692 /*
693  * head and tail points to the first and last character
694  * of a string which consists of components separated by token.
695  * get and copy the last component into comp and
696  * strip it out of the string, so tail would point to the last
697  * token or the head of the string.
698  */
699 static void
700 get_last_component(char *head, char **tail, char *comp, char token)
701 {
702         char *ptr, *cptr;
703
704         *comp = 0;
705
706         if (tail == NULL)
707                 return;
708         else
709                 cptr = *tail;
710
711         while (cptr != head && *cptr != token)
712                 cptr--;
713
714         if (*cptr == token)
715                 ptr = cptr + 1;
716         else
717                 ptr = cptr;
718
719         while (ptr != (*tail + 1))
720                 *comp++ = *ptr++;
721
722         *tail = cptr;
723
724         *comp = 0;
725 }
726
727 static boolean_t
728 match_forward(char *str1, char *str2)
729 {
730         char com1[BUFSIZ], com2[BUFSIZ];
731
732         if (str1 == NULL || str2 == NULL)
733                 return (B_FALSE);
734
735         while (B_TRUE) {
736                 get_component(&str1, com1, '.');
737                 get_component(&str2, com2, '.');
738
739                 if (*com1) {
740                         if (*com2 == '\0')
741                                 return (B_TRUE);
742                 } else {
743                         if (*com2 == '\0')
744                                 return (B_TRUE);
745                         else
746                                 return (B_FALSE);
747                 }
748
749                 if (strcasecmp(com1, com2) != 0)
750                         return (B_FALSE);
751
752                 /* take care of case: a.b a. */
753                 if (strcmp(str2, ".") == 0
754                     && (strcmp(str1, ".") != 0 || *str1 != '\0'))
755                         return (B_FALSE);
756
757                 /* skip "." */
758                 if (*str1 == '.') {
759                         if (*str2 == '\0')
760                                 return (B_TRUE);
761                         else {
762                                 str1++;
763                                 str2++;
764                         }
765                 } else if (strcmp(str2, ".") == 0 || *str2 == '\0')
766                         return (B_TRUE);
767                 else
768                         return (B_FALSE);
769         }
770 }
771
772 static boolean_t
773 match_backward(char *str1, char *str2)
774 {
775         int len1, len2;
776         char *ptr1, *ptr2;
777         char com1[BUFSIZ], com2[BUFSIZ];
778
779         if (str1 == NULL || str2 == NULL)
780                 return (B_FALSE);
781
782         len1 = strlen(str1);
783         len2 = strlen(str2);
784         if (len2 > len1)
785                 return (B_FALSE);
786         else if (len2 == 0)
787                 return (B_TRUE);
788
789         ptr1 = (len1 ? (str1 + len1 - 1) : str1);
790         ptr2 = (len2 ? (str2 + len2 - 1) : str2);
791
792         if (*ptr1 == '.' && ptr1 != str1)
793                 ptr1--;
794
795         if (*ptr2 == '.' && ptr2 != str2)
796                 ptr2--;
797
798         while (B_TRUE) {
799                 get_last_component(str1, &ptr1, com1, '.');
800                 get_last_component(str2, &ptr2, com2, '.');
801
802                 if (*com1) {
803                         if (*com2 == '\0')
804                                 return (B_TRUE);
805                 } else {
806                         if (*com2 == '\0')
807                                 return (B_TRUE);
808                         else
809                                 return (B_FALSE);
810                 }
811
812                 if (strcasecmp(com1, com2) != 0)
813                         return (B_FALSE);
814
815                 /* skip "." */
816                 if (*ptr1 == '.') {
817                         if (ptr1 != str1)
818                                 ptr1--;
819                         else
820                                 return (B_FALSE); /* bad format */
821                 } else
822                         return (B_TRUE); /* done */
823
824                 if (*ptr2 == '.') {
825                         if (ptr2 != str2)
826                                 ptr2--;
827                         else
828                                 return (B_FALSE); /* bad format */
829                 } else
830                         return (B_TRUE); /* done */
831         }
832 }
833
834 /*
835  * Correct format assumed, i.e. str = label1[.label2 ...]
836  * Compare str2 against str1 which should be more fully qualified than str2
837  */
838 extern boolean_t
839 same_path(char *str1, char *str2)
840 {
841         char *ptr1,*ptr2;
842         char *user;
843         int res, n;
844
845         if (str1 == NULL || str2 == NULL)
846                 return(B_FALSE);
847
848         /* check format */
849         if (*str1 == '.' || *str2 == '.')
850                 return (B_FALSE); /* bad format */
851
852         if (match_forward(str1, str2) == B_TRUE)
853                 return (B_TRUE);
854         else
855                 return (match_backward(str1, str2));
856 }
857
858 /*
859  * compare user1 and user2
860  * user1 = user@host[.domain]
861  * user2 = any format in (user, user@host[.domain], user@domain)
862  */
863 extern boolean_t
864 same_user(char *user1, char *user2)
865 {
866         char *str1, *str2;
867         char *host, *domain;
868         char buf[BUFSIZ];
869         boolean_t res;
870
871         if (user1 == NULL || user2 == NULL)
872                 return B_FALSE;
873
874         /* compare user name */
875         str1 = get_head(user1, '@');
876         str2 = get_head(user2, '@');
877
878         if (str1 == NULL || str2 == NULL)
879                 return(B_FALSE);
880
881         if (strcmp(str1, str2)) {
882                 free(str1);
883                 free(str2);
884                 return(B_FALSE);
885         }
886         free(str1);
887         free(str2);
888
889         /* if only user name is specified, don't need to check domain */
890         str2 = strchr(user2, '@');
891         if (str2 == NULL)
892                 return(B_TRUE);
893
894         /* first assume user2=user@domain */
895         str1 = strchr(user1, '.');
896         if (str1 == NULL) {
897                 if (same_path(cm_get_local_domain(), ++str2))
898                         return(B_TRUE);
899         } else {
900                 if (same_path(++str1, ++str2))
901                         return(B_TRUE);
902         }
903
904         /* assume user2=user@host[.domain] */
905         if (str1 == NULL) {
906                 str1 = strchr(user1, '@');
907                 sprintf(buf, "%s.%s", ++str1, cm_get_local_domain());
908                 str1 = buf;
909         } else {
910                 str1 = strchr(user1, '@');
911                 str1++;
912         }
913
914         if (same_path(str1, str2))
915                 return(B_TRUE);
916         else
917                 return(B_FALSE);
918 }
919
920 /*
921  * A blank line is one that consists of only \b, \t or \n.
922  */
923 extern int
924 blank_buf(char *buf)
925 {
926         char *ptr = buf;
927
928         if (ptr == NULL) return B_TRUE;
929         while (ptr && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n'))
930                 ptr++;
931         if (*ptr == '\0')
932                 return B_TRUE;
933         else
934                 return B_FALSE;
935 }
936
937 extern int
938 embedded_blank(char *buf)
939 {
940         char *ptr = buf;
941  
942         if (ptr == NULL) return B_TRUE;
943         while (ptr && *ptr) {
944                 if ((*ptr == ' ') || (*ptr == '\t'))
945                         return B_TRUE;
946                 *ptr++;
947         }
948  
949         return B_FALSE;
950 }
951
952 extern int
953 get_data_version(CSA_session_handle session) {
954         int             ver = 0;
955         Dtcm_calendar   *c;
956         CSA_attribute_reference names[1];
957         CSA_uint32      number_attrs_returned;
958         CSA_attribute   *attrs_returned;
959
960         names[0] = CSA_X_DT_CAL_ATTR_DATA_VERSION;
961
962
963         if (csa_read_calendar_attributes(session, 
964                                          1, 
965                                          names, 
966                                          &number_attrs_returned, 
967                                          &attrs_returned, 
968                                          NULL) == CSA_SUCCESS) {
969                 ver = attrs_returned[0].value->item.uint32_value;
970                 csa_free(attrs_returned);
971         }
972
973         return ver;
974 }
975
976 extern int
977 get_server_version(CSA_session_handle session) {
978         int             ver = 0;
979         Dtcm_calendar   *c;
980         CSA_attribute_reference names[1];
981         CSA_uint32      number_attrs_returned;
982         CSA_attribute   *attrs_returned;
983
984         names[0] = CSA_X_DT_CAL_ATTR_SERVER_VERSION;
985
986         if (csa_read_calendar_attributes(session, 
987                                          1, 
988                                          names, 
989                                          &number_attrs_returned, 
990                                          &attrs_returned, 
991                                          NULL) == CSA_SUCCESS) {
992                 ver = attrs_returned[0].value->item.uint32_value;
993                 csa_free(attrs_returned);
994         }
995
996         return ver;
997 }
998
999 extern CSA_sint32
1000 privacy_set(Dtcm_appointment *appt) {
1001
1002         CSA_sint32      privacy = CSA_CLASS_PUBLIC;
1003
1004         if (!appt)
1005                 return(privacy);
1006
1007         if (!appt->private)
1008                 return(privacy);
1009
1010         if (!appt->private->value)
1011                 return(privacy);
1012
1013         privacy = appt->private->value->item.sint32_value;
1014         return(privacy);
1015
1016 }
1017
1018 extern CSA_sint32
1019 showtime_set(Dtcm_appointment *appt) {
1020  
1021         CSA_sint32      showtime = 0;
1022  
1023         if (!appt)
1024                 return(showtime);
1025  
1026         if (!appt->show_time)
1027                 return(showtime);
1028  
1029         if (!appt->show_time->value)
1030                 return(showtime);
1031  
1032         showtime = appt->show_time->value->item.sint32_value;
1033         return(showtime);
1034  
1035 }
1036
1037 /*
1038 **  Parse the date string and get the month, day, and year
1039 */
1040 extern int
1041 parse_date(OrderingType order, SeparatorType sep, char *datestr, char *m,
1042         char *d, char *y) {
1043  
1044         char *first, *second, *third;
1045         char *tmp_date, *str = separator_str(sep);
1046         _Xstrtokparams strtok_buf;
1047  
1048         m[0] = '\0';
1049         d[0] = '\0';
1050         y[0] = '\0';
1051  
1052         if (datestr == NULL)
1053                 return 0;
1054  
1055         tmp_date = cm_strdup(datestr);
1056         first = _XStrtok(tmp_date, str, strtok_buf);
1057                 /*
1058                 ** Check to see if the date entered has legit separator
1059                 */
1060                 if ( strcoll(first, datestr) == 0 ) {
1061                         free(tmp_date);
1062                         return 0;
1063                 }
1064         second = _XStrtok(NULL, str, strtok_buf);
1065         third = _XStrtok(NULL, str, strtok_buf);
1066  
1067         switch (order) {
1068         case ORDER_DMY:
1069                 if (second)
1070                         cm_strcpy(m, second);
1071                 if (first)
1072                         cm_strcpy(d, first);
1073                 if (third)
1074                         cm_strcpy(y, third);
1075                 break;
1076         case ORDER_YMD:
1077                 if (second)
1078                         cm_strcpy(m, second);
1079                 if (third)
1080                         cm_strcpy(d, third);
1081                 if (first)
1082                         cm_strcpy(y, first);
1083                 break;
1084         case ORDER_MDY:
1085         default:
1086                 if (first)
1087                         cm_strcpy(m, first);
1088                 if (second)
1089                         cm_strcpy(d, second);
1090                 if (third)
1091                         cm_strcpy(y, third);
1092                 break;
1093         }
1094         free(tmp_date);
1095                 return 1;
1096 }
1097
1098 /*
1099 **  Reformat the date string into m/d/y format and write it into the buffer
1100 */
1101 extern int
1102 datestr2mdy(char *datestr, OrderingType order, SeparatorType sep, char *buf) {
1103         char m[3], d[3], y[5];
1104  
1105         buf[0] = '\0';
1106         if (datestr == NULL)
1107                 return 0;
1108  
1109         if (order == ORDER_MDY && sep == SEPARATOR_SLASH)
1110                 cm_strcpy(buf, datestr);
1111         else {
1112                 if ( parse_date(order, sep, datestr, m, d, y) ) {
1113                         sprintf(buf, "%s/%s/%s", m, d, y);
1114                 } else {
1115                         return 0;
1116                 }
1117  
1118         }
1119         return 1;
1120 }
1121
1122 /*
1123 **  Format the date according to display property and write it into buffer
1124 */
1125 extern void
1126 format_tick(Tick tick, OrderingType order, SeparatorType sep, char *buff) {
1127         char            *str = separator_str(sep);
1128         struct tm       *tm;
1129         _Xltimeparams   localtime_buf;
1130  
1131         buff[0] = '\0';
1132         tm = _XLocaltime(&tick, localtime_buf);
1133  
1134         switch (order) {
1135         case ORDER_DMY:
1136                 sprintf(buff, "%d%s%d%s%d", tm->tm_mday, str,
1137                         tm->tm_mon+1, str, tm->tm_year+1900);
1138                 break;
1139         case ORDER_YMD:
1140                 sprintf(buff, "%d%s%d%s%d", tm->tm_year+1900, str,
1141                         tm->tm_mon+1, str, tm->tm_mday);
1142                 break;
1143         case ORDER_MDY:
1144         default:
1145                 sprintf(buff, "%d%s%d%s%d", tm->tm_mon+1, str,
1146                         tm->tm_mday, str, tm->tm_year+1900);
1147                 break;
1148         }
1149 }
1150
1151 extern void
1152 format_time(Tick t, DisplayType dt, char *buffer) {
1153         int             hr = hour(t);
1154         boolean_t       am;
1155
1156         if (t == 0) {
1157                 buffer[0] = '\0';
1158
1159         } else if (dt == HOUR12) {
1160                 am = adjust_hour(&hr);
1161                 sprintf(buffer, "%2d:%02d%s",
1162                         hr, minute(t), (am) ? "am" : "pm");
1163         } else
1164                 sprintf(buffer, "%02d%02d", hr, minute(t));
1165 }
1166
1167 /*
1168  * The V5 back end uses arrays to pass attributes back and forth.  However,
1169  * keeping hard coded references into those arrays (i.e. declaring the tick
1170  * value will always be into position 0 of the array, the what value in
1171  * position 3, etc.) is a bad idea and hard to maintain.
1172  *
1173  * Thus these convenience functions will translate from an attribute array
1174  * received from the back end into defined structure which the front end can
1175  * use.
1176  *
1177  * IF YOU UPDATE THE STRUCTURES, MAKE SURE YOU UPDATE THESE COUNT CONSTANTS!!
1178  */
1179 static const int APPT_ATTR_COUNT = 35;
1180 static const int RW_APPT_ATTR_COUNT = 15;
1181 static const int CAL_ATTR_COUNT = 12;
1182 static const int RW_CAL_ATTR_COUNT = 2;
1183 static const int DEF_V5_APPT_ATTR_COUNT = 22;
1184 static const int DEF_V4_APPT_ATTR_COUNT = 20;
1185 static const int DEF_V3_APPT_ATTR_COUNT = 17;
1186 static const int DEF_CAL_ATTR_COUNT = 6;
1187 static const int default_appt_attrs[] = {CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I,
1188                         CSA_ENTRY_ATTR_LAST_UPDATE_I,
1189                         CSA_ENTRY_ATTR_ORGANIZER_I,
1190                         CSA_ENTRY_ATTR_START_DATE_I,
1191                         CSA_ENTRY_ATTR_TYPE_I,
1192                         CSA_ENTRY_ATTR_SUBTYPE_I,
1193                         CSA_ENTRY_ATTR_CLASSIFICATION_I,
1194                         CSA_ENTRY_ATTR_END_DATE_I,
1195                         CSA_X_DT_ENTRY_ATTR_SHOWTIME_I,
1196                         CSA_ENTRY_ATTR_SUMMARY_I,
1197                         CSA_ENTRY_ATTR_STATUS_I,
1198                         CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I,
1199                         CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I,
1200                         CSA_ENTRY_ATTR_AUDIO_REMINDER_I,
1201                         CSA_ENTRY_ATTR_FLASHING_REMINDER_I,
1202                         CSA_ENTRY_ATTR_MAIL_REMINDER_I,
1203                         CSA_ENTRY_ATTR_POPUP_REMINDER_I,
1204                         CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I,
1205                         CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I,
1206                         CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I,
1207                         CSA_ENTRY_ATTR_RECURRENCE_RULE_I,
1208                         CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I
1209                         };
1210 static const int default_cal_attrs[] = {CSA_CAL_ATTR_ACCESS_LIST_I,
1211                                         CSA_CAL_ATTR_CALENDAR_NAME_I,
1212                                         CSA_CAL_ATTR_CALENDAR_SIZE_I,
1213                                         CSA_CAL_ATTR_NUMBER_ENTRIES_I,
1214                                         CSA_CAL_ATTR_TIME_ZONE_I,
1215                                         CSA_X_DT_CAL_ATTR_DATA_VERSION_I
1216                                         };
1217
1218 /*
1219  * NOTE that this loop is dependent on the first appointment attribute define
1220  * (DT_CM_ATTR_IDENTIFER_I) in the api - if that is changed and is no longer
1221  * the first appointment define, this needs to be changed.
1222  *
1223  * NOTE that this function checks if the api indexes specified are read-only:
1224  * This assumes that if you need value space (and have set the need_value_space
1225  * flag to B_TRUE), you're setting attributes and since you can't set read-only
1226  * attributes, it will ignore read-only attributes if the need_value_space flag
1227  * is B_TRUE.
1228  */
1229 Dtcm_appointment *allocate_appt_struct (Allocation_reason reason, int version, ...) {
1230         int                     idx = 0, api_idx;
1231         va_list                 pvar;
1232         CmDataList              *api_ids = CmDataListCreate();
1233         Dtcm_appointment        *appt;
1234         int                     def_attr_count;
1235
1236         /*
1237          * The Dtcm_appointment wrapper array
1238          */
1239         idx = sizeof(Dtcm_appointment);
1240         appt = (Dtcm_appointment *)ckalloc(idx);
1241         memset(appt, 0, idx);
1242         appt->reason = reason;
1243         appt->version = version;
1244
1245         /*
1246          * Step through the variable argument list and build the list of
1247          * attributes we're looking for
1248          */
1249         va_start(pvar, version);
1250         api_idx = va_arg(pvar, int);
1251         while (api_idx) {
1252                 if ((reason == appt_read) || !entry_ident_index_ro(api_idx, version))
1253                         CmDataListAdd(api_ids, (void *) (intptr_t) api_idx, 0);
1254                 api_idx = va_arg(pvar, int);
1255         }
1256         va_end(pvar);
1257
1258         /*
1259          * No attributes specified, assume the caller wanted all of them
1260          */
1261         if (api_ids->count <= 0) {
1262
1263                 if ((version == DATAVER2) || (version == DATAVER1))
1264                         def_attr_count = DEF_V3_APPT_ATTR_COUNT;
1265                 else if (version == DATAVER3)
1266                         def_attr_count = DEF_V4_APPT_ATTR_COUNT;
1267                 else if (version == DATAVER4)
1268                         def_attr_count = DEF_V5_APPT_ATTR_COUNT;
1269                 else if (version == DATAVER_ARCHIVE)
1270                         def_attr_count = DEF_V5_APPT_ATTR_COUNT;
1271
1272                 for (idx = 0; idx < def_attr_count; idx++) {
1273                         if ((reason == appt_write) && entry_ident_index_ro(default_appt_attrs[idx], version))
1274                                 continue;
1275                         CmDataListAdd(api_ids, (void *) (intptr_t) default_appt_attrs[idx], 0);
1276                 }
1277         }
1278
1279         /*
1280          * We've determined the number of attributes we're retrieving, so
1281          * allocate the name array, and the attribute array (if we are 
1282          * going to be writing attributes).
1283          */
1284
1285         appt->num_names = api_ids->count;
1286         idx = sizeof(CSA_attribute_reference *) * appt->num_names;
1287         appt->names = (CSA_attribute_reference *)ckalloc(idx);
1288         memset(appt->names, 0, idx);
1289
1290         appt->count = api_ids->count;
1291         if (reason == appt_write) {
1292                 idx = sizeof(CSA_attribute) * appt->count;
1293                 appt->attrs = (CSA_attribute *)ckalloc(idx);
1294                 memset(appt->attrs, 0, idx);
1295         }
1296
1297         /*
1298          * Now loop through and set the names and initialize the attributes
1299          */
1300         for (idx = 0; idx < appt->count; idx++) {
1301                 api_idx = (int) (intptr_t) CmDataListGetData(api_ids, idx + 1);
1302                 appt->names[idx] = strdup(_CSA_entry_attribute_names[api_idx]);
1303                 if (reason == appt_write)
1304                         initialize_entry_attr(api_idx, &appt->attrs[idx], reason, version);
1305         }
1306
1307         if (reason == appt_write)
1308                 set_appt_links(appt);
1309
1310         CmDataListDestroy(api_ids, 0);
1311         return appt;
1312 }
1313
1314 CSA_return_code
1315 query_appt_struct(CSA_session_handle session, 
1316                   CSA_entry_handle entry_handle, 
1317                   Dtcm_appointment *appt) {
1318
1319         CSA_return_code         status;
1320
1321         /* if there is old query material laying around, toss it */
1322
1323         if (appt->filled) {
1324                 csa_free(appt->attrs);
1325                 appt->filled = False;
1326         }
1327
1328
1329         if ((status = csa_read_entry_attributes(session, 
1330                                          entry_handle, 
1331                                          appt->num_names, 
1332                                          appt->names, 
1333                                          &appt->count, 
1334                                          &appt->attrs, 
1335                                          NULL)) == CSA_SUCCESS) {
1336                 set_appt_links(appt);
1337                 appt->filled = True;
1338         }
1339
1340         return(status);
1341 }
1342
1343
1344 /*
1345  * NOTE that this function checks if the api indexes specified are read-only:
1346  * This assumes that if you need value space (and have set the need_value_space
1347  * flag to B_TRUE), you're setting attributes and since you can't set read-only
1348  * attributes, it will ignore read-only attributes if the need_value_space flag
1349  * is B_TRUE.
1350  */
1351 Dtcm_calendar*
1352 allocate_cal_struct(Allocation_reason reason, int version, ...) {
1353         int             idx = 0, api_idx;
1354         va_list         pvar;
1355         CmDataList      *api_ids = CmDataListCreate();
1356         Dtcm_calendar   *cal;
1357
1358         /*
1359          * The Dtcm_apopintment wrapper array
1360          */
1361         idx = sizeof(Dtcm_calendar);
1362         cal = (Dtcm_calendar *)ckalloc(idx);
1363         memset(cal, 0, idx);
1364         cal->reason = reason;
1365         cal->version = version;
1366
1367         /*
1368          * Step through the variable argument list and build the list of
1369          * attributes we're looking for
1370          */
1371         va_start(pvar, version);
1372         api_idx = va_arg(pvar, int);
1373         while (api_idx) {
1374                 if ((reason == appt_read) || !cal_ident_index_ro(api_idx, version))
1375                         CmDataListAdd(api_ids, (void *) (intptr_t) api_idx, 0);
1376                 api_idx = va_arg(pvar, int);
1377         }
1378         va_end(pvar);
1379
1380         /*
1381          * No attributes specified, assume the caller wanted all of them
1382          */
1383         if (api_ids->count <= 0) {
1384                 for (idx = 0; idx < DEF_CAL_ATTR_COUNT; idx++) {
1385                         if ((reason == appt_write) && cal_ident_index_ro(default_cal_attrs[idx], version))
1386                                 continue;
1387                         CmDataListAdd(api_ids, (void *) (intptr_t) default_cal_attrs[idx], 0);
1388                 }
1389         }
1390
1391         /*
1392          * We've determined the number of attributes we're retrieving, so
1393          * allocate the name arrya, and the attribute array (if we are 
1394          * going to be writing attributes).
1395          */
1396
1397         cal->num_names = api_ids->count;
1398         idx = sizeof(CSA_attribute_reference) * cal->num_names;
1399         cal->names = (CSA_attribute_reference *)ckalloc(idx);
1400         memset(cal->names, 0, idx);
1401
1402         cal->count = api_ids->count;
1403         if (reason == appt_write) {
1404                 idx = sizeof(CSA_attribute) * cal->count;
1405                 cal->attrs = (CSA_attribute *)ckalloc(idx);
1406                 memset(cal->attrs, 0, idx);
1407         }
1408
1409         /*
1410          * Now loop through and set the names and initialize the attributes
1411          */
1412         for (idx = 0; idx < cal->count; idx++) {
1413                 api_idx = (int) (intptr_t) CmDataListGetData(api_ids, idx + 1);
1414                 cal->names[idx] = strdup(_CSA_calendar_attribute_names[api_idx]);
1415                 if (reason == appt_write)
1416                         initialize_cal_attr(api_idx, &cal->attrs[idx], reason, version);
1417         }
1418
1419         if (reason == appt_write) 
1420                 set_cal_links(cal);
1421
1422         CmDataListDestroy(api_ids, 0);
1423
1424
1425         return cal;
1426 }
1427
1428 CSA_return_code
1429 query_cal_struct(CSA_session_handle session, 
1430                  Dtcm_calendar *cal) {
1431
1432         CSA_return_code status;
1433
1434         /* if there is old query material laying around, toss it */
1435
1436         if (cal->filled) {
1437                 csa_free(cal->attrs);
1438                 cal->filled = False;
1439         }
1440
1441         if ((status = csa_read_calendar_attributes(session, 
1442                                          cal->num_names, 
1443                                          cal->names, 
1444                                          &cal->count, 
1445                                          &cal->attrs, 
1446                                          NULL)) == CSA_SUCCESS) {
1447                 set_cal_links(cal);
1448                 cal->filled = True;
1449         }
1450
1451         return(status);
1452 }
1453
1454 extern void
1455 scrub_cal_attr_list(Dtcm_calendar *cal) {
1456
1457         int     i;
1458
1459         for (i = 0; i < cal->count; i++) {
1460                 if (cal->attrs[i].value->type == CSA_VALUE_REMINDER) {
1461                         if ((cal->attrs[i].value->item.reminder_value->lead_time == NULL) || 
1462                              (cal->attrs[i].value->item.reminder_value->lead_time[0] == '\0')) {
1463                                 free(cal->attrs[i].name);
1464                                 cal->attrs[i].name = NULL;
1465                         }
1466                 }
1467                 else if ((cal->attrs[i].value->type == CSA_VALUE_ACCESS_LIST) && (cal->attrs[i].value->item.access_list_value == NULL)) {
1468                         free(cal->attrs[i].name);
1469                         cal->attrs[i].name = NULL;
1470                 }
1471                 else if ((cal->attrs[i].value->type == CSA_VALUE_STRING) && (cal->attrs[i].value->item.string_value == NULL)) {
1472                         free(cal->attrs[i].name);
1473                         cal->attrs[i].name = NULL;
1474                 }
1475                 else if ((cal->attrs[i].value->type == CSA_VALUE_DATE_TIME) && (cal->attrs[i].value->item.date_time_value == NULL)) {
1476                         free(cal->attrs[i].name);
1477                         cal->attrs[i].name = NULL;
1478                 }
1479         }
1480 }
1481
1482 extern boolean_t
1483 cal_ident_index_ro(int id, int version) {
1484         boolean_t       r_ro;
1485
1486         switch(id) {
1487         case CSA_CAL_ATTR_CALENDAR_NAME_I:
1488         case CSA_CAL_ATTR_CALENDAR_OWNER_I:
1489         case CSA_CAL_ATTR_CALENDAR_SIZE_I:
1490         case CSA_CAL_ATTR_CHARACTER_SET_I:
1491         case CSA_CAL_ATTR_NUMBER_ENTRIES_I:
1492         case CSA_CAL_ATTR_DATE_CREATED_I:
1493         case CSA_CAL_ATTR_PRODUCT_IDENTIFIER_I:
1494         case CSA_X_DT_CAL_ATTR_DATA_VERSION_I:
1495         case CSA_CAL_ATTR_TIME_ZONE_I:
1496                 r_ro = B_TRUE;
1497                 break;
1498         default:
1499                 r_ro = B_FALSE;
1500                 break;
1501         }
1502
1503         return r_ro;
1504 }
1505
1506 extern boolean_t
1507 entry_ident_index_ro(int id, int version) {
1508         boolean_t       r_ro;
1509
1510         switch(id) {
1511         case CSA_ENTRY_ATTR_DATE_CREATED_I:
1512         case CSA_ENTRY_ATTR_LAST_UPDATE_I:
1513         case CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I:
1514         case CSA_ENTRY_ATTR_ORGANIZER_I:
1515         case CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I:
1516         case CSA_ENTRY_ATTR_SEQUENCE_NUMBER_I:
1517                 r_ro = B_TRUE;
1518                 break;
1519         case CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I:
1520         case CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I:
1521         case CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I:
1522         case CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I:
1523         case CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I:
1524                 if (version >= DATAVER4)
1525                         r_ro = B_TRUE;
1526                 else
1527                         r_ro = B_FALSE;
1528                 break;
1529         default:
1530                 r_ro = B_FALSE;
1531                 break;
1532         }
1533
1534         return r_ro;
1535 }
1536
1537 extern CSA_enum
1538 cal_ident_index_tag(int id) {
1539         CSA_enum        r_tag;
1540
1541         switch(id) {
1542         case CSA_CAL_ATTR_CALENDAR_NAME_I:
1543         case CSA_CAL_ATTR_CHARACTER_SET_I:
1544         case CSA_CAL_ATTR_COUNTRY_I:
1545         case CSA_CAL_ATTR_PRODUCT_IDENTIFIER_I:
1546         case CSA_CAL_ATTR_TIME_ZONE_I:
1547         case CSA_CAL_ATTR_LANGUAGE_I:
1548                 r_tag = CSA_VALUE_STRING;
1549                 break;
1550         case CSA_CAL_ATTR_CALENDAR_OWNER_I:
1551                 r_tag = CSA_VALUE_CALENDAR_USER;
1552                 break;
1553         case CSA_CAL_ATTR_DATE_CREATED_I:
1554                 r_tag = CSA_VALUE_DATE_TIME;
1555                 break;
1556         case CSA_CAL_ATTR_CALENDAR_SIZE_I:
1557         case CSA_CAL_ATTR_NUMBER_ENTRIES_I:
1558         case CSA_X_DT_CAL_ATTR_DATA_VERSION_I:
1559                 r_tag = CSA_VALUE_UINT32;
1560                 break;
1561         case CSA_CAL_ATTR_ACCESS_LIST_I:
1562                 r_tag = CSA_VALUE_ACCESS_LIST;
1563                 break;
1564         case CSA_CAL_ATTR_WORK_SCHEDULE_I:
1565         default:
1566                 r_tag = CSA_VALUE_OPAQUE_DATA;
1567                 break;
1568         }
1569
1570         return r_tag;
1571 }
1572
1573 extern CSA_enum
1574 entry_ident_index_tag(int id) {
1575         CSA_enum        r_tag;
1576
1577         switch(id) {
1578         case CSA_ENTRY_ATTR_DESCRIPTION_I:
1579         case CSA_ENTRY_ATTR_EXCEPTION_RULE_I:
1580         case CSA_ENTRY_ATTR_RECURRENCE_RULE_I:
1581         case CSA_ENTRY_ATTR_SUBTYPE_I:
1582         case CSA_ENTRY_ATTR_SUMMARY_I:
1583                 r_tag = CSA_VALUE_STRING;
1584                 break;
1585         case CSA_ENTRY_ATTR_DATE_COMPLETED_I:
1586         case CSA_ENTRY_ATTR_DATE_CREATED_I:
1587         case CSA_ENTRY_ATTR_DUE_DATE_I:
1588         case CSA_ENTRY_ATTR_END_DATE_I:
1589         case CSA_ENTRY_ATTR_LAST_UPDATE_I:
1590         case CSA_ENTRY_ATTR_START_DATE_I:
1591         case CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE_I:
1592                 r_tag = CSA_VALUE_DATE_TIME;
1593                 break;
1594         case CSA_ENTRY_ATTR_EXCEPTION_DATES_I:
1595         case CSA_ENTRY_ATTR_RECURRING_DATES_I:
1596                 r_tag = CSA_VALUE_DATE_TIME_LIST;
1597                 break;
1598         case CSA_ENTRY_ATTR_CLASSIFICATION_I:
1599         case CSA_ENTRY_ATTR_NUMBER_RECURRENCES_I:
1600         case CSA_ENTRY_ATTR_PRIORITY_I:
1601         case CSA_ENTRY_ATTR_SEQUENCE_NUMBER_I:
1602         case CSA_ENTRY_ATTR_STATUS_I:
1603         case CSA_ENTRY_ATTR_TYPE_I:
1604         case CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES_I:
1605         case CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL_I:
1606                 r_tag = CSA_VALUE_UINT32;
1607                 break;
1608         case CSA_ENTRY_ATTR_TIME_TRANSPARENCY_I:
1609         case CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE_I:
1610         case CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM_I:
1611         case CSA_X_DT_ENTRY_ATTR_SHOWTIME_I:
1612                 r_tag = CSA_VALUE_SINT32;
1613                 break;
1614         case CSA_ENTRY_ATTR_AUDIO_REMINDER_I:
1615         case CSA_ENTRY_ATTR_FLASHING_REMINDER_I:
1616         case CSA_ENTRY_ATTR_MAIL_REMINDER_I:
1617         case CSA_ENTRY_ATTR_POPUP_REMINDER_I:
1618                 r_tag = CSA_VALUE_REMINDER;
1619                 break;
1620         case CSA_ENTRY_ATTR_ORGANIZER_I:
1621         case CSA_ENTRY_ATTR_SPONSOR_I:
1622                 r_tag = CSA_VALUE_CALENDAR_USER;
1623                 break;
1624         case CSA_ENTRY_ATTR_ATTENDEE_LIST_I:
1625                 r_tag = CSA_VALUE_ATTENDEE_LIST;
1626                 break;
1627         case CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER_I:
1628         default:
1629                 r_tag = CSA_VALUE_OPAQUE_DATA;
1630                 break;
1631         }
1632
1633         return r_tag;
1634 }
1635
1636 extern boolean_t
1637 ident_name_ro(char *name, int version) {
1638         boolean_t       r_ro = B_FALSE;
1639
1640         if (strcmp(name, CSA_CAL_ATTR_CALENDAR_NAME) == 0 ||
1641             strcmp(name, CSA_CAL_ATTR_CALENDAR_OWNER) == 0 ||
1642             strcmp(name, CSA_CAL_ATTR_CALENDAR_SIZE) == 0 ||
1643             strcmp(name, CSA_CAL_ATTR_DATE_CREATED) == 0 ||
1644             strcmp(name, CSA_CAL_ATTR_PRODUCT_IDENTIFIER) == 0 ||
1645             strcmp(name, CSA_X_DT_CAL_ATTR_DATA_VERSION) == 0 ||
1646             strcmp(name, CSA_ENTRY_ATTR_SEQUENCE_NUMBER) == 0 ||
1647             strcmp(name, CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER) == 0 ||
1648             strcmp(name, CSA_ENTRY_ATTR_ORGANIZER) == 0 ||
1649             strcmp(name, CSA_ENTRY_ATTR_LAST_UPDATE) == 0 ||
1650             strcmp(name, CSA_ENTRY_ATTR_DATE_CREATED) == 0 ||
1651             strcmp(name, CSA_ENTRY_ATTR_NUMBER_RECURRENCES) == 0)
1652                 r_ro = B_TRUE;
1653
1654         if ((version >= DATAVER4) &&
1655             (strcmp(name, CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE) == 0 ||
1656              strcmp(name, CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES) == 0 ||
1657              strcmp(name, CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL) == 0 ||
1658              strcmp(name, CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM) == 0))
1659                 r_ro = B_TRUE;
1660
1661         return r_ro;
1662 }
1663
1664 extern void
1665 initialize_cal_attr(int id, CSA_attribute *attrs, Allocation_reason reason, int version) {
1666         int     size;
1667
1668         attrs->name = cm_strdup(_CSA_calendar_attribute_names[id]);
1669         if ((reason == appt_write) && !cal_ident_index_ro(id, version)) {
1670                 size = sizeof(CSA_attribute_value);
1671                 attrs->value = (CSA_attribute_value *)ckalloc(size);
1672                 memset(attrs->value, 0, size);
1673                 attrs->value->type = cal_ident_index_tag(id);
1674                 if (attrs->value->type == CSA_VALUE_REMINDER)
1675                         attrs->value->item.reminder_value = (CSA_reminder *) calloc(sizeof(CSA_reminder), 1);
1676         }
1677 }
1678
1679 static void
1680 free_attr(CSA_attribute *attr) {
1681
1682         if (attr == NULL)
1683                 return;
1684
1685         if (attr->name)
1686                 free(attr->name);
1687
1688
1689         if (attr->value){
1690                 if ((attr->value->type == CSA_VALUE_STRING) && attr->value->item.string_value != NULL)
1691                         free(attr->value->item.string_value);
1692                 else if ((attr->value->type == CSA_VALUE_DATE_TIME) && attr->value->item.date_time_value != NULL)
1693                         free(attr->value->item.date_time_value);
1694                 else if ((attr->value->type == CSA_VALUE_REMINDER) && attr->value->item.reminder_value != NULL) {
1695                         if (attr->value->item.reminder_value->lead_time)
1696                                 free(attr->value->item.reminder_value->lead_time);
1697                         if (attr->value->item.reminder_value->reminder_data.data)
1698                                 free(attr->value->item.reminder_value->reminder_data.data);
1699
1700                         free(attr->value->item.reminder_value);
1701                 }
1702
1703                 free(attr->value);
1704
1705         }
1706 }
1707
1708 extern void
1709 initialize_entry_attr(int id, CSA_attribute *attrs, Allocation_reason reason, int version) {
1710         int     size;
1711
1712         attrs->name = cm_strdup(_CSA_entry_attribute_names[id]);
1713         if ((reason == appt_write) && !entry_ident_index_ro(id, version)) {
1714                 size = sizeof(CSA_attribute_value);
1715                 attrs->value = (CSA_attribute_value *)ckalloc(size);
1716                 memset(attrs->value, 0, size);
1717                 attrs->value->type = entry_ident_index_tag(id);
1718                 if (attrs->value->type == CSA_VALUE_REMINDER)
1719                         attrs->value->item.reminder_value = (CSA_reminder *) calloc(sizeof(CSA_reminder), 1);
1720         }
1721 }
1722
1723 extern void
1724 free_appt_struct(Dtcm_appointment **appt) {
1725         int     i;
1726
1727         if (!appt)
1728                 return;
1729
1730         if ((*appt)->names) {
1731                 for (i = 0; i < (*appt)->num_names; i++)
1732                         if ((*appt)->names[i])
1733                                 free((*appt)->names[i]);
1734
1735                 free((*appt)->names);
1736         }
1737
1738         /* potential memory leak here.  We must be careful, as results 
1739            from querys should be thrown away with csa_free(), while 
1740            structures we've set up to do update/write operations were 
1741            allocated by the client, and need to be freed by that client. */
1742
1743         if (((*appt)->reason == appt_read) && ((*appt)->filled == True))
1744                 csa_free((*appt)->attrs);
1745         else 
1746                 if ((*appt)->attrs) {
1747                         for (i = 0; i < (*appt)->count; i++) 
1748                                 free_attr(&((*appt)->attrs[i]));
1749
1750                         free((*appt)->attrs);
1751                 }
1752
1753         free(*appt);
1754         *appt = NULL;
1755 }
1756
1757 extern void
1758 free_cal_struct(Dtcm_calendar **cal) {
1759         int     i;
1760
1761         if (!cal)
1762                 return;
1763
1764         if ((*cal)->names) {
1765                 for (i = 0; i < (*cal)->num_names; i++)
1766                         if ((*cal)->names[i])
1767                                 free((*cal)->names[i]);
1768
1769                 free((*cal)->names);
1770         }
1771
1772         /* potential memory leak here.  We must be careful, as results 
1773            from querys should be thrown away with csa_free(), while 
1774            structures we've set up to do update/write operations were 
1775            allocated by the client, and need to be freed by that client. */
1776
1777         if (((*cal)->reason == appt_read) && ((*cal)->filled == True))
1778                 csa_free((*cal)->attrs);
1779         else
1780                 if ((*cal)->attrs) {
1781                         for (i = 0; i < (*cal)->count; i++)
1782                                 free_attr(&((*cal)->attrs[i]));
1783                         free((*cal)->attrs);
1784                 }
1785
1786         free(*cal);
1787         *cal = NULL;
1788 }
1789
1790 extern void
1791 set_appt_links(Dtcm_appointment *appt) {
1792         int     idx;
1793         char    *idx_name;
1794
1795         appt->identifier = NULL;
1796         appt->modified_time = NULL;
1797         appt->author = NULL;
1798         appt->number_recurrence = NULL;
1799         appt->time = NULL;
1800         appt->type = NULL;
1801         appt->subtype = NULL;
1802         appt->private = NULL;
1803         appt->end_time = NULL;
1804         appt->show_time = NULL;
1805         appt->what = NULL;
1806         appt->state = NULL;
1807         appt->repeat_type = NULL;
1808         appt->repeat_times = NULL;
1809         appt->repeat_interval = NULL;
1810         appt->repeat_week_num = NULL;
1811         appt->recurrence_rule = NULL;
1812         appt->beep = NULL;
1813         appt->flash = NULL;
1814         appt->mail = NULL;
1815         appt->popup = NULL;
1816         appt->sequence_end_date = NULL;
1817
1818         for (idx = 0; idx < appt->count; idx++) {
1819                 idx_name = appt->attrs[idx].name;
1820                 if (!idx_name)
1821                         continue;
1822                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_REFERENCE_IDENTIFIER) == 0)
1823                         appt->identifier = &appt->attrs[idx];
1824                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_LAST_UPDATE) == 0)
1825                         appt->modified_time = &appt->attrs[idx];
1826                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_ORGANIZER) == 0)
1827                         appt->author = &appt->attrs[idx];
1828                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_NUMBER_RECURRENCES) == 0)
1829                         appt->number_recurrence = &appt->attrs[idx];
1830                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_START_DATE) == 0)
1831                         appt->time = &appt->attrs[idx];
1832                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_TYPE) == 0)
1833                         appt->type = &appt->attrs[idx];
1834                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_SUBTYPE) == 0)
1835                         appt->subtype = &appt->attrs[idx];
1836                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_CLASSIFICATION) == 0)
1837                         appt->private = &appt->attrs[idx];
1838                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_END_DATE) == 0)
1839                         appt->end_time = &appt->attrs[idx];
1840                 else if (strcmp(idx_name, CSA_X_DT_ENTRY_ATTR_SHOWTIME) == 0)
1841                         appt->show_time = &appt->attrs[idx];
1842                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_SUMMARY) == 0)
1843                         appt->what = &appt->attrs[idx];
1844                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_STATUS) == 0)
1845                         appt->state = &appt->attrs[idx];
1846                 else if (strcmp(idx_name, CSA_X_DT_ENTRY_ATTR_REPEAT_TYPE) == 0)
1847                         appt->repeat_type = &appt->attrs[idx];
1848                 else if (strcmp(idx_name, CSA_X_DT_ENTRY_ATTR_REPEAT_TIMES) == 0)
1849                         appt->repeat_times = &appt->attrs[idx];
1850                 else if (strcmp(idx_name, CSA_X_DT_ENTRY_ATTR_REPEAT_INTERVAL) == 0)
1851                         appt->repeat_interval = &appt->attrs[idx];
1852                 else if (strcmp(idx_name, CSA_X_DT_ENTRY_ATTR_REPEAT_OCCURRENCE_NUM) == 0)
1853                         appt->repeat_week_num = &appt->attrs[idx];
1854                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_RECURRENCE_RULE) == 0)
1855                         appt->recurrence_rule = &appt->attrs[idx];
1856                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_AUDIO_REMINDER) == 0)
1857                         appt->beep = &appt->attrs[idx];
1858                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_FLASHING_REMINDER) == 0)
1859                         appt->flash = &appt->attrs[idx];
1860                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_MAIL_REMINDER) == 0)
1861                         appt->mail = &appt->attrs[idx];
1862                 else if (strcmp(idx_name, CSA_ENTRY_ATTR_POPUP_REMINDER) == 0)
1863                         appt->popup = &appt->attrs[idx];
1864                 else if (strcmp(idx_name, CSA_X_DT_ENTRY_ATTR_SEQUENCE_END_DATE) == 0)
1865                         appt->sequence_end_date = &appt->attrs[idx];
1866         }
1867 }
1868
1869 extern void
1870 set_cal_links(Dtcm_calendar *cal) {
1871         int     idx;
1872         char    *idx_name;
1873
1874         for (idx = 0; idx < cal->count; idx++) {
1875                 idx_name = cal->attrs[idx].name;
1876                 if (strcmp(idx_name, CSA_CAL_ATTR_CALENDAR_NAME) == 0)
1877                         cal->cal_name = &cal->attrs[idx];
1878                 else if (strcmp(idx_name, CSA_X_DT_CAL_ATTR_DATA_VERSION) == 0)
1879                         cal->server_version = &cal->attrs[idx];
1880                 else if (strcmp(idx_name, CSA_CAL_ATTR_NUMBER_ENTRIES) == 0)
1881                         cal->num_entries = &cal->attrs[idx];
1882                 else if (strcmp(idx_name, CSA_CAL_ATTR_CALENDAR_SIZE) == 0)
1883                         cal->cal_size = &cal->attrs[idx];
1884                 else if (strcmp(idx_name, CSA_CAL_ATTR_ACCESS_LIST) == 0)
1885                         cal->access_list = &cal->attrs[idx];
1886                 else if (strcmp(idx_name, CSA_CAL_ATTR_TIME_ZONE) == 0)
1887                         cal->time_zone = &cal->attrs[idx];
1888         }
1889 }
1890
1891 extern void
1892 setup_range(CSA_attribute **attrs, CSA_enum **ops, int *count, time_t start,
1893             time_t stop, CSA_sint32 type, CSA_sint32 state, boolean_t use_state,
1894             int version) {
1895         int             a_size, o_size;
1896         CSA_enum        *op_ptr;
1897         CSA_attribute   *attr_ptr;
1898
1899
1900         if (use_state)
1901                 *count = 4;
1902         else
1903                 *count = 3;
1904
1905         a_size = sizeof(CSA_attribute) * (*count);
1906         attr_ptr = (CSA_attribute *)ckalloc(a_size);
1907         memset(attr_ptr, 0, a_size);
1908
1909         o_size = sizeof(CSA_enum) * (*count);
1910         op_ptr = (CSA_enum *)ckalloc(o_size);
1911         memset(op_ptr, 0, o_size);
1912
1913         initialize_entry_attr(CSA_ENTRY_ATTR_START_DATE_I, &attr_ptr[0], appt_write, version);
1914         attr_ptr[0].value->item.string_value = malloc(BUFSIZ);
1915         _csa_tick_to_iso8601(start, attr_ptr[0].value->item.string_value);
1916
1917         op_ptr[0] = CSA_MATCH_GREATER_THAN_OR_EQUAL_TO;
1918
1919         initialize_entry_attr(CSA_ENTRY_ATTR_START_DATE_I, &attr_ptr[1], appt_write, version);
1920         attr_ptr[1].value->item.string_value = malloc(BUFSIZ);
1921         _csa_tick_to_iso8601(stop, attr_ptr[1].value->item.string_value);
1922         op_ptr[1] = CSA_MATCH_LESS_THAN_OR_EQUAL_TO;
1923
1924         initialize_entry_attr(CSA_ENTRY_ATTR_TYPE_I, &attr_ptr[2], appt_write, version);
1925         attr_ptr[2].value->item.sint32_value = type;
1926         op_ptr[2] = CSA_MATCH_EQUAL_TO;
1927
1928         if (use_state) {
1929                 initialize_entry_attr(CSA_ENTRY_ATTR_STATUS_I, &attr_ptr[3], appt_write, version);
1930                 attr_ptr[3].value->item.sint32_value = state;
1931                 op_ptr[3] = CSA_MATCH_EQUAL_TO;
1932         }
1933
1934         *attrs = attr_ptr;
1935         *ops = op_ptr;
1936 }
1937
1938 extern void
1939 free_range(CSA_attribute **attrs, CSA_enum **ops, int count) {
1940         int     i;
1941
1942         for (i = 0; i < count; i++) {
1943                 free((*attrs)[i].name);
1944                 if (((*attrs)[i].value->type == CSA_VALUE_STRING) ||
1945                     ((*attrs)[i].value->type == CSA_VALUE_DATE_TIME))
1946                         if ((*attrs)[i].value->item.string_value)
1947                                 free((*attrs)[i].value->item.string_value);
1948
1949                 free((*attrs)[i].value);
1950         }
1951
1952         /* This memory was allocated by the client, and must be freed 
1953            by the client */
1954
1955         free(*attrs);
1956
1957         *attrs = NULL;
1958
1959         free(*ops);
1960         *ops = NULL;
1961 }
1962
1963 /*
1964  * In Motif you can't associate user data with items in a list.  To get around
1965  * this we have the following simple functions (CmDataList*) that maintain
1966  * a list of user data.  We follow the intrinscs coding style to re-inforce
1967  * the relationship these routines have to the XmList* functions.
1968  */
1969
1970 /*
1971  * Create a list to store user data
1972  */
1973 CmDataList *
1974 CmDataListCreate(void)
1975
1976 {
1977         return (CmDataList *)calloc(1, sizeof(CmDataList));
1978 }
1979
1980 /*
1981  * Destroy list
1982  */
1983 void
1984 CmDataListDestroy(CmDataList *list, int free_data)
1985
1986 {
1987         CmDataListDeleteAll(list, free_data);
1988         free(list);
1989 }
1990
1991 /*
1992  * Create node to hold data in list.
1993  */
1994 static CmDataItem *
1995 CmDataItemCreate(void)
1996
1997 {
1998         return (CmDataItem *)calloc(1, sizeof(CmDataItem));
1999 }
2000
2001 /*
2002  * Add user data to list at specified position. Note that this
2003  * routine must be called for every item added to a list.
2004  * If the item has no user data, just pass NULL.
2005  *
2006  *      list            List to add data to
2007  *      data            User data. NULL for no data.
2008  *      position        Where to insert data, starting with 1 for the
2009  *                      first item.  0 to append to end of list.
2010  *
2011  * Returns
2012  *              1       Success
2013  *              -1      Invalid position
2014  */
2015 int
2016 CmDataListAdd(CmDataList *list, void *data, int position)
2017
2018 {
2019         CmDataItem      *item, *p;
2020         int             n;
2021
2022         /* Create new node to hold data */
2023         item = CmDataItemCreate();
2024         item->data = data;
2025
2026         /* Insert node into list at appropriate spot */
2027         if (list->head == NULL) {
2028                 list->head = item;
2029         } else if (position == 0) {
2030                 /* Special case.  0 means append to end */
2031                 list->tail->next = item;
2032         } else if (position == 1) {
2033                 item->next = list->head;
2034                 list->head = item;
2035         } else {
2036                 for (n = 2, p = list->head; p != NULL && n < position;
2037                      p = p->next, n++)
2038                         ;
2039
2040                 if (p == NULL) {
2041                         return -1;
2042                 }
2043
2044                 item->next = p->next;
2045                 p->next = item;
2046         }
2047
2048         /* If new item is at the end of the list, update tail */
2049         if (item->next == NULL) {
2050                 list->tail = item;
2051         }
2052
2053         list->count++;
2054
2055         return 1;
2056 }
2057
2058 /*
2059  * Delete user data from a position in the list.  If free_data is
2060  * True then this routine will call free(3C) on the user data, otherwise
2061  * the user data is returned so that the caller can dispose of it.
2062  * This routine should be called anytime you delete an item from a
2063  * scrolling list.
2064  *
2065  *      list            List to delete data from
2066  *      position        Location of item to delete. 0 for last item
2067  *      free_data       True if you want this routine to call free()
2068  *                      on the data for you.  Otherwise this routine
2069  *                      will return the address of the data.
2070  *
2071  * Returns
2072  *      NULL    No data found for item at the specified position
2073  *      1       Success (free_data was True)
2074  *      other   Address of data for item at the specified position.
2075  *              (free_data was False)
2076  */
2077 void *
2078 CmDataListDeletePos(CmDataList *list, int position, int free_data)
2079
2080 {
2081         void            *data;
2082         CmDataItem      *p, *item;
2083         int             n;
2084
2085         /* Special case. 0 means delete last item */
2086         if (position == 0) {
2087                 position = list->count;
2088         }
2089
2090         if (list->head == NULL) {
2091                 return NULL;
2092         } else if (position == 1) {
2093                 item = list->head;
2094                 list->head = item->next;
2095                 if (list->tail == item) {
2096                         list->tail = item->next;
2097                 }
2098         } else {
2099                 for (n = 2, p = list->head; p->next != NULL && n < position;
2100                      p = p->next, n++)
2101                         ;
2102                 
2103                 if (p->next == NULL) {
2104                         return NULL;
2105                 }
2106
2107                 item = p->next;
2108                 p->next = item->next;
2109                 if (list->tail == item) {
2110                         list->tail = p;
2111                 }
2112         }
2113
2114         list->count--;
2115
2116         data = item->data;
2117         free(item);
2118
2119         if (free_data) {
2120                 if (data != NULL) 
2121                         free(data);
2122                 return (void *)1;
2123         } else {
2124                 return data;
2125         }
2126 }
2127
2128 /* 
2129  * Delete all nodes in the list.
2130  *
2131  *      list            List to delete nodes from
2132  *      free_data       True if you want this routine to call free()
2133  *                      on the data for you.
2134  */
2135 void
2136 CmDataListDeleteAll(CmDataList *list, int free_data)
2137
2138 {
2139         CmDataItem      *p, *tmp;
2140
2141         p = list->head;
2142         while (p != NULL) {
2143                 if (free_data && p->data != NULL) {
2144                         free(p->data);
2145                 }
2146
2147                 tmp = p;
2148                 p = p->next;
2149                 free(tmp);
2150         }
2151
2152         list->count = 0;
2153         list->head = NULL;
2154         list->tail = NULL;
2155
2156         return;
2157 }
2158
2159 /*
2160  * Get data for the item at a particular position in a list.
2161  */
2162 void *
2163 CmDataListGetData(CmDataList *list, int position)
2164
2165 {
2166         void            *data;
2167         CmDataItem      *p, *item;
2168         int             n;
2169
2170         if (list->head == NULL) {
2171                 return NULL;
2172         } else if (position == 0) {
2173                 data = list->tail->data;
2174         } else {
2175                 for (n = 1, p = list->head; p != NULL && n < position;
2176                      p = p->next, n++)
2177                         ;
2178                 if (p == NULL) {
2179                         return NULL;
2180                 }
2181                 data = p->data;
2182         }
2183
2184         return data;
2185 }
2186
2187 #ifdef DEBUG
2188 /*
2189  * For dumping contents of list
2190  */
2191 void
2192 CmDataListDump(CmDataList *list)
2193
2194 {
2195         CmDataItem      *p;
2196         int             n;
2197
2198         printf("***** %d items:\n", list->count);
2199
2200         for (p = list->head, n = 1; p != NULL; p = p->next, n++) {
2201                 printf("%3d: %s\n", n, p->data ? (char *)p->data : "<nil>");
2202         }
2203
2204         return;
2205 }
2206 #endif