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, uint32 *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     close(fd);
46     return NULL;
47   }
48   if (lseek(fd, (off_t)0L, SEEK_SET) < 0) {
49     close(fd);
50     return NULL;
51   }
52
53   if (filelen < 0) {
54     SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
55     close(fd);
56     return NULL;
57   }
58   
59   buffer = silc_calloc(filelen + 1, sizeof(char));
60   
61   if ((read(fd, buffer, filelen)) == -1) {
62     memset(buffer, 0, sizeof(buffer));
63     close(fd);
64     SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
65                     strerror(errno)));
66     return NULL;
67   }
68
69   close(fd);
70   buffer[filelen] = EOF;
71
72   if (return_len)
73     *return_len = filelen;
74
75   return buffer;
76 }
77
78 /* Writes a buffer to the file. */
79
80 int silc_file_write(const char *filename, const char *buffer, uint32 len)
81 {
82   int fd;
83         
84   if ((fd = creat(filename, 0644)) == -1) {
85     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
86                     strerror(errno)));
87     return -1;
88   }
89   
90   if ((write(fd, buffer, len)) == -1) {
91     SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
92     close(fd);
93     return -1;
94   }
95
96   close(fd);
97   
98   return 0;
99 }
100
101 /* Writes a buffer to the file.  If the file is created specific mode is
102    set to the file. */
103
104 int silc_file_write_mode(const char *filename, const char *buffer, 
105                          uint32 len, int mode)
106 {
107   int fd;
108         
109   if ((fd = creat(filename, mode)) == -1) {
110     SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename,
111                     strerror(errno)));
112     return -1;
113   }
114   
115   if ((write(fd, buffer, len)) == -1) {
116     SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, strerror(errno)));
117     close(fd);
118     return -1;
119   }
120
121   close(fd);
122   
123   return 0;
124 }
125
126 /* Gets line from a buffer. Stops reading when a newline or EOF occurs.
127    This doesn't remove the newline sign from the destination buffer. The
128    argument begin is returned and should be passed again for the function. */
129
130 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
131 {
132   static int start = 0;
133   int i;
134   
135   memset(dest, 0, destlen);
136   
137   if (begin != start)
138     start = 0;
139   
140   i = 0;
141   for ( ; start <= srclen; i++, start++) {
142     if (i > destlen)
143       return -1;
144     
145     dest[i] = src[start];
146     
147     if (dest[i] == EOF) 
148       return EOF;
149     
150     if (dest[i] == '\n') 
151       break;
152   }
153   start++;
154   
155   return start;
156 }
157
158 /* Checks line for illegal characters. Return -1 when illegal character
159    were found. This is used to check for bad lines when reading data from
160    for example a configuration file. */
161
162 int silc_check_line(char *buf) 
163 {
164   /* Illegal characters in line */
165   if (strchr(buf, '#')) return -1;
166   if (strchr(buf, '\'')) return -1;
167   if (strchr(buf, '\\')) return -1;
168   if (strchr(buf, '\r')) return -1;
169   if (strchr(buf, '\a')) return -1;
170   if (strchr(buf, '\b')) return -1;
171   if (strchr(buf, '\f')) return -1;
172   
173   /* Empty line */
174   if (buf[0] == '\n')
175     return -1;
176   
177   return 0;
178 }
179
180 /* Returns current time as string. */
181
182 char *silc_get_time()
183 {
184   time_t curtime;
185   char *return_time;
186
187   curtime = time(NULL);
188   return_time = ctime(&curtime);
189   return_time[strlen(return_time) - 1] = '\0';
190
191   return return_time;
192 }
193
194 /* Converts string to capital characters */
195
196 char *silc_to_upper(char *string)
197 {
198   int i;
199   char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
200
201   for (i = 0; i < strlen(string); i++)
202     ret[i] = toupper(string[i]);
203
204   return ret;
205 }
206
207 static unsigned char pem_enc[64] =
208 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
209
210 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
211    data string. Note: This is originally public domain code and is 
212    still PD. */
213
214 char *silc_encode_pem(unsigned char *data, uint32 len)
215 {
216   int i, j;
217   uint32 bits, c, char_count;
218   char *pem;
219
220   char_count = 0;
221   bits = 0;
222   j = 0;
223
224   pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
225
226   for (i = 0; i < len; i++) {
227     c = data[i];
228     bits += c;
229     char_count++;
230
231     if (char_count == 3) {
232       pem[j++] = pem_enc[bits  >> 18];
233       pem[j++] = pem_enc[(bits >> 12) & 0x3f];
234       pem[j++] = pem_enc[(bits >> 6)  & 0x3f];
235       pem[j++] = pem_enc[bits & 0x3f];
236       bits = 0;
237       char_count = 0;
238     } else {
239       bits <<= 8;
240     }
241   }
242
243   if (char_count != 0) {
244     bits <<= 16 - (8 * char_count);
245     pem[j++] = pem_enc[bits >> 18];
246     pem[j++] = pem_enc[(bits >> 12) & 0x3f];
247
248     if (char_count == 1) {
249       pem[j++] = '=';
250       pem[j] = '=';
251     } else {
252       pem[j++] = pem_enc[(bits >> 6) & 0x3f];
253       pem[j] = '=';
254     }
255   }
256
257   return pem;
258 }
259
260 /* Same as above but puts newline ('\n') every 72 characters. */
261
262 char *silc_encode_pem_file(unsigned char *data, uint32 data_len)
263 {
264   int i, j;
265   uint32 len, cols;
266   char *pem, *pem2;
267
268   pem = silc_encode_pem(data, data_len);
269   len = strlen(pem);
270
271   pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
272
273   for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
274     if (cols == 72) {
275       pem2[i] = '\n';
276       cols = 0;
277       len++;
278       continue;
279     }
280
281     pem2[i] = pem[j++];
282   }
283
284   silc_free(pem);
285   return pem2;
286 }
287
288 /* Decodes PEM into data. Returns the decoded data. Note: This is
289    originally public domain code and is still PD. */
290
291 unsigned char *silc_decode_pem(unsigned char *pem, uint32 pem_len,
292                                uint32 *ret_len)
293 {
294   int i, j;
295   uint32 len, c, char_count, bits;
296   unsigned char *data;
297   static char ialpha[256], decoder[256];
298
299   for (i = 64 - 1; i >= 0; i--) {
300     ialpha[pem_enc[i]] = 1;
301     decoder[pem_enc[i]] = i;
302   }
303
304   char_count = 0;
305   bits = 0;
306   j = 0;
307
308   if (!pem_len)
309     len = strlen(pem);
310   else
311     len = pem_len;
312
313   data = silc_calloc(((len * 6) / 8), sizeof(*data));
314
315   for (i = 0; i < len; i++) {
316     c = pem[i];
317
318     if (c == '=')
319       break;
320
321     if (c > 127 || !ialpha[c])
322       continue;
323
324     bits += decoder[c];
325     char_count++;
326
327     if (char_count == 4) {
328       data[j++] = bits >> 16;
329       data[j++] = (bits >> 8) & 0xff;
330       data[j++] = bits & 0xff;
331       bits = 0;
332       char_count = 0;
333     } else {
334       bits <<= 6;
335     }
336   }
337
338   switch(char_count) {
339   case 1:
340     silc_free(data);
341     return NULL;
342     break;
343   case 2:
344     data[j++] = bits >> 10;
345     break;
346   case 3:
347     data[j++] = bits >> 16;
348     data[j++] = (bits >> 8) & 0xff;
349     break;
350   }
351
352   if (ret_len)
353     *ret_len = j;
354
355   return data;
356 }
357
358 /* Parse nickname string. The format may be <num>!<nickname>@<server> to
359    support multiple same nicknames. The <num> is the final unifier if same
360    nickname is on same server. Note, this is only local format and server
361    does not know anything about these. */
362
363 int silc_parse_nickname(char *string, char **nickname, char **server,
364                         uint32 *num)
365 {
366   uint32 tlen;
367
368   if (!string)
369     return FALSE;
370
371   if (strchr(string, '!')) {
372     char *tmp;
373     tlen = strcspn(string, "!");
374     tmp = silc_calloc(tlen + 1, sizeof(*tmp));
375     memcpy(tmp, string, tlen);
376
377     if (num)
378       *num = atoi(tmp);
379
380     silc_free(tmp);
381
382     if (tlen >= strlen(string))
383       return FALSE;
384
385     string += tlen + 1;
386   }
387
388   if (strchr(string, '@')) {
389     tlen = strcspn(string, "@");
390     
391     if (nickname) {
392       *nickname = silc_calloc(tlen + 1, sizeof(char));
393       memcpy(*nickname, string, tlen);
394     }
395     
396     if (server) {
397       *server = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
398       memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
399     }
400   } else {
401     if (nickname)
402       *nickname = strdup(string);
403   }
404
405   return TRUE;
406 }
407
408 /* Parses command line. At most `max_args' is taken. Rest of the line
409    will be allocated as the last argument if there are more than `max_args'
410    arguments in the line. Note that the command name is counted as one
411    argument and is saved. */
412
413 void silc_parse_command_line(unsigned char *buffer, 
414                              unsigned char ***parsed,
415                              uint32 **parsed_lens,
416                              uint32 **parsed_types,
417                              uint32 *parsed_num,
418                              uint32 max_args)
419 {
420   int i, len = 0;
421   int argc = 0;
422   const char *cp = buffer;
423   char *tmp;
424
425   *parsed = silc_calloc(1, sizeof(**parsed));
426   *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
427
428   /* Get the command first */
429   len = strcspn(cp, " ");
430   tmp = silc_to_upper((char *)cp);
431   (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
432   memcpy((*parsed)[0], tmp, len);
433   silc_free(tmp);
434   (*parsed_lens)[0] = len;
435   cp += len;
436   while (*cp == ' ')
437     cp++;
438   argc++;
439
440   /* Parse arguments */
441   if (strchr(cp, ' ') || strlen(cp) != 0) {
442     for (i = 1; i < max_args; i++) {
443
444       if (i != max_args - 1)
445         len = strcspn(cp, " ");
446       else
447         len = strlen(cp);
448       while (len && cp[len - 1] == ' ')
449         len--;
450       if (!len)
451         break;
452       
453       *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
454       *parsed_lens = silc_realloc(*parsed_lens, 
455                                   sizeof(**parsed_lens) * (argc + 1));
456       (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
457       memcpy((*parsed)[argc], cp, len);
458       (*parsed_lens)[argc] = len;
459       argc++;
460
461       cp += len;
462       if (strlen(cp) == 0)
463         break;
464       else
465         while (*cp == ' ')
466           cp++;
467     }
468   }
469
470   /* Save argument types. Protocol defines all argument types but
471      this implementation makes sure that they are always in correct
472      order hence this simple code. */
473   *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
474   for (i = 0; i < argc; i++)
475     (*parsed_types)[i] = i;
476
477   *parsed_num = argc;
478 }
479
480 /* Formats arguments to a string and returns it after allocating memory
481    for it. It must be remembered to free it later. */
482
483 char *silc_format(char *fmt, ...)
484 {
485   va_list args;
486   static char buf[8192];
487
488   memset(buf, 0, sizeof(buf));
489   va_start(args, fmt);
490   vsnprintf(buf, sizeof(buf) - 1, fmt, args);
491   va_end(args);
492
493   return strdup(buf);
494 }
495
496 /* Renders ID to suitable to print for example to log file. */
497
498 static char rid[256];
499
500 char *silc_id_render(void *id, uint16 type)
501 {
502   char tmp[100];
503   unsigned char tmps[2];
504
505   memset(rid, 0, sizeof(rid));
506   switch(type) {
507   case SILC_ID_SERVER:
508     {
509       SilcServerID *server_id = (SilcServerID *)id;
510       struct in_addr ipv4;
511
512       if (server_id->ip.data_len > 4) {
513
514       } else {
515         SILC_GET32_MSB(ipv4.s_addr, server_id->ip.data);
516         strcat(rid, inet_ntoa(ipv4));
517       }
518
519       memset(tmp, 0, sizeof(tmp));
520       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(server_id->port));
521       strcat(rid, tmp);
522       SILC_PUT16_MSB(server_id->rnd, tmps);
523       memset(tmp, 0, sizeof(tmp));
524       snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
525       strcat(rid, tmp);
526     }
527     break;
528   case SILC_ID_CLIENT:
529     {
530       SilcClientID *client_id = (SilcClientID *)id;
531       struct in_addr ipv4;
532
533       if (client_id->ip.data_len > 4) {
534
535       } else {
536         SILC_GET32_MSB(ipv4.s_addr, client_id->ip.data);
537         strcat(rid, inet_ntoa(ipv4));
538       }
539
540       memset(tmp, 0, sizeof(tmp));
541       snprintf(tmp, sizeof(tmp), ",%02x,", client_id->rnd);
542       strcat(rid, tmp);
543       memset(tmp, 0, sizeof(tmp));
544       snprintf(tmp, sizeof(tmp), "[%02x %02x %02x %02x...]", 
545                client_id->hash[0], client_id->hash[1],
546                client_id->hash[2], client_id->hash[3]);
547       strcat(rid, tmp);
548     }
549     break;
550   case SILC_ID_CHANNEL:
551     {
552       SilcChannelID *channel_id = (SilcChannelID *)id;
553       struct in_addr ipv4;
554
555       if (channel_id->ip.data_len > 4) {
556
557       } else {
558         SILC_GET32_MSB(ipv4.s_addr, channel_id->ip.data);
559         strcat(rid, inet_ntoa(ipv4));
560       }
561
562       memset(tmp, 0, sizeof(tmp));
563       snprintf(tmp, sizeof(tmp), ",%d,", ntohs(channel_id->port));
564       strcat(rid, tmp);
565       SILC_PUT16_MSB(channel_id->rnd, tmps);
566       memset(tmp, 0, sizeof(tmp));
567       snprintf(tmp, sizeof(tmp), "[%02x %02x]", tmps[0], tmps[1]);
568       strcat(rid, tmp);
569     }
570     break;
571   }
572
573   return rid;
574 }
575
576 /* Compares two strings. Strings may include wildcards * and ?.
577    Returns TRUE if strings match. */
578
579 int silc_string_compare(char *string1, char *string2)
580 {
581   int i;
582   int slen1 = strlen(string1);
583   int slen2 = strlen(string2);
584   char *tmpstr1, *tmpstr2;
585
586   if (!string1 || !string2)
587     return FALSE;
588
589   /* See if they are same already */
590   if (!strncmp(string1, string2, strlen(string2)))
591     return TRUE;
592
593   if (slen2 < slen1)
594     if (!strchr(string1, '*'))
595       return FALSE;
596   
597   /* Take copies of the original strings as we will change them */
598   tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
599   memcpy(tmpstr1, string1, slen1);
600   tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
601   memcpy(tmpstr2, string2, slen2);
602   
603   for (i = 0; i < slen1; i++) {
604     
605     /* * wildcard. Only one * wildcard is possible. */
606     if (tmpstr1[i] == '*')
607       if (!strncmp(tmpstr1, tmpstr2, i)) {
608         memset(tmpstr2, 0, slen2);
609         strncpy(tmpstr2, tmpstr1, i);
610         break;
611       }
612     
613     /* ? wildcard */
614     if (tmpstr1[i] == '?') {
615       if (!strncmp(tmpstr1, tmpstr2, i)) {
616         if (!(slen1 < i + 1))
617           if (tmpstr1[i + 1] != '?' &&
618               tmpstr1[i + 1] != tmpstr2[i + 1])
619             continue;
620         
621         if (!(slen1 < slen2))
622           tmpstr2[i] = '?';
623       }
624     }
625   }
626   
627   /* if using *, remove it */
628   if (strchr(tmpstr1, '*'))
629     *strchr(tmpstr1, '*') = 0;
630   
631   if (!strcmp(tmpstr1, tmpstr2)) {
632     memset(tmpstr1, 0, slen1);
633     memset(tmpstr2, 0, slen2);
634     silc_free(tmpstr1);
635     silc_free(tmpstr2);
636     return TRUE;
637   }
638   
639   memset(tmpstr1, 0, slen1);
640   memset(tmpstr2, 0, slen2);
641   silc_free(tmpstr1);
642   silc_free(tmpstr2);
643   return FALSE;
644 }
645
646 /* Inspects the `string' for wildcards and returns regex string that can
647    be used by the GNU regex library. A comma (`,') in the `string' means
648    that the string is list. */
649
650 char *silc_string_regexify(const char *string)
651 {
652   int i, len, count;
653   char *regex;
654
655   len = strlen(string);
656   count = 4;
657   for (i = 0; i < len; i++)
658     if (string[i] == '*' || string[i] == '?')
659       count++;
660
661   regex = silc_calloc(len + count, sizeof(*regex));
662
663   count = 0;
664   regex[count] = '(';
665   count++;
666
667   for (i = 0; i < len; i++) {
668     if (string[i] == '*' || string[i] == '?') {
669       regex[count] = '.';
670       count++;
671     } else if (string[i] == ',') {
672       regex[count] = '|';
673       count++;
674       continue;
675     }
676
677     regex[count] = string[i];
678     count++;
679   }
680
681   regex[count - 1] = ')';
682   regex[count] = '$';
683
684   return regex;
685 }
686
687 /* Combines two regex strings into one regex string so that they can be
688    used as one by the GNU regex library. The `string2' is combine into
689    the `string1'. */
690
691 char *silc_string_regex_combine(const char *string1, const char *string2)
692 {
693   char *tmp;
694   int len1, len2;
695
696   len1 = strlen(string1);
697   len2 = strlen(string2);
698
699   tmp = silc_calloc(2 + len1 + len2, sizeof(*tmp));
700   strncat(tmp, string1, len1 - 2);
701   strncat(tmp, "|", 1);
702   strncat(tmp, string2 + 1, len2 - 1);
703
704   return tmp;
705 }
706
707 /* Matches the two strings and returns TRUE if the strings match. */
708
709 int silc_string_regex_match(const char *regex, const char *string)
710 {
711   regex_t preg;
712   int ret = FALSE;
713   
714   if (regcomp(&preg, regex, REG_NOSUB | REG_EXTENDED) < 0)
715     return FALSE;
716
717   if (regexec(&preg, string, 0, NULL, 0) == 0)
718     ret = TRUE;
719
720   regfree(&preg);
721
722   return ret;
723 }
724
725 /* Do regex match to the two strings `string1' and `string2'. If the
726    `string2' matches the `string1' this returns TRUE. */
727
728 int silc_string_match(const char *string1, const char *string2)
729 {
730   char *s1;
731   int ret = FALSE;
732
733   s1 = silc_string_regexify(string1);
734   ret = silc_string_regex_match(s1, string2);
735   silc_free(s1);
736
737   return ret;
738 }
739
740 /* Returns the username of the user. If the global variable LOGNAME
741    does not exists we will get the name from the password file. */
742
743 char *silc_get_username()
744 {
745   char *logname = NULL;
746   
747   logname = getenv("LOGNAME");
748   if (!logname) {
749     logname = getlogin();
750     if (!logname) {
751       struct passwd *pw;
752
753       pw = getpwuid(getuid());
754       if (!pw) {
755         fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
756         return NULL;
757       }
758       
759       logname = pw->pw_name;
760     }
761   }
762   
763   return strdup(logname);
764 }                          
765
766 /* Returns the real name of ther user. */
767
768 char *silc_get_real_name()
769 {
770   char *realname = NULL;
771   struct passwd *pw;
772     
773   pw = getpwuid(getuid());
774   if (!pw) {
775     fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
776     return NULL;
777   }
778
779   if (strchr(pw->pw_gecos, ','))
780     *strchr(pw->pw_gecos, ',') = 0;
781
782   realname = strdup(pw->pw_gecos);
783
784   return realname;
785 }
786
787 /* Basic has function to hash strings. May be used with the SilcHashTable. 
788    Note that this lowers the characters of the string (with tolower()) so
789    this is used usually with nicknames, channel and server names to provide
790    case insensitive keys. */
791
792 uint32 silc_hash_string(void *key, void *user_context)
793 {
794   char *s = (char *)key;
795   uint32 h = 0, g;
796   
797   while (*s != '\0') {
798     h = (h << 4) + tolower(*s);
799     if ((g = h & 0xf0000000)) {
800       h = h ^ (g >> 24);
801       h = h ^ g;
802     }
803     s++;
804   }
805   
806   return h;
807 }
808
809 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
810
811 uint32 silc_hash_uint(void *key, void *user_context)
812 {
813   return *(uint32 *)key;
814 }
815
816 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
817
818 uint32 silc_hash_ptr(void *key, void *user_context)
819 {
820   return (uint32)key;
821 }
822
823 /* Hash a ID. The `user_context' is the ID type. */
824
825 uint32 silc_hash_id(void *key, void *user_context)
826 {
827   SilcIdType id_type = (SilcIdType)(uint32)user_context;
828   uint32 h = 0;
829   int i;
830
831   switch (id_type) {
832   case SILC_ID_CLIENT:
833     {
834       SilcClientID *id = (SilcClientID *)key;
835       uint32 g;
836   
837       /* The client ID is hashed by hashing the hash of the ID 
838          (which is a truncated MD5 hash of the nickname) so that we
839          can access the entry from the cache with both Client ID but
840          with just a hash from the ID as well. */
841
842       for (i = 0; i < sizeof(id->hash); i++) {
843         h = (h << 4) + id->hash[i];
844         if ((g = h & 0xf0000000)) {
845           h = h ^ (g >> 24);
846           h = h ^ g;
847         }
848       }
849
850       return h;
851     }
852     break;
853   case SILC_ID_SERVER:
854     {
855       SilcServerID *id = (SilcServerID *)key;
856       
857       h = id->port * id->rnd;
858       for (i = 0; i < id->ip.data_len; i++)
859         h ^= id->ip.data[i];
860       
861       return h;
862     }
863     break;
864   case SILC_ID_CHANNEL:
865     {
866       SilcChannelID *id = (SilcChannelID *)key;
867       
868       h = id->port * id->rnd;
869       for (i = 0; i < id->ip.data_len; i++)
870         h ^= id->ip.data[i];
871       
872       return h;
873     }
874     break;
875   default:
876     break;
877   }
878
879   return h;
880 }
881
882 /* Hash binary data. The `user_context' is the data length. */
883
884 uint32 silc_hash_data(void *key, void *user_context)
885 {
886   uint32 len = (uint32)user_context, h = 0;
887   unsigned char *data = (unsigned char *)key;
888   int i;
889
890   h = (data[0] * data[len - 1] + 1) * len;
891   for (i = 0; i < len; i++)
892     h ^= data[i];
893
894   return h;
895 }
896
897 /* Compares two strings. May be used as SilcHashTable comparison function. */
898
899 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
900 {
901   return !strcasecmp((char *)key1, (char *)key2);
902 }
903
904 /* Compares two ID's. May be used as SilcHashTable comparison function. 
905    The Client ID's compares only the hash of the Client ID not any other
906    part of the Client ID. Other ID's are fully compared. */
907
908 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
909 {
910   SilcIdType id_type = (SilcIdType)(uint32)user_context;
911   return (id_type == SILC_ID_CLIENT ? 
912           SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
913           SILC_ID_COMPARE_TYPE(key1, key2, id_type));
914 }
915
916 /* Compare two Client ID's entirely and not just the hash from the ID. */
917
918 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
919 {
920   return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
921 }
922
923 /* Compares binary data. May be used as SilcHashTable comparison function. */
924
925 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
926 {
927   uint32 len = (uint32)user_context;
928   return !memcmp(key1, key2, len);
929 }
930
931 /* Parses mode mask and returns the mode as string. */
932
933 char *silc_client_chmode(uint32 mode, const char *cipher, const char *hmac)
934 {
935   char string[100];
936
937   if (!mode)
938     return NULL;
939
940   memset(string, 0, sizeof(string));
941
942   if (mode & SILC_CHANNEL_MODE_PRIVATE)
943     strncat(string, "p", 1);
944
945   if (mode & SILC_CHANNEL_MODE_SECRET)
946     strncat(string, "s", 1);
947
948   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
949     strncat(string, "k", 1);
950
951   if (mode & SILC_CHANNEL_MODE_INVITE)
952     strncat(string, "i", 1);
953
954   if (mode & SILC_CHANNEL_MODE_TOPIC)
955     strncat(string, "t", 1);
956
957   if (mode & SILC_CHANNEL_MODE_ULIMIT)
958     strncat(string, "l", 1);
959
960   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
961     strncat(string, "a", 1);
962
963   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
964     strncat(string, "f", 1);
965
966   if (mode & SILC_CHANNEL_MODE_CIPHER)
967     strncat(string, cipher, strlen(cipher));
968
969   if (mode & SILC_CHANNEL_MODE_HMAC)
970     strncat(string, hmac, strlen(hmac));
971
972   /* Rest of mode is ignored */
973
974   return strdup(string);
975 }
976
977 /* Parses channel user mode mask and returns te mode as string */
978
979 char *silc_client_chumode(uint32 mode)
980 {
981   char string[4];
982
983   if (!mode)
984     return NULL;
985
986   memset(string, 0, sizeof(string));
987
988   if (mode & SILC_CHANNEL_UMODE_CHANFO)
989     strncat(string, "f", 1);
990
991   if (mode & SILC_CHANNEL_UMODE_CHANOP)
992     strncat(string, "o", 1);
993
994   return strdup(string);
995 }
996
997 /* Parses channel user mode and returns it as special mode character. */
998
999 char *silc_client_chumode_char(uint32 mode)
1000 {
1001   char string[4];
1002
1003   if (!mode)
1004     return NULL;
1005
1006   memset(string, 0, sizeof(string));
1007
1008   if (mode & SILC_CHANNEL_UMODE_CHANFO)
1009     strncat(string, "*", 1);
1010
1011   if (mode & SILC_CHANNEL_UMODE_CHANOP)
1012     strncat(string, "@", 1);
1013
1014   return strdup(string);
1015 }