d85e47ed7328b2bc55084ab6f18332abe80c1015
[citadel.git] / webcit / tools.c
1 /*
2  * $Id$
3  *
4  * Miscellaneous routines 
5  */
6
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <fcntl.h>
12 #include <signal.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <sys/socket.h>
16 #include <sys/time.h>
17 #include <limits.h>
18 #include <netinet/in.h>
19 #include <netdb.h>
20 #include <string.h>
21 #include <pwd.h>
22 #include <errno.h>
23 #include <stdarg.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <sys/time.h>
27 #include "webcit.h"
28 #include "webserver.h"
29
30 typedef unsigned char byte;
31
32 #define FALSE 0
33 #define TRUE 1
34
35 static byte dtable[256];        /* base64 encode / decode table */
36
37 char *safestrncpy(char *dest, const char *src, size_t n)
38 {
39         if (dest == NULL || src == NULL) {
40                 abort();
41         }
42         strncpy(dest, src, n);
43         dest[n - 1] = 0;
44         return dest;
45 }
46
47
48
49 /*
50  * num_tokens()  -  discover number of parameters/tokens in a string
51  */
52 int num_tokens(char *source, char tok)
53 {
54         int a;
55         int count = 1;
56
57         if (source == NULL)
58                 return (0);
59         for (a = 0; a < strlen(source); ++a) {
60                 if (source[a] == tok)
61                         ++count;
62         }
63         return (count);
64 }
65
66 /*
67  * extract_token() - a string tokenizer
68  */
69 void extract_token(char *dest, const char *source, int parmnum, char separator, int maxlen)
70 {
71         char *d;                /* dest */
72         const char *s;          /* source */
73         int count = 0;
74         int len = 0;
75
76         dest[0] = 0;
77
78         /* Locate desired parameter */
79         s = source;
80         while (count < parmnum) {
81                 /* End of string, bail! */
82                 if (!*s) {
83                         s = NULL;
84                         break;
85                 }
86                 if (*s == separator) {
87                         count++;
88                 }
89                 s++;
90         }
91         if (!s) return;         /* Parameter not found */
92
93         for (d = dest; *s && *s != separator && ++len<maxlen; s++, d++) {
94                 *d = *s;
95         }
96         *d = 0;
97 }
98
99
100
101 /*
102  * remove_token()  -  a tokenizer that kills, maims, and destroys
103  */
104 void remove_token(char *source, int parmnum, char separator)
105 {
106         int i;
107         int len;
108         int curr_parm;
109         int start, end;
110
111         len = 0;
112         curr_parm = 0;
113         start = (-1);
114         end = (-1);
115
116         if (strlen(source) == 0) {
117                 return;
118         }
119
120         for (i = 0; i < strlen(source); ++i) {
121                 if ((start < 0) && (curr_parm == parmnum)) {
122                         start = i;
123                 }
124
125                 if ((end < 0) && (curr_parm == (parmnum + 1))) {
126                         end = i;
127                 }
128
129                 if (source[i] == separator) {
130                         ++curr_parm;
131                 }
132         }
133
134         if (end < 0)
135                 end = strlen(source);
136
137         strcpy(&source[start], &source[end]);
138 }
139
140
141
142
143 /*
144  * extract_int()  -  extract an int parm w/o supplying a buffer
145  */
146 int extract_int(const char *source, int parmnum)
147 {
148         char buf[32];
149         
150         extract_token(buf, source, parmnum, '|', sizeof buf);
151         return(atoi(buf));
152 }
153
154 /*
155  * extract_long()  -  extract an long parm w/o supplying a buffer
156  */
157 long extract_long(const char *source, int parmnum)
158 {
159         char buf[32];
160         
161         extract_token(buf, source, parmnum, '|', sizeof buf);
162         return(atol(buf));
163 }
164
165
166
167
168
169
170 /*
171  * check for the presence of a character within a string (returns count)
172  */
173 int haschar(st, ch)
174 char st[];
175 char ch;
176 {
177         int a, b;
178         b = 0;
179         for (a = 0; a < strlen(st); ++a)
180                 if (st[a] == ch)
181                         ++b;
182         return (b);
183 }
184
185
186 /*
187  * Utility function to "readline" from memory
188  * (returns new pointer)
189  */
190 char *memreadline(char *start, char *buf, int maxlen)
191 {
192         char ch;
193         char *ptr;
194         int len = 0;            /* tally our own length to avoid strlen() delays */
195
196         ptr = start;
197         memset(buf, 0, maxlen);
198
199         while (1) {
200                 ch = *ptr++;
201                 if ((len < (maxlen - 1)) && (ch != 13) && (ch != 10)) {
202                         buf[strlen(buf) + 1] = 0;
203                         buf[strlen(buf)] = ch;
204                         ++len;
205                 }
206                 if ((ch == 10) || (ch == 0)) {
207                         return ptr;
208                 }
209         }
210 }
211
212
213
214 /*
215  * pattern2()  -  searches for patn within search string, returns pos
216  */
217 int pattern2(char *search, char *patn)
218 {
219         int a;
220         for (a = 0; a < strlen(search); ++a) {
221                 if (!strncasecmp(&search[a], patn, strlen(patn)))
222                         return (a);
223         }
224         return (-1);
225 }
226
227
228 /*
229  * Strip leading and trailing spaces from a string
230  */
231 void striplt(char *buf)
232 {
233         if (strlen(buf) == 0) return;
234         while ((strlen(buf) > 0) && (isspace(buf[0])))
235                 strcpy(buf, &buf[1]);
236         if (strlen(buf) == 0) return;
237         while (isspace(buf[strlen(buf) - 1]))
238                 buf[strlen(buf) - 1] = 0;
239 }
240
241
242 /*
243  * Determine whether the specified message number is contained within the
244  * specified set.
245  */
246 int is_msg_in_mset(char *mset, long msgnum) {
247         int num_sets;
248         int s;
249         char setstr[SIZ], lostr[SIZ], histr[SIZ];       /* was 1024 */
250         long lo, hi;
251
252         /*
253          * Now set it for all specified messages.
254          */
255         num_sets = num_tokens(mset, ',');
256         for (s=0; s<num_sets; ++s) {
257                 extract_token(setstr, mset, s, ',', sizeof setstr);
258
259                 extract_token(lostr, setstr, 0, ':', sizeof lostr);
260                 if (num_tokens(setstr, ':') >= 2) {
261                         extract_token(histr, setstr, 1, ':', sizeof histr);
262                         if (!strcmp(histr, "*")) {
263                                 snprintf(histr, sizeof histr, "%ld", LONG_MAX);
264                         }
265                 } 
266                 else {
267                         strcpy(histr, lostr);
268                 }
269                 lo = atol(lostr);
270                 hi = atol(histr);
271
272                 if ((msgnum >= lo) && (msgnum <= hi)) return(1);
273         }
274
275         return(0);
276 }
277
278
279
280 /*
281  * Strip a boundarized substring out of a string (for example, remove
282  * parentheses and anything inside them).
283  *
284  * This improved version can strip out *multiple* boundarized substrings.
285  */
286 void stripout(char *str, char leftboundary, char rightboundary)
287 {
288         int a;
289         int lb = (-1);
290         int rb = (-1);
291
292         do {
293                 lb = (-1);
294                 rb = (-1);
295
296                 for (a = 0; a < strlen(str); ++a) {
297                         if (str[a] == leftboundary)
298                                 lb = a;
299                         if (str[a] == rightboundary)
300                                 rb = a;
301                 }
302
303                 if ((lb > 0) && (rb > lb)) {
304                         strcpy(&str[lb - 1], &str[rb + 1]);
305                 }
306
307         } while ((lb > 0) && (rb > lb));
308
309 }
310
311
312
313 /*
314  * Replacement for sleep() that uses select() in order to avoid SIGALRM
315  */
316 void sleeeeeeeeeep(int seconds)
317 {
318         struct timeval tv;
319
320         tv.tv_sec = seconds;
321         tv.tv_usec = 0;
322         select(0, NULL, NULL, NULL, &tv);
323 }
324
325
326
327 /*
328  * CtdlDecodeBase64() and CtdlEncodeBase64() are adaptations of code by
329  * John Walker, copied over from the Citadel server.
330  */
331
332 void CtdlEncodeBase64(char *dest, const char *source, size_t sourcelen)
333 {
334         int i, hiteof = FALSE;
335         int spos = 0;
336         int dpos = 0;
337         int thisline = 0;
338
339         /*  Fill dtable with character encodings.  */
340
341         for (i = 0; i < 26; i++) {
342                 dtable[i] = 'A' + i;
343                 dtable[26 + i] = 'a' + i;
344         }
345         for (i = 0; i < 10; i++) {
346                 dtable[52 + i] = '0' + i;
347         }
348         dtable[62] = '+';
349         dtable[63] = '/';
350
351         while (!hiteof) {
352                 byte igroup[3], ogroup[4];
353                 int c, n;
354
355                 igroup[0] = igroup[1] = igroup[2] = 0;
356                 for (n = 0; n < 3; n++) {
357                         if (spos >= sourcelen) {
358                                 hiteof = TRUE;
359                                 break;
360                         }
361                         c = source[spos++];
362                         igroup[n] = (byte) c;
363                 }
364                 if (n > 0) {
365                         ogroup[0] = dtable[igroup[0] >> 2];
366                         ogroup[1] =
367                             dtable[((igroup[0] & 3) << 4) |
368                                    (igroup[1] >> 4)];
369                         ogroup[2] =
370                             dtable[((igroup[1] & 0xF) << 2) |
371                                    (igroup[2] >> 6)];
372                         ogroup[3] = dtable[igroup[2] & 0x3F];
373
374                         /* Replace characters in output stream with "=" pad
375                            characters if fewer than three characters were
376                            read from the end of the input stream. */
377
378                         if (n < 3) {
379                                 ogroup[3] = '=';
380                                 if (n < 2) {
381                                         ogroup[2] = '=';
382                                 }
383                         }
384                         for (i = 0; i < 4; i++) {
385                                 dest[dpos++] = ogroup[i];
386                                 dest[dpos] = 0;
387                         }
388                         thisline += 4;
389                         if (thisline > 70) {
390                                 dest[dpos++] = '\r';
391                                 dest[dpos++] = '\n';
392                                 dest[dpos] = 0;
393                                 thisline = 0;
394                         }
395                 }
396         }
397         if (thisline > 70) {
398                 dest[dpos++] = '\r';
399                 dest[dpos++] = '\n';
400                 dest[dpos] = 0;
401                 thisline = 0;
402         }
403 }
404
405
406 /* 
407  * Convert base64-encoded to binary.  Returns the length of the decoded data.
408  * It will stop after reading 'length' bytes.
409  */
410 int CtdlDecodeBase64(char *dest, const char *source, size_t length)
411 {
412         int i, c;
413         int dpos = 0;
414         int spos = 0;
415
416         for (i = 0; i < 255; i++) {
417                 dtable[i] = 0x80;
418         }
419         for (i = 'A'; i <= 'Z'; i++) {
420                 dtable[i] = 0 + (i - 'A');
421         }
422         for (i = 'a'; i <= 'z'; i++) {
423                 dtable[i] = 26 + (i - 'a');
424         }
425         for (i = '0'; i <= '9'; i++) {
426                 dtable[i] = 52 + (i - '0');
427         }
428         dtable['+'] = 62;
429         dtable['/'] = 63;
430         dtable['='] = 0;
431
432          /*CONSTANTCONDITION*/ while (TRUE) {
433                 byte a[4], b[4], o[3];
434
435                 for (i = 0; i < 4; i++) {
436                         if (spos >= length) {
437                                 return (dpos);
438                         }
439                         c = source[spos++];
440
441                         if (c == 0) {
442                                 if (i > 0) {
443                                         return (dpos);
444                                 }
445                                 return (dpos);
446                         }
447                         if (dtable[c] & 0x80) {
448                                 /* Ignoring errors: discard invalid character */
449                                 i--;
450                                 continue;
451                         }
452                         a[i] = (byte) c;
453                         b[i] = (byte) dtable[c];
454                 }
455                 o[0] = (b[0] << 2) | (b[1] >> 4);
456                 o[1] = (b[1] << 4) | (b[2] >> 2);
457                 o[2] = (b[2] << 6) | b[3];
458                 i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
459                 if (i >= 1)
460                         dest[dpos++] = o[0];
461                 if (i >= 2)
462                         dest[dpos++] = o[1];
463                 if (i >= 3)
464                         dest[dpos++] = o[2];
465                 dest[dpos] = 0;
466                 if (i < 3) {
467                         return (dpos);
468                 }
469         }
470 }
471
472
473
474 /*
475  * Generate a new, globally unique UID parameter for a calendar etc. object
476  */
477 void generate_uuid(char *buf) {
478         static int seq = 0;
479
480         sprintf(buf, "%s-%lx-%x-%x",
481                 serv_info.serv_nodename,
482                 time(NULL),
483                 getpid(),
484                 (seq++)
485         );
486 }
487