Added preliminary backup router support for standalone routers.
[silc.git] / lib / silcutil / silcutil.c
1 /*
2
3   silcutil.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /*
20  * These are general utility functions that doesn't belong to any specific
21  * group of routines.
22  */
23 /* $Id$ */
24
25 #include "silcincludes.h"
26
27 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
28    This doesn't remove the newline sign from the destination buffer. The
29    argument begin is returned and should be passed again for the function. */
30
31 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
32 {
33   static int start = 0;
34   int i;
35
36   memset(dest, 0, destlen);
37
38   if (begin != start)
39     start = 0;
40
41   i = 0;
42   for ( ; start <= srclen; i++, start++) {
43     if (i > destlen)
44       return -1;
45
46     dest[i] = src[start];
47
48     if (dest[i] == EOF)
49       return EOF;
50
51     if (dest[i] == '\n')
52       break;
53   }
54   start++;
55
56   return start;
57 }
58
59 /* Checks line for illegal characters. Return -1 when illegal character
60    were found. This is used to check for bad lines when reading data from
61    for example a configuration file. */
62
63 int silc_check_line(char *buf)
64 {
65   /* Illegal characters in line */
66   if (strchr(buf, '#')) return -1;
67   if (strchr(buf, '\'')) return -1;
68   if (strchr(buf, '\\')) return -1;
69   if (strchr(buf, '\r')) return -1;
70   if (strchr(buf, '\a')) return -1;
71   if (strchr(buf, '\b')) return -1;
72   if (strchr(buf, '\f')) return -1;
73
74   /* Empty line */
75   if (buf[0] == '\n')
76     return -1;
77
78   return 0;
79 }
80
81 /* Returns current time as string. */
82
83 char *silc_get_time()
84 {
85   time_t curtime;
86   char *return_time;
87
88   curtime = time(NULL);
89   return_time = ctime(&curtime);
90   return_time[strlen(return_time) - 1] = '\0';
91
92   return return_time;
93 }
94
95 /* Converts string to capital characters. */
96
97 bool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
98 {
99   int i;
100
101   if (strlen(string) > dest_size)
102     return FALSE;
103
104   for (i = 0; i < strlen(string); i++)
105     dest[i] = toupper(string[i]);
106
107   return TRUE;
108 }
109
110 /* Converts string to lower letter characters. */
111
112 bool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
113 {
114   int i;
115
116   if (strlen(string) > dest_size)
117     return FALSE;
118
119   for (i = 0; i < strlen(string); i++)
120     dest[i] = tolower(string[i]);
121
122   return TRUE;
123 }
124
125 /* Parse userfqdn string which is in user@fqdn format. */
126
127 bool silc_parse_userfqdn(const char *string, char **left, char **right)
128 {
129   SilcUInt32 tlen;
130
131   if (!string)
132     return FALSE;
133
134   if (string[0] == '@') {
135     if (left)
136       *left = strdup(string);
137     return TRUE;
138   }
139
140   if (strchr(string, '@')) {
141     tlen = strcspn(string, "@");
142
143     if (left) {
144       *left = silc_calloc(tlen + 1, sizeof(char));
145       memcpy(*left, string, tlen);
146     }
147
148     if (right) {
149       *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
150       memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
151     }
152   } else {
153     if (left)
154       *left = strdup(string);
155   }
156
157   return TRUE;
158 }
159
160 /* Parses command line. At most `max_args' is taken. Rest of the line
161    will be allocated as the last argument if there are more than `max_args'
162    arguments in the line. Note that the command name is counted as one
163    argument and is saved. */
164
165 void silc_parse_command_line(unsigned char *buffer,
166                              unsigned char ***parsed,
167                              SilcUInt32 **parsed_lens,
168                              SilcUInt32 **parsed_types,
169                              SilcUInt32 *parsed_num,
170                              SilcUInt32 max_args)
171 {
172   int i, len = 0;
173   int argc = 0;
174   const char *cp = buffer;
175   char *tmp;
176
177   *parsed = silc_calloc(1, sizeof(**parsed));
178   *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
179
180   /* Get the command first */
181   len = strcspn(cp, " ");
182   tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp));
183   if (!tmp)
184     return;
185   silc_to_upper(cp, tmp, strlen(cp));
186   (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
187   memcpy((*parsed)[0], tmp, len);
188   silc_free(tmp);
189   (*parsed_lens)[0] = len;
190   cp += len;
191   while (*cp == ' ')
192     cp++;
193   argc++;
194
195   /* Parse arguments */
196   if (strchr(cp, ' ') || strlen(cp) != 0) {
197     for (i = 1; i < max_args; i++) {
198
199       if (i != max_args - 1)
200         len = strcspn(cp, " ");
201       else
202         len = strlen(cp);
203       while (len && cp[len - 1] == ' ')
204         len--;
205       if (!len)
206         break;
207
208       *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
209       *parsed_lens = silc_realloc(*parsed_lens,
210                                   sizeof(**parsed_lens) * (argc + 1));
211       (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
212       memcpy((*parsed)[argc], cp, len);
213       (*parsed_lens)[argc] = len;
214       argc++;
215
216       cp += len;
217       if (strlen(cp) == 0)
218         break;
219       else
220         while (*cp == ' ')
221           cp++;
222     }
223   }
224
225   /* Save argument types. Protocol defines all argument types but
226      this implementation makes sure that they are always in correct
227      order hence this simple code. */
228   *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
229   for (i = 0; i < argc; i++)
230     (*parsed_types)[i] = i;
231
232   *parsed_num = argc;
233 }
234
235 /* Formats arguments to a string and returns it after allocating memory
236    for it. It must be remembered to free it later. */
237
238 char *silc_format(char *fmt, ...)
239 {
240   va_list args;
241   static char buf[8192];
242
243   memset(buf, 0, sizeof(buf));
244   va_start(args, fmt);
245   vsnprintf(buf, sizeof(buf) - 1, fmt, args);
246   va_end(args);
247
248   return strdup(buf);
249 }
250
251 /* Renders ID to suitable to print for example to log file. */
252
253 static char rid[256];
254 #define _PUT_STRING(__d__, __s__)                                       \
255 do {                                                                    \
256   int __sp = sizeof(__d__) - 1 - strlen(__d__);                         \
257   if (__sp < strlen(__s__)) {                                           \
258     if (__sp)                                                           \
259       strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__));       \
260   } else {                                                              \
261     strncat(__d__, __s__, strlen(__s__));                               \
262   }                                                                     \
263 } while(0)
264
265 char *silc_id_render(void *id, SilcUInt16 type)
266 {
267   char tmp[100];
268   unsigned char tmps[2];
269   char *cp;
270
271   memset(rid, 0, sizeof(rid));
272   switch(type) {
273   case SILC_ID_SERVER:
274     {
275       SilcServerID *server_id = (SilcServerID *)id;
276       if (server_id->ip.data_len > 4) {
277 #ifdef HAVE_IPV6
278         struct sockaddr_in6 ipv6;
279         memset(&ipv6, 0, sizeof(ipv6));
280         ipv6.sin6_family = AF_INET6;
281         memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
282         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
283                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
284           _PUT_STRING(rid, tmp);
285 #endif
286       } else {
287         struct in_addr ipv4;
288         memmove(&ipv4.s_addr, server_id->ip.data, 4);
289         cp = inet_ntoa(ipv4);
290         if (cp)
291           _PUT_STRING(rid, cp);
292       }
293
294       memset(tmp, 0, sizeof(tmp));
295       snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
296       _PUT_STRING(rid, tmp);
297       SILC_PUT16_MSB(server_id->rnd, tmps);
298       memset(tmp, 0, sizeof(tmp));
299       snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
300       _PUT_STRING(rid, tmp);
301     }
302     break;
303   case SILC_ID_CLIENT:
304     {
305       SilcClientID *client_id = (SilcClientID *)id;
306       if (client_id->ip.data_len > 4) {
307 #ifdef HAVE_IPV6
308         struct sockaddr_in6 ipv6;
309         memset(&ipv6, 0, sizeof(ipv6));
310         ipv6.sin6_family = AF_INET6;
311         memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
312         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
313                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
314           _PUT_STRING(rid, tmp);
315 #endif
316       } else {
317         struct in_addr ipv4;
318         memmove(&ipv4.s_addr, client_id->ip.data, 4);
319         cp = inet_ntoa(ipv4);
320         if (cp)
321           _PUT_STRING(rid, cp);
322       }
323
324       memset(tmp, 0, sizeof(tmp));
325       snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
326       _PUT_STRING(rid, tmp);
327       memset(tmp, 0, sizeof(tmp));
328       snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
329                client_id->hash[0], client_id->hash[1],
330                client_id->hash[2], client_id->hash[3]);
331       _PUT_STRING(rid, tmp);
332     }
333     break;
334   case SILC_ID_CHANNEL:
335     {
336       SilcChannelID *channel_id = (SilcChannelID *)id;
337       if (channel_id->ip.data_len > 4) {
338 #ifdef HAVE_IPV6
339         struct sockaddr_in6 ipv6;
340         memset(&ipv6, 0, sizeof(ipv6));
341         ipv6.sin6_family = AF_INET6;
342         memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
343         if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
344                          tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
345           _PUT_STRING(rid, tmp);
346 #endif
347       } else {
348         struct in_addr ipv4;
349         memmove(&ipv4.s_addr, channel_id->ip.data, 4);
350         cp = inet_ntoa(ipv4);
351         if (cp)
352           _PUT_STRING(rid, cp);
353       }
354
355       memset(tmp, 0, sizeof(tmp));
356       snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
357       _PUT_STRING(rid, tmp);
358       SILC_PUT16_MSB(channel_id->rnd, tmps);
359       memset(tmp, 0, sizeof(tmp));
360       snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
361       _PUT_STRING(rid, tmp);
362     }
363     break;
364   }
365
366   return rid;
367 }
368 #undef _PUT_STRING
369
370 /* Compares two strings. Strings may include wildcards '*' and '?'.
371    Returns TRUE if strings match. */
372
373 int silc_string_compare(char *string1, char *string2)
374 {
375   int i;
376   int slen1;
377   int slen2;
378   char *tmpstr1, *tmpstr2;
379
380   if (!string1 || !string2)
381     return FALSE;
382
383   slen1 = strlen(string1);
384   slen2 = strlen(string2);
385
386   /* See if they are same already */
387   if (!strncmp(string1, string2, strlen(string2)))
388     return TRUE;
389
390   if (slen2 < slen1)
391     if (!strchr(string1, '*'))
392       return FALSE;
393
394   /* Take copies of the original strings as we will change them */
395   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
396   memcpy(tmpstr1, string1, slen1);
397   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
398   memcpy(tmpstr2, string2, slen2);
399
400   for (i = 0; i < slen1; i++) {
401
402     /* * wildcard. Only one * wildcard is possible. */
403     if (tmpstr1[i] == '*')
404       if (!strncmp(tmpstr1, tmpstr2, i)) {
405         memset(tmpstr2, 0, slen2);
406         strncpy(tmpstr2, tmpstr1, i);
407         break;
408       }
409
410     /* ? wildcard */
411     if (tmpstr1[i] == '?') {
412       if (!strncmp(tmpstr1, tmpstr2, i)) {
413         if (!(slen1 < i + 1))
414           if (tmpstr1[i + 1] != '?' &&
415               tmpstr1[i + 1] != tmpstr2[i + 1])
416             continue;
417
418         if (!(slen1 < slen2))
419           tmpstr2[i] = '?';
420       }
421     }
422   }
423
424   /* if using *, remove it */
425   if (strchr(tmpstr1, '*'))
426     *strchr(tmpstr1, '*') = 0;
427
428   if (!strcmp(tmpstr1, tmpstr2)) {
429     memset(tmpstr1, 0, slen1);
430     memset(tmpstr2, 0, slen2);
431     silc_free(tmpstr1);
432     silc_free(tmpstr2);
433     return TRUE;
434   }
435
436   memset(tmpstr1, 0, slen1);
437   memset(tmpstr2, 0, slen2);
438   silc_free(tmpstr1);
439   silc_free(tmpstr2);
440   return FALSE;
441 }
442
443 /* Basic has function to hash strings. May be used with the SilcHashTable.
444    Note that this lowers the characters of the string (with tolower()) so
445    this is used usually with nicknames, channel and server names to provide
446    case insensitive keys. */
447
448 SilcUInt32 silc_hash_string(void *key, void *user_context)
449 {
450   char *s = (char *)key;
451   SilcUInt32 h = 0, g;
452
453   while (*s != '\0') {
454     h = (h << 4) + tolower(*s);
455     if ((g = h & 0xf0000000)) {
456       h = h ^ (g >> 24);
457       h = h ^ g;
458     }
459     s++;
460   }
461
462   return h;
463 }
464
465 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
466
467 SilcUInt32 silc_hash_uint(void *key, void *user_context)
468 {
469   return *(SilcUInt32 *)key;
470 }
471
472 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
473
474 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
475 {
476   return (SilcUInt32)key;
477 }
478
479 /* Hash a ID. The `user_context' is the ID type. */
480
481 SilcUInt32 silc_hash_id(void *key, void *user_context)
482 {
483   SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
484   SilcUInt32 h = 0;
485   int i;
486
487   switch (id_type) {
488   case SILC_ID_CLIENT:
489     {
490       SilcClientID *id = (SilcClientID *)key;
491
492       /* The client ID is hashed by hashing the hash of the ID
493          (which is a truncated MD5 hash of the nickname) so that we
494          can access the entry from the cache with both Client ID but
495          with just a hash from the ID as well. */
496       return silc_hash_client_id_hash(id->hash, NULL);
497     }
498     break;
499   case SILC_ID_SERVER:
500     {
501       SilcServerID *id = (SilcServerID *)key;
502
503       h = id->port * id->rnd;
504       for (i = 0; i < id->ip.data_len; i++)
505         h ^= id->ip.data[i];
506
507       return h;
508     }
509     break;
510   case SILC_ID_CHANNEL:
511     {
512       SilcChannelID *id = (SilcChannelID *)key;
513
514       h = id->port * id->rnd;
515       for (i = 0; i < id->ip.data_len; i++)
516         h ^= id->ip.data[i];
517
518       return h;
519     }
520     break;
521   default:
522     break;
523   }
524
525   return h;
526 }
527
528 /* Hash Client ID's hash. */
529
530 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
531 {
532   int i;
533   unsigned char *hash = key;
534   SilcUInt32 h = 0, g;
535
536   for (i = 0; i < CLIENTID_HASH_LEN; i++) {
537     h = (h << 4) + hash[i];
538     if ((g = h & 0xf0000000)) {
539       h = h ^ (g >> 24);
540       h = h ^ g;
541     }
542   }
543
544   return h;
545 }
546
547 /* Hash binary data. The `user_context' is the data length. */
548
549 SilcUInt32 silc_hash_data(void *key, void *user_context)
550 {
551   SilcUInt32 len = (SilcUInt32)user_context, h = 0;
552   unsigned char *data = (unsigned char *)key;
553   int i;
554
555   h = (data[0] * data[len - 1] + 1) * len;
556   for (i = 0; i < len; i++)
557     h ^= data[i];
558
559   return h;
560 }
561
562 /* Hashed SILC Public key. */
563
564 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
565 {
566   SilcPublicKey pk = (SilcPublicKey)key;
567   return (pk->len + silc_hash_string(pk->name, NULL) +
568           silc_hash_string(pk->identifier, NULL) +
569           silc_hash_data(pk->pk, (void *)pk->pk_len));
570 }
571
572 /* Compares two strings. It may be used as SilcHashTable comparison
573    function. */
574
575 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
576 {
577   return !strcasecmp((char *)key1, (char *)key2);
578 }
579
580 /* Compares two ID's. May be used as SilcHashTable comparison function.
581    The Client ID's compares only the hash of the Client ID not any other
582    part of the Client ID. Other ID's are fully compared. */
583
584 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
585 {
586   SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
587   return (id_type == SILC_ID_CLIENT ?
588           SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
589           SILC_ID_COMPARE_TYPE(key1, key2, id_type));
590 }
591
592 /* Compare two Client ID's entirely and not just the hash from the ID. */
593
594 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
595 {
596   return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
597 }
598
599 /* Compares binary data. May be used as SilcHashTable comparison function. */
600
601 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
602 {
603   SilcUInt32 len = (SilcUInt32)user_context;
604   return !memcmp(key1, key2, len);
605 }
606
607 /* Compares two SILC Public keys. It may be used as SilcHashTable
608    comparison function. */
609
610 bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
611 {
612   return silc_pkcs_public_key_compare(key1, key2);
613 }
614
615 /* Parses mode mask and returns the mode as string. */
616
617 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
618 {
619   char string[100];
620
621   if (!mode)
622     return NULL;
623
624   memset(string, 0, sizeof(string));
625
626   if (mode & SILC_CHANNEL_MODE_PRIVATE)
627     strncat(string, "p", 1);
628
629   if (mode & SILC_CHANNEL_MODE_SECRET)
630     strncat(string, "s", 1);
631
632   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
633     strncat(string, "k", 1);
634
635   if (mode & SILC_CHANNEL_MODE_INVITE)
636     strncat(string, "i", 1);
637
638   if (mode & SILC_CHANNEL_MODE_TOPIC)
639     strncat(string, "t", 1);
640
641   if (mode & SILC_CHANNEL_MODE_ULIMIT)
642     strncat(string, "l", 1);
643
644   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
645     strncat(string, "a", 1);
646
647   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
648     strncat(string, "f", 1);
649
650   if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
651     strncat(string, "m", 1);
652
653   if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
654     strncat(string, "M", 1);
655
656   if (mode & SILC_CHANNEL_MODE_CIPHER)
657     strncat(string, cipher, strlen(cipher));
658
659   if (mode & SILC_CHANNEL_MODE_HMAC)
660     strncat(string, hmac, strlen(hmac));
661
662   /* Rest of mode is ignored */
663
664   return strdup(string);
665 }
666
667 /* Parses channel user mode mask and returns te mode as string */
668
669 char *silc_client_chumode(SilcUInt32 mode)
670 {
671   char string[4];
672
673   if (!mode)
674     return NULL;
675
676   memset(string, 0, sizeof(string));
677
678   if (mode & SILC_CHANNEL_UMODE_CHANFO)
679     strncat(string, "f", 1);
680
681   if (mode & SILC_CHANNEL_UMODE_CHANOP)
682     strncat(string, "o", 1);
683
684   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
685     strncat(string, "b", 1);
686
687   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
688     strncat(string, "u", 1);
689
690   if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
691     strncat(string, "r", 1);
692
693   if (mode & SILC_CHANNEL_UMODE_QUIET)
694     strncat(string, "q", 1);
695
696   return strdup(string);
697 }
698
699 /* Parses channel user mode and returns it as special mode character. */
700
701 char *silc_client_chumode_char(SilcUInt32 mode)
702 {
703   char string[4];
704
705   if (!mode)
706     return NULL;
707
708   memset(string, 0, sizeof(string));
709
710   if (mode & SILC_CHANNEL_UMODE_CHANFO)
711     strncat(string, "*", 1);
712
713   if (mode & SILC_CHANNEL_UMODE_CHANOP)
714     strncat(string, "@", 1);
715
716   if (mode & SILC_CHANNEL_UMODE_QUIET)
717     strncat(string, "&", 1);
718
719   return strdup(string);
720 }
721
722 /* Creates fingerprint from data, usually used with SHA1 digests */
723
724 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
725 {
726   char fingerprint[64], *cp;
727   int i;
728
729   memset(fingerprint, 0, sizeof(fingerprint));
730   cp = fingerprint;
731   for (i = 0; i < data_len; i++) {
732     snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
733     cp += 2;
734
735     if ((i + 1) % 2 == 0)
736       snprintf(cp++, sizeof(fingerprint), " ");
737
738     if ((i + 1) % 10 == 0)
739       snprintf(cp++, sizeof(fingerprint), " ");
740   }
741   i--;
742   if ((i + 1) % 2 == 0)
743     cp[-2] = 0;
744   if ((i + 1) % 10 == 0)
745     cp[-1] = 0;
746
747   return strdup(fingerprint);
748 }
749
750 /* Return TRUE if the `data' is ASCII string. */
751
752 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
753 {
754   int i;
755
756   for (i = 0; i < data_len; i++) {
757     if (!isascii(data[i]))
758       return FALSE;
759   }
760
761   return TRUE;
762 }
763
764 /* Parses SILC protocol style version string. */
765
766 bool silc_parse_version_string(const char *version,
767                                SilcUInt32 *protocol_version,
768                                char **protocol_version_string,
769                                SilcUInt32 *software_version,
770                                char **software_version_string,
771                                char **vendor_version)
772 {
773   char *cp, buf[32];
774   int maj = 0, min = 0;
775
776   if (!strstr(version, "SILC-"))
777     return FALSE;
778
779   cp = (char *)version + 5;
780   if (!cp)
781     return FALSE;
782
783   /* Take protocol version */
784
785   maj = atoi(cp);
786   cp = strchr(cp, '.');
787   if (cp) {
788     min = atoi(cp + 1);
789     cp++;
790   }
791
792   memset(buf, 0, sizeof(buf));
793   snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
794   if (protocol_version)
795     *protocol_version = atoi(buf);
796   memset(buf, 0, sizeof(buf));
797   snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
798   if (protocol_version_string)
799     *protocol_version_string = strdup(buf);
800
801   /* Take software version */
802
803   maj = 0;
804   min = 0;
805   cp = strchr(cp, '-');
806   if (!cp)
807     return FALSE;
808
809   maj = atoi(cp + 1);
810   cp = strchr(cp, '.');
811   if (cp)
812     min = atoi(cp + 1);
813
814   memset(buf, 0, sizeof(buf));
815   snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
816   if (software_version)
817     *software_version = atoi(buf);
818   memset(buf, 0, sizeof(buf));
819   snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
820   if (software_version_string)
821     *software_version_string = strdup(buf);
822
823   /* Take vendor string */
824
825   cp++;
826   if (cp) {
827     cp = strchr(cp, '.');
828     if (cp && cp + 1 && vendor_version)
829       *vendor_version = strdup(cp + 1);
830   }
831
832   return TRUE;
833 }
834
835 /* Converts version string x.x into number representation. */
836
837 SilcUInt32 silc_version_to_num(const char *version)
838 {
839   int maj = 0, min = 0;
840   char *cp, buf[32];
841
842   if (!version)
843     return 0;
844
845   cp = (char *)version;
846   maj = atoi(cp);
847   cp = strchr(cp, '.');
848   if (cp)
849     min = atoi(cp + 1);
850
851   memset(buf, 0, sizeof(buf));
852   snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
853   return (SilcUInt32)atoi(buf);
854 }
855
856 /* Displays input prompt on command line and takes input data from user */
857
858 char *silc_get_input(const char *prompt, bool echo_off)
859 {
860 #ifdef SILC_UNIX
861   if (echo_off) {
862     char *ret = NULL;
863 #ifdef HAVE_TERMIOS_H
864     char input[2048];
865     int fd;
866     struct termios to;
867     struct termios to_old;
868
869     fd = open("/dev/tty", O_RDONLY);
870     if (fd < 0) {
871       fprintf(stderr, "silc: %s\n", strerror(errno));
872       return NULL;
873     }
874
875     signal(SIGINT, SIG_IGN);
876
877     /* Get terminal info */
878     tcgetattr(fd, &to);
879     to_old = to;
880
881     /* Echo OFF */
882     to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
883     tcsetattr(fd, TCSANOW, &to);
884
885     memset(input, 0, sizeof(input));
886
887     printf("%s", prompt);
888     fflush(stdout);
889
890     if ((read(fd, input, sizeof(input))) < 0) {
891       fprintf(stderr, "silc: %s\n", strerror(errno));
892       return NULL;
893     }
894
895     if (strlen(input) <= 1) {
896       tcsetattr(fd, TCSANOW, &to_old);
897       return NULL;
898     }
899
900     if (strchr(input, '\n'))
901       *strchr(input, '\n') = '\0';
902
903     /* Restore old terminfo */
904     tcsetattr(fd, TCSANOW, &to_old);
905     signal(SIGINT, SIG_DFL);
906
907     ret = silc_calloc(strlen(input), sizeof(char));
908     memcpy(ret, input, strlen(input));
909     memset(input, 0, sizeof(input));
910 #endif /* HAVE_TERMIOS_H */
911     return ret;
912   } else {
913     char input[2048];
914     int fd;
915
916     fd = open("/dev/tty", O_RDONLY);
917     if (fd < 0) {
918       fprintf(stderr, "silc: %s\n", strerror(errno));
919       return NULL;
920     }
921
922     memset(input, 0, sizeof(input));
923
924     printf("%s", prompt);
925     fflush(stdout);
926
927     if ((read(fd, input, sizeof(input))) < 0) {
928       fprintf(stderr, "silc: %s\n", strerror(errno));
929       return NULL;
930     }
931
932     if (strlen(input) <= 1)
933       return NULL;
934
935     if (strchr(input, '\n'))
936       *strchr(input, '\n') = '\0';
937
938     return strdup(input);
939   }
940 #else
941   return NULL;
942 #endif /* SILC_UNIX */
943 }
944
945 /* Return mode list */
946
947 bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
948                         SilcUInt32 **list)
949 {
950   int i;
951
952   if (mode_list->len / 4 != mode_list_count)
953     return FALSE;
954
955   *list = silc_calloc(mode_list_count, sizeof(**list));
956
957   for (i = 0; i < mode_list_count; i++) {
958     SILC_GET32_MSB((*list)[i], mode_list->data);
959     silc_buffer_pull(mode_list, 4);
960   }
961
962   silc_buffer_push(mode_list, mode_list->data - mode_list->head);
963
964   return TRUE;
965 }
966
967 /* Status message structure. Messages are defined below. */
968 typedef struct {
969   SilcStatus status;
970   const char *message;
971 } SilcStatusMessage;
972
973 #define STAT(x) SILC_STATUS_ERR_##x
974 static const SilcStatusMessage silc_status_messages[] = {
975
976   { STAT(NO_SUCH_NICK),      "There was no such nickname" },
977   { STAT(NO_SUCH_CHANNEL),   "There was no such channel" },
978   { STAT(NO_SUCH_SERVER),    "There was no such server" },
979   { STAT(INCOMPLETE_INFORMATION),  "Incomplete registration information" },
980   { STAT(NO_RECIPIENT),      "No recipient given" },
981   { STAT(UNKNOWN_COMMAND),   "Unknown command" },
982   { STAT(WILDCARDS),         "Wilcrads not allowed" },
983   { STAT(NO_CLIENT_ID),      "No Client ID given" },
984   { STAT(NO_CHANNEL_ID),     "No Channel ID given" },
985   { STAT(NO_SERVER_ID),      "No Server ID given" },
986   { STAT(BAD_CLIENT_ID),     "Bad Client ID" },
987   { STAT(BAD_CHANNEL_ID),    "Bad Channel ID" },
988   { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
989   { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
990   { STAT(NICKNAME_IN_USE),   "Nickname already exists" },
991   { STAT(NOT_ON_CHANNEL),    "You are not on that channel" },
992   { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
993   { STAT(USER_ON_CHANNEL),   "User already on the channel" },
994   { STAT(NOT_REGISTERED),    "You have not registered" },
995   { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
996   { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
997   { STAT(PERM_DENIED),       "Permission denied" },
998   { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" },
999   { STAT(BAD_PASSWORD),      "Cannot join channel. Incorrect password" },
1000   { STAT(CHANNEL_IS_FULL),   "Cannot join channel. Channel is full" },
1001   { STAT(NOT_INVITED),     "Cannot join channel. You have not been invited" },
1002   { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
1003   { STAT(UNKNOWN_MODE),    "Unknown mode" },
1004   { STAT(NOT_YOU),         "Cannot change mode for other users" },
1005   { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
1006   { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
1007   { STAT(NO_SERVER_PRIV),  "Permission denied. You are not server operator" },
1008   { STAT(NO_ROUTER_PRIV),  "Permission denied. You are not SILC operator" },
1009   { STAT(BAD_NICKNAME),    "Bad nickname" },
1010   { STAT(BAD_CHANNEL),     "Bad channel name" },
1011   { STAT(AUTH_FAILED),     "Authentication failed" },
1012   { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
1013   { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
1014   { STAT(RESOURCE_LIMIT), "No more free resources" },
1015   { STAT(NO_SUCH_SERVICE), "Service doesn't exist" },
1016   { STAT(NOT_AUTHENTICATED), "You have not been authenticated" },
1017   { STAT(BAD_SERVER_ID), "Server ID is not valid" },
1018   { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" },
1019   { STAT(BAD_VERSION), "Bad version" },
1020
1021   { 0, NULL }
1022 };
1023
1024 /* Returns status message string */
1025
1026 const char *silc_get_status_message(unsigned char status)
1027 {
1028   int i;
1029
1030   for (i = 0; silc_status_messages[i].message; i++) {
1031     if (silc_status_messages[i].status == status)
1032       break;
1033   }
1034
1035   if (silc_status_messages[i].message == NULL)
1036     return "";
1037
1038   return silc_status_messages[i].message;
1039 }
1040
1041 static const char *packet_name[] = {
1042   "NONE",
1043   "DISCONNECT",
1044   "SUCCESS",
1045   "FAILURE",
1046   "REJECT",
1047   "NOTIFY",
1048   "ERROR",
1049   "CHANNEL MESSAGE",
1050   "CHANNEL KEY",
1051   "PRIVATE MESSAGE",
1052   "PRIVATE MESSAGE KEY",
1053   "COMMAND",
1054   "COMMAND REPLY",
1055   "KEY EXCHANGE",
1056   "KEY EXCHANGE 1",
1057   "KEY EXCHANGE 2",
1058   "CONNECTION AUTH REQUEST",
1059   "CONNECTION AUTH",
1060   "NEW ID",
1061   "NEW CLIENT",
1062   "NEW SERVER",
1063   "NEW CHANNEL",
1064   "REKEY",
1065   "REKEY_DONE",
1066   "HEARTBEAT",
1067   "KEY AGREEMENT",
1068   "RESUME ROUTER",
1069   "FTP",
1070   "RESUME CLIENT",
1071 };
1072
1073 /* Returns packet type name */
1074
1075 const char *silc_get_packet_name(unsigned char type)
1076 {
1077   if (type >= SILC_PACKET_MAX)
1078     return "RESERVED";
1079   if (type >= SILC_PACKET_PRIVATE)
1080     return "PRIVATE RANGE";
1081   if (type > (sizeof(packet_name) / sizeof(*packet_name)))
1082     return "UNKNOWN";
1083   return packet_name[type];
1084 }
1085
1086 static const char *command_name[] = {
1087   "NONE",
1088   "WHOIS",
1089   "WHOWAS",
1090   "IDENTIFY",
1091   "NICK",
1092   "LIST",
1093   "TOPIC",
1094   "INVITE",
1095   "QUIT",
1096   "KILL",
1097   "INFO",
1098   "STATS",
1099   "PING",
1100   "OPER",
1101   "JOIN",
1102   "MOTD",
1103   "UMODE",
1104   "CMODE",
1105   "CUMODE",
1106   "KICK",
1107   "BAN",
1108   "DETACH",
1109   "WATCH",
1110   "SILCOPER",
1111   "LEAVE",
1112   "USERS",
1113   "GETKEY",
1114   "SERVICE",
1115 };
1116
1117 /* Returns command name */
1118
1119 const char *silc_get_command_name(unsigned char command)
1120 {
1121   if (command >= SILC_COMMAND_RESERVED)
1122     return "RESERVED";
1123   if (command >= SILC_COMMAND_PRIVATE)
1124     return "PRIVATE RANGE";
1125   if (command > (sizeof(command_name) / sizeof(*command_name)))
1126     return "UNKNOWN";
1127   return command_name[command];
1128 }