8117cf1d26fce9ce9f18c8d8d06c8a65db49e105
[citadel.git] / citadel / tools.c
1 /*
2  * tools.c -- Miscellaneous routines used by both the client and server.
3  * $Id$
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include "tools.h"
11
12 #define TRUE  1
13 #define FALSE 0
14
15 typedef unsigned char byte;           /* Byte type */
16 static byte dtable[256];              /* base64 encode / decode table */
17
18
19 char *safestrncpy(char *dest, const char *src, size_t n)
20 {
21   if (dest == NULL || src == NULL)
22     {
23       fprintf(stderr, "safestrncpy: NULL argument\n");
24       abort();
25     }
26   strncpy(dest, src, n);
27   dest[n - 1] = 0;
28   return dest;
29 }
30
31
32 /*
33  * num_parms()  -  discover number of parameters...
34  */
35 int num_parms(char *source)
36 {
37         int a;
38         int count = 1;
39
40         for (a=0; a<strlen(source); ++a) 
41                 if (source[a]=='|') ++count;
42         return(count);
43 }
44
45 /*
46  * extract()  -  a smarter string tokenizer
47  */
48 void extract_token(char *dest, char *source, int parmnum, char separator)
49 {
50         int i;
51         int len;
52         int curr_parm;
53
54         strcpy(dest,"");
55         len = 0;
56         curr_parm = 0;
57
58         if (strlen(source)==0) {
59                 return;
60                 }
61
62         for (i=0; i<strlen(source); ++i) {
63                 if (source[i]==separator) {
64                         ++curr_parm;
65                 }
66                 else if (curr_parm == parmnum) {
67                         dest[len+1] = 0;
68                         dest[len++] = source[i];
69                 }
70         }
71 }
72
73 /*
74  * extract_int()  -  extract an int parm w/o supplying a buffer
75  */
76 int extract_int(char *source, int parmnum)
77 {
78         char buf[256];
79         
80         extract_token(buf, source, parmnum, '|');
81         return(atoi(buf));
82 }
83
84 /*
85  * extract_long()  -  extract an long parm w/o supplying a buffer
86  */
87 long extract_long(char *source, long int parmnum)
88 {
89         char buf[256];
90         
91         extract_token(buf, source, parmnum, '|');
92         return(atol(buf));
93 }
94
95
96
97 /*
98  * decode_base64() and encode_base64() are adaptations of code by
99  * John Walker, found in full in the file "base64.c" included with this
100  * distribution.  The difference between those functions and these is that
101  * these are intended to encode/decode small string buffers, and those are
102  * intended to encode/decode entire MIME parts.
103  */
104
105 void encode_base64(char *dest, char *source)
106 {
107     int i, hiteof = FALSE;
108     int spos = 0;
109     int dpos = 0;
110
111     /*  Fill dtable with character encodings.  */
112
113     for (i = 0; i < 26; i++) {
114         dtable[i] = 'A' + i;
115         dtable[26 + i] = 'a' + i;
116     }
117     for (i = 0; i < 10; i++) {
118         dtable[52 + i] = '0' + i;
119     }
120     dtable[62] = '+';
121     dtable[63] = '/';
122
123     while (!hiteof) {
124         byte igroup[3], ogroup[4];
125         int c, n;
126
127         igroup[0] = igroup[1] = igroup[2] = 0;
128         for (n = 0; n < 3; n++) {
129             c = source[spos++];
130             if (c == 0) {
131                 hiteof = TRUE;
132                 break;
133             }
134             igroup[n] = (byte) c;
135         }
136         if (n > 0) {
137             ogroup[0] = dtable[igroup[0] >> 2];
138             ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
139             ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
140             ogroup[3] = dtable[igroup[2] & 0x3F];
141
142             /* Replace characters in output stream with "=" pad
143                characters if fewer than three characters were
144                read from the end of the input stream. */
145
146             if (n < 3) {
147                 ogroup[3] = '=';
148                 if (n < 2) {
149                     ogroup[2] = '=';
150                 }
151             }
152             for (i = 0; i < 4; i++) {
153                 dest[dpos++] = ogroup[i];
154                 dest[dpos] = 0;
155             }
156         }
157     }
158 }
159
160
161
162 void decode_base64(char *dest, char *source)
163 {
164     int i;
165     int dpos = 0;
166     int spos = 0;
167
168     for (i = 0; i < 255; i++) {
169         dtable[i] = 0x80;
170     }
171     for (i = 'A'; i <= 'Z'; i++) {
172         dtable[i] = 0 + (i - 'A');
173     }
174     for (i = 'a'; i <= 'z'; i++) {
175         dtable[i] = 26 + (i - 'a');
176     }
177     for (i = '0'; i <= '9'; i++) {
178         dtable[i] = 52 + (i - '0');
179     }
180     dtable['+'] = 62;
181     dtable['/'] = 63;
182     dtable['='] = 0;
183
184     /*CONSTANTCONDITION*/
185     while (TRUE) {
186         byte a[4], b[4], o[3];
187
188         for (i = 0; i < 4; i++) {
189             int c = source[spos++];
190
191             if (c == 0) {
192                 if (i > 0) {
193                     return;
194                 }
195                 return;
196             }
197             if (dtable[c] & 0x80) {
198                 /* Ignoring errors: discard invalid character. */
199                 i--;
200                 continue;
201             }
202             a[i] = (byte) c;
203             b[i] = (byte) dtable[c];
204         }
205         o[0] = (b[0] << 2) | (b[1] >> 4);
206         o[1] = (b[1] << 4) | (b[2] >> 2);
207         o[2] = (b[2] << 6) | b[3];
208         i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
209         if (i>=1) dest[dpos++] = o[0];
210         if (i>=2) dest[dpos++] = o[1];
211         if (i>=3) dest[dpos++] = o[2];
212         dest[dpos] = 0;
213         if (i < 3) {
214             return;
215         }
216     }
217 }
218
219
220
221 /*
222  * Strip leading and trailing spaces from a string
223  */
224 void striplt(char *buf)
225 {
226         while ((strlen(buf) > 0) && (buf[0] == 32))
227                 strcpy(buf, &buf[1]);
228         while (buf[strlen(buf) - 1] == 32)
229                 buf[strlen(buf) - 1] = 0;
230 }
231
232
233
234
235
236 /* 
237  * Return the number of occurances of character ch in string st
238  */ 
239 int haschar(char *st, int ch)
240 {
241         int a, b;
242         b = 0;
243         for (a = 0; a < strlen(st); ++a)
244                 if (st[a] == ch)
245                         ++b;
246         return (b);
247 }
248
249
250
251
252 /*
253  * Compare two strings, insensitive to case, punctuation, and non-alnum chars
254  */
255 int collapsed_strcmp(char *s1, char *s2) {
256         char *c1, *c2;
257         int i, ret;
258
259         c1 = strdup(s1);
260         c2 = strdup(s2);
261
262         for (i=0; i<strlen(c1); ++i) {
263                 if (isupper(c1[i])) c1[i]=tolower(c1[i]);
264                 while (!isalnum(c1[i])) strcpy(&c1[i], &c1[i+1]);
265         }
266
267         for (i=0; i<strlen(c2); ++i) {
268                 if (isupper(c2[i])) c2[i]=tolower(c2[i]);
269                 while (!isalnum(c2[i])) strcpy(&c2[i], &c2[i+1]);
270         }
271
272         ret = strcmp(c1, c2);
273         free(c1);
274         free(c2);
275         return(ret);
276 }