5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 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
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 /* Converts string to capital characters. */
83 SilcBool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
87 if (strlen(string) > dest_size)
90 for (i = 0; i < strlen(string); i++)
91 dest[i] = (char)toupper((int)string[i]);
96 /* Converts string to lower letter characters. */
98 SilcBool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
102 if (strlen(string) > dest_size)
105 for (i = 0; i < strlen(string); i++)
106 dest[i] = (char)tolower((int)string[i]);
111 /* Parse userfqdn string which is in user@fqdn format. */
113 int silc_parse_userfqdn(const char *string,
114 char *user, SilcUInt32 user_size,
115 char *fqdn, SilcUInt32 fqdn_size)
122 memset(user, 0, user_size);
123 memset(fqdn, 0, fqdn_size);
128 if (string[0] == '@') {
130 silc_strncat(user, user_size, string, strlen(string));
135 if (strchr(string, '@')) {
136 tlen = strcspn(string, "@");
139 silc_strncat(user, user_size, string, tlen);
142 silc_strncat(fqdn, fqdn_size, string + tlen + 1,
143 strlen(string) - tlen - 1);
149 silc_strncat(user, user_size, string, strlen(string));
154 /* Parses command line. At most `max_args' is taken. Rest of the line
155 will be allocated as the last argument if there are more than `max_args'
156 arguments in the line. Note that the command name is counted as one
157 argument and is saved. */
159 void silc_parse_command_line(unsigned char *buffer,
160 unsigned char ***parsed,
161 SilcUInt32 **parsed_lens,
162 SilcUInt32 **parsed_types,
163 SilcUInt32 *parsed_num,
168 const char *cp = (const char *)buffer;
171 *parsed = silc_calloc(1, sizeof(**parsed));
172 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
174 /* Get the command first */
175 len = strcspn(cp, " ");
176 tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp));
179 silc_to_upper(cp, tmp, strlen(cp));
180 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
181 memcpy((*parsed)[0], tmp, len);
183 (*parsed_lens)[0] = len;
189 /* Parse arguments */
190 if (strchr(cp, ' ') || strlen(cp) != 0) {
191 for (i = 1; i < max_args; i++) {
193 if (i != max_args - 1)
194 len = strcspn(cp, " ");
197 while (len && cp[len - 1] == ' ')
202 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
203 *parsed_lens = silc_realloc(*parsed_lens,
204 sizeof(**parsed_lens) * (argc + 1));
205 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
206 memcpy((*parsed)[argc], cp, len);
207 (*parsed_lens)[argc] = len;
219 /* Save argument types. Protocol defines all argument types but
220 this implementation makes sure that they are always in correct
221 order hence this simple code. */
222 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
223 for (i = 0; i < argc; i++)
224 (*parsed_types)[i] = i;
229 /* Formats arguments to a string and returns it after allocating memory
230 for it. It must be remembered to free it later. */
232 char *silc_format(char *fmt, ...)
237 memset(buf, 0, sizeof(buf));
239 silc_vsnprintf(buf, sizeof(buf) - 1, fmt, args);
245 /* Basic has function to hash strings. May be used with the SilcHashTable.
246 Note that this lowers the characters of the string (with tolower()) so
247 this is used usually with nicknames, channel and server names to provide
248 case insensitive keys. */
250 SilcUInt32 silc_hash_string(void *key, void *user_context)
252 char *s = (char *)key;
256 h = (h << 4) + tolower((int)*s);
257 if ((g = h & 0xf0000000)) {
267 /* Hash UTF-8 string */
269 SilcUInt32 silc_hash_utf8_string(void *key, void *user_context)
271 unsigned char *s = (unsigned char *)key;
276 if ((g = h & 0xf0000000)) {
286 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
288 SilcUInt32 silc_hash_uint(void *key, void *user_context)
290 return SILC_PTR_TO_32(key);
293 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
295 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
297 return SILC_PTR_TO_32(key);
300 /* Hash a ID. The `user_context' is the ID type. */
302 SilcUInt32 silc_hash_id(void *key, void *user_context)
304 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
311 SilcClientID *id = (SilcClientID *)key;
313 /* The client ID is hashed by hashing the hash of the ID
314 (which is a truncated MD5 hash of the nickname) so that we
315 can access the entry from the cache with both Client ID but
316 with just a hash from the ID as well. */
317 return silc_hash_client_id_hash(id->hash, NULL);
322 SilcServerID *id = (SilcServerID *)key;
324 h = id->port * id->rnd;
325 for (i = 0; i < id->ip.data_len; i++)
331 case SILC_ID_CHANNEL:
333 SilcChannelID *id = (SilcChannelID *)key;
335 h = id->port * id->rnd;
336 for (i = 0; i < id->ip.data_len; i++)
349 /* Hash Client ID's hash. */
351 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
354 unsigned char *hash = key;
357 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
358 h = (h << 4) + hash[i];
359 if ((g = h & 0xf0000000)) {
368 /* Hash binary data. The `user_context' is the data length. */
370 SilcUInt32 silc_hash_data(void *key, void *user_context)
372 SilcUInt32 len = SILC_PTR_TO_32(user_context), h = 0;
373 unsigned char *data = (unsigned char *)key;
376 h = (data[0] * data[len - 1] + 1) * len;
377 for (i = 0; i < len; i++)
383 /* Compares two strings. It may be used as SilcHashTable comparison
386 SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context)
388 return !strcasecmp((char *)key1, (char *)key2);
391 /* Compares two ID's. May be used as SilcHashTable comparison function.
392 The Client ID's compares only the hash of the Client ID not any other
393 part of the Client ID. Other ID's are fully compared. */
395 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
397 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
398 return (id_type == SILC_ID_CLIENT ?
399 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
400 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
403 /* Compares two ID's. Compares full IDs. */
405 SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
407 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
408 return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
411 /* Compare two Client ID's entirely and not just the hash from the ID. */
413 SilcBool silc_hash_client_id_compare(void *key1, void *key2,
416 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
419 /* Compares binary data. May be used as SilcHashTable comparison function. */
421 SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context)
423 SilcUInt32 len = SILC_PTR_TO_32(user_context);
424 return !memcmp(key1, key2, len);
427 /* Compares UTF-8 string. */
429 SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
431 int l1 = strlen((char *)key1);
432 int l2 = strlen((char *)key2);
435 return !memcmp(key1, key2, l2);
438 /* Creates fingerprint from data, usually used with SHA1 digests */
440 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
442 char fingerprint[64], *cp;
445 memset(fingerprint, 0, sizeof(fingerprint));
447 for (i = 0; i < data_len; i++) {
448 silc_snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
451 if ((i + 1) % 2 == 0)
452 silc_snprintf(cp++, sizeof(fingerprint), " ");
454 if ((i + 1) % 10 == 0)
455 silc_snprintf(cp++, sizeof(fingerprint), " ");
458 if ((i + 1) % 2 == 0)
460 if ((i + 1) % 10 == 0)
463 return strdup(fingerprint);
466 /* Return TRUE if the `data' is ASCII string. */
468 SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
472 for (i = 0; i < data_len; i++) {
473 if (!isascii(data[i]))
480 /* Displays input prompt on command line and takes input data from user */
482 char *silc_get_input(const char *prompt, SilcBool echo_off)
490 #ifdef HAVE_TERMIOS_H
492 struct termios to_old;
494 fd = open("/dev/tty", O_RDONLY);
496 fprintf(stderr, "silc: %s\n", strerror(errno));
500 signal(SIGINT, SIG_IGN);
502 /* Get terminal info */
506 /* Echo OFF, and assure we can prompt and get input */
507 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
508 to.c_lflag |= ICANON;
510 tcsetattr(fd, TCSANOW, &to);
512 memset(input, 0, sizeof(input));
514 printf("%s", prompt);
517 if ((read(fd, input, sizeof(input))) < 0) {
518 fprintf(stderr, "silc: %s\n", strerror(errno));
519 tcsetattr(fd, TCSANOW, &to_old);
523 if (strlen(input) <= 1) {
524 tcsetattr(fd, TCSANOW, &to_old);
528 if (strchr(input, '\n'))
529 *strchr(input, '\n') = '\0';
531 /* Restore old terminfo */
532 tcsetattr(fd, TCSANOW, &to_old);
533 signal(SIGINT, SIG_DFL);
535 ret = silc_memdup(input, strlen(input));
536 memset(input, 0, sizeof(input));
537 #endif /* HAVE_TERMIOS_H */
540 fd = open("/dev/tty", O_RDONLY);
542 fprintf(stderr, "silc: %s\n", strerror(errno));
546 memset(input, 0, sizeof(input));
548 printf("%s", prompt);
551 if ((read(fd, input, sizeof(input))) < 0) {
552 fprintf(stderr, "silc: %s\n", strerror(errno));
556 if (strlen(input) <= 1)
559 if (strchr(input, '\n'))
560 *strchr(input, '\n') = '\0';
562 return strdup(input);
566 #endif /* SILC_UNIX */
571 void silc_hexdump(const unsigned char *data, SilcUInt32 data_len,
584 if ((len - pos) < 16 && (len - pos <= len - off))
594 fprintf(output, "%08X ", k++ * 16);
596 for (i = 0; i < count; i++) {
597 fprintf(output, "%02X ", data[pos + i]);
599 if ((i + 1) % 4 == 0)
600 fprintf(output, " ");
603 if (count && count < 16) {
606 for (j = 0; j < 16 - count; j++) {
607 fprintf(output, " ");
609 if ((j + count + 1) % 4 == 0)
610 fprintf(output, " ");
614 for (i = 0; i < count; i++) {
617 if (data[pos] < 32 || data[pos] >= 127)
622 fprintf(output, "%c", ch);
627 fprintf(output, "\n");
634 /* Convert hex string to data. Each hex number must have two characters. */
636 SilcBool silc_hex2data(const char *hex, unsigned char *data,
637 SilcUInt32 data_size, SilcUInt32 *ret_data_len)
639 char *cp = (char *)hex;
643 if (data_size < strlen(hex) / 2)
646 for (i = 0; i < strlen(hex) / 2; i++) {
650 h -= h < 'A' ? '0' : 'A' - 10;
651 l -= l < 'A' ? '0' : 'A' - 10;
653 data[i] = (h << 4) | (l & 0xf);
659 SILC_LOG_HEXDUMP(("len %d", i), data, i);
664 /* Converts binary data to HEX string */
666 SilcBool silc_data2hex(const unsigned char *data, SilcUInt32 data_len,
667 char *hex, SilcUInt32 hex_size)
673 if (hex_size - 1 < data_len * 2)
676 memset(hex, 0, hex_size);
678 for (i = 0; i < data_len; i++) {
683 *cp++ = h + (h > 9 ? 'A' - 10 : '0');
684 *cp++ = l + (l > 9 ? 'A' - 10 : '0');
687 SILC_LOG_DEBUG(("HEX string: '%s'", hex));