5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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, int begin)
36 memset(dest, 0, destlen);
42 for ( ; start <= srclen; i++, start++) {
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. */
63 int silc_check_line(char *buf)
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;
81 /* Returns current time as string. */
89 return_time = ctime(&curtime);
90 return_time[strlen(return_time) - 1] = '\0';
95 /* Converts string to capital characters. */
97 bool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
101 if (strlen(string) > dest_size)
104 for (i = 0; i < strlen(string); i++)
105 dest[i] = toupper(string[i]);
110 /* Converts string to lower letter characters. */
112 bool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
116 if (strlen(string) > dest_size)
119 for (i = 0; i < strlen(string); i++)
120 dest[i] = tolower(string[i]);
125 /* Parse userfqdn string which is in user@fqdn format. */
127 bool silc_parse_userfqdn(const char *string, char **left, char **right)
134 if (string[0] == '@') {
136 *left = strdup(string);
140 if (strchr(string, '@')) {
141 tlen = strcspn(string, "@");
144 *left = silc_calloc(tlen + 1, sizeof(char));
145 memcpy(*left, string, tlen);
149 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
150 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
154 *left = strdup(string);
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. */
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,
174 const char *cp = buffer;
177 *parsed = silc_calloc(1, sizeof(**parsed));
178 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
180 /* Get the command first */
181 len = strcspn(cp, " ");
182 tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp));
185 silc_to_upper(cp, tmp, strlen(cp));
186 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
187 memcpy((*parsed)[0], tmp, len);
189 (*parsed_lens)[0] = len;
195 /* Parse arguments */
196 if (strchr(cp, ' ') || strlen(cp) != 0) {
197 for (i = 1; i < max_args; i++) {
199 if (i != max_args - 1)
200 len = strcspn(cp, " ");
203 while (len && cp[len - 1] == ' ')
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;
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;
235 /* Formats arguments to a string and returns it after allocating memory
236 for it. It must be remembered to free it later. */
238 char *silc_format(char *fmt, ...)
241 static char buf[8192];
243 memset(buf, 0, sizeof(buf));
245 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
251 /* Renders ID to suitable to print for example to log file. */
253 static char rid[256];
254 #define _PUT_STRING(__d__, __s__) \
256 int __sp = sizeof(__d__) - 1 - strlen(__d__); \
257 if (__sp < strlen(__s__)) { \
259 strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__)); \
261 strncat(__d__, __s__, strlen(__s__)); \
265 char *silc_id_render(void *id, SilcUInt16 type)
268 unsigned char tmps[2];
271 memset(rid, 0, sizeof(rid));
275 SilcServerID *server_id = (SilcServerID *)id;
276 if (server_id->ip.data_len > 4) {
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);
288 memmove(&ipv4.s_addr, server_id->ip.data, 4);
289 cp = inet_ntoa(ipv4);
291 _PUT_STRING(rid, cp);
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);
305 SilcClientID *client_id = (SilcClientID *)id;
306 if (client_id->ip.data_len > 4) {
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);
318 memmove(&ipv4.s_addr, client_id->ip.data, 4);
319 cp = inet_ntoa(ipv4);
321 _PUT_STRING(rid, cp);
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);
334 case SILC_ID_CHANNEL:
336 SilcChannelID *channel_id = (SilcChannelID *)id;
337 if (channel_id->ip.data_len > 4) {
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);
349 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
350 cp = inet_ntoa(ipv4);
352 _PUT_STRING(rid, cp);
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);
370 /* Compares two strings. Strings may include wildcards '*' and '?'.
371 Returns TRUE if strings match. */
373 int silc_string_compare(char *string1, char *string2)
378 char *tmpstr1, *tmpstr2;
380 if (!string1 || !string2)
383 slen1 = strlen(string1);
384 slen2 = strlen(string2);
386 /* See if they are same already */
387 if (!strncmp(string1, string2, strlen(string2)))
391 if (!strchr(string1, '*'))
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);
400 for (i = 0; i < slen1; i++) {
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);
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])
418 if (!(slen1 < slen2))
424 /* if using *, remove it */
425 if (strchr(tmpstr1, '*'))
426 *strchr(tmpstr1, '*') = 0;
428 if (!strcmp(tmpstr1, tmpstr2)) {
429 memset(tmpstr1, 0, slen1);
430 memset(tmpstr2, 0, slen2);
436 memset(tmpstr1, 0, slen1);
437 memset(tmpstr2, 0, slen2);
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. */
448 SilcUInt32 silc_hash_string(void *key, void *user_context)
450 char *s = (char *)key;
454 h = (h << 4) + tolower(*s);
455 if ((g = h & 0xf0000000)) {
465 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
467 SilcUInt32 silc_hash_uint(void *key, void *user_context)
469 return *(SilcUInt32 *)key;
472 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
474 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
476 return (SilcUInt32)key;
479 /* Hash a ID. The `user_context' is the ID type. */
481 SilcUInt32 silc_hash_id(void *key, void *user_context)
483 SilcIdType id_type = (SilcIdType)(SilcUInt32)user_context;
490 SilcClientID *id = (SilcClientID *)key;
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);
501 SilcServerID *id = (SilcServerID *)key;
503 h = id->port * id->rnd;
504 for (i = 0; i < id->ip.data_len; i++)
510 case SILC_ID_CHANNEL:
512 SilcChannelID *id = (SilcChannelID *)key;
514 h = id->port * id->rnd;
515 for (i = 0; i < id->ip.data_len; i++)
528 /* Hash Client ID's hash. */
530 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
533 unsigned char *hash = key;
536 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
537 h = (h << 4) + hash[i];
538 if ((g = h & 0xf0000000)) {
547 /* Hash binary data. The `user_context' is the data length. */
549 SilcUInt32 silc_hash_data(void *key, void *user_context)
551 SilcUInt32 len = (SilcUInt32)user_context, h = 0;
552 unsigned char *data = (unsigned char *)key;
555 h = (data[0] * data[len - 1] + 1) * len;
556 for (i = 0; i < len; i++)
562 /* Hashed SILC Public key. */
564 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
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));
572 /* Compares two strings. It may be used as SilcHashTable comparison
575 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
577 return !strcasecmp((char *)key1, (char *)key2);
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. */
584 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
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));
592 /* Compare two Client ID's entirely and not just the hash from the ID. */
594 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
596 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
599 /* Compares binary data. May be used as SilcHashTable comparison function. */
601 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
603 SilcUInt32 len = (SilcUInt32)user_context;
604 return !memcmp(key1, key2, len);
607 /* Compares two SILC Public keys. It may be used as SilcHashTable
608 comparison function. */
610 bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
612 return silc_pkcs_public_key_compare(key1, key2);
615 /* Parses mode mask and returns the mode as string. */
617 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
624 memset(string, 0, sizeof(string));
626 if (mode & SILC_CHANNEL_MODE_PRIVATE)
627 strncat(string, "p", 1);
629 if (mode & SILC_CHANNEL_MODE_SECRET)
630 strncat(string, "s", 1);
632 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
633 strncat(string, "k", 1);
635 if (mode & SILC_CHANNEL_MODE_INVITE)
636 strncat(string, "i", 1);
638 if (mode & SILC_CHANNEL_MODE_TOPIC)
639 strncat(string, "t", 1);
641 if (mode & SILC_CHANNEL_MODE_ULIMIT)
642 strncat(string, "l", 1);
644 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
645 strncat(string, "a", 1);
647 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
648 strncat(string, "f", 1);
650 if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
651 strncat(string, "m", 1);
653 if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
654 strncat(string, "M", 1);
656 if (mode & SILC_CHANNEL_MODE_CIPHER)
657 strncat(string, cipher, strlen(cipher));
659 if (mode & SILC_CHANNEL_MODE_HMAC)
660 strncat(string, hmac, strlen(hmac));
662 /* Rest of mode is ignored */
664 return strdup(string);
667 /* Parses channel user mode mask and returns te mode as string */
669 char *silc_client_chumode(SilcUInt32 mode)
676 memset(string, 0, sizeof(string));
678 if (mode & SILC_CHANNEL_UMODE_CHANFO)
679 strncat(string, "f", 1);
681 if (mode & SILC_CHANNEL_UMODE_CHANOP)
682 strncat(string, "o", 1);
684 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
685 strncat(string, "b", 1);
687 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
688 strncat(string, "u", 1);
690 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
691 strncat(string, "r", 1);
693 if (mode & SILC_CHANNEL_UMODE_QUIET)
694 strncat(string, "q", 1);
696 return strdup(string);
699 /* Parses channel user mode and returns it as special mode character. */
701 char *silc_client_chumode_char(SilcUInt32 mode)
708 memset(string, 0, sizeof(string));
710 if (mode & SILC_CHANNEL_UMODE_CHANFO)
711 strncat(string, "*", 1);
713 if (mode & SILC_CHANNEL_UMODE_CHANOP)
714 strncat(string, "@", 1);
716 if (mode & SILC_CHANNEL_UMODE_QUIET)
717 strncat(string, "&", 1);
719 return strdup(string);
722 /* Creates fingerprint from data, usually used with SHA1 digests */
724 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
726 char fingerprint[64], *cp;
729 memset(fingerprint, 0, sizeof(fingerprint));
731 for (i = 0; i < data_len; i++) {
732 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
735 if ((i + 1) % 2 == 0)
736 snprintf(cp++, sizeof(fingerprint), " ");
738 if ((i + 1) % 10 == 0)
739 snprintf(cp++, sizeof(fingerprint), " ");
742 if ((i + 1) % 2 == 0)
744 if ((i + 1) % 10 == 0)
747 return strdup(fingerprint);
750 /* Return TRUE if the `data' is ASCII string. */
752 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
756 for (i = 0; i < data_len; i++) {
757 if (!isascii(data[i]))
764 /* Parses SILC protocol style version string. */
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)
774 int maj = 0, min = 0;
776 if (!strstr(version, "SILC-"))
779 cp = (char *)version + 5;
783 /* Take protocol version */
786 if (!strchr(cp, '.'))
788 cp = strchr(cp, '.') + 1;
793 memset(buf, 0, sizeof(buf));
794 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
795 if (protocol_version)
796 *protocol_version = atoi(buf);
797 memset(buf, 0, sizeof(buf));
798 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
799 if (protocol_version_string)
800 *protocol_version_string = strdup(buf);
802 /* Take software version */
806 if (!strchr(cp, '-'))
808 cp = strchr(cp, '-') + 1;
813 if (strchr(cp, '.')) {
814 cp = strchr(cp, '.') + 1;
819 memset(buf, 0, sizeof(buf));
820 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
821 if (software_version)
822 *software_version = atoi(buf);
823 memset(buf, 0, sizeof(buf));
824 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
825 if (software_version_string)
826 *software_version_string = strdup(buf);
828 /* Take vendor string */
830 if (strchr(cp, '.')) {
831 cp = strchr(cp, '.') + 1;
832 if (cp && *cp && vendor_version)
833 *vendor_version = strdup(cp);
839 /* Converts version string x.x into number representation. */
841 SilcUInt32 silc_version_to_num(const char *version)
843 int maj = 0, min = 0;
849 cp = (char *)version;
851 cp = strchr(cp, '.');
855 memset(buf, 0, sizeof(buf));
856 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
857 return (SilcUInt32)atoi(buf);
860 /* Displays input prompt on command line and takes input data from user */
862 char *silc_get_input(const char *prompt, bool echo_off)
867 #ifdef HAVE_TERMIOS_H
871 struct termios to_old;
873 fd = open("/dev/tty", O_RDONLY);
875 fprintf(stderr, "silc: %s\n", strerror(errno));
879 signal(SIGINT, SIG_IGN);
881 /* Get terminal info */
886 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
887 tcsetattr(fd, TCSANOW, &to);
889 memset(input, 0, sizeof(input));
891 printf("%s", prompt);
894 if ((read(fd, input, sizeof(input))) < 0) {
895 fprintf(stderr, "silc: %s\n", strerror(errno));
899 if (strlen(input) <= 1) {
900 tcsetattr(fd, TCSANOW, &to_old);
904 if (strchr(input, '\n'))
905 *strchr(input, '\n') = '\0';
907 /* Restore old terminfo */
908 tcsetattr(fd, TCSANOW, &to_old);
909 signal(SIGINT, SIG_DFL);
911 ret = silc_calloc(strlen(input), sizeof(char));
912 memcpy(ret, input, strlen(input));
913 memset(input, 0, sizeof(input));
914 #endif /* HAVE_TERMIOS_H */
920 fd = open("/dev/tty", O_RDONLY);
922 fprintf(stderr, "silc: %s\n", strerror(errno));
926 memset(input, 0, sizeof(input));
928 printf("%s", prompt);
931 if ((read(fd, input, sizeof(input))) < 0) {
932 fprintf(stderr, "silc: %s\n", strerror(errno));
936 if (strlen(input) <= 1)
939 if (strchr(input, '\n'))
940 *strchr(input, '\n') = '\0';
942 return strdup(input);
946 #endif /* SILC_UNIX */
949 /* Return mode list */
951 bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
956 if (mode_list->len / 4 != mode_list_count)
959 *list = silc_calloc(mode_list_count, sizeof(**list));
961 for (i = 0; i < mode_list_count; i++) {
962 SILC_GET32_MSB((*list)[i], mode_list->data);
963 silc_buffer_pull(mode_list, 4);
966 silc_buffer_push(mode_list, mode_list->data - mode_list->head);
971 /* Status message structure. Messages are defined below. */
977 #define STAT(x) SILC_STATUS_ERR_##x
978 static const SilcStatusMessage silc_status_messages[] = {
980 { STAT(NO_SUCH_NICK), "There was no such nickname" },
981 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
982 { STAT(NO_SUCH_SERVER), "There was no such server" },
983 { STAT(INCOMPLETE_INFORMATION), "Incomplete registration information" },
984 { STAT(NO_RECIPIENT), "No recipient given" },
985 { STAT(UNKNOWN_COMMAND), "Unknown command" },
986 { STAT(WILDCARDS), "Wilcrads not allowed" },
987 { STAT(NO_CLIENT_ID), "No Client ID given" },
988 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
989 { STAT(NO_SERVER_ID), "No Server ID given" },
990 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
991 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
992 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
993 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
994 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
995 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
996 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
997 { STAT(USER_ON_CHANNEL), "User already on the channel" },
998 { STAT(NOT_REGISTERED), "You have not registered" },
999 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
1000 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
1001 { STAT(PERM_DENIED), "Permission denied" },
1002 { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" },
1003 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
1004 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
1005 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
1006 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
1007 { STAT(UNKNOWN_MODE), "Unknown mode" },
1008 { STAT(NOT_YOU), "Cannot change mode for other users" },
1009 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
1010 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
1011 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
1012 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
1013 { STAT(BAD_NICKNAME), "Bad nickname" },
1014 { STAT(BAD_CHANNEL), "Bad channel name" },
1015 { STAT(AUTH_FAILED), "Authentication failed" },
1016 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
1017 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
1018 { STAT(RESOURCE_LIMIT), "No more free resources" },
1019 { STAT(NO_SUCH_SERVICE), "Service doesn't exist" },
1020 { STAT(NOT_AUTHENTICATED), "You have not been authenticated" },
1021 { STAT(BAD_SERVER_ID), "Server ID is not valid" },
1022 { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" },
1023 { STAT(BAD_VERSION), "Bad version" },
1028 /* Returns status message string */
1030 const char *silc_get_status_message(unsigned char status)
1034 for (i = 0; silc_status_messages[i].message; i++) {
1035 if (silc_status_messages[i].status == status)
1039 if (silc_status_messages[i].message == NULL)
1042 return silc_status_messages[i].message;
1045 static const char *packet_name[] = {
1056 "PRIVATE MESSAGE KEY",
1062 "CONNECTION AUTH REQUEST",
1077 /* Returns packet type name */
1079 const char *silc_get_packet_name(unsigned char type)
1081 if (type >= SILC_PACKET_MAX)
1083 if (type >= SILC_PACKET_PRIVATE)
1084 return "PRIVATE RANGE";
1085 if (type > (sizeof(packet_name) / sizeof(*packet_name)))
1087 return packet_name[type];
1090 static const char *command_name[] = {
1121 /* Returns command name */
1123 const char *silc_get_command_name(unsigned char command)
1125 if (command >= SILC_COMMAND_RESERVED)
1127 if (command >= SILC_COMMAND_PRIVATE)
1128 return "PRIVATE RANGE";
1129 if (command > (sizeof(command_name) / sizeof(*command_name)))
1131 return command_name[command];