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