5cb896c6f16da59bf3b87904e55f75324a94959b
[citadel.git] / citadel / tools.c
1 /*
2  * tools.c -- Miscellaneous routines used by both the client and server.
3  * $Id$
4  */
5
6 #include "sysdep.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <ctype.h>
10 #include <string.h>
11 #include <sys/time.h>
12 #include "tools.h"
13
14 #define TRUE  1
15 #define FALSE 0
16
17 typedef unsigned char byte;           /* Byte type */
18 static byte dtable[256];              /* base64 encode / decode table */
19
20
21 char *safestrncpy(char *dest, const char *src, size_t n)
22 {
23         if (dest == NULL || src == NULL) {
24                 fprintf(stderr, "safestrncpy: NULL argument\n");
25                 abort();
26         }
27         strncpy(dest, src, n);
28         dest[n - 1] = 0;
29         return dest;
30 }
31
32
33
34 #ifndef HAVE_STRNCASECMP
35 int strncasecmp(char *lstr, char *rstr, int len)
36 {
37         int pos = 0;
38         char lc,rc;
39         while (pos<len) {
40                 lc=tolower(lstr[pos]);
41                 rc=tolower(rstr[pos]);
42                 if ((lc==0)&&(rc==0)) return(0);
43                 if (lc<rc) return(-1);
44                 if (lc>rc) return(1);
45                 pos=pos+1;
46         }
47         return(0);
48 }
49 #endif
50
51
52
53 /*
54  * num_tokens()  -  discover number of parameters/tokens in a string
55  */
56 int num_tokens(char *source, char tok) {
57         int a;
58         int count = 1;
59
60         for (a=0; a<strlen(source); ++a) {
61                 if (source[a]==tok) ++count;
62         }
63         return(count);
64 }
65
66 /*
67  * extract_token()  -  a smarter string tokenizer
68  */
69 void extract_token(char *dest, char *source, int parmnum, char separator) 
70 {
71         int i;
72         int len;
73         int curr_parm;
74
75         strcpy(dest,"");
76         len = 0;
77         curr_parm = 0;
78
79         if (strlen(source)==0) {
80                 return;
81                 }
82
83         for (i=0; i<strlen(source); ++i) {
84                 if (source[i]==separator) {
85                         ++curr_parm;
86                 }
87                 else if (curr_parm == parmnum) {
88                         dest[len+1] = 0;
89                         dest[len++] = source[i];
90                 }
91         }
92 }
93
94
95
96 /*
97  * remove_token()  -  a tokenizer that kills, maims, and destroys
98  */
99 void remove_token(char *source, int parmnum, char separator)
100 {
101         int i;
102         int len;
103         int curr_parm;
104         int start, end;
105
106         len = 0;
107         curr_parm = 0;
108         start = (-1);
109         end = (-1);
110
111         if (strlen(source)==0) {
112                 return;
113                 }
114
115         for (i=0; i<strlen(source); ++i) {
116                 if ( (start < 0) && (curr_parm == parmnum) ) {
117                         start = i;
118                 }
119
120                 if ( (end < 0) && (curr_parm == (parmnum+1)) ) {
121                         end = i;
122                 }
123
124                 if (source[i]==separator) {
125                         ++curr_parm;
126                 }
127         }
128
129         if (end < 0) end = strlen(source);
130
131         printf("%d .. %d\n", start, end);
132
133         strcpy(&source[start], &source[end]);
134 }
135
136
137
138
139 /*
140  * extract_int()  -  extract an int parm w/o supplying a buffer
141  */
142 int extract_int(char *source, int parmnum)
143 {
144         char buf[256];
145         
146         extract_token(buf, source, parmnum, '|');
147         return(atoi(buf));
148 }
149
150 /*
151  * extract_long()  -  extract an long parm w/o supplying a buffer
152  */
153 long extract_long(char *source, long int parmnum)
154 {
155         char buf[256];
156         
157         extract_token(buf, source, parmnum, '|');
158         return(atol(buf));
159 }
160
161
162
163 /*
164  * decode_base64() and encode_base64() are adaptations of code by
165  * John Walker, found in full in the file "base64.c" included with this
166  * distribution.  The difference between those functions and these is that
167  * these are intended to encode/decode small string buffers, and those are
168  * intended to encode/decode entire MIME parts.
169  */
170
171 void encode_base64(char *dest, char *source)
172 {
173     int i, hiteof = FALSE;
174     int spos = 0;
175     int dpos = 0;
176
177     /*  Fill dtable with character encodings.  */
178
179     for (i = 0; i < 26; i++) {
180         dtable[i] = 'A' + i;
181         dtable[26 + i] = 'a' + i;
182     }
183     for (i = 0; i < 10; i++) {
184         dtable[52 + i] = '0' + i;
185     }
186     dtable[62] = '+';
187     dtable[63] = '/';
188
189     while (!hiteof) {
190         byte igroup[3], ogroup[4];
191         int c, n;
192
193         igroup[0] = igroup[1] = igroup[2] = 0;
194         for (n = 0; n < 3; n++) {
195             c = source[spos++];
196             if (c == 0) {
197                 hiteof = TRUE;
198                 break;
199             }
200             igroup[n] = (byte) c;
201         }
202         if (n > 0) {
203             ogroup[0] = dtable[igroup[0] >> 2];
204             ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
205             ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
206             ogroup[3] = dtable[igroup[2] & 0x3F];
207
208             /* Replace characters in output stream with "=" pad
209                characters if fewer than three characters were
210                read from the end of the input stream. */
211
212             if (n < 3) {
213                 ogroup[3] = '=';
214                 if (n < 2) {
215                     ogroup[2] = '=';
216                 }
217             }
218             for (i = 0; i < 4; i++) {
219                 dest[dpos++] = ogroup[i];
220                 dest[dpos] = 0;
221             }
222         }
223     }
224 }
225
226
227
228 void decode_base64(char *dest, char *source)
229 {
230     int i;
231     int dpos = 0;
232     int spos = 0;
233
234     for (i = 0; i < 255; i++) {
235         dtable[i] = 0x80;
236     }
237     for (i = 'A'; i <= 'Z'; i++) {
238         dtable[i] = 0 + (i - 'A');
239     }
240     for (i = 'a'; i <= 'z'; i++) {
241         dtable[i] = 26 + (i - 'a');
242     }
243     for (i = '0'; i <= '9'; i++) {
244         dtable[i] = 52 + (i - '0');
245     }
246     dtable['+'] = 62;
247     dtable['/'] = 63;
248     dtable['='] = 0;
249
250     /*CONSTANTCONDITION*/
251     while (TRUE) {
252         byte a[4], b[4], o[3];
253
254         for (i = 0; i < 4; i++) {
255             int c = source[spos++];
256
257             if (c == 0) {
258                 if (i > 0) {
259                     return;
260                 }
261                 return;
262             }
263             if (dtable[c] & 0x80) {
264                 /* Ignoring errors: discard invalid character. */
265                 i--;
266                 continue;
267             }
268             a[i] = (byte) c;
269             b[i] = (byte) dtable[c];
270         }
271         o[0] = (b[0] << 2) | (b[1] >> 4);
272         o[1] = (b[1] << 4) | (b[2] >> 2);
273         o[2] = (b[2] << 6) | b[3];
274         i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
275         if (i>=1) dest[dpos++] = o[0];
276         if (i>=2) dest[dpos++] = o[1];
277         if (i>=3) dest[dpos++] = o[2];
278         dest[dpos] = 0;
279         if (i < 3) {
280             return;
281         }
282     }
283 }
284
285
286
287 /*
288  * Strip leading and trailing spaces from a string
289  */
290 void striplt(char *buf)
291 {
292         while ((strlen(buf) > 0) && (buf[0] == 32))
293                 strcpy(buf, &buf[1]);
294         while (buf[strlen(buf) - 1] == 32)
295                 buf[strlen(buf) - 1] = 0;
296 }
297
298
299
300
301
302 /* 
303  * Return the number of occurances of character ch in string st
304  */ 
305 int haschar(char *st, int ch)
306 {
307         int a, b;
308         b = 0;
309         for (a = 0; a < strlen(st); ++a)
310                 if (st[a] == ch)
311                         ++b;
312         return (b);
313 }
314
315
316
317
318 /*
319  * Compare two strings, insensitive to case, punctuation, and non-alnum chars
320  */
321 int collapsed_strcmp(char *s1, char *s2) {
322         char *c1, *c2;
323         int i, ret, pos;
324
325         c1 = malloc(strlen(s1)+1);
326         c2 = malloc(strlen(s2)+1);
327         c1[0] = 0;
328         c2[0] = 0;
329
330         pos = 0;
331         for (i=0; i<strlen(s1); ++i) {
332                 if (isalnum(s1[i])) {
333                         c1[pos] = tolower(s1[i]);
334                         c1[++pos] = 0;
335                 }
336         }
337
338         pos = 0;
339         for (i=0; i<strlen(s2); ++i) {
340                 if (isalnum(s2[i])) {
341                         c2[pos] = tolower(s2[i]);
342                         c2[++pos] = 0;
343                 }
344         }
345
346         ret = strcmp(c1, c2);
347         free(c1);
348         free(c2);
349         return(ret);
350 }
351
352
353
354 /*
355  * Format a date/time stamp for output 
356  */
357 void fmt_date(char *buf, time_t thetime) {
358         struct tm *tm;
359         int hour;
360
361         char *ascmonths[] = {
362                 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
363                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
364         };
365
366         strcpy(buf, "");
367         tm = localtime(&thetime);
368
369         hour = tm->tm_hour;
370         if (hour == 0)  hour = 12;
371         else if (hour > 12) hour = hour - 12;
372
373         sprintf(buf, "%s %d %4d %d:%02d%s",
374                 ascmonths[tm->tm_mon],
375                 tm->tm_mday,
376                 tm->tm_year + 1900,
377                 hour,
378                 tm->tm_min,
379                 ( (tm->tm_hour >= 12) ? "pm" : "am" )
380         );
381 }
382
383
384
385
386
387