Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2008 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
* These are general utility functions that doesn't belong to any specific
* group of routines.
*/
-/* $Id$ */
-#include "silc.h"
+#include "silcruntime.h"
/* Gets line from a buffer. Stops reading when a newline or EOF occurs.
This doesn't remove the newline sign from the destination buffer. The
i = 0;
for ( ; start <= srclen; i++, start++) {
- if (i > destlen)
+ if (i > destlen) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
return -1;
+ }
dest[i] = src[start];
- if (dest[i] == EOF)
+ if (dest[i] == EOF) {
+ silc_set_errno(SILC_ERR_EOF);
return EOF;
+ }
if (dest[i] == '\n')
break;
return start;
}
-/* Checks line for illegal characters. Return -1 when illegal character
- were found. This is used to check for bad lines when reading data from
- for example a configuration file. */
-
-int silc_check_line(char *buf)
-{
- /* Illegal characters in line */
- if (strchr(buf, '#')) return -1;
- if (strchr(buf, '\'')) return -1;
- if (strchr(buf, '\\')) return -1;
- if (strchr(buf, '\r')) return -1;
- if (strchr(buf, '\a')) return -1;
- if (strchr(buf, '\b')) return -1;
- if (strchr(buf, '\f')) return -1;
-
- /* Empty line */
- if (buf[0] == '\n')
- return -1;
-
- return 0;
-}
-
/* Converts string to capital characters. */
SilcBool silc_to_upper(const char *string, char *dest, SilcUInt32 dest_size)
{
int i;
- if (strlen(string) > dest_size)
+ if (strlen(string) > dest_size) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
return FALSE;
+ }
for (i = 0; i < strlen(string); i++)
dest[i] = (char)toupper((int)string[i]);
{
int i;
- if (strlen(string) > dest_size)
+ if (strlen(string) > dest_size) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
return FALSE;
+ }
for (i = 0; i < strlen(string); i++)
dest[i] = (char)tolower((int)string[i]);
{
SilcUInt32 tlen;
- if (!user && !fqdn)
+ if (!user && !fqdn) {
+ silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
return 0;
+ }
- memset(user, 0, user_size);
- memset(fqdn, 0, fqdn_size);
+ if (user)
+ memset(user, 0, user_size);
+ if (fqdn)
+ memset(fqdn, 0, fqdn_size);
- if (!string)
+ if (!string) {
+ silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
return 0;
+ }
if (string[0] == '@') {
if (user)
{
int i, len = 0;
int argc = 0;
- const char *cp = buffer;
+ const char *cp = (const char *)buffer;
char *tmp;
*parsed = silc_calloc(1, sizeof(**parsed));
va_list args;
char buf[8192];
- memset(buf, 0, sizeof(buf));
va_start(args, fmt);
- silc_vsnprintf(buf, sizeof(buf) - 1, fmt, args);
+ silc_vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
- return strdup(buf);
-}
-
-/* Basic has function to hash strings. May be used with the SilcHashTable.
- Note that this lowers the characters of the string (with tolower()) so
- this is used usually with nicknames, channel and server names to provide
- case insensitive keys. */
-
-SilcUInt32 silc_hash_string(void *key, void *user_context)
-{
- char *s = (char *)key;
- SilcUInt32 h = 0, g;
-
- while (*s != '\0') {
- h = (h << 4) + tolower((int)*s);
- if ((g = h & 0xf0000000)) {
- h = h ^ (g >> 24);
- h = h ^ g;
- }
- s++;
- }
-
- return h;
-}
-
-/* Hash UTF-8 string */
-
-SilcUInt32 silc_hash_utf8_string(void *key, void *user_context)
-{
- unsigned char *s = (unsigned char *)key;
- SilcUInt32 h = 0, g;
-
- while (*s != '\0') {
- h = (h << 4) + *s;
- if ((g = h & 0xf0000000)) {
- h = h ^ (g >> 24);
- h = h ^ g;
- }
- s++;
- }
-
- return h;
-}
-
-/* Basic hash function to hash integers. May be used with the SilcHashTable. */
-
-SilcUInt32 silc_hash_uint(void *key, void *user_context)
-{
- return SILC_PTR_TO_32(key);
-}
-
-/* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
-
-SilcUInt32 silc_hash_ptr(void *key, void *user_context)
-{
- return SILC_PTR_TO_32(key);
+ return silc_strdup(buf);
}
-/* Hash a ID. The `user_context' is the ID type. */
+/* Creates fingerprint from data, usually used with SHA1 digests */
-SilcUInt32 silc_hash_id(void *key, void *user_context)
+char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
{
- SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
- SilcUInt32 h = 0;
- int i;
-
- switch (id_type) {
- case SILC_ID_CLIENT:
- {
- SilcClientID *id = (SilcClientID *)key;
-
- /* The client ID is hashed by hashing the hash of the ID
- (which is a truncated MD5 hash of the nickname) so that we
- can access the entry from the cache with both Client ID but
- with just a hash from the ID as well. */
- return silc_hash_client_id_hash(id->hash, NULL);
- }
- break;
- case SILC_ID_SERVER:
- {
- SilcServerID *id = (SilcServerID *)key;
+ unsigned char *fingerprint, *cp;
+ unsigned int len, blocks, i;
- h = id->port * id->rnd;
- for (i = 0; i < id->ip.data_len; i++)
- h ^= id->ip.data[i];
-
- return h;
- }
- break;
- case SILC_ID_CHANNEL:
- {
- SilcChannelID *id = (SilcChannelID *)key;
-
- h = id->port * id->rnd;
- for (i = 0; i < id->ip.data_len; i++)
- h ^= id->ip.data[i];
-
- return h;
- }
- break;
- default:
- break;
+ if (!data || !data_len) {
+ silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
+ return NULL;
}
- return h;
-}
-
-/* Hash Client ID's hash. */
-
-SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
-{
- int i;
- unsigned char *hash = key;
- SilcUInt32 h = 0, g;
-
- for (i = 0; i < CLIENTID_HASH_LEN; i++) {
- h = (h << 4) + hash[i];
- if ((g = h & 0xf0000000)) {
- h = h ^ (g >> 24);
- h = h ^ g;
- }
- }
-
- return h;
-}
-
-/* Hash binary data. The `user_context' is the data length. */
-
-SilcUInt32 silc_hash_data(void *key, void *user_context)
-{
- SilcUInt32 len = SILC_PTR_TO_32(user_context), h = 0;
- unsigned char *data = (unsigned char *)key;
- int i;
-
- h = (data[0] * data[len - 1] + 1) * len;
- for (i = 0; i < len; i++)
- h ^= data[i];
-
- return h;
-}
-
-/* Compares two strings. It may be used as SilcHashTable comparison
- function. */
-
-SilcBool silc_hash_string_compare(void *key1, void *key2, void *user_context)
-{
- return !strcasecmp((char *)key1, (char *)key2);
-}
-
-/* Compares two ID's. May be used as SilcHashTable comparison function.
- The Client ID's compares only the hash of the Client ID not any other
- part of the Client ID. Other ID's are fully compared. */
-
-SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
-{
- SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
- return (id_type == SILC_ID_CLIENT ?
- SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
- SILC_ID_COMPARE_TYPE(key1, key2, id_type));
-}
-
-/* Compares two ID's. Compares full IDs. */
-
-SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
-{
- SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
- return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
-}
-
-/* Compare two Client ID's entirely and not just the hash from the ID. */
-
-SilcBool silc_hash_client_id_compare(void *key1, void *key2,
- void *user_context)
-{
- return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
-}
+ if (data_len >= 256)
+ data_len = 255;
-/* Compares binary data. May be used as SilcHashTable comparison function. */
+ /* Align and calculate total length */
+ len = ((data_len + 19) / 20) * 20;
+ blocks = (len / 10);
+ len = (len * 2) + ((blocks - 1) * 2) + (4 * blocks) + 2 + 1;
-SilcBool silc_hash_data_compare(void *key1, void *key2, void *user_context)
-{
- SilcUInt32 len = SILC_PTR_TO_32(user_context);
- return !memcmp(key1, key2, len);
-}
+ cp = fingerprint = silc_calloc(len, sizeof(*fingerprint));
+ if (!cp)
+ return NULL;
-/* Compares UTF-8 string. */
-
-SilcBool silc_hash_utf8_compare(void *key1, void *key2, void *user_context)
-{
- int l1 = strlen((char *)key1);
- int l2 = strlen((char *)key2);
- if (l1 != l2)
- return FALSE;
- return !memcmp(key1, key2, l2);
-}
-
-/* Creates fingerprint from data, usually used with SHA1 digests */
-
-char *silc_fingerprint(const unsigned char *data, SilcUInt32 data_len)
-{
- char fingerprint[64], *cp;
- int i;
-
- memset(fingerprint, 0, sizeof(fingerprint));
- cp = fingerprint;
for (i = 0; i < data_len; i++) {
- silc_snprintf(cp, sizeof(fingerprint), "%02X", data[i]);
+ silc_snprintf((char *)cp, len, "%02X", data[i]);
cp += 2;
+ len -= 2;
if ((i + 1) % 2 == 0)
- silc_snprintf(cp++, sizeof(fingerprint), " ");
-
+ silc_snprintf((char *)cp++, len--, " ");
if ((i + 1) % 10 == 0)
- silc_snprintf(cp++, sizeof(fingerprint), " ");
+ silc_snprintf((char *)cp++, len--, " ");
}
i--;
- if ((i + 1) % 2 == 0)
- cp[-2] = 0;
if ((i + 1) % 10 == 0)
- cp[-1] = 0;
+ *(--cp) = '\0';
+ if ((i + 1) % 2 == 0)
+ *(--cp) = '\0';
- return strdup(fingerprint);
+ return (char *)fingerprint;
}
/* Return TRUE if the `data' is ASCII string. */
fd = open("/dev/tty", O_RDONLY);
if (fd < 0) {
- fprintf(stderr, "silc: %s\n", strerror(errno));
+ silc_set_errno_posix(errno);
return NULL;
}
fflush(stdout);
if ((read(fd, input, sizeof(input))) < 0) {
- fprintf(stderr, "silc: %s\n", strerror(errno));
+ silc_set_errno_posix(errno);
tcsetattr(fd, TCSANOW, &to_old);
return NULL;
}
if (strlen(input) <= 1) {
tcsetattr(fd, TCSANOW, &to_old);
+ silc_set_errno(SILC_ERR_EOF);
return NULL;
}
} else {
fd = open("/dev/tty", O_RDONLY);
if (fd < 0) {
- fprintf(stderr, "silc: %s\n", strerror(errno));
+ silc_set_errno_posix(errno);
return NULL;
}
fflush(stdout);
if ((read(fd, input, sizeof(input))) < 0) {
- fprintf(stderr, "silc: %s\n", strerror(errno));
+ silc_set_errno_posix(errno);
return NULL;
}
- if (strlen(input) <= 1)
+ if (strlen(input) <= 1) {
+ silc_set_errno(SILC_ERR_EOF);
return NULL;
+ }
if (strchr(input, '\n'))
*strchr(input, '\n') = '\0';
- return strdup(input);
+ return silc_strdup(input);
}
#else
return NULL;
break;
}
}
+
+/* Convert hex string to data. Each hex number must have two characters. */
+
+SilcBool silc_hex2data(const char *hex, unsigned char *data,
+ SilcUInt32 data_size, SilcUInt32 *ret_data_len)
+{
+ char *cp = (char *)hex;
+ unsigned char l, h;
+ int i;
+
+ if (data_size < strlen(hex) / 2) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return FALSE;
+ }
+
+ for (i = 0; i < strlen(hex) / 2; i++) {
+ h = *cp++;
+ l = *cp++;
+
+ h -= h < 'A' ? '0' : 'A' - 10;
+ l -= l < 'A' ? '0' : 'A' - 10;
+
+ data[i] = (h << 4) | (l & 0xf);
+ }
+
+ if (ret_data_len)
+ *ret_data_len = i;
+
+ return TRUE;
+}
+
+/* Converts binary data to HEX string */
+
+SilcBool silc_data2hex(const unsigned char *data, SilcUInt32 data_len,
+ char *hex, SilcUInt32 hex_size)
+{
+ unsigned char l, h;
+ char *cp = hex;
+ int i;
+
+ if (hex_size - 1 < data_len * 2) {
+ silc_set_errno(SILC_ERR_OVERFLOW);
+ return FALSE;
+ }
+
+ memset(hex, 0, hex_size);
+
+ for (i = 0; i < data_len; i++) {
+ l = data[i];
+ h = l >> 4;
+ l &= 0xf;
+
+ *cp++ = h + (h > 9 ? 'A' - 10 : '0');
+ *cp++ = l + (l > 9 ? 'A' - 10 : '0');
+ }
+
+ return TRUE;
+}