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 char fingerprint[64], *cp;
338 memset(fingerprint, 0, sizeof(fingerprint));
340 for (i = 0; i < data_len; i++) {
341 silc_snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
344 if ((i + 1) % 2 == 0)
345 silc_snprintf(cp++, sizeof(fingerprint), " ");
347 if ((i + 1) % 10 == 0)
348 silc_snprintf(cp++, sizeof(fingerprint), " ");
351 if ((i + 1) % 2 == 0)
353 if ((i + 1) % 10 == 0)
356 return silc_strdup(fingerprint);
359 /* Return TRUE if the `data' is ASCII string. */
361 SilcBool silc_string_is_ascii(const unsigned char *data, SilcUInt32 data_len)
365 for (i = 0; i < data_len; i++) {
366 if (!isascii(data[i]))
373 /* Displays input prompt on command line and takes input data from user */
375 char *silc_get_input(const char *prompt, SilcBool echo_off)
383 #ifdef HAVE_TERMIOS_H
385 struct termios to_old;
387 fd = open("/dev/tty", O_RDONLY);
389 silc_set_errno_posix(errno);
393 signal(SIGINT, SIG_IGN);
395 /* Get terminal info */
399 /* Echo OFF, and assure we can prompt and get input */
400 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
401 to.c_lflag |= ICANON;
403 tcsetattr(fd, TCSANOW, &to);
405 memset(input, 0, sizeof(input));
407 printf("%s", prompt);
410 if ((read(fd, input, sizeof(input))) < 0) {
411 silc_set_errno_posix(errno);
412 tcsetattr(fd, TCSANOW, &to_old);
416 if (strlen(input) <= 1) {
417 tcsetattr(fd, TCSANOW, &to_old);
418 silc_set_errno(SILC_ERR_EOF);
422 if (strchr(input, '\n'))
423 *strchr(input, '\n') = '\0';
425 /* Restore old terminfo */
426 tcsetattr(fd, TCSANOW, &to_old);
427 signal(SIGINT, SIG_DFL);
429 ret = silc_memdup(input, strlen(input));
430 memset(input, 0, sizeof(input));
431 #endif /* HAVE_TERMIOS_H */
434 fd = open("/dev/tty", O_RDONLY);
436 silc_set_errno_posix(errno);
440 memset(input, 0, sizeof(input));
442 printf("%s", prompt);
445 if ((read(fd, input, sizeof(input))) < 0) {
446 silc_set_errno_posix(errno);
450 if (strlen(input) <= 1) {
451 silc_set_errno(SILC_ERR_EOF);
455 if (strchr(input, '\n'))
456 *strchr(input, '\n') = '\0';
458 return silc_strdup(input);
462 #endif /* SILC_UNIX */
467 void silc_hexdump(const unsigned char *data, SilcUInt32 data_len,
480 if ((len - pos) < 16 && (len - pos <= len - off))
490 fprintf(output, "%08X ", k++ * 16);
492 for (i = 0; i < count; i++) {
493 fprintf(output, "%02X ", data[pos + i]);
495 if ((i + 1) % 4 == 0)
496 fprintf(output, " ");
499 if (count && count < 16) {
502 for (j = 0; j < 16 - count; j++) {
503 fprintf(output, " ");
505 if ((j + count + 1) % 4 == 0)
506 fprintf(output, " ");
510 for (i = 0; i < count; i++) {
513 if (data[pos] < 32 || data[pos] >= 127)
518 fprintf(output, "%c", ch);
523 fprintf(output, "\n");
530 /* Convert hex string to data. Each hex number must have two characters. */
532 SilcBool silc_hex2data(const char *hex, unsigned char *data,
533 SilcUInt32 data_size, SilcUInt32 *ret_data_len)
535 char *cp = (char *)hex;
539 if (data_size < strlen(hex) / 2) {
540 silc_set_errno(SILC_ERR_OVERFLOW);
544 for (i = 0; i < strlen(hex) / 2; i++) {
548 h -= h < 'A' ? '0' : 'A' - 10;
549 l -= l < 'A' ? '0' : 'A' - 10;
551 data[i] = (h << 4) | (l & 0xf);
557 SILC_LOG_HEXDUMP(("len %d", i), data, i);
562 /* Converts binary data to HEX string */
564 SilcBool silc_data2hex(const unsigned char *data, SilcUInt32 data_len,
565 char *hex, SilcUInt32 hex_size)
571 if (hex_size - 1 < data_len * 2) {
572 silc_set_errno(SILC_ERR_OVERFLOW);
576 memset(hex, 0, hex_size);
578 for (i = 0; i < data_len; i++) {
583 *cp++ = h + (h > 9 ? 'A' - 10 : '0');
584 *cp++ = l + (l > 9 ? 'A' - 10 : '0');
587 SILC_LOG_DEBUG(("HEX string: '%s'", hex));