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