]> code.citadel.org Git - citadel.git/blob - citadel/tools.c
* support autoconf 2.53
[citadel.git] / citadel / tools.c
1 /*
2  * $Id$
3  *
4  * Utility functions that are used by both the client and server.
5  *
6  */
7
8 #ifdef DLL_EXPORT
9 #define IN_LIBCIT
10 #endif
11
12 #include "sysdep.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <stdarg.h>
18
19 #if TIME_WITH_SYS_TIME
20 # include <sys/time.h>
21 # include <time.h>
22 #else
23 # if HAVE_SYS_TIME_H
24 #  include <sys/time.h>
25 # else
26 #  include <time.h>
27 # endif
28 #endif
29
30 #include "tools.h"
31 #include "citadel.h"
32
33 #define TRUE  1
34 #define FALSE 0
35
36 typedef unsigned char byte;           /* Byte type */
37 static byte dtable[256];              /* base64 encode / decode table */
38
39
40 char *safestrncpy(char *dest, const char *src, size_t n)
41 {
42         if (dest == NULL || src == NULL) {
43                 fprintf(stderr, "safestrncpy: NULL argument\n");
44                 abort();
45         }
46         strncpy(dest, src, n);
47         dest[n - 1] = 0;
48         return dest;
49 }
50
51
52
53 #ifndef HAVE_STRNCASECMP
54 int strncasecmp(char *lstr, char *rstr, int len)
55 {
56         int pos = 0;
57         char lc,rc;
58         while (pos<len) {
59                 lc=tolower(lstr[pos]);
60                 rc=tolower(rstr[pos]);
61                 if ((lc==0)&&(rc==0)) return(0);
62                 if (lc<rc) return(-1);
63                 if (lc>rc) return(1);
64                 pos=pos+1;
65         }
66         return(0);
67 }
68 #endif
69
70
71
72 /*
73  * num_tokens()  -  discover number of parameters/tokens in a string
74  */
75 int num_tokens(char *source, char tok) {
76         int a;
77         int count = 1;
78
79         if (source == NULL) return(0);
80         for (a=0; a<strlen(source); ++a) {
81                 if (source[a]==tok) ++count;
82         }
83         return(count);
84 }
85
86 /*
87  * extract_token()  -  a smarter string tokenizer
88  */
89 void extract_token(char *dest, char *source, int parmnum, char separator) 
90 {
91         int i;
92         int len;
93         int curr_parm;
94
95         strcpy(dest,"");
96         len = 0;
97         curr_parm = 0;
98
99         if (strlen(source)==0) {
100                 return;
101                 }
102
103         for (i=0; i<strlen(source); ++i) {
104                 if (source[i]==separator) {
105                         ++curr_parm;
106                 }
107                 else if (curr_parm == parmnum) {
108                         dest[len+1] = 0;
109                         dest[len++] = source[i];
110                 }
111         }
112 }
113
114
115
116 /*
117  * remove_token()  -  a tokenizer that kills, maims, and destroys
118  */
119 void remove_token(char *source, int parmnum, char separator)
120 {
121         int i;
122         int len;
123         int curr_parm;
124         int start, end;
125
126         len = 0;
127         curr_parm = 0;
128         start = (-1);
129         end = (-1);
130
131         if (strlen(source)==0) {
132                 return;
133                 }
134
135         for (i=0; i<strlen(source); ++i) {
136                 if ( (start < 0) && (curr_parm == parmnum) ) {
137                         start = i;
138                 }
139
140                 if ( (end < 0) && (curr_parm == (parmnum+1)) ) {
141                         end = i;
142                 }
143
144                 if (source[i]==separator) {
145                         ++curr_parm;
146                 }
147         }
148
149         if (end < 0) end = strlen(source);
150         strcpy(&source[start], &source[end]);
151 }
152
153
154
155
156 /*
157  * extract_int()  -  extract an int parm w/o supplying a buffer
158  */
159 int extract_int(char *source, int parmnum)
160 {
161         char buf[SIZ];
162         
163         extract_token(buf, source, parmnum, '|');
164         return(atoi(buf));
165 }
166
167 /*
168  * extract_long()  -  extract an long parm w/o supplying a buffer
169  */
170 long extract_long(char *source, long int parmnum)
171 {
172         char buf[SIZ];
173         
174         extract_token(buf, source, parmnum, '|');
175         return(atol(buf));
176 }
177
178
179
180 /*
181  * decode_base64() and encode_base64() are adaptations of code by
182  * John Walker, found in full in the file "base64.c" included with this
183  * distribution.  The difference between those functions and these is that
184  * these are intended to encode/decode small string buffers, and those are
185  * intended to encode/decode entire MIME parts.
186  */
187
188 void encode_base64(char *dest, char *source)
189 {
190     int i, hiteof = FALSE;
191     int spos = 0;
192     int dpos = 0;
193
194     /*  Fill dtable with character encodings.  */
195
196     for (i = 0; i < 26; i++) {
197         dtable[i] = 'A' + i;
198         dtable[26 + i] = 'a' + i;
199     }
200     for (i = 0; i < 10; i++) {
201         dtable[52 + i] = '0' + i;
202     }
203     dtable[62] = '+';
204     dtable[63] = '/';
205
206     while (!hiteof) {
207         byte igroup[3], ogroup[4];
208         int c, n;
209
210         igroup[0] = igroup[1] = igroup[2] = 0;
211         for (n = 0; n < 3; n++) {
212             c = source[spos++];
213             if (c == 0) {
214                 hiteof = TRUE;
215                 break;
216             }
217             igroup[n] = (byte) c;
218         }
219         if (n > 0) {
220             ogroup[0] = dtable[igroup[0] >> 2];
221             ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
222             ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
223             ogroup[3] = dtable[igroup[2] & 0x3F];
224
225             /* Replace characters in output stream with "=" pad
226                characters if fewer than three characters were
227                read from the end of the input stream. */
228
229             if (n < 3) {
230                 ogroup[3] = '=';
231                 if (n < 2) {
232                     ogroup[2] = '=';
233                 }
234             }
235             for (i = 0; i < 4; i++) {
236                 dest[dpos++] = ogroup[i];
237                 dest[dpos] = 0;
238             }
239         }
240     }
241 }
242
243
244 /* 
245  * Convert base64-encoded to binary.  Returns the length of the decoded data.
246  * It will stop after reading 'length' bytes.
247  */
248 int decode_base64(char *dest, char *source, size_t length)
249 {
250     int i, c;
251     int dpos = 0;
252     int spos = 0;
253
254     for (i = 0; i < 255; i++) {
255         dtable[i] = 0x80;
256     }
257     for (i = 'A'; i <= 'Z'; i++) {
258         dtable[i] = 0 + (i - 'A');
259     }
260     for (i = 'a'; i <= 'z'; i++) {
261         dtable[i] = 26 + (i - 'a');
262     }
263     for (i = '0'; i <= '9'; i++) {
264         dtable[i] = 52 + (i - '0');
265     }
266     dtable['+'] = 62;
267     dtable['/'] = 63;
268     dtable['='] = 0;
269
270     /*CONSTANTCONDITION*/
271     while (TRUE) {
272         byte a[4], b[4], o[3];
273
274         for (i = 0; i < 4; i++) {
275             if (spos >= length) {
276                 return(dpos);
277             }
278             c = source[spos++];
279
280             if (c == 0) {
281                 if (i > 0) {
282                     return(dpos);
283                 }
284                 return(dpos);
285             }
286             if (dtable[c] & 0x80) {
287                 /* Ignoring errors: discard invalid character. */
288                 i--;
289                 continue;
290             }
291             a[i] = (byte) c;
292             b[i] = (byte) dtable[c];
293         }
294         o[0] = (b[0] << 2) | (b[1] >> 4);
295         o[1] = (b[1] << 4) | (b[2] >> 2);
296         o[2] = (b[2] << 6) | b[3];
297         i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
298         if (i>=1) dest[dpos++] = o[0];
299         if (i>=2) dest[dpos++] = o[1];
300         if (i>=3) dest[dpos++] = o[2];
301         dest[dpos] = 0;
302         if (i < 3) {
303             return(dpos);
304         }
305     }
306 }
307
308
309
310 /*
311  * Strip leading and trailing spaces from a string
312  */
313 void striplt(char *buf)
314 {
315         while ((strlen(buf) > 0) && (isspace(buf[0])))
316                 strcpy(buf, &buf[1]);
317         while (isspace(buf[strlen(buf) - 1]))
318                 buf[strlen(buf) - 1] = 0;
319 }
320
321
322
323
324
325 /* 
326  * Return the number of occurances of character ch in string st
327  */ 
328 int haschar(const char *st, int ch)
329 {
330         int a, b;
331         b = 0;
332         for (a = 0; a < strlen(st); ++a)
333                 if (st[a] == ch)
334                         ++b;
335         return (b);
336 }
337
338
339
340
341 /*
342  * Compare two strings, insensitive to case, punctuation, and non-alnum chars
343  */
344 int collapsed_strcmp(char *s1, char *s2) {
345         char *c1, *c2;
346         int i, ret, pos;
347
348         c1 = malloc(strlen(s1)+1);
349         c2 = malloc(strlen(s2)+1);
350         c1[0] = 0;
351         c2[0] = 0;
352
353         pos = 0;
354         for (i=0; i<strlen(s1); ++i) {
355                 if (isalnum(s1[i])) {
356                         c1[pos] = tolower(s1[i]);
357                         c1[++pos] = 0;
358                 }
359         }
360
361         pos = 0;
362         for (i=0; i<strlen(s2); ++i) {
363                 if (isalnum(s2[i])) {
364                         c2[pos] = tolower(s2[i]);
365                         c2[++pos] = 0;
366                 }
367         }
368
369         ret = strcmp(c1, c2);
370         free(c1);
371         free(c2);
372         return(ret);
373 }
374
375
376
377 /*
378  * Format a date/time stamp for output 
379  * seconds is whether to print the seconds
380  */
381 void fmt_date(char *buf, size_t n, time_t thetime, int seconds) {
382         struct tm *tm;
383         int hour;
384
385         char *ascmonths[] = {
386                 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
387                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
388         };
389
390         strcpy(buf, "");
391         tm = localtime(&thetime);
392
393         hour = tm->tm_hour;
394         if (hour == 0)  hour = 12;
395         else if (hour > 12) hour = hour - 12;
396
397         if (seconds) {
398                 snprintf(buf, n, "%s %d %4d %d:%02d:%02d%s",
399                         ascmonths[tm->tm_mon],
400                         tm->tm_mday,
401                         tm->tm_year + 1900,
402                         hour,
403                         tm->tm_min,
404                         tm->tm_sec,
405                         ( (tm->tm_hour >= 12) ? "pm" : "am" )
406                 );
407         } else {
408                 snprintf(buf, n, "%s %d %4d %d:%02d%s",
409                         ascmonths[tm->tm_mon],
410                         tm->tm_mday,
411                         tm->tm_year + 1900,
412                         hour,
413                         tm->tm_min,
414                         ( (tm->tm_hour >= 12) ? "pm" : "am" )
415                 );
416         }
417 }
418
419
420
421 /*
422  * Determine whether the specified message number is contained within the
423  * specified set.
424  */
425 int is_msg_in_mset(char *mset, long msgnum) {
426         int num_sets;
427         int s;
428         char setstr[SIZ], lostr[SIZ], histr[SIZ];       /* was 1024 */
429         long lo, hi;
430
431         /*
432          * Now set it for all specified messages.
433          */
434         num_sets = num_tokens(mset, ',');
435         for (s=0; s<num_sets; ++s) {
436                 extract_token(setstr, mset, s, ',');
437
438                 extract_token(lostr, setstr, 0, ':');
439                 if (num_tokens(setstr, ':') >= 2) {
440                         extract_token(histr, setstr, 1, ':');
441                         if (!strcmp(histr, "*")) {
442                                 snprintf(histr, sizeof histr, "%ld", LONG_MAX);
443                         }
444                 } 
445                 else {
446                         strcpy(histr, lostr);
447                 }
448                 lo = atol(lostr);
449                 hi = atol(histr);
450
451                 if ((msgnum >= lo) && (msgnum <= hi)) return(1);
452         }
453
454         return(0);
455 }
456
457
458 /*
459  * Utility function to "readline" from memory
460  * (returns new pointer)
461  */
462 char *memreadline(char *start, char *buf, int maxlen)
463 {
464         char ch;
465         char *ptr;
466         int len = 0;    /* tally our own length to avoid strlen() delays */
467
468         ptr = start;
469         memset(buf, 0, maxlen);
470
471         while (1) {
472                 ch = *ptr++;
473                 if ( (len < (maxlen - 1)) && (ch != 13) && (ch != 10) ) {
474                         buf[strlen(buf) + 1] = 0;
475                         buf[strlen(buf)] = ch;
476                         ++len;
477                 }
478                 if ((ch == 10) || (ch == 0)) {
479                         return ptr;
480                 }
481         }
482 }
483
484
485 /*
486  * Strip a boundarized substring out of a string (for example, remove
487  * parentheses and anything inside them).
488  */
489 void stripout(char *str, char leftboundary, char rightboundary) {
490         int a;
491         int lb = (-1);
492         int rb = (-1);
493
494         for (a = 0; a < strlen(str); ++a) {
495                 if (str[a] == leftboundary) lb = a;
496                 if (str[a] == rightboundary) rb = a;
497         }
498
499         if ( (lb > 0) && (rb > lb) ) {
500                 strcpy(&str[lb - 1], &str[rb + 1]);
501         }
502
503 }
504
505
506 /*
507  * Reduce a string down to a boundarized substring (for example, remove
508  * parentheses and anything outside them).
509  */
510 void stripallbut(char *str, char leftboundary, char rightboundary) {
511         int a;
512
513         for (a = 0; a < strlen(str); ++ a) {
514                 if (str[a] == leftboundary) strcpy(str, &str[a+1]);
515         }
516
517         for (a = 0; a < strlen(str); ++ a) {
518                 if (str[a] == rightboundary) str[a] = 0;
519         }
520
521 }
522
523 char *myfgets(char *s, int size, FILE *stream) {
524         char *ret = fgets(s, size, stream);
525         char *nl;
526
527         if (ret != NULL) {
528                 nl = strchr(s, '\n');
529
530                 if (nl != NULL)
531                         *nl = 0;
532         }
533
534         return ret;
535 }