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 /* Hash a ID. The `user_context' is the ID type. */
237 SilcUInt32 silc_hash_id(void *key, void *user_context)
239 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
246 SilcClientID *id = (SilcClientID *)key;
248 /* The client ID is hashed by hashing the hash of the ID
249 (which is a truncated MD5 hash of the nickname) so that we
250 can access the entry from the cache with both Client ID but
251 with just a hash from the ID as well. */
252 return silc_hash_client_id_hash(id->hash, NULL);
257 SilcServerID *id = (SilcServerID *)key;
259 h = id->port * id->rnd;
260 for (i = 0; i < id->ip.data_len; i++)
266 case SILC_ID_CHANNEL:
268 SilcChannelID *id = (SilcChannelID *)key;
270 h = id->port * id->rnd;
271 for (i = 0; i < id->ip.data_len; i++)
284 /* Hash Client ID's hash. */
286 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
289 unsigned char *hash = key;
292 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
293 h = (h << 4) + hash[i];
294 if ((g = h & 0xf0000000)) {
303 /* Compares two ID's. May be used as SilcHashTable comparison function.
304 The Client ID's compares only the hash of the Client ID not any other
305 part of the Client ID. Other ID's are fully compared. */
307 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
309 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
310 return (id_type == SILC_ID_CLIENT ?
311 SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
312 SILC_ID_COMPARE_TYPE(key1, key2, id_type));
315 /* Compares two ID's. Compares full IDs. */
317 SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
319 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
320 return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
323 /* Compare two Client ID's entirely and not just the hash from the ID. */
325 SilcBool silc_hash_client_id_compare(void *key1, void *key2,
328 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
331 /* Creates fingerprint from data, usually used with SHA1 digests */
333 char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
335 unsigned char *fingerprint, *cp;
336 unsigned int len, blocks, i;
338 if (!data || !data_len) {
339 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
346 /* Align and calculate total length */
347 len = ((data_len + 19) / 20) * 20;
349 len = (len * 2) + ((blocks - 1) * 2) + (4 * blocks) + 2 + 1;
351 cp = fingerprint = silc_calloc(len, sizeof(*fingerprint));
355 for (i = 0; i < data_len; i++) {
356 silc_snprintf(cp, len, "%02X", data[i]);
360 if ((i + 1) % 2 == 0)
361 silc_snprintf(cp++, len--, " ");
362 if ((i + 1) % 10 == 0)
363 silc_snprintf(cp++, len--, " ");
366 if ((i + 1) % 10 == 0)
368 if ((i + 1) % 2 == 0)
374 /* Return TRUE if the `data' is ASCII string. */
376 SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
380 for (i = 0; i < data_len; i++) {
381 if (!isascii(data[i]))
388 /* Displays input prompt on command line and takes input data from user */
390 char *silc_get_input(const char *prompt, SilcBool echo_off)
398 #ifdef HAVE_TERMIOS_H
400 struct termios to_old;
402 fd = open("/dev/tty", O_RDONLY);
404 silc_set_errno_posix(errno);
408 signal(SIGINT, SIG_IGN);
410 /* Get terminal info */
414 /* Echo OFF, and assure we can prompt and get input */
415 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
416 to.c_lflag |= ICANON;
418 tcsetattr(fd, TCSANOW, &to);
420 memset(input, 0, sizeof(input));
422 printf("%s", prompt);
425 if ((read(fd, input, sizeof(input))) < 0) {
426 silc_set_errno_posix(errno);
427 tcsetattr(fd, TCSANOW, &to_old);
431 if (strlen(input) <= 1) {
432 tcsetattr(fd, TCSANOW, &to_old);
433 silc_set_errno(SILC_ERR_EOF);
437 if (strchr(input, '\n'))
438 *strchr(input, '\n') = '\0';
440 /* Restore old terminfo */
441 tcsetattr(fd, TCSANOW, &to_old);
442 signal(SIGINT, SIG_DFL);
444 ret = silc_memdup(input, strlen(input));
445 memset(input, 0, sizeof(input));
446 #endif /* HAVE_TERMIOS_H */
449 fd = open("/dev/tty", O_RDONLY);
451 silc_set_errno_posix(errno);
455 memset(input, 0, sizeof(input));
457 printf("%s", prompt);
460 if ((read(fd, input, sizeof(input))) < 0) {
461 silc_set_errno_posix(errno);
465 if (strlen(input) <= 1) {
466 silc_set_errno(SILC_ERR_EOF);
470 if (strchr(input, '\n'))
471 *strchr(input, '\n') = '\0';
473 return silc_strdup(input);
477 #endif /* SILC_UNIX */
482 void silc_hexdump(const unsigned char *data, SilcUInt32 data_len,
495 if ((len - pos) < 16 && (len - pos <= len - off))
505 fprintf(output, "%08X ", k++ * 16);
507 for (i = 0; i < count; i++) {
508 fprintf(output, "%02X ", data[pos + i]);
510 if ((i + 1) % 4 == 0)
511 fprintf(output, " ");
514 if (count && count < 16) {
517 for (j = 0; j < 16 - count; j++) {
518 fprintf(output, " ");
520 if ((j + count + 1) % 4 == 0)
521 fprintf(output, " ");
525 for (i = 0; i < count; i++) {
528 if (data[pos] < 32 || data[pos] >= 127)
533 fprintf(output, "%c", ch);
538 fprintf(output, "\n");
545 /* Convert hex string to data. Each hex number must have two characters. */
547 SilcBool silc_hex2data(const char *hex, unsigned char *data,
548 SilcUInt32 data_size, SilcUInt32 *ret_data_len)
550 char *cp = (char *)hex;
554 if (data_size < strlen(hex) / 2) {
555 silc_set_errno(SILC_ERR_OVERFLOW);
559 for (i = 0; i < strlen(hex) / 2; i++) {
563 h -= h < 'A' ? '0' : 'A' - 10;
564 l -= l < 'A' ? '0' : 'A' - 10;
566 data[i] = (h << 4) | (l & 0xf);
572 SILC_LOG_HEXDUMP(("len %d", i), data, i);
577 /* Converts binary data to HEX string */
579 SilcBool silc_data2hex(const unsigned char *data, SilcUInt32 data_len,
580 char *hex, SilcUInt32 hex_size)
586 if (hex_size - 1 < data_len * 2) {
587 silc_set_errno(SILC_ERR_OVERFLOW);
591 memset(hex, 0, hex_size);
593 for (i = 0; i < data_len; i++) {
598 *cp++ = h + (h > 9 ? 'A' - 10 : '0');
599 *cp++ = l + (l > 9 ? 'A' - 10 : '0');
602 SILC_LOG_DEBUG(("HEX string: '%s'", hex));