updates.
[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 /* $Id$ */
25
26 #include "silcincludes.h"
27
28 /* Reads a file to a buffer. The allocated buffer is returned. Length of
29    the file read is returned to the return_len argument. */
30
31 char *silc_file_read(const char *filename, int *return_len)
32 {
33   int fd;
34   char *buffer;
35   int filelen;
36
37   fd = open(filename, O_RDONLY);
38   if (fd < 0) {
39     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
40     return NULL;
41   }
42
43   filelen = lseek(fd, (off_t)0L, SEEK_END);
44   if (filelen < 0)
45     return NULL;
46   if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
47     return NULL;
48
49   if (filelen < 0) {
50     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
51     return NULL;
52   }
53   
54   buffer = silc_calloc(filelen + 1, sizeof(char));
55   
56   if ((read(fd, buffer, filelen)) == -1) {
57     memset(buffer, 0, sizeof(buffer));
58     close(fd);
59     SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
60                     strerror(errno)));
61     return NULL;
62   }
63
64   close(fd);
65   buffer[filelen] = EOF;
66
67   if (return_len)
68     *return_len = filelen;
69
70   return buffer;
71 }
72
73 /* Writes a buffer to the file. */
74
75 int silc_file_write(const char *filename, const char *buffer, int len)
76 {
77   int fd;
78         
79   if ((fd = creat(filename, 0644)) == -1) {
80     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
81     return -1;
82   }
83   
84   if ((write(fd, buffer, len)) == -1) {
85     SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
86     return -1;
87   }
88
89   close(fd);
90   
91   return 0;
92 }
93
94 /* Writes a buffer to the file.  If the file is created specific mode is
95    set to the file. */
96
97 int silc_file_write_mode(const char *filename, const char *buffer, 
98                          int len, int mode)
99 {
100   int fd;
101         
102   if ((fd = creat(filename, mode)) == -1) {
103     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
104     return -1;
105   }
106   
107   if ((write(fd, buffer, len)) == -1) {
108     SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
109     return -1;
110   }
111
112   close(fd);
113   
114   return 0;
115 }
116
117 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
118    This doesn't remove the newline sign from the destination buffer. The
119    argument begin is returned and should be passed again for the function. */
120
121 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
122 {
123   static int start = 0;
124   int i;
125   
126   memset(dest, 0, destlen);
127   
128   if (begin != start)
129     start = 0;
130   
131   i = 0;
132   for ( ; start <= srclen; i++, start++) {
133     if (i > destlen)
134       return -1;
135     
136     dest[i] = src[start];
137     
138     if (dest[i] == EOF) 
139       return EOF;
140     
141     if (dest[i] == '\n') 
142       break;
143   }
144   start++;
145   
146   return start;
147 }
148
149 /* Checks line for illegal characters. Return -1 when illegal character
150    were found. This is used to check for bad lines when reading data from
151    for example a configuration file. */
152
153 int silc_check_line(char *buf) 
154 {
155   /* Illegal characters in line */
156   if (strchr(buf, '#')) return -1;
157   if (strchr(buf, '\'')) return -1;
158   if (strchr(buf, '\\')) return -1;
159   if (strchr(buf, '\r')) return -1;
160   if (strchr(buf, '\a')) return -1;
161   if (strchr(buf, '\b')) return -1;
162   if (strchr(buf, '\f')) return -1;
163   
164   /* Empty line */
165   if (buf[0] == '\n')
166     return -1;
167   
168   return 0;
169 }
170
171 /* Returns current time as string. */
172
173 char *silc_get_time()
174 {
175   time_t curtime;
176   char *return_time;
177
178   curtime = time(NULL);
179   return_time = ctime(&curtime);
180   return_time[strlen(return_time) - 1] = '\0';
181
182   return return_time;
183 }
184
185 /* Converts string to capital characters */
186
187 char *silc_to_upper(char *string)
188 {
189   int i;
190   char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
191
192   for (i = 0; i < strlen(string); i++)
193     ret[i] = toupper(string[i]);
194
195   return ret;
196 }
197
198 static unsigned char pem_enc[64] =
199 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
200
201 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
202    data string. Note: This is originally public domain code and is 
203    still PD. */
204
205 char *silc_encode_pem(unsigned char *data, unsigned int len)
206 {
207   int i, j;
208   unsigned int bits, c, char_count;
209   char *pem;
210
211   char_count = 0;
212   bits = 0;
213   j = 0;
214
215   pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
216
217   for (i = 0; i < len; i++) {
218     c = data[i];
219     bits += c;
220     char_count++;
221
222     if (char_count == 3) {
223       pem[j++] = pem_enc[bits  >> 18];
224       pem[j++] = pem_enc[(bits >> 12) & 0x3f];
225       pem[j++] = pem_enc[(bits >> 6)  & 0x3f];
226       pem[j++] = pem_enc[bits & 0x3f];
227       bits = 0;
228       char_count = 0;
229     } else {
230       bits <<= 8;
231     }
232   }
233
234   if (char_count != 0) {
235     bits <<= 16 - (8 * char_count);
236     pem[j++] = pem_enc[bits >> 18];
237     pem[j++] = pem_enc[(bits >> 12) & 0x3f];
238
239     if (char_count == 1) {
240       pem[j++] = '=';
241       pem[j] = '=';
242     } else {
243       pem[j++] = pem_enc[(bits >> 6) & 0x3f];
244       pem[j] = '=';
245     }
246   }
247
248   return pem;
249 }
250
251 /* Same as above but puts newline ('\n') every 72 characters. */
252
253 char *silc_encode_pem_file(unsigned char *data, unsigned int data_len)
254 {
255   int i, j;
256   unsigned int len, cols;
257   char *pem, *pem2;
258
259   pem = silc_encode_pem(data, data_len);
260   len = strlen(pem);
261
262   pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
263
264   for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
265     if (cols == 72) {
266       pem2[i] = '\n';
267       cols = 0;
268       len++;
269       continue;
270     }
271
272     pem2[i] = pem[j++];
273   }
274
275   return pem2;
276 }
277
278 /* Decodes PEM into data. Returns the decoded data. Note: This is
279    originally public domain code and is still PD. */
280
281 unsigned char *silc_decode_pem(unsigned char *pem, unsigned int pem_len,
282                                unsigned int *ret_len)
283 {
284   int i, j;
285   unsigned int len, c, char_count, bits;
286   unsigned char *data;
287   static char ialpha[256], decoder[256];
288
289   for (i = 64 - 1; i >= 0; i--) {
290     ialpha[pem_enc[i]] = 1;
291     decoder[pem_enc[i]] = i;
292   }
293
294   char_count = 0;
295   bits = 0;
296   j = 0;
297
298   if (!pem_len)
299     len = strlen(pem);
300   else
301     len = pem_len;
302
303   data = silc_calloc(((len * 6) / 8), sizeof(*data));
304
305   for (i = 0; i < len; i++) {
306     c = pem[i];
307
308     if (c == '=')
309       break;
310
311     if (c > 127 || !ialpha[c])
312       continue;
313
314     bits += decoder[c];
315     char_count++;
316
317     if (char_count == 4) {
318       data[j++] = bits >> 16;
319       data[j++] = (bits >> 8) & 0xff;
320       data[j++] = bits & 0xff;
321       bits = 0;
322       char_count = 0;
323     } else {
324       bits <<= 6;
325     }
326   }
327
328   switch(char_count) {
329   case 1:
330     silc_free(data);
331     return NULL;
332     break;
333   case 2:
334     data[j++] = bits >> 10;
335     break;
336   case 3:
337     data[j++] = bits >> 16;
338     data[j++] = (bits >> 8) & 0xff;
339     break;
340   }
341
342   if (ret_len)
343     *ret_len = j;
344
345   return data;
346 }
347
348 /* Parse nickname string. The format may be <num>!<nickname>@<server> to
349    support multiple same nicknames. The <num> is the final unifier if same
350    nickname is on same server. Note, this is only local format and server
351    does not know anything about these. */
352
353 int silc_parse_nickname(char *string, char **nickname, char **server,
354                         unsigned int *num)
355 {
356   unsigned int tlen;
357   char tmp[256];
358
359   if (!string)
360     return FALSE;
361
362   if (strchr(string, '!')) {
363     tlen = strcspn(string, "!");
364     memset(tmp, 0, sizeof(tmp));
365     memcpy(tmp, string, tlen);
366
367     if (num)
368       *num = atoi(tmp);
369
370     if (tlen >= strlen(string))
371       return FALSE;
372
373     string += tlen + 1;
374   }
375
376   if (strchr(string, '@')) {
377     tlen = strcspn(string, "@");
378     
379     if (nickname) {
380       *nickname = silc_calloc(tlen + 1, sizeof(char));
381       memcpy(*nickname, string, tlen);
382     }
383     
384     if (server) {
385       *server = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
386       memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
387     }
388   } else {
389     if (nickname)
390       *nickname = strdup(string);
391   }
392
393   return TRUE;
394 }
395
396 /* Parses command line. At most `max_args' is taken. Rest of the line
397    will be allocated as the last argument if there are more than `max_args'
398    arguments in the line. Note that the command name is counted as one
399    argument and is saved. */
400
401 void silc_parse_command_line(unsigned char *buffer, 
402                              unsigned char ***parsed,
403                              unsigned int **parsed_lens,
404                              unsigned int **parsed_types,
405                              unsigned int *parsed_num,
406                              unsigned int max_args)
407 {
408   int i, len = 0;
409   int argc = 0;
410   const char *cp = buffer;
411
412   *parsed = silc_calloc(1, sizeof(**parsed));
413   *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
414
415   /* Get the command first */
416   len = strcspn(cp, " ");
417   (*parsed)[0] = silc_to_upper((char *)cp);
418   (*parsed_lens)[0] = len;
419   cp += len + 1;
420   argc++;
421
422   /* Parse arguments */
423   if (strchr(cp, ' ') || strlen(cp) != 0) {
424     for (i = 1; i < max_args; i++) {
425
426       if (i != max_args - 1)
427         len = strcspn(cp, " ");
428       else
429         len = strlen(cp);
430       
431       *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
432       *parsed_lens = silc_realloc(*parsed_lens, 
433                                   sizeof(**parsed_lens) * (argc + 1));
434       (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
435       memcpy((*parsed)[argc], cp, len);
436       (*parsed_lens)[argc] = len;
437       argc++;
438
439       cp += len;
440       if (strlen(cp) == 0)
441         break;
442       else
443         cp++;
444     }
445   }
446
447   /* Save argument types. Protocol defines all argument types but
448      this implementation makes sure that they are always in correct
449      order hence this simple code. */
450   *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
451   for (i = 0; i < argc; i++)
452     (*parsed_types)[i] = i;
453
454   *parsed_num = argc;
455 }
456
457 /* Formats arguments to a string and returns it after allocating memory
458    for it. It must be remembered to free it later. */
459
460 char *silc_format(char *fmt, ...)
461 {
462   va_list args;
463   static char buf[8192];
464
465   memset(buf, 0, sizeof(buf));
466   va_start(args, fmt);
467   vsnprintf(buf, sizeof(buf) - 1, fmt, args);
468   va_end(args);
469
470   return strdup(buf);
471 }
472
473 /* Renders ID to suitable to print for example to log file. */
474
475 static char rid[256];
476
477 char *silc_id_render(void *id, unsigned short type)
478 {
479   char tmp[100];
480   unsigned char tmps[2];
481
482   memset(rid, 0, sizeof(rid));
483   switch(type) {
484   case SILC_ID_SERVER:
485     {
486       SilcServerID *server_id = (SilcServerID *)id;
487       strcat(rid, inet_ntoa(server_id->ip));
488       memset(tmp, 0, sizeof(tmp));
489       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
490       strcat(rid, tmp);
491       SILC_PUT16_MSB(server_id->rnd, tmps);
492       memset(tmp, 0, sizeof(tmp));
493       snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
494       strcat(rid, tmp);
495     }
496     break;
497   case SILC_ID_CLIENT:
498     {
499       SilcClientID *client_id = (SilcClientID *)id;
500       strcat(rid, inet_ntoa(client_id->ip));
501       memset(tmp, 0, sizeof(tmp));
502       snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
503       strcat(rid, tmp);
504       memset(tmp, 0, sizeof(tmp));
505       snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]", 
506                client_id->hash[0], client_id->hash[1],
507                client_id->hash[2], client_id->hash[3]);
508       strcat(rid, tmp);
509     }
510     break;
511   case SILC_ID_CHANNEL:
512     {
513       SilcChannelID *channel_id = (SilcChannelID *)id;
514       strcat(rid, inet_ntoa(channel_id->ip));
515       memset(tmp, 0, sizeof(tmp));
516       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
517       strcat(rid, tmp);
518       SILC_PUT16_MSB(channel_id->rnd, tmps);
519       memset(tmp, 0, sizeof(tmp));
520       snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
521       strcat(rid, tmp);
522     }
523     break;
524   }
525
526   return rid;
527 }
528
529 /* Compares two strings. Strings may include wildcards * and ?.
530    Returns TRUE if strings match. */
531
532 int silc_string_compare(char *string1, char *string2)
533 {
534   int i;
535   int slen1 = strlen(string1);
536   int slen2 = strlen(string2);
537   char *tmpstr1, *tmpstr2;
538
539   if (!string1 || !string2)
540     return FALSE;
541
542   /* See if they are same already */
543   if (!strncmp(string1, string2, strlen(string2)))
544     return TRUE;
545
546   if (slen2 < slen1)
547     if (!strchr(string1, '*'))
548       return FALSE;
549   
550   /* Take copies of the original strings as we will change them */
551   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
552   memcpy(tmpstr1, string1, slen1);
553   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
554   memcpy(tmpstr2, string2, slen2);
555   
556   for (i = 0; i < slen2; i++) {
557     
558     /* * wildcard. Only one * wildcard is possible. */
559     if (tmpstr1[i] == '*')
560       if (!strncmp(tmpstr1, tmpstr2, i)) {
561         memset(tmpstr2, 0, slen2);
562         strncpy(tmpstr2, tmpstr1, i);
563         break;
564       }
565     
566     /* ? wildcard */
567     if (tmpstr1[i] == '?') {
568       if (!strncmp(tmpstr1, tmpstr2, i)) {
569         if (!(slen1 < i + 1))
570           if (tmpstr1[i + 1] != '?' &&
571               tmpstr1[i + 1] != tmpstr2[i + 1])
572             continue;
573         
574         if (!(slen1 < slen2))
575           tmpstr2[i] = '?';
576       }
577 #if 0
578     } else {
579       if (strncmp(tmpstr1, tmpstr2, i))
580         strncpy(tmpstr2, string2, slen2);
581 #endif
582     }
583   }
584   
585   /* if using *, remove it */
586   if (strchr(tmpstr1, '*'))
587     *strchr(tmpstr1, '*') = 0;
588   
589   if (!strcmp(tmpstr1, tmpstr2)) {
590     memset(tmpstr1, 0, slen1);
591     memset(tmpstr2, 0, slen2);
592     silc_free(tmpstr1);
593     silc_free(tmpstr2);
594     return TRUE;
595   }
596   
597   memset(tmpstr1, 0, slen1);
598   memset(tmpstr2, 0, slen2);
599   silc_free(tmpstr1);
600   silc_free(tmpstr2);
601   return FALSE;
602 }
603
604 /* Inspects the `string' for wildcards and returns regex string that can
605    be used by the GNU regex library. This has a lot overhead but luckily
606    this is used only for short strings. */
607
608 char *silc_string_regexify(const char *string)
609 {
610   int i, len, count;
611   char *regex;
612
613   /* If there is no wildcards then we don't need to regexify the string. */
614   if (!strchr(string, '*') && !strchr(string, '?'))
615     return strdup(string);
616
617   len = strlen(string);
618   count = 0;
619
620   for (i = 0; i < len; i++)
621     if (string[i] == '*' || string[i] == '?')
622       count++;
623
624   regex = silc_calloc(len + count + 4, sizeof(*regex));
625
626   count = 0;
627   regex[count] = '(';
628   count++;
629
630   for (i = 0; i < len; i++) {
631     if (string[i] == '*' || string[i] == '?') {
632       regex[count] = '.';
633       count++;
634     }
635
636     regex[count] = string[i];
637     count++;
638   }
639
640   regex[count - 1] = ')';
641   regex[count] = '$';
642
643   return regex;
644 }
645
646 /* Combines two regex strings into one regex string so that they can be
647    used as one by the GNU regex library. The `string2' is combine into
648    the `string1'. */
649
650 char *silc_string_regex_combine(const char *string1, const char *string2)
651 {
652   char *tmp;
653   int len1, len2;
654
655   len1 = strlen(string1);
656   len2 = strlen(string2);
657
658   tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
659   memcpy(tmp, string1, len1 - 2);
660   memcpy(tmp, "|", 1);
661   memcpy(tmp, string2 + 1, len2 - 1);
662
663   return tmp;
664 }
665
666 /* Matches the two strings and returns TRUE if the strings match. */
667
668 int silc_string_regex_match(const char *regex, const char *string)
669 {
670   regex_t preg;
671   int ret = FALSE;
672   
673   if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
674     return FALSE;
675
676   if (regexec(&preg, string, 0, NULL, 0) == 0)
677     ret = TRUE;
678
679   regfree(&preg);
680
681   return ret;
682 }