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