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)
123 memset(user, 0, user_size);
125 memset(fqdn, 0, fqdn_size);
130 if (string[0] == '@') {
132 silc_strncat(user, user_size, string, strlen(string));
137 if (strchr(string, '@')) {
138 tlen = strcspn(string, "@");
141 silc_strncat(user, user_size, string, tlen);
144 silc_strncat(fqdn, fqdn_size, string + tlen + 1,
145 strlen(string) - tlen - 1);
151 silc_strncat(user, user_size, string, strlen(string));
156 /* Parses command line. At most `max_args' is taken. Rest of the line
157 will be allocated as the last argument if there are more than `max_args'
158 arguments in the line. Note that the command name is counted as one
159 argument and is saved. */
161 void silc_parse_command_line(unsigned char *buffer,
162 unsigned char ***parsed,
163 SilcUInt32 **parsed_lens,
164 SilcUInt32 **parsed_types,
165 SilcUInt32 *parsed_num,
170 const char *cp = buffer;
173 *parsed = silc_calloc(1, sizeof(**parsed));
174 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
176 /* Get the command first */
177 len = strcspn(cp, " ");
178 tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp));
181 silc_to_upper(cp, tmp, strlen(cp));
182 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
183 memcpy((*parsed)[0], tmp, len);
185 (*parsed_lens)[0] = len;
191 /* Parse arguments */
192 if (strchr(cp, ' ') || strlen(cp) != 0) {
193 for (i = 1; i < max_args; i++) {
195 if (i != max_args - 1)
196 len = strcspn(cp, " ");
199 while (len && cp[len - 1] == ' ')
204 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
205 *parsed_lens = silc_realloc(*parsed_lens,
206 sizeof(**parsed_lens) * (argc + 1));
207 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
208 memcpy((*parsed)[argc], cp, len);
209 (*parsed_lens)[argc] = len;
221 /* Save argument types. Protocol defines all argument types but
222 this implementation makes sure that they are always in correct
223 order hence this simple code. */
224 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
225 for (i = 0; i < argc; i++)
226 (*parsed_types)[i] = i;
231 /* Formats arguments to a string and returns it after allocating memory
232 for it. It must be remembered to free it later. */
234 char *silc_format(char *fmt, ...)
239 memset(buf, 0, sizeof(buf));
241 silc_vsnprintf(buf, sizeof(buf) - 1, fmt, args);
247 /* Basic has function to hash strings. May be used with the SilcHashTable.
248 Note that this lowers the characters of the string (with tolower()) so
249 this is used usually with nicknames, channel and server names to provide
250 case insensitive keys. */
252 SilcUInt32 silc_hash_string(void *key, void *user_context)
254 char *s = (char *)key;
258 h = (h << 4) + tolower((int)*s);
259 if ((g = h & 0xf0000000)) {
269 /* Hash UTF-8 string */
271 SilcUInt32 silc_hash_utf8_string(void *key, void *user_context)
273 unsigned char *s = (unsigned char *)key;
278 if ((g = h & 0xf0000000)) {
288 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
290 SilcUInt32 silc_hash_uint(void *key, void *user_context)
292 return SILC_PTR_TO_32(key);
295 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
297 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
299 return SILC_PTR_TO_32(key);
302 /* Hash a ID. The `user_context' is the ID type. */
304 SilcUInt32 silc_hash_id(void *key, void *user_context)
306 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
313 SilcClientID *id = (SilcClientID *)key;
315 /* The client ID is hashed by hashing the hash of the ID
316 (which is a truncated MD5 hash of the nickname) so that we
317 can access the entry from the cache with both Client ID but
318 with just a hash from the ID as well. */
319 return silc_hash_client_id_hash(id->hash, NULL);
324 SilcServerID *id = (SilcServerID *)key;
326 h = id->port * id->rnd;
327 for (i = 0; i < id->ip.data_len; i++)
333 case SILC_ID_CHANNEL:
335 SilcChannelID *id = (SilcChannelID *)key;
337 h = id->port * id->rnd;
338 for (i = 0; i < id->ip.data_len; i++)
351 /* Hash Client ID's hash. */
353 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
356 unsigned char *hash = key;
359 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
360 h = (h << 4) + hash[i];
361 if ((g = h & 0xf0000000)) {
370 /* Hash binary data. The `user_context' is the data length. */
372 SilcUInt32 silc_hash_data(void *key, void *user_context)
374 SilcUInt32 len = SILC_PTR_TO_32(user_context), h = 0;
375 unsigned char *data = (unsigned char *)key;
378 h = (data[0] * data[len - 1] + 1) * len;
379 for (i = 0; i < len; i++)
385 /* Hash public key of any type. */
387 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
389 SilcPublicKey public_key = key;
394 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
398 hash = silc_hash_data(pk, SILC_32_TO_PTR(pk_len));
404 /* Compares two strings. It may be used as SilcHashTable comparison
407 SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context)
409 return !strcasecmp((char *)key1, (char *)key2);
412 /* Compares two ID's. May be used as SilcHashTable comparison function.
413 The Client ID's compares only the hash of the Client ID not any other
414 part of the Client ID. Other ID's are fully compared. */
416 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
418 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
419 return (id_type == SILC_ID_CLIENT ?
420 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
421 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
424 /* Compares two ID's. Compares full IDs. */
426 SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
428 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
429 return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
432 /* Compare two Client ID's entirely and not just the hash from the ID. */
434 SilcBool silc_hash_client_id_compare(void *key1, void *key2,
437 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
440 /* Compares binary data. May be used as SilcHashTable comparison function. */
442 SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context)
444 SilcUInt32 len = SILC_PTR_TO_32(user_context);
445 return !memcmp(key1, key2, len);
448 /* Compares UTF-8 string. */
450 SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
452 int l1 = strlen((char *)key1);
453 int l2 = strlen((char *)key2);
456 return !memcmp(key1, key2, l2);
459 /* Compares two SILC Public keys. It may be used as SilcHashTable
460 comparison function. */
462 SilcBool silc_hash_public_key_compare(void *key1, void *key2,
465 return silc_pkcs_public_key_compare(key1, key2);
468 /* Creates fingerprint from data, usually used with SHA1 digests */
470 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
472 unsigned char *fingerprint, *cp;
473 unsigned int len, blocks, i;
475 if (!data || !data_len)
481 /* Align and calculate total length */
482 len = ((data_len + 19) / 20) * 20;
484 len = (len * 2) + ((blocks - 1) * 2) + (4 * blocks) + 2 + 1;
486 cp = fingerprint = silc_calloc(len, sizeof(*fingerprint));
490 for (i = 0; i < data_len; i++) {
491 silc_snprintf(cp, len, "%02X", data[i]);
495 if ((i + 1) % 2 == 0)
496 silc_snprintf(cp++, len--, " ");
497 if ((i + 1) % 10 == 0)
498 silc_snprintf(cp++, len--, " ");
501 if ((i + 1) % 10 == 0)
503 if ((i + 1) % 2 == 0)
509 /* Return TRUE if the `data' is ASCII string. */
511 SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
515 for (i = 0; i < data_len; i++) {
516 if (!isascii(data[i]))
523 /* Displays input prompt on command line and takes input data from user */
525 char *silc_get_input(const char *prompt, SilcBool echo_off)
533 #ifdef HAVE_TERMIOS_H
535 struct termios to_old;
537 fd = open("/dev/tty", O_RDONLY);
539 fprintf(stderr, "silc: %s\n", strerror(errno));
543 signal(SIGINT, SIG_IGN);
545 /* Get terminal info */
549 /* Echo OFF, and assure we can prompt and get input */
550 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
551 to.c_lflag |= ICANON;
553 tcsetattr(fd, TCSANOW, &to);
555 memset(input, 0, sizeof(input));
557 printf("%s", prompt);
561 if ((read(fd, input, sizeof(input))) < 0) {
562 if (errno == EAGAIN || errno == EINTR)
564 fprintf(stderr, "silc: %s\n", strerror(errno));
565 signal(SIGINT, SIG_DFL);
566 tcsetattr(fd, TCSANOW, &to_old);
570 if (strlen(input) <= 1) {
571 signal(SIGINT, SIG_DFL);
572 tcsetattr(fd, TCSANOW, &to_old);
576 if (strchr(input, '\n'))
577 *strchr(input, '\n') = '\0';
579 /* Restore old terminfo */
580 tcsetattr(fd, TCSANOW, &to_old);
581 signal(SIGINT, SIG_DFL);
583 ret = silc_memdup(input, strlen(input));
584 memset(input, 0, sizeof(input));
585 #endif /* HAVE_TERMIOS_H */
588 fd = open("/dev/tty", O_RDONLY);
590 fprintf(stderr, "silc: %s\n", strerror(errno));
594 memset(input, 0, sizeof(input));
596 printf("%s", prompt);
599 signal(SIGINT, SIG_IGN);
602 if ((read(fd, input, sizeof(input))) < 0) {
603 if (errno == EAGAIN || errno == EINTR)
605 fprintf(stderr, "silc: %s\n", strerror(errno));
606 signal(SIGINT, SIG_DFL);
610 signal(SIGINT, SIG_DFL);
612 if (strlen(input) <= 1)
615 if (strchr(input, '\n'))
616 *strchr(input, '\n') = '\0';
618 return strdup(input);
622 #endif /* SILC_UNIX */