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 = 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 /* Hash public key of any type. */
385 SilcUInt32 silc_hash_public_key(void *key, void *user_context)
387 SilcPublicKey public_key = key;
392 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
396 hash = silc_hash_data(pk, SILC_32_TO_PTR(pk_len));
402 /* Compares two strings. It may be used as SilcHashTable comparison
405 SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context)
407 return !strcasecmp((char *)key1, (char *)key2);
410 /* Compares two ID's. May be used as SilcHashTable comparison function.
411 The Client ID's compares only the hash of the Client ID not any other
412 part of the Client ID. Other ID's are fully compared. */
414 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
416 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
417 return (id_type == SILC_ID_CLIENT ?
418 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
419 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
422 /* Compares two ID's. Compares full IDs. */
424 SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
426 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
427 return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
430 /* Compare two Client ID's entirely and not just the hash from the ID. */
432 SilcBool silc_hash_client_id_compare(void *key1, void *key2,
435 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
438 /* Compares binary data. May be used as SilcHashTable comparison function. */
440 SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context)
442 SilcUInt32 len = SILC_PTR_TO_32(user_context);
443 return !memcmp(key1, key2, len);
446 /* Compares UTF-8 string. */
448 SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
450 int l1 = strlen((char *)key1);
451 int l2 = strlen((char *)key2);
454 return !memcmp(key1, key2, l2);
457 /* Compares two SILC Public keys. It may be used as SilcHashTable
458 comparison function. */
460 SilcBool silc_hash_public_key_compare(void *key1, void *key2,
463 return silc_pkcs_public_key_compare(key1, key2);
466 /* Creates fingerprint from data, usually used with SHA1 digests */
468 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
470 char fingerprint[64], *cp;
473 memset(fingerprint, 0, sizeof(fingerprint));
475 for (i = 0; i < data_len; i++) {
476 silc_snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
479 if ((i + 1) % 2 == 0)
480 silc_snprintf(cp++, sizeof(fingerprint), " ");
482 if ((i + 1) % 10 == 0)
483 silc_snprintf(cp++, sizeof(fingerprint), " ");
486 if ((i + 1) % 2 == 0)
488 if ((i + 1) % 10 == 0)
491 return strdup(fingerprint);
494 /* Return TRUE if the `data' is ASCII string. */
496 SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
500 for (i = 0; i < data_len; i++) {
501 if (!isascii(data[i]))
508 /* Displays input prompt on command line and takes input data from user */
510 char *silc_get_input(const char *prompt, SilcBool echo_off)
518 #ifdef HAVE_TERMIOS_H
520 struct termios to_old;
522 fd = open("/dev/tty", O_RDONLY);
524 fprintf(stderr, "silc: %s\n", strerror(errno));
528 signal(SIGINT, SIG_IGN);
530 /* Get terminal info */
534 /* Echo OFF, and assure we can prompt and get input */
535 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
536 to.c_lflag |= ICANON;
538 tcsetattr(fd, TCSANOW, &to);
540 memset(input, 0, sizeof(input));
542 printf("%s", prompt);
545 if ((read(fd, input, sizeof(input))) < 0) {
546 fprintf(stderr, "silc: %s\n", strerror(errno));
547 tcsetattr(fd, TCSANOW, &to_old);
551 if (strlen(input) <= 1) {
552 tcsetattr(fd, TCSANOW, &to_old);
556 if (strchr(input, '\n'))
557 *strchr(input, '\n') = '\0';
559 /* Restore old terminfo */
560 tcsetattr(fd, TCSANOW, &to_old);
561 signal(SIGINT, SIG_DFL);
563 ret = silc_memdup(input, strlen(input));
564 memset(input, 0, sizeof(input));
565 #endif /* HAVE_TERMIOS_H */
568 fd = open("/dev/tty", O_RDONLY);
570 fprintf(stderr, "silc: %s\n", strerror(errno));
574 memset(input, 0, sizeof(input));
576 printf("%s", prompt);
579 if ((read(fd, input, sizeof(input))) < 0) {
580 fprintf(stderr, "silc: %s\n", strerror(errno));
584 if (strlen(input) <= 1)
587 if (strchr(input, '\n'))
588 *strchr(input, '\n') = '\0';
590 return strdup(input);
594 #endif /* SILC_UNIX */