5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005 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 time as string. If the the `timeval' is non-zero that
82 value is returned as string. If it is zero the current time of the
83 local machine is returned. */
85 const char *silc_get_time(SilcUInt32 timeval)
93 curtime = (time_t)timeval;
94 return_time = ctime(&curtime);
95 return_time[strlen(return_time) - 1] = '\0';
97 return (const char *)return_time;
100 /* Converts string to capital characters. */
102 bool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
106 if (strlen(string) > dest_size)
109 for (i = 0; i < strlen(string); i++)
110 dest[i] = toupper(string[i]);
115 /* Converts string to lower letter characters. */
117 bool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
121 if (strlen(string) > dest_size)
124 for (i = 0; i < strlen(string); i++)
125 dest[i] = tolower(string[i]);
130 /* Parse userfqdn string which is in user@fqdn format. */
132 bool silc_parse_userfqdn(const char *string, char **left, char **right)
139 if (string[0] == '@') {
141 *left = strdup(string);
145 if (strchr(string, '@')) {
146 tlen = strcspn(string, "@");
149 *left = silc_calloc(tlen + 1, sizeof(char));
150 memcpy(*left, string, tlen);
154 *right = silc_calloc((strlen(string) - tlen) + 1, sizeof(char));
155 memcpy(*right, string + tlen + 1, strlen(string) - tlen - 1);
159 *left = silc_memdup(string, strlen(string));
165 /* Parses command line. At most `max_args' is taken. Rest of the line
166 will be allocated as the last argument if there are more than `max_args'
167 arguments in the line. Note that the command name is counted as one
168 argument and is saved. */
170 void silc_parse_command_line(unsigned char *buffer,
171 unsigned char ***parsed,
172 SilcUInt32 **parsed_lens,
173 SilcUInt32 **parsed_types,
174 SilcUInt32 *parsed_num,
179 const char *cp = buffer;
182 *parsed = silc_calloc(1, sizeof(**parsed));
183 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
185 /* Get the command first */
186 len = strcspn(cp, " ");
187 tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp));
190 silc_to_upper(cp, tmp, strlen(cp));
191 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
192 memcpy((*parsed)[0], tmp, len);
194 (*parsed_lens)[0] = len;
200 /* Parse arguments */
201 if (strchr(cp, ' ') || strlen(cp) != 0) {
202 for (i = 1; i < max_args; i++) {
204 if (i != max_args - 1)
205 len = strcspn(cp, " ");
208 while (len && cp[len - 1] == ' ')
213 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
214 *parsed_lens = silc_realloc(*parsed_lens,
215 sizeof(**parsed_lens) * (argc + 1));
216 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
217 memcpy((*parsed)[argc], cp, len);
218 (*parsed_lens)[argc] = len;
230 /* Save argument types. Protocol defines all argument types but
231 this implementation makes sure that they are always in correct
232 order hence this simple code. */
233 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
234 for (i = 0; i < argc; i++)
235 (*parsed_types)[i] = i;
240 /* Formats arguments to a string and returns it after allocating memory
241 for it. It must be remembered to free it later. */
243 char *silc_format(char *fmt, ...)
246 static char buf[8192];
248 memset(buf, 0, sizeof(buf));
250 vsnprintf(buf, sizeof(buf) - 1, fmt, args);
256 /* Renders ID to suitable to print for example to log file. */
258 static char rid[256];
259 #define _PUT_STRING(__d__, __s__) \
261 int __sp = sizeof(__d__) - 1 - strlen(__d__); \
262 if (__sp < strlen(__s__)) { \
264 strncat(__d__, __s__, (sizeof(__d__) - 1) - strlen(__d__)); \
266 strncat(__d__, __s__, strlen(__s__)); \
270 char *silc_id_render(void *id, SilcUInt16 type)
273 unsigned char tmps[2];
276 memset(rid, 0, sizeof(rid));
280 SilcServerID *server_id = (SilcServerID *)id;
281 if (server_id->ip.data_len > 4) {
283 struct sockaddr_in6 ipv6;
284 memset(&ipv6, 0, sizeof(ipv6));
285 ipv6.sin6_family = AF_INET6;
286 memmove(&ipv6.sin6_addr, server_id->ip.data, sizeof(ipv6.sin6_addr));
287 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
288 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
289 _PUT_STRING(rid, tmp);
293 memmove(&ipv4.s_addr, server_id->ip.data, 4);
294 cp = inet_ntoa(ipv4);
296 _PUT_STRING(rid, cp);
299 memset(tmp, 0, sizeof(tmp));
300 snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(server_id->port));
301 _PUT_STRING(rid, tmp);
302 SILC_PUT16_MSB(server_id->rnd, tmps);
303 memset(tmp, 0, sizeof(tmp));
304 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
305 _PUT_STRING(rid, tmp);
310 SilcClientID *client_id = (SilcClientID *)id;
311 if (client_id->ip.data_len > 4) {
313 struct sockaddr_in6 ipv6;
314 memset(&ipv6, 0, sizeof(ipv6));
315 ipv6.sin6_family = AF_INET6;
316 memmove(&ipv6.sin6_addr, client_id->ip.data, sizeof(ipv6.sin6_addr));
317 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
318 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
319 _PUT_STRING(rid, tmp);
323 memmove(&ipv4.s_addr, client_id->ip.data, 4);
324 cp = inet_ntoa(ipv4);
326 _PUT_STRING(rid, cp);
329 memset(tmp, 0, sizeof(tmp));
330 snprintf(tmp, sizeof(tmp) - 1, ",%02x,", client_id->rnd);
331 _PUT_STRING(rid, tmp);
332 memset(tmp, 0, sizeof(tmp));
333 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x %02x %02x...]",
334 client_id->hash[0], client_id->hash[1],
335 client_id->hash[2], client_id->hash[3]);
336 _PUT_STRING(rid, tmp);
339 case SILC_ID_CHANNEL:
341 SilcChannelID *channel_id = (SilcChannelID *)id;
342 if (channel_id->ip.data_len > 4) {
344 struct sockaddr_in6 ipv6;
345 memset(&ipv6, 0, sizeof(ipv6));
346 ipv6.sin6_family = AF_INET6;
347 memmove(&ipv6.sin6_addr, channel_id->ip.data, sizeof(ipv6.sin6_addr));
348 if (!getnameinfo((struct sockaddr *)&ipv6, sizeof(ipv6),
349 tmp, sizeof(tmp) - 1, NULL, 0, NI_NUMERICHOST))
350 _PUT_STRING(rid, tmp);
354 memmove(&ipv4.s_addr, channel_id->ip.data, 4);
355 cp = inet_ntoa(ipv4);
357 _PUT_STRING(rid, cp);
360 memset(tmp, 0, sizeof(tmp));
361 snprintf(tmp, sizeof(tmp) - 1, ",%d,", ntohs(channel_id->port));
362 _PUT_STRING(rid, tmp);
363 SILC_PUT16_MSB(channel_id->rnd, tmps);
364 memset(tmp, 0, sizeof(tmp));
365 snprintf(tmp, sizeof(tmp) - 1, "[%02x %02x]", tmps[0], tmps[1]);
366 _PUT_STRING(rid, tmp);
375 /* Compares two strings. Strings may include wildcards '*' and '?'.
376 Returns TRUE if strings match. */
378 int silc_string_compare(char *string1, char *string2)
383 char *tmpstr1, *tmpstr2;
385 if (!string1 || !string2)
388 slen1 = strlen(string1);
389 slen2 = strlen(string2);
391 /* See if they are same already */
392 if (!strncmp(string1, string2, slen2) && slen2 == slen1)
396 if (!strchr(string1, '*'))
399 /* Take copies of the original strings as we will change them */
400 tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
401 memcpy(tmpstr1, string1, slen1);
402 tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
403 memcpy(tmpstr2, string2, slen2);
405 for (i = 0; i < slen1; i++) {
407 /* * wildcard. Only one * wildcard is possible. */
408 if (tmpstr1[i] == '*')
409 if (!strncmp(tmpstr1, tmpstr2, i)) {
410 memset(tmpstr2, 0, slen2);
411 strncpy(tmpstr2, tmpstr1, i);
416 if (tmpstr1[i] == '?') {
417 if (!strncmp(tmpstr1, tmpstr2, i)) {
418 if (!(slen1 < i + 1))
419 if (tmpstr1[i + 1] != '?' &&
420 tmpstr1[i + 1] != tmpstr2[i + 1])
423 if (!(slen1 < slen2))
429 /* if using *, remove it */
430 if (strchr(tmpstr1, '*'))
431 *strchr(tmpstr1, '*') = 0;
433 if (!strcmp(tmpstr1, tmpstr2)) {
434 memset(tmpstr1, 0, slen1);
435 memset(tmpstr2, 0, slen2);
441 memset(tmpstr1, 0, slen1);
442 memset(tmpstr2, 0, slen2);
448 /* Basic has function to hash strings. May be used with the SilcHashTable.
449 Note that this lowers the characters of the string (with tolower()) so
450 this is used usually with nicknames, channel and server names to provide
451 case insensitive keys. */
453 SilcUInt32 silc_hash_string(void *key, void *user_context)
455 char *s = (char *)key;
459 h = (h << 4) + tolower(*s);
460 if ((g = h & 0xf0000000)) {
470 /* Hash UTF-8 string */
472 SilcUInt32 silc_hash_utf8_string(void *key, void *user_context)
474 unsigned char *s = (unsigned char *)key;
479 if ((g = h & 0xf0000000)) {
489 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
491 SilcUInt32 silc_hash_uint(void *key, void *user_context)
493 return *(SilcUInt32 *)key;
496 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
498 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
500 return SILC_PTR_TO_32(key);
503 /* Hash a ID. The `user_context' is the ID type. */
505 SilcUInt32 silc_hash_id(void *key, void *user_context)
507 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
514 SilcClientID *id = (SilcClientID *)key;
516 /* The client ID is hashed by hashing the hash of the ID
517 (which is a truncated MD5 hash of the nickname) so that we
518 can access the entry from the cache with both Client ID but
519 with just a hash from the ID as well. */
520 return silc_hash_client_id_hash(id->hash, NULL);
525 SilcServerID *id = (SilcServerID *)key;
527 h = id->port * id->rnd;
528 for (i = 0; i < id->ip.data_len; i++)
534 case SILC_ID_CHANNEL:
536 SilcChannelID *id = (SilcChannelID *)key;
538 h = id->port * id->rnd;
539 for (i = 0; i < id->ip.data_len; i++)
552 /* Hash Client ID's hash. */
554 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
557 unsigned char *hash = key;
560 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
561 h = (h << 4) + hash[i];
562 if ((g = h & 0xf0000000)) {
571 /* Hash binary data. The `user_context' is the data length. */
573 SilcUInt32 silc_hash_data(void *key, void *user_context)
575 SilcUInt32 len = SILC_PTR_TO_32(user_context), h = 0;
576 unsigned char *data = (unsigned char *)key;
579 h = (data[0] * data[len - 1] + 1) * len;
580 for (i = 0; i < len; i++)
586 /* Hashed SILC Public key. */
588 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
590 SilcPublicKey pk = (SilcPublicKey)key;
591 return (pk->len + (silc_hash_string(pk->name, NULL) ^
592 silc_hash_string(pk->identifier, NULL) ^
593 silc_hash_data(pk->pk, SILC_32_TO_PTR(pk->pk_len))));
596 /* Compares two strings. It may be used as SilcHashTable comparison
599 bool silc_hash_string_compare(void *key1, void *key2, void *user_context)
601 return !strcasecmp((char *)key1, (char *)key2);
604 /* Compares two ID's. May be used as SilcHashTable comparison function.
605 The Client ID's compares only the hash of the Client ID not any other
606 part of the Client ID. Other ID's are fully compared. */
608 bool silc_hash_id_compare(void *key1, void *key2, void *user_context)
610 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
611 return (id_type == SILC_ID_CLIENT ?
612 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
613 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
616 /* Compare two Client ID's entirely and not just the hash from the ID. */
618 bool silc_hash_client_id_compare(void *key1, void *key2, void *user_context)
620 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
623 /* Compares binary data. May be used as SilcHashTable comparison function. */
625 bool silc_hash_data_compare(void *key1, void *key2, void *user_context)
627 SilcUInt32 len = SILC_PTR_TO_32(user_context);
628 return !memcmp(key1, key2, len);
631 /* Compares UTF-8 string. */
633 bool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
635 int l1 = strlen((char *)key1);
636 int l2 = strlen((char *)key2);
639 return !memcmp(key1, key2, l2);
642 /* Compares two SILC Public keys. It may be used as SilcHashTable
643 comparison function. */
645 bool silc_hash_public_key_compare(void *key1, void *key2, void *user_context)
647 return silc_pkcs_public_key_compare(key1, key2);
650 /* Parses mode mask and returns the mode as string. */
652 char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
659 memset(string, 0, sizeof(string));
661 if (mode & SILC_CHANNEL_MODE_PRIVATE)
662 strncat(string, "p", 1);
664 if (mode & SILC_CHANNEL_MODE_SECRET)
665 strncat(string, "s", 1);
667 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
668 strncat(string, "k", 1);
670 if (mode & SILC_CHANNEL_MODE_INVITE)
671 strncat(string, "i", 1);
673 if (mode & SILC_CHANNEL_MODE_TOPIC)
674 strncat(string, "t", 1);
676 if (mode & SILC_CHANNEL_MODE_ULIMIT)
677 strncat(string, "l", 1);
679 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
680 strncat(string, "a", 1);
682 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
683 strncat(string, "f", 1);
685 if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
686 strncat(string, "C", 1);
688 if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
689 strncat(string, "m", 1);
691 if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
692 strncat(string, "M", 1);
694 if (mode & SILC_CHANNEL_MODE_CIPHER)
695 strncat(string, "c", 1);
697 if (mode & SILC_CHANNEL_MODE_HMAC)
698 strncat(string, "h", 1);
700 if (mode & SILC_CHANNEL_MODE_CIPHER) {
701 if (strlen(cipher) + strlen(string) + 1< sizeof(string)) {
702 strncat(string, " ", 1);
703 strncat(string, cipher, strlen(cipher));
707 if (mode & SILC_CHANNEL_MODE_HMAC) {
708 if (strlen(hmac) + strlen(string) + 1< sizeof(string)) {
709 strncat(string, " ", 1);
710 strncat(string, hmac, strlen(hmac));
714 /* Rest of mode is ignored */
716 return strdup(string);
719 /* Parses channel user mode mask and returns te mode as string */
721 char *silc_client_chumode(SilcUInt32 mode)
728 memset(string, 0, sizeof(string));
730 if (mode & SILC_CHANNEL_UMODE_CHANFO)
731 strncat(string, "f", 1);
733 if (mode & SILC_CHANNEL_UMODE_CHANOP)
734 strncat(string, "o", 1);
736 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
737 strncat(string, "b", 1);
739 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
740 strncat(string, "u", 1);
742 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
743 strncat(string, "r", 1);
745 if (mode & SILC_CHANNEL_UMODE_QUIET)
746 strncat(string, "q", 1);
748 return strdup(string);
751 /* Parses channel user mode and returns it as special mode character. */
753 char *silc_client_chumode_char(SilcUInt32 mode)
760 memset(string, 0, sizeof(string));
762 if (mode & SILC_CHANNEL_UMODE_CHANFO)
763 strncat(string, "*", 1);
765 if (mode & SILC_CHANNEL_UMODE_CHANOP)
766 strncat(string, "@", 1);
768 if (mode & SILC_CHANNEL_UMODE_QUIET)
769 strncat(string, "&", 1);
771 return strdup(string);
774 /* Creates fingerprint from data, usually used with SHA1 digests */
776 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
778 char fingerprint[64], *cp;
781 memset(fingerprint, 0, sizeof(fingerprint));
783 for (i = 0; i < data_len; i++) {
784 snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
787 if ((i + 1) % 2 == 0)
788 snprintf(cp++, sizeof(fingerprint), " ");
790 if ((i + 1) % 10 == 0)
791 snprintf(cp++, sizeof(fingerprint), " ");
794 if ((i + 1) % 2 == 0)
796 if ((i + 1) % 10 == 0)
799 return strdup(fingerprint);
802 /* Return TRUE if the `data' is ASCII string. */
804 bool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
808 for (i = 0; i < data_len; i++) {
809 if (!isascii(data[i]))
816 /* Parses SILC protocol style version string. */
818 bool silc_parse_version_string(const char *version,
819 SilcUInt32 *protocol_version,
820 char **protocol_version_string,
821 SilcUInt32 *software_version,
822 char **software_version_string,
823 char **vendor_version)
826 int maj = 0, min = 0;
828 if (!strstr(version, "SILC-"))
831 cp = (char *)version + 5;
835 /* Take protocol version */
838 if (!strchr(cp, '.'))
840 cp = strchr(cp, '.') + 1;
845 memset(buf, 0, sizeof(buf));
846 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
847 if (protocol_version)
848 *protocol_version = atoi(buf);
849 memset(buf, 0, sizeof(buf));
850 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
851 if (protocol_version_string)
852 *protocol_version_string = strdup(buf);
854 /* Take software version */
858 if (!strchr(cp, '-'))
860 cp = strchr(cp, '-') + 1;
865 if (strchr(cp, '.')) {
866 cp = strchr(cp, '.') + 1;
871 memset(buf, 0, sizeof(buf));
872 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
873 if (software_version)
874 *software_version = atoi(buf);
875 memset(buf, 0, sizeof(buf));
876 snprintf(buf, sizeof(buf) - 1, "%d.%d", maj, min);
877 if (software_version_string)
878 *software_version_string = strdup(buf);
880 /* Take vendor string */
882 if (strchr(cp, '.')) {
883 cp = strchr(cp, '.') + 1;
884 if (cp && *cp && vendor_version)
885 *vendor_version = strdup(cp);
891 /* Converts version string x.x into number representation. */
893 SilcUInt32 silc_version_to_num(const char *version)
895 int maj = 0, min = 0;
901 cp = (char *)version;
903 cp = strchr(cp, '.');
907 memset(buf, 0, sizeof(buf));
908 snprintf(buf, sizeof(buf) - 1, "%d%d", maj, min);
909 return (SilcUInt32)atoi(buf);
912 /* Displays input prompt on command line and takes input data from user */
914 char *silc_get_input(const char *prompt, bool echo_off)
922 #ifdef HAVE_TERMIOS_H
924 struct termios to_old;
926 fd = open("/dev/tty", O_RDONLY);
928 fprintf(stderr, "silc: %s\n", strerror(errno));
932 signal(SIGINT, SIG_IGN);
934 /* Get terminal info */
938 /* Echo OFF, and assure we can prompt and get input */
939 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
940 to.c_lflag |= ICANON;
942 tcsetattr(fd, TCSANOW, &to);
944 memset(input, 0, sizeof(input));
946 printf("%s", prompt);
949 if ((read(fd, input, sizeof(input))) < 0) {
950 fprintf(stderr, "silc: %s\n", strerror(errno));
951 tcsetattr(fd, TCSANOW, &to_old);
955 if (strlen(input) <= 1) {
956 tcsetattr(fd, TCSANOW, &to_old);
960 if (strchr(input, '\n'))
961 *strchr(input, '\n') = '\0';
963 /* Restore old terminfo */
964 tcsetattr(fd, TCSANOW, &to_old);
965 signal(SIGINT, SIG_DFL);
967 ret = silc_memdup(input, strlen(input));
968 memset(input, 0, sizeof(input));
969 #endif /* HAVE_TERMIOS_H */
972 fd = open("/dev/tty", O_RDONLY);
974 fprintf(stderr, "silc: %s\n", strerror(errno));
978 memset(input, 0, sizeof(input));
980 printf("%s", prompt);
983 if ((read(fd, input, sizeof(input))) < 0) {
984 fprintf(stderr, "silc: %s\n", strerror(errno));
988 if (strlen(input) <= 1)
991 if (strchr(input, '\n'))
992 *strchr(input, '\n') = '\0';
994 return strdup(input);
998 #endif /* SILC_UNIX */
1001 /* Return mode list */
1003 bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
1008 if (mode_list->len / 4 != mode_list_count)
1011 *list = silc_calloc(mode_list_count, sizeof(**list));
1013 for (i = 0; i < mode_list_count; i++) {
1014 SILC_GET32_MSB((*list)[i], mode_list->data);
1015 silc_buffer_pull(mode_list, 4);
1018 silc_buffer_push(mode_list, mode_list->data - mode_list->head);
1023 /* Status message structure. Messages are defined below. */
1026 const char *message;
1027 } SilcStatusMessage;
1029 #define STAT(x) SILC_STATUS_ERR_##x
1030 static const SilcStatusMessage silc_status_messages[] = {
1032 { STAT(NO_SUCH_NICK), "There was no such nickname" },
1033 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
1034 { STAT(NO_SUCH_SERVER), "There was no such server" },
1035 { STAT(INCOMPLETE_INFORMATION), "Incomplete registration information" },
1036 { STAT(NO_RECIPIENT), "No recipient given" },
1037 { STAT(UNKNOWN_COMMAND), "Unknown command" },
1038 { STAT(WILDCARDS), "Wilcrads not allowed" },
1039 { STAT(NO_CLIENT_ID), "No Client ID given" },
1040 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
1041 { STAT(NO_SERVER_ID), "No Server ID given" },
1042 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
1043 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
1044 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
1045 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
1046 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
1047 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
1048 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
1049 { STAT(USER_ON_CHANNEL), "User already on the channel" },
1050 { STAT(NOT_REGISTERED), "You have not registered" },
1051 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
1052 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
1053 { STAT(PERM_DENIED), "Permission denied" },
1054 { STAT(BANNED_FROM_SERVER),"You are not allowed to connect" },
1055 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
1056 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
1057 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
1058 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
1059 { STAT(UNKNOWN_MODE), "Unknown mode" },
1060 { STAT(NOT_YOU), "Cannot change mode for other users" },
1061 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
1062 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
1063 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
1064 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
1065 { STAT(BAD_NICKNAME), "Bad nickname" },
1066 { STAT(BAD_CHANNEL), "Bad channel name" },
1067 { STAT(AUTH_FAILED), "Authentication failed" },
1068 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
1069 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
1070 { STAT(RESOURCE_LIMIT), "No more free resources" },
1071 { STAT(NO_SUCH_SERVICE), "Service doesn't exist" },
1072 { STAT(NOT_AUTHENTICATED), "You have not been authenticated" },
1073 { STAT(BAD_SERVER_ID), "Server ID is not valid" },
1074 { STAT(KEY_EXCHANGE_FAILED), "Key exchange failed" },
1075 { STAT(BAD_VERSION), "Bad version" },
1076 { STAT(TIMEDOUT), "Service timed out" },
1077 { STAT(UNSUPPORTED_PUBLIC_KEY), "Unsupported public key type" },
1078 { STAT(OPERATION_ALLOWED), "Operation is not allowed" },
1079 { STAT(BAD_SERVER), "Bad server name" },
1080 { STAT(BAD_USERNAME), "Bad user name" },
1085 /* Returns status message string */
1087 const char *silc_get_status_message(unsigned char status)
1091 for (i = 0; silc_status_messages[i].message; i++) {
1092 if (silc_status_messages[i].status == status)
1096 if (silc_status_messages[i].message == NULL)
1099 return silc_status_messages[i].message;
1102 static const char *packet_name[] = {
1113 "PRIVATE MESSAGE KEY",
1119 "CONNECTION AUTH REQUEST",
1134 /* Returns packet type name */
1136 const char *silc_get_packet_name(unsigned char type)
1138 if (type >= SILC_PACKET_MAX)
1140 if (type >= SILC_PACKET_PRIVATE)
1141 return "PRIVATE RANGE";
1142 if (type > (sizeof(packet_name) / sizeof(*packet_name)))
1144 return packet_name[type];
1147 static const char *command_name[] = {
1178 /* Returns command name */
1180 const char *silc_get_command_name(unsigned char command)
1182 if (command >= SILC_COMMAND_RESERVED)
1184 if (command >= SILC_COMMAND_PRIVATE)
1185 return "PRIVATE RANGE";
1186 if (command > (sizeof(command_name) / sizeof(*command_name)))
1188 return command_name[command];
1191 /* Return TRUE if `smaller' is smaller than `bigger'. */
1193 bool silc_compare_timeval(struct timeval *smaller,
1194 struct timeval *bigger)
1196 if ((smaller->tv_sec < bigger->tv_sec) ||
1197 ((smaller->tv_sec == bigger->tv_sec) &&
1198 (smaller->tv_usec < bigger->tv_usec)))