Created SILC Client Libary by moving stuff from silc/ directory.
[silc.git] / lib / silcutil / silcutil.c
1 /*
2
3   silcutil.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * These are general utility functions that doesn't belong to any specific
22  * group of routines.
23  */
24 /*
25  * $Id$
26  * $Log$
27  * Revision 1.1  2000/09/13 17:45:16  priikone
28  *      Splitted SILC core library. Core library includes now only
29  *      SILC protocol specific stuff. New utility library includes the
30  *      old stuff from core library that is more generic purpose stuff.
31  *
32  * Revision 1.4  2000/07/19 07:04:04  priikone
33  *      Minor bug fix in silc_encode_pem
34  *
35  * Revision 1.3  2000/07/10 05:34:40  priikone
36  *      Added PEM encoding/decoding functions.
37  *
38  * Revision 1.2  2000/07/05 06:06:12  priikone
39  *      Added file saving with specific mode.
40  *
41  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
42  *      Imported from internal CVS/Added Log headers.
43  *
44  *
45  */
46
47 #include "silcincludes.h"
48
49 /* Reads a file to a buffer. The allocated buffer is returned. Length of
50    the file read is returned to the return_len argument. */
51
52 char *silc_file_read(const char *filename, int *return_len)
53 {
54   int fd;
55   char *buffer;
56   int filelen;
57
58   fd = open(filename, O_RDONLY);
59   if (fd < 0) {
60     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
61     return NULL;
62   }
63
64   filelen = lseek(fd, (off_t)0L, SEEK_END);
65   if (filelen < 0)
66     return NULL;
67   if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
68     return NULL;
69
70   if (filelen < 0) {
71     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
72     return NULL;
73   }
74   
75   buffer = silc_calloc(filelen + 1, sizeof(char));
76   
77   if ((read(fd, buffer, filelen)) == -1) {
78     memset(buffer, 0, sizeof(buffer));
79     close(fd);
80     SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
81                     strerror(errno)));
82     return NULL;
83   }
84
85   close(fd);
86   buffer[filelen] = EOF;
87   
88   *return_len = filelen;
89   return buffer;
90 }
91
92 /* Writes a buffer to the file. */
93
94 int silc_file_write(const char *filename, const char *buffer, int len)
95 {
96   int fd;
97         
98   if ((fd = creat(filename, 0644)) == -1) {
99     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
100     return -1;
101   }
102   
103   if ((write(fd, buffer, len)) == -1) {
104     SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
105     return -1;
106   }
107
108   close(fd);
109   
110   return 0;
111 }
112
113 /* Writes a buffer to the file.  If the file is created specific mode is
114    set to the file. */
115
116 int silc_file_write_mode(const char *filename, const char *buffer, 
117                          int len, int mode)
118 {
119   int fd;
120         
121   if ((fd = creat(filename, mode)) == -1) {
122     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
123     return -1;
124   }
125   
126   if ((write(fd, buffer, len)) == -1) {
127     SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
128     return -1;
129   }
130
131   close(fd);
132   
133   return 0;
134 }
135
136 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
137    This doesn't remove the newline sign from the destination buffer. The
138    argument begin is returned and should be passed again for the function. */
139
140 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
141 {
142   static int start = 0;
143   int i;
144   
145   memset(dest, 0, destlen);
146   
147   if (begin != start)
148     start = 0;
149   
150   i = 0;
151   for ( ; start <= srclen; i++, start++) {
152     if (i > destlen)
153       return -1;
154     
155     dest[i] = src[start];
156     
157     if (dest[i] == EOF) 
158       return EOF;
159     
160     if (dest[i] == '\n') 
161       break;
162   }
163   start++;
164   
165   return start;
166 }
167
168 /* Checks line for illegal characters. Return -1 when illegal character
169    were found. This is used to check for bad lines when reading data from
170    for example a configuration file. */
171
172 int silc_check_line(char *buf) 
173 {
174   /* Illegal characters in line */
175   if (strchr(buf, '#')) return -1;
176   if (strchr(buf, '\'')) return -1;
177   if (strchr(buf, '\\')) return -1;
178   if (strchr(buf, '\r')) return -1;
179   if (strchr(buf, '\a')) return -1;
180   if (strchr(buf, '\b')) return -1;
181   if (strchr(buf, '\f')) return -1;
182   
183   /* Empty line */
184   if (buf[0] == '\n')
185     return -1;
186   
187   return 0;
188 }
189
190 /* Returns current time as string. */
191
192 char *silc_get_time()
193 {
194   time_t curtime;
195   char *return_time;
196
197   curtime = time(NULL);
198   return_time = ctime(&curtime);
199   return_time[strlen(return_time) - 1] = '\0';
200
201   return return_time;
202 }
203
204 /* Converts string to capital characters */
205
206 char *silc_to_upper(char *string)
207 {
208   int i;
209   char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
210
211   for (i = 0; i < strlen(string); i++)
212     ret[i] = toupper(string[i]);
213
214   return ret;
215 }
216
217 /* Compares two strings. Strings may include wildcards * and ?.
218    Returns TRUE if strings match. */
219
220 int silc_string_compare(char *string1, char *string2)
221 {
222   int i;
223   int slen1 = strlen(string1);
224   int slen2 = strlen(string2);
225   char *tmpstr1, *tmpstr2;
226
227   if (!string1 || !string2)
228     return FALSE;
229
230   /* See if they are same already */
231   if (!strncmp(string1, string2, strlen(string2)))
232     return TRUE;
233
234   if (slen2 < slen1)
235     if (!strchr(string1, '*'))
236       return FALSE;
237   
238   /* Take copies of the original strings as we will change them */
239   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
240   memcpy(tmpstr1, string1, slen1);
241   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
242   memcpy(tmpstr2, string2, slen2);
243   
244   for (i = 0; i < slen2; i++) {
245     
246     /* * wildcard. Only one * wildcard is possible. */
247     if (tmpstr1[i] == '*')
248       if (!strncmp(tmpstr1, tmpstr2, i)) {
249         memset(tmpstr2, 0, slen2);
250         strncpy(tmpstr2, tmpstr1, i);
251         break;
252       }
253     
254     /* ? wildcard */
255     if (tmpstr1[i] == '?') {
256       if (!strncmp(tmpstr1, tmpstr2, i)) {
257         if (!(slen1 < i + 1))
258           if (tmpstr1[i + 1] != '?' &&
259               tmpstr1[i + 1] != tmpstr2[i + 1])
260             continue;
261         
262         if (!(slen1 < slen2))
263           tmpstr2[i] = '?';
264       }
265 #if 0
266     } else {
267       if (strncmp(tmpstr1, tmpstr2, i))
268         strncpy(tmpstr2, string2, slen2);
269 #endif
270     }
271   }
272   
273   /* if using *, remove it */
274   if (strchr(tmpstr1, '*'))
275     *strchr(tmpstr1, '*') = 0;
276   
277   if (!strcmp(tmpstr1, tmpstr2)) {
278     memset(tmpstr1, 0, slen1);
279     memset(tmpstr2, 0, slen2);
280     silc_free(tmpstr1);
281     silc_free(tmpstr2);
282     return TRUE;
283   }
284   
285   memset(tmpstr1, 0, slen1);
286   memset(tmpstr2, 0, slen2);
287   silc_free(tmpstr1);
288   silc_free(tmpstr2);
289   return FALSE;
290 }
291
292 unsigned char pem_enc[64] =
293 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
294
295 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
296    data string. Note: This is originally public domain code and is 
297    still PD. */
298
299 char *silc_encode_pem(unsigned char *data, unsigned int len)
300 {
301   int i, j;
302   unsigned int bits, c, char_count;
303   char *pem;
304
305   char_count = 0;
306   bits = 0;
307   j = 0;
308
309   pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
310
311   for (i = 0; i < len; i++) {
312     c = data[i];
313     bits += c;
314     char_count++;
315
316     if (char_count == 3) {
317       pem[j++] = pem_enc[bits  >> 18];
318       pem[j++] = pem_enc[(bits >> 12) & 0x3f];
319       pem[j++] = pem_enc[(bits >> 6)  & 0x3f];
320       pem[j++] = pem_enc[bits & 0x3f];
321       bits = 0;
322       char_count = 0;
323     } else {
324       bits <<= 8;
325     }
326   }
327
328   if (char_count != 0) {
329     bits <<= 16 - (8 * char_count);
330     pem[j++] = pem_enc[bits >> 18];
331     pem[j++] = pem_enc[(bits >> 12) & 0x3f];
332
333     if (char_count == 1) {
334       pem[j++] = '=';
335       pem[j] = '=';
336     } else {
337       pem[j++] = pem_enc[(bits >> 6) & 0x3f];
338       pem[j] = '=';
339     }
340   }
341
342   return pem;
343 }
344
345 /* Same as above but puts newline ('\n') every 72 characters. */
346
347 char *silc_encode_pem_file(unsigned char *data, unsigned int data_len)
348 {
349   int i, j;
350   unsigned int len, cols;
351   char *pem, *pem2;
352
353   pem = silc_encode_pem(data, data_len);
354   len = strlen(pem);
355
356   pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
357
358   for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
359     if (cols == 72) {
360       pem2[i] = '\n';
361       cols = 0;
362       len++;
363       continue;
364     }
365
366     pem2[i] = pem[j++];
367   }
368
369   return pem2;
370 }
371
372 /* Decodes PEM into data. Returns the decoded data. Note: This is
373    originally public domain code and is still PD. */
374
375 unsigned char *silc_decode_pem(unsigned char *pem, unsigned int pem_len,
376                                unsigned int *ret_len)
377 {
378   int i, j;
379   unsigned int len, c, char_count, bits;
380   unsigned char *data;
381   static char ialpha[256], decoder[256];
382
383   for (i = 64 - 1; i >= 0; i--) {
384     ialpha[pem_enc[i]] = 1;
385     decoder[pem_enc[i]] = i;
386   }
387
388   char_count = 0;
389   bits = 0;
390   j = 0;
391
392   if (!pem_len)
393     len = strlen(pem);
394   else
395     len = pem_len;
396
397   data = silc_calloc(((len * 6) / 8), sizeof(*data));
398
399   for (i = 0; i < len; i++) {
400     c = pem[i];
401
402     if (c == '=')
403       break;
404
405     if (c > 127 || !ialpha[c])
406       continue;
407
408     bits += decoder[c];
409     char_count++;
410
411     if (char_count == 4) {
412       data[j++] = bits >> 16;
413       data[j++] = (bits >> 8) & 0xff;
414       data[j++] = bits & 0xff;
415       bits = 0;
416       char_count = 0;
417     } else {
418       bits <<= 6;
419     }
420   }
421
422   switch(char_count) {
423   case 1:
424     silc_free(data);
425     return NULL;
426     break;
427   case 2:
428     data[j++] = bits >> 10;
429     break;
430   case 3:
431     data[j++] = bits >> 16;
432     data[j++] = (bits >> 8) & 0xff;
433     break;
434   }
435
436   if (ret_len)
437     *ret_len = j;
438
439   return data;
440 }
441
442 /* Parse nickname string. The format may be <num>!<nickname>@<server> to
443    support multiple same nicknames. The <num> is the final unifier if same
444    nickname is on same server. Note, this is only local format and server
445    does not know anything about these. */
446
447 int silc_parse_nickname(char *string, char **nickname, char **server,
448                         unsigned int *num)
449 {
450   unsigned int tlen;
451   char tmp[256];
452
453   if (!string)
454     return FALSE;
455
456   if (strchr(string, '!')) {
457     tlen = strcspn(string, "!");
458     memset(tmp, 0, sizeof(tmp));
459     memcpy(tmp, string, tlen);
460
461     if (num)
462       *num = atoi(tmp);
463
464     if (tlen >= strlen(string))
465       return FALSE;
466
467     string += tlen + 1;
468   }
469
470   if (strchr(string, '@')) {
471     tlen = strcspn(string, "@");
472     
473     if (nickname) {
474       *nickname = silc_calloc(tlen + 1, sizeof(char));
475       memcpy(*nickname, string, tlen);
476     }
477     
478     if (server) {
479       *server = silc_calloc(strlen(string) - tlen, sizeof(char));
480       memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
481     }
482   } else {
483     if (nickname)
484       *nickname = strdup(string);
485   }
486
487   return TRUE;
488 }
489
490 /* Parses command line. At most `max_args' is taken. Rest of the line
491    will be allocated as the last argument if there are more than `max_args'
492    arguments in the line. Note that the command name is counted as one
493    argument and is saved. */
494
495 void silc_parse_command_line(unsigned char *buffer, 
496                              unsigned char ***parsed,
497                              unsigned int **parsed_lens,
498                              unsigned int **parsed_types,
499                              unsigned int *parsed_num,
500                              unsigned int max_args)
501 {
502   int i, len = 0;
503   int argc = 0;
504   const char *cp = buffer;
505
506   *parsed = silc_calloc(1, sizeof(**parsed));
507   *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
508
509   /* Get the command first */
510   len = strcspn(cp, " ");
511   (*parsed)[0] = silc_to_upper((char *)cp);
512   (*parsed_lens)[0] = len;
513   cp += len + 1;
514   argc++;
515
516   /* Parse arguments */
517   if (strchr(cp, ' ') || strlen(cp) != 0) {
518     for (i = 1; i < max_args; i++) {
519
520       if (i != max_args - 1)
521         len = strcspn(cp, " ");
522       else
523         len = strlen(cp);
524       
525       *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
526       *parsed_lens = silc_realloc(*parsed_lens, 
527                                   sizeof(**parsed_lens) * (argc + 1));
528       (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
529       memcpy((*parsed)[argc], cp, len);
530       (*parsed_lens)[argc] = len;
531       argc++;
532
533       cp += len;
534       if (strlen(cp) == 0)
535         break;
536       else
537         cp++;
538     }
539   }
540
541   /* Save argument types. Protocol defines all argument types but
542      this implementation makes sure that they are always in correct
543      order hence this simple code. */
544   *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
545   for (i = 0; i < argc; i++)
546     (*parsed_types)[i] = i;
547
548   *parsed_num = argc;
549 }