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++) {
44 silc_set_errno(SILC_ERR_OVERFLOW);
51 silc_set_errno(SILC_ERR_EOF);
63 /* Converts string to capital characters. */
65 SilcBool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
69 if (strlen(string) > dest_size) {
70 silc_set_errno(SILC_ERR_OVERFLOW);
74 for (i = 0; i < strlen(string); i++)
75 dest[i] = (char)toupper((int)string[i]);
80 /* Converts string to lower letter characters. */
82 SilcBool silc_to_lower(const char *string, char *dest, SilcUInt32 dest_size)
86 if (strlen(string) > dest_size) {
87 silc_set_errno(SILC_ERR_OVERFLOW);
91 for (i = 0; i < strlen(string); i++)
92 dest[i] = (char)tolower((int)string[i]);
97 /* Parse userfqdn string which is in user@fqdn format. */
99 int silc_parse_userfqdn(const char *string,
100 char *user, SilcUInt32 user_size,
101 char *fqdn, SilcUInt32 fqdn_size)
105 if (!user && !fqdn) {
106 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
110 memset(user, 0, user_size);
111 memset(fqdn, 0, fqdn_size);
114 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
118 if (string[0] == '@') {
120 silc_strncat(user, user_size, string, strlen(string));
125 if (strchr(string, '@')) {
126 tlen = strcspn(string, "@");
129 silc_strncat(user, user_size, string, tlen);
132 silc_strncat(fqdn, fqdn_size, string + tlen + 1,
133 strlen(string) - tlen - 1);
139 silc_strncat(user, user_size, string, strlen(string));
144 /* Parses command line. At most `max_args' is taken. Rest of the line
145 will be allocated as the last argument if there are more than `max_args'
146 arguments in the line. Note that the command name is counted as one
147 argument and is saved. */
149 void silc_parse_command_line(unsigned char *buffer,
150 unsigned char ***parsed,
151 SilcUInt32 **parsed_lens,
152 SilcUInt32 **parsed_types,
153 SilcUInt32 *parsed_num,
158 const char *cp = (const char *)buffer;
161 *parsed = silc_calloc(1, sizeof(**parsed));
162 *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
164 /* Get the command first */
165 len = strcspn(cp, " ");
166 tmp = silc_calloc(strlen(cp) + 1, sizeof(*tmp));
169 silc_to_upper(cp, tmp, strlen(cp));
170 (*parsed)[0] = silc_calloc(len + 1, sizeof(char));
171 memcpy((*parsed)[0], tmp, len);
173 (*parsed_lens)[0] = len;
179 /* Parse arguments */
180 if (strchr(cp, ' ') || strlen(cp) != 0) {
181 for (i = 1; i < max_args; i++) {
183 if (i != max_args - 1)
184 len = strcspn(cp, " ");
187 while (len && cp[len - 1] == ' ')
192 *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
193 *parsed_lens = silc_realloc(*parsed_lens,
194 sizeof(**parsed_lens) * (argc + 1));
195 (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
196 memcpy((*parsed)[argc], cp, len);
197 (*parsed_lens)[argc] = len;
209 /* Save argument types. Protocol defines all argument types but
210 this implementation makes sure that they are always in correct
211 order hence this simple code. */
212 *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
213 for (i = 0; i < argc; i++)
214 (*parsed_types)[i] = i;
219 /* Formats arguments to a string and returns it after allocating memory
220 for it. It must be remembered to free it later. */
222 char *silc_format(char *fmt, ...)
227 memset(buf, 0, sizeof(buf));
229 silc_vsnprintf(buf, sizeof(buf) - 1, fmt, args);
232 return silc_strdup(buf);
235 /* Basic has function to hash strings. May be used with the SilcHashTable.
236 Note that this lowers the characters of the string (with tolower()) so
237 this is used usually with nicknames, channel and server names to provide
238 case insensitive keys. */
240 SilcUInt32 silc_hash_string(void *key, void *user_context)
242 char *s = (char *)key;
246 h = (h << 4) + tolower((int)*s);
247 if ((g = h & 0xf0000000)) {
257 /* Hash UTF-8 string */
259 SilcUInt32 silc_hash_utf8_string(void *key, void *user_context)
261 unsigned char *s = (unsigned char *)key;
266 if ((g = h & 0xf0000000)) {
276 /* Basic hash function to hash integers. May be used with the SilcHashTable. */
278 SilcUInt32 silc_hash_uint(void *key, void *user_context)
280 return SILC_PTR_TO_32(key);
283 /* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
285 SilcUInt32 silc_hash_ptr(void *key, void *user_context)
287 return SILC_PTR_TO_32(key);
290 /* Hash a ID. The `user_context' is the ID type. */
292 SilcUInt32 silc_hash_id(void *key, void *user_context)
294 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
301 SilcClientID *id = (SilcClientID *)key;
303 /* The client ID is hashed by hashing the hash of the ID
304 (which is a truncated MD5 hash of the nickname) so that we
305 can access the entry from the cache with both Client ID but
306 with just a hash from the ID as well. */
307 return silc_hash_client_id_hash(id->hash, NULL);
312 SilcServerID *id = (SilcServerID *)key;
314 h = id->port * id->rnd;
315 for (i = 0; i < id->ip.data_len; i++)
321 case SILC_ID_CHANNEL:
323 SilcChannelID *id = (SilcChannelID *)key;
325 h = id->port * id->rnd;
326 for (i = 0; i < id->ip.data_len; i++)
339 /* Hash Client ID's hash. */
341 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
344 unsigned char *hash = key;
347 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
348 h = (h << 4) + hash[i];
349 if ((g = h & 0xf0000000)) {
358 /* Hash binary data. The `user_context' is the data length. */
360 SilcUInt32 silc_hash_data(void *key, void *user_context)
362 SilcUInt32 len = SILC_PTR_TO_32(user_context), h = 0;
363 unsigned char *data = (unsigned char *)key;
366 h = (data[0] * data[len - 1] + 1) * len;
367 for (i = 0; i < len; i++)
373 /* Compares two strings. It may be used as SilcHashTable comparison
376 SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context)
378 return !strcasecmp((char *)key1, (char *)key2);
381 /* Compares two ID's. May be used as SilcHashTable comparison function.
382 The Client ID's compares only the hash of the Client ID not any other
383 part of the Client ID. Other ID's are fully compared. */
385 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
387 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
388 return (id_type == SILC_ID_CLIENT ?
389 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
390 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
393 /* Compares two ID's. Compares full IDs. */
395 SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
397 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
398 return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
401 /* Compare two Client ID's entirely and not just the hash from the ID. */
403 SilcBool silc_hash_client_id_compare(void *key1, void *key2,
406 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
409 /* Compares binary data. May be used as SilcHashTable comparison function. */
411 SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context)
413 SilcUInt32 len = SILC_PTR_TO_32(user_context);
414 return !memcmp(key1, key2, len);
417 /* Compares UTF-8 string. */
419 SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
421 int l1 = strlen((char *)key1);
422 int l2 = strlen((char *)key2);
425 return !memcmp(key1, key2, l2);
428 /* Creates fingerprint from data, usually used with SHA1 digests */
430 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
432 char fingerprint[64], *cp;
435 memset(fingerprint, 0, sizeof(fingerprint));
437 for (i = 0; i < data_len; i++) {
438 silc_snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
441 if ((i + 1) % 2 == 0)
442 silc_snprintf(cp++, sizeof(fingerprint), " ");
444 if ((i + 1) % 10 == 0)
445 silc_snprintf(cp++, sizeof(fingerprint), " ");
448 if ((i + 1) % 2 == 0)
450 if ((i + 1) % 10 == 0)
453 return silc_strdup(fingerprint);
456 /* Return TRUE if the `data' is ASCII string. */
458 SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
462 for (i = 0; i < data_len; i++) {
463 if (!isascii(data[i]))
470 /* Displays input prompt on command line and takes input data from user */
472 char *silc_get_input(const char *prompt, SilcBool echo_off)
480 #ifdef HAVE_TERMIOS_H
482 struct termios to_old;
484 fd = open("/dev/tty", O_RDONLY);
486 silc_set_errno_posix(errno);
490 signal(SIGINT, SIG_IGN);
492 /* Get terminal info */
496 /* Echo OFF, and assure we can prompt and get input */
497 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
498 to.c_lflag |= ICANON;
500 tcsetattr(fd, TCSANOW, &to);
502 memset(input, 0, sizeof(input));
504 printf("%s", prompt);
507 if ((read(fd, input, sizeof(input))) < 0) {
508 silc_set_errno_posix(errno);
509 tcsetattr(fd, TCSANOW, &to_old);
513 if (strlen(input) <= 1) {
514 tcsetattr(fd, TCSANOW, &to_old);
515 silc_set_errno(SILC_ERR_EOF);
519 if (strchr(input, '\n'))
520 *strchr(input, '\n') = '\0';
522 /* Restore old terminfo */
523 tcsetattr(fd, TCSANOW, &to_old);
524 signal(SIGINT, SIG_DFL);
526 ret = silc_memdup(input, strlen(input));
527 memset(input, 0, sizeof(input));
528 #endif /* HAVE_TERMIOS_H */
531 fd = open("/dev/tty", O_RDONLY);
533 silc_set_errno_posix(errno);
537 memset(input, 0, sizeof(input));
539 printf("%s", prompt);
542 if ((read(fd, input, sizeof(input))) < 0) {
543 silc_set_errno_posix(errno);
547 if (strlen(input) <= 1) {
548 silc_set_errno(SILC_ERR_EOF);
552 if (strchr(input, '\n'))
553 *strchr(input, '\n') = '\0';
555 return silc_strdup(input);
559 #endif /* SILC_UNIX */
564 void silc_hexdump(const unsigned char *data, SilcUInt32 data_len,
577 if ((len - pos) < 16 && (len - pos <= len - off))
587 fprintf(output, "%08X ", k++ * 16);
589 for (i = 0; i < count; i++) {
590 fprintf(output, "%02X ", data[pos + i]);
592 if ((i + 1) % 4 == 0)
593 fprintf(output, " ");
596 if (count && count < 16) {
599 for (j = 0; j < 16 - count; j++) {
600 fprintf(output, " ");
602 if ((j + count + 1) % 4 == 0)
603 fprintf(output, " ");
607 for (i = 0; i < count; i++) {
610 if (data[pos] < 32 || data[pos] >= 127)
615 fprintf(output, "%c", ch);
620 fprintf(output, "\n");
627 /* Convert hex string to data. Each hex number must have two characters. */
629 SilcBool silc_hex2data(const char *hex, unsigned char *data,
630 SilcUInt32 data_size, SilcUInt32 *ret_data_len)
632 char *cp = (char *)hex;
636 if (data_size < strlen(hex) / 2) {
637 silc_set_errno(SILC_ERR_OVERFLOW);
641 for (i = 0; i < strlen(hex) / 2; i++) {
645 h -= h < 'A' ? '0' : 'A' - 10;
646 l -= l < 'A' ? '0' : 'A' - 10;
648 data[i] = (h << 4) | (l & 0xf);
654 SILC_LOG_HEXDUMP(("len %d", i), data, i);
659 /* Converts binary data to HEX string */
661 SilcBool silc_data2hex(const unsigned char *data, SilcUInt32 data_len,
662 char *hex, SilcUInt32 hex_size)
668 if (hex_size - 1 < data_len * 2) {
669 silc_set_errno(SILC_ERR_OVERFLOW);
673 memset(hex, 0, hex_size);
675 for (i = 0; i < data_len; i++) {
680 *cp++ = h + (h > 9 ? 'A' - 10 : '0');
681 *cp++ = l + (l > 9 ? 'A' - 10 : '0');
684 SILC_LOG_DEBUG(("HEX string: '%s'", hex));