5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2003 Pekka Riikonen
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.
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.
20 * These are general utility functions that doesn't belong to any specific
25 #include "silcincludes.h"
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. */
31 int silc_gets(char *dest, int destlen, const char *src, int srclen,
37 memset(dest, 0, destlen);
39 if (off + 1 >= srclen)
43 for ( ; off <= srclen; i++) {
60 /* Checks line for illegal characters. Return -1 when illegal character
61 were found. This is used to check for bad lines when reading data from
62 for example a configuration file. */
64 int silc_check_line(char *buf)
66 /* Illegal characters in line */
67 if (strchr(buf, '#')) return -1;
68 if (strchr(buf, '\'')) return -1;
69 if (strchr(buf, '\\')) return -1;
70 if (strchr(buf, '\r')) return -1;
71 if (strchr(buf, '\a')) return -1;
72 if (strchr(buf, '\b')) return -1;
73 if (strchr(buf, '\f')) return -1;
82 /* Returns time as string. If the the `timeval' is non-zero that
83 value is returned as string. If it is zero the current time of the
84 local machine is returned. */
86 const char *silc_get_time(SilcUInt32 timeval)
94 curtime = (time_t)timeval;
95 return_time = ctime(&curtime);
96 return_time[strlen(return_time) - 1] = '\0';
98 return (const char *)return_time;
101 /* Converts string to capital characters. */
103 bool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
107 if (strlen(string) > dest_size)
110 for (i = 0; i < strlen(string); i++)
111 dest[i] = toupper(string[i]);
116 /* Converts string to lower letter characters. */
118 bool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
122 if (strlen(string) > dest_size)
125 for (i = 0; i < strlen(string); i++)
126 dest[i] = tolower(string[i]);
131 /* Parse userfqdn string which is in user@fqdn format. */
133 bool silc_parse_userfqdn(const char *string, char **left, char **right)
140 if (string[0] == '@') {
142 *left = strdup(string);
146 if (strchr(string, '@')) {
147 tlen = strcspn(string, "@");
150 *left = silc_calloc(tlen + 1, sizeof(char));
151 memcpy(*left, string, tlen);
155 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
156 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
160 *left = strdup(string);
166 /* Parses command line. At most `max_args' is taken. Rest of the line
167 will be allocated as the last argument if there are more than `max_args'
168 arguments in the line. Note that the command name is counted as one
169 argument and is saved. */
171 void silc_parse_command_line(unsigned char *buffer,
172 unsigned char ***parsed,
173 SilcUInt32 **parsed_lens,
174 SilcUInt32 **parsed_types,
175 SilcUInt32 *parsed_num,
180 const char *cp = buffer;
183 *parsed = silc_calloc(1, sizeof(**parsed));
184 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
186 /* Get the command first */
187 len = strcspn(cp, " ");
188 tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp));
191 silc_to_upper(cp, tmp, strlen(cp));
192 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
193 memcpy((*parsed)[0], tmp, len);
195 (*parsed_lens)[0] = len;
201 /* Parse arguments */
202 if (strchr(cp, ' ') || strlen(cp) != 0) {
203 for (i = 1; i < max_args; i++) {
205 if (i != max_args - 1)
206 len = strcspn(cp, " ");
209 while (len && cp[len - 1] == ' ')
214 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
215 *parsed_lens = silc_realloc(*parsed_lens,
216 sizeof(**parsed_lens) * (argc + 1));
217 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
218 memcpy((*parsed)[argc], cp, len);
219 (*parsed_lens)[argc] = len;
231 /* Save argument types. Protocol defines all argument types but
232 this implementation makes sure that they are always in correct
233 order hence this simple code. */
234 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
235 for (i = 0; i < argc; i++)
236 (*parsed_types)[i] = i;
241 /* Formats arguments to a string and returns it after allocating memory
242 for it. It must be remembered to free it later. */
244 char *silc_format(char *fmt, ...)
247 static char buf[8192];
249 memset(buf, 0, sizeof(buf));
251 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
257 /* Renders ID to suitable to print for example to log file. */
259 static char rid[256];
260 #define _PUT_STRING(__d__, __s__) \
262 int __sp = sizeof(__d__) - 1 - strlen(__d__); \
263 if (__sp < strlen(__s__)) { \
265 strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__)); \
267 strncat(__d__, __s__, strlen(__s__)); \
271 char *silc_id_render(void *id, SilcUInt16 type)
274 unsigned char tmps[2];
277 memset(rid, 0, sizeof(rid));
281 SilcServerID *server_id = (SilcServerID *)id;
282 if (server_id->ip.data_len > 4) {
284 struct sockaddr_in6 ipv6;
285 memset(&ipv6, 0, sizeof(ipv6));
286 ipv6.sin6_family = AF_INET6;
287 memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
288 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
289 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
290 _PUT_STRING(rid, tmp);
294 memmove(&ipv4.s_addr, server_id->ip.data, 4);
295 cp = inet_ntoa(ipv4);
297 _PUT_STRING(rid, cp);
300 memset(tmp, 0, sizeof(tmp));
301 snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
302 _PUT_STRING(rid, tmp);
303 SILC_PUT16_MSB(server_id->rnd, tmps);
304 memset(tmp, 0, sizeof(tmp));
305 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
306 _PUT_STRING(rid, tmp);
311 SilcClientID *client_id = (SilcClientID *)id;
312 if (client_id->ip.data_len > 4) {
314 struct sockaddr_in6 ipv6;
315 memset(&ipv6, 0, sizeof(ipv6));
316 ipv6.sin6_family = AF_INET6;
317 memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
318 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
319 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
320 _PUT_STRING(rid, tmp);
324 memmove(&ipv4.s_addr, client_id->ip.data, 4);
325 cp = inet_ntoa(ipv4);
327 _PUT_STRING(rid, cp);
330 memset(tmp, 0, sizeof(tmp));
331 snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
332 _PUT_STRING(rid, tmp);
333 memset(tmp, 0, sizeof(tmp));
334 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
335 client_id->hash[0], client_id->hash[1],
336 client_id->hash[2], client_id->hash[3]);
337 _PUT_STRING(rid, tmp);
340 case SILC_ID_CHANNEL:
342 SilcChannelID *channel_id = (SilcChannelID *)id;
343 if (channel_id->ip.data_len > 4) {
345 struct sockaddr_in6 ipv6;
346 memset(&ipv6, 0, sizeof(ipv6));
347 ipv6.sin6_family = AF_INET6;
348 memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
349 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
350 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
351 _PUT_STRING(rid, tmp);
355 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
356 cp = inet_ntoa(ipv4);
358 _PUT_STRING(rid, cp);
361 memset(tmp, 0, sizeof(tmp));
362 snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
363 _PUT_STRING(rid, tmp);
364 SILC_PUT16_MSB(channel_id->rnd, tmps);
365 memset(tmp, 0, sizeof(tmp));
366 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
367 _PUT_STRING(rid, tmp);
376 /* Compares two strings. Strings may include wildcards '*' and '?'.
377 Returns TRUE if strings match. */
379 int silc_string_compare(char *string1, char *string2)
384 char *tmpstr1, *tmpstr2;
386 if (!string1 || !string2)
389 slen1 = strlen(string1);
390 slen2 = strlen(string2);
392 /* See if they are same already */
393 if (!strncmp(string1, string2, slen2) && slen2 == slen1)
397 if (!strchr(string1, '*'))
400 /* Take copies of the original strings as we will change them */
401 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
402 memcpy(tmpstr1, string1, slen1);
403 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
404 memcpy(tmpstr2, string2, slen2);
406 for (i = 0; i < slen1; i++) {
408 /* * wildcard. Only one * wildcard is possible. */
409 if (tmpstr1[i] == '*')
410 if (!strncmp(tmpstr1, tmpstr2, i)) {
411 memset(tmpstr2, 0, slen2);
412 strncpy(tmpstr2, tmpstr1, i);
417 if (tmpstr1[i] == '?') {
418 if (!strncmp(tmpstr1, tmpstr2, i)) {
419 if (!(slen1 < i + 1))
420 if (tmpstr1[i + 1] != '?' &&
421 tmpstr1[i + 1] != tmpstr2[i + 1])
424 if (!(slen1 < slen2))
430 /* if using *, remove it */
431 if (strchr(tmpstr1, '*'))
432 *strchr(tmpstr1, '*') = 0;
434 if (!strcmp(tmpstr1, tmpstr2)) {
435 memset(tmpstr1, 0, slen1);
436 memset(tmpstr2, 0, slen2);
442 memset(tmpstr1, 0, slen1);
443 memset(tmpstr2, 0, slen2);
449 /* Basic has function to hash strings. May be used with the SilcHashTable.
450 Note that this lowers the characters of the string (with tolower()) so
451 this is used usually with nicknames, channel and server names to provide
452 case insensitive keys. */
454 SilcUInt32 silc_hash_string(void *key, void *user_context)
456 char *s = (char *)key;
460 h = (h << 4) + tolower(*s);
461 if ((g = h & 0xf0000000)) {
471 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
473 SilcUInt32 silc_hash_uint(void *key, void *user_context)
475 return *(SilcUInt32 *)key;
478 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
480 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
482 return (SilcUInt32)key;
485 /* Hash a ID. The `user_context' is the ID type. */
487 SilcUInt32 silc_hash_id(void *key, void *user_context)
489 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
496 SilcClientID *id = (SilcClientID *)key;
498 /* The client ID is hashed by hashing the hash of the ID
499 (which is a truncated MD5 hash of the nickname) so that we
500 can access the entry from the cache with both Client ID but
501 with just a hash from the ID as well. */
502 return silc_hash_client_id_hash(id->hash, NULL);
507 SilcServerID *id = (SilcServerID *)key;
509 h = id->port * id->rnd;
510 for (i = 0; i < id->ip.data_len; i++)
516 case SILC_ID_CHANNEL:
518 SilcChannelID *id = (SilcChannelID *)key;
520 h = id->port * id->rnd;
521 for (i = 0; i < id->ip.data_len; i++)
534 /* Hash Client ID's hash. */
536 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
539 unsigned char *hash = key;
542 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
543 h = (h << 4) + hash[i];
544 if ((g = h & 0xf0000000)) {
553 /* Hash binary data. The `user_context' is the data length. */
555 SilcUInt32 silc_hash_data(void *key, void *user_context)
557 SilcUInt32 len = (SilcUInt32)user_context, h = 0;
558 unsigned char *data = (unsigned char *)key;
561 h = (data[0] * data[len - 1] + 1) * len;
562 for (i = 0; i < len; i++)
568 /* Hashed SILC Public key. */
570 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
572 SilcPublicKey pk = (SilcPublicKey)key;
573 return (pk->len + silc_hash_string(pk->name, NULL) +
574 silc_hash_string(pk->identifier, NULL) +
575 silc_hash_data(pk->pk, (void *)pk->pk_len));
578 /* Compares two strings. It may be used as SilcHashTable comparison
581 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
583 return !strcasecmp((char *)key1, (char *)key2);
586 /* Compares two ID's. May be used as SilcHashTable comparison function.
587 The Client ID's compares only the hash of the Client ID not any other
588 part of the Client ID. Other ID's are fully compared. */
590 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
592 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
593 return (id_type == SILC_ID_CLIENT ?
594 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
595 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
598 /* Compare two Client ID's entirely and not just the hash from the ID. */
600 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
602 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
605 /* Compares binary data. May be used as SilcHashTable comparison function. */
607 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
609 SilcUInt32 len = (SilcUInt32)user_context;
610 return !memcmp(key1, key2, len);
613 /* Compares two SILC Public keys. It may be used as SilcHashTable
614 comparison function. */
616 bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
618 return silc_pkcs_public_key_compare(key1, key2);
621 /* Parses mode mask and returns the mode as string. */
623 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
630 memset(string, 0, sizeof(string));
632 if (mode & SILC_CHANNEL_MODE_PRIVATE)
633 strncat(string, "p", 1);
635 if (mode & SILC_CHANNEL_MODE_SECRET)
636 strncat(string, "s", 1);
638 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
639 strncat(string, "k", 1);
641 if (mode & SILC_CHANNEL_MODE_INVITE)
642 strncat(string, "i", 1);
644 if (mode & SILC_CHANNEL_MODE_TOPIC)
645 strncat(string, "t", 1);
647 if (mode & SILC_CHANNEL_MODE_ULIMIT)
648 strncat(string, "l", 1);
650 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
651 strncat(string, "a", 1);
653 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
654 strncat(string, "f", 1);
656 if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
657 strncat(string, "m", 1);
659 if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
660 strncat(string, "M", 1);
662 if (mode & SILC_CHANNEL_MODE_CIPHER)
663 strncat(string, "c", 1);
665 if (mode & SILC_CHANNEL_MODE_HMAC)
666 strncat(string, "h", 1);
668 if (mode & SILC_CHANNEL_MODE_CIPHER) {
669 if (strlen(cipher) + strlen(string) + 1< sizeof(string)) {
670 strncat(string, " ", 1);
671 strncat(string, cipher, strlen(cipher));
675 if (mode & SILC_CHANNEL_MODE_HMAC) {
676 if (strlen(hmac) + strlen(string) + 1< sizeof(string)) {
677 strncat(string, " ", 1);
678 strncat(string, hmac, strlen(hmac));
682 /* Rest of mode is ignored */
684 return strdup(string);
687 /* Parses channel user mode mask and returns te mode as string */
689 char *silc_client_chumode(SilcUInt32 mode)
696 memset(string, 0, sizeof(string));
698 if (mode & SILC_CHANNEL_UMODE_CHANFO)
699 strncat(string, "f", 1);
701 if (mode & SILC_CHANNEL_UMODE_CHANOP)
702 strncat(string, "o", 1);
704 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
705 strncat(string, "b", 1);
707 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
708 strncat(string, "u", 1);
710 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
711 strncat(string, "r", 1);
713 if (mode & SILC_CHANNEL_UMODE_QUIET)
714 strncat(string, "q", 1);
716 return strdup(string);
719 /* Parses channel user mode and returns it as special mode character. */
721 char *silc_client_chumode_char(SilcUInt32 mode)
728 memset(string, 0, sizeof(string));
730 if (mode & SILC_CHANNEL_UMODE_CHANFO)
731 strncat(string, "*", 1);
733 if (mode & SILC_CHANNEL_UMODE_CHANOP)
734 strncat(string, "@", 1);
736 if (mode & SILC_CHANNEL_UMODE_QUIET)
737 strncat(string, "&", 1);
739 return strdup(string);
742 /* Creates fingerprint from data, usually used with SHA1 digests */
744 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
746 char fingerprint[64], *cp;
749 memset(fingerprint, 0, sizeof(fingerprint));
751 for (i = 0; i < data_len; i++) {
752 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
755 if ((i + 1) % 2 == 0)
756 snprintf(cp++, sizeof(fingerprint), " ");
758 if ((i + 1) % 10 == 0)
759 snprintf(cp++, sizeof(fingerprint), " ");
762 if ((i + 1) % 2 == 0)
764 if ((i + 1) % 10 == 0)
767 return strdup(fingerprint);
770 /* Return TRUE if the `data' is ASCII string. */
772 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
776 for (i = 0; i < data_len; i++) {
777 if (!isascii(data[i]))
784 /* Parses SILC protocol style version string. */
786 bool silc_parse_version_string(const char *version,
787 SilcUInt32 *protocol_version,
788 char **protocol_version_string,
789 SilcUInt32 *software_version,
790 char **software_version_string,
791 char **vendor_version)
794 int maj = 0, min = 0;
796 if (!strstr(version, "SILC-"))
799 cp = (char *)version + 5;
803 /* Take protocol version */
806 if (!strchr(cp, '.'))
808 cp = strchr(cp, '.') + 1;
813 memset(buf, 0, sizeof(buf));
814 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
815 if (protocol_version)
816 *protocol_version = atoi(buf);
817 memset(buf, 0, sizeof(buf));
818 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
819 if (protocol_version_string)
820 *protocol_version_string = strdup(buf);
822 /* Take software version */
826 if (!strchr(cp, '-'))
828 cp = strchr(cp, '-') + 1;
833 if (strchr(cp, '.')) {
834 cp = strchr(cp, '.') + 1;
839 memset(buf, 0, sizeof(buf));
840 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
841 if (software_version)
842 *software_version = atoi(buf);
843 memset(buf, 0, sizeof(buf));
844 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
845 if (software_version_string)
846 *software_version_string = strdup(buf);
848 /* Take vendor string */
850 if (strchr(cp, '.')) {
851 cp = strchr(cp, '.') + 1;
852 if (cp && *cp && vendor_version)
853 *vendor_version = strdup(cp);
859 /* Converts version string x.x into number representation. */
861 SilcUInt32 silc_version_to_num(const char *version)
863 int maj = 0, min = 0;
869 cp = (char *)version;
871 cp = strchr(cp, '.');
875 memset(buf, 0, sizeof(buf));
876 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
877 return (SilcUInt32)atoi(buf);
880 /* Displays input prompt on command line and takes input data from user */
882 char *silc_get_input(const char *prompt, bool echo_off)
890 #ifdef HAVE_TERMIOS_H
892 struct termios to_old;
894 fd = open("/dev/tty", O_RDONLY);
896 fprintf(stderr, "silc: %s\n", strerror(errno));
900 signal(SIGINT, SIG_IGN);
902 /* Get terminal info */
906 /* Echo OFF, and assure we can prompt and get input */
907 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
908 to.c_lflag |= ICANON;
910 tcsetattr(fd, TCSANOW, &to);
912 memset(input, 0, sizeof(input));
914 printf("%s", prompt);
917 if ((read(fd, input, sizeof(input))) < 0) {
918 fprintf(stderr, "silc: %s\n", strerror(errno));
919 tcsetattr(fd, TCSANOW, &to_old);
923 if (strlen(input) <= 1) {
924 tcsetattr(fd, TCSANOW, &to_old);
928 if (strchr(input, '\n'))
929 *strchr(input, '\n') = '\0';
931 /* Restore old terminfo */
932 tcsetattr(fd, TCSANOW, &to_old);
933 signal(SIGINT, SIG_DFL);
935 ret = silc_memdup(input, strlen(input));
936 memset(input, 0, sizeof(input));
937 #endif /* HAVE_TERMIOS_H */
940 fd = open("/dev/tty", O_RDONLY);
942 fprintf(stderr, "silc: %s\n", strerror(errno));
946 memset(input, 0, sizeof(input));
948 printf("%s", prompt);
951 if ((read(fd, input, sizeof(input))) < 0) {
952 fprintf(stderr, "silc: %s\n", strerror(errno));
956 if (strlen(input) <= 1)
959 if (strchr(input, '\n'))
960 *strchr(input, '\n') = '\0';
962 return strdup(input);
966 #endif /* SILC_UNIX */
969 /* Return mode list */
971 bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
976 if (mode_list->len / 4 != mode_list_count)
979 *list = silc_calloc(mode_list_count, sizeof(**list));
981 for (i = 0; i < mode_list_count; i++) {
982 SILC_GET32_MSB((*list)[i], mode_list->data);
983 silc_buffer_pull(mode_list, 4);
986 silc_buffer_push(mode_list, mode_list->data - mode_list->head);
991 /* Status message structure. Messages are defined below. */
997 #define STAT(x) SILC_STATUS_ERR_##x
998 static const SilcStatusMessage silc_status_messages[] = {
1000 { STAT(NO_SUCH_NICK), "There was no such nickname" },
1001 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
1002 { STAT(NO_SUCH_SERVER), "There was no such server" },
1003 { STAT(INCOMPLETE_INFORMATION), "Incomplete registration information" },
1004 { STAT(NO_RECIPIENT), "No recipient given" },
1005 { STAT(UNKNOWN_COMMAND), "Unknown command" },
1006 { STAT(WILDCARDS), "Wilcrads not allowed" },
1007 { STAT(NO_CLIENT_ID), "No Client ID given" },
1008 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
1009 { STAT(NO_SERVER_ID), "No Server ID given" },
1010 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
1011 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
1012 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
1013 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
1014 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
1015 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
1016 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
1017 { STAT(USER_ON_CHANNEL), "User already on the channel" },
1018 { STAT(NOT_REGISTERED), "You have not registered" },
1019 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
1020 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
1021 { STAT(PERM_DENIED), "Permission denied" },
1022 { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" },
1023 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
1024 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
1025 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
1026 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
1027 { STAT(UNKNOWN_MODE), "Unknown mode" },
1028 { STAT(NOT_YOU), "Cannot change mode for other users" },
1029 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
1030 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
1031 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
1032 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
1033 { STAT(BAD_NICKNAME), "Bad nickname" },
1034 { STAT(BAD_CHANNEL), "Bad channel name" },
1035 { STAT(AUTH_FAILED), "Authentication failed" },
1036 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
1037 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
1038 { STAT(RESOURCE_LIMIT), "No more free resources" },
1039 { STAT(NO_SUCH_SERVICE), "Service doesn't exist" },
1040 { STAT(NOT_AUTHENTICATED), "You have not been authenticated" },
1041 { STAT(BAD_SERVER_ID), "Server ID is not valid" },
1042 { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" },
1043 { STAT(BAD_VERSION), "Bad version" },
1044 { STAT(TIMEDOUT), "Service timed out" },
1045 { STAT(UNSUPPORTED_PUBLIC_KEY), "Unsupported public key type" },
1046 { STAT(OPERATION_ALLOWED), "Operation is not allowed" },
1051 /* Returns status message string */
1053 const char *silc_get_status_message(unsigned char status)
1057 for (i = 0; silc_status_messages[i].message; i++) {
1058 if (silc_status_messages[i].status == status)
1062 if (silc_status_messages[i].message == NULL)
1065 return silc_status_messages[i].message;
1068 static const char *packet_name[] = {
1079 "PRIVATE MESSAGE KEY",
1085 "CONNECTION AUTH REQUEST",
1100 /* Returns packet type name */
1102 const char *silc_get_packet_name(unsigned char type)
1104 if (type >= SILC_PACKET_MAX)
1106 if (type >= SILC_PACKET_PRIVATE)
1107 return "PRIVATE RANGE";
1108 if (type > (sizeof(packet_name) / sizeof(*packet_name)))
1110 return packet_name[type];
1113 static const char *command_name[] = {
1144 /* Returns command name */
1146 const char *silc_get_command_name(unsigned char command)
1148 if (command >= SILC_COMMAND_RESERVED)
1150 if (command >= SILC_COMMAND_PRIVATE)
1151 return "PRIVATE RANGE";
1152 if (command > (sizeof(command_name) / sizeof(*command_name)))
1154 return command_name[command];
1157 /* Return TRUE if `smaller' is smaller than `bigger'. */
1159 bool silc_compare_timeval(struct timeval *smaller,
1160 struct timeval *bigger)
1162 if ((smaller->tv_sec < bigger->tv_sec) ||
1163 ((smaller->tv_sec == bigger->tv_sec) &&
1164 (smaller->tv_usec < bigger->tv_usec)))