silcprotocol.c \
silcvcard.c \
silcapputil.c \
+ silcmime.c \
silcutf8.c \
silcstringprep.c
silcstrutil.h \
silcvcard.h \
silcapputil.h \
+ silcmime.h \
silcutf8.h \
silcstringprep.h \
silctypes.h
--- /dev/null
+/*
+
+ silcmime.c
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2005 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+#include "silcmime.h"
+
+struct SilcMimeStruct {
+ SilcHashTable fields;
+ unsigned char *data;
+ SilcUInt32 data_len;
+ SilcDList multiparts;
+ char *boundary;
+};
+
+struct SilcMimeAssemblerStruct {
+ SilcMimeComplete complete;
+ void *complete_context;
+ SilcHashTable fragments;
+};
+
+static void silc_mime_field_dest(void *key, void *context, void *user_context)
+{
+ silc_free(key);
+ silc_free(context);
+}
+
+SilcMime silc_mime_alloc(void)
+{
+ SilcMime mime;
+
+ mime = silc_calloc(1, sizeof(*mime));
+ if (!mime)
+ return NULL;
+
+ mime->fields = silc_hash_table_alloc(0, silc_hash_string, mime,
+ silc_hash_string_compare, mime,
+ silc_mime_field_dest, mime, TRUE);
+ if (!mime->fields) {
+ silc_mime_free(mime);
+ return NULL;
+ }
+
+ return mime;
+}
+
+void silc_mime_free(SilcMime mime)
+{
+ SilcMime m;
+
+ if (mime->fields)
+ silc_hash_table_free(mime->fields);
+
+ if (mime->multiparts) {
+ silc_dlist_start(mime->multiparts);
+ while ((m = silc_dlist_get(mime->multiparts)) != SILC_LIST_END)
+ silc_mime_free(m);
+ silc_dlist_uninit(mime->multiparts);
+ }
+ silc_free(mime->boundary);
+ silc_free(mime);
+}
+
+static void silc_mime_assembler_dest(void *key, void *context,
+ void *user_context)
+{
+ silc_free(key);
+ silc_hash_table_free(context);
+}
+
+SilcMimeAssembler silc_mime_assembler_alloc(SilcMimeComplete complete,
+ void *complete_context)
+{
+ SilcMimeAssembler assembler;
+
+ assembler = silc_calloc(1, sizeof(*assembler));
+ if (!assembler)
+ return NULL;
+
+ assembler->complete = complete;
+ assembler->complete_context = complete_context;
+ assembler->fragments =
+ silc_hash_table_alloc(0, silc_hash_string, NULL,
+ silc_hash_string_compare, NULL,
+ silc_mime_assembler_dest, assembler, TRUE);
+ if (!assembler->fragments) {
+ silc_mime_assembler_free(assembler);
+ return NULL;
+ }
+
+ return assembler;
+}
+
+void silc_mime_assembler_free(SilcMimeAssembler assembler)
+{
+ silc_hash_table_free(assembler->fragments);
+ silc_free(assembler);
+}
+
+SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len)
+{
+ SilcMime mime;
+ int i, k;
+ char *tmp, *field, *value, *line;
+
+ SILC_LOG_DEBUG(("Parsing MIME message"));
+
+ if (!data)
+ return NULL;
+
+ mime = silc_mime_alloc();
+ if (!mime)
+ return NULL;
+
+ /* Parse the fields */
+ line = tmp = (char *)data;
+ for (i = 0; i < data_len; i++) {
+ /* Get field line */
+ if (data_len - i >= 2 && tmp[i] == '\r' && tmp[i + 1] == '\n') {
+ /* Get field */
+ field = strchr(line, ':');
+ if (!field)
+ goto err;
+ field = silc_memdup(line, field - line);
+ if (!field)
+ goto err;
+
+ /* Get value. Remove whitespaces too. */
+ value = strchr(line, ':');
+ if ((tmp + i) - value < 2)
+ goto err;
+ value++;
+ for (k = 0; k < (tmp + i) - value; k++) {
+ if (value[k] == '\r')
+ goto err;
+ if (value[k] != ' ' && value[k] != '\t')
+ break;
+ }
+ value += k;
+ if ((tmp + i) - value < 1)
+ goto err;
+ value = silc_memdup(value, (tmp + i) - value);
+ if (!value)
+ goto err;
+
+ SILC_LOG_DEBUG(("Header '%s' '%s'", field, value));
+
+ /* Add field and value */
+ silc_mime_add_field(mime, field, value);
+ silc_free(field);
+ silc_free(value);
+
+ /* Mark start of next line */
+ line = (tmp + i) + 2;
+ i += 2;
+
+ /* Break if this is last header */
+ if (data_len - i >= 2 &&
+ tmp[i] == '\r' && tmp[i + 1] == '\n') {
+ i += 2;
+ break;
+ }
+ }
+ }
+
+ /* Parse multiparts if present */
+ field = (char *)silc_mime_get_field(mime, "Content-Type");
+ if (field && strstr(field, "multipart")) {
+ char b[1024];
+ SilcMime p;
+
+ mime->multiparts = silc_dlist_init();
+ if (!mime->multiparts)
+ goto err;
+
+ /* Get boundary */
+ value = strrchr(field, '=');
+ if (value && strlen(value) > 1) {
+ value++;
+
+ SILC_LOG_DEBUG(("Boundary '%s'", value));
+
+ memset(b, 0, sizeof(b));
+ line = strdup(value);
+ if (strrchr(line, '"')) {
+ *strrchr(line, '"') = '\0';
+ snprintf(b, sizeof(b) - 1, "--%s", line + 1);
+ mime->boundary = strdup(line + 1);
+ } else {
+ snprintf(b, sizeof(b) - 1, "--%s", line);
+ mime->boundary = strdup(line);
+ }
+ silc_free(line);
+
+ for (i = i; i < data_len; i++) {
+ /* Get boundary data */
+ if (data_len - i >= strlen(b) &&
+ tmp[i] == '-' && tmp[i + 1] == '-') {
+ if (memcmp(tmp + i, b, strlen(b)))
+ continue;
+
+ i += strlen(b);
+
+ if (data_len - i >= 4 &&
+ tmp[i ] == '\r' && tmp[i + 1] == '\n' &&
+ tmp[i + 2] == '\r' && tmp[i + 3] == '\n')
+ i += 4;
+ else if (data_len - i >= 2 &&
+ tmp[i] == '\r' && tmp[i + 1] == '\n')
+ i += 2;
+ else if (data_len - i >= 2 &&
+ tmp[i] == '-' && tmp[i + 1] == '-')
+ break;
+
+ line = tmp + i;
+
+ /* Find end of boundary */
+ for (k = i; k < data_len; k++)
+ if (data_len - k >= strlen(b) &&
+ tmp[k] == '-' && tmp[k + 1] == '-')
+ if (!memcmp(tmp + k, b, strlen(b)))
+ break;
+ if (k >= data_len)
+ goto err;
+
+ /* Remove preceding CRLF */
+ k -= 2;
+
+ /* Parse the part */
+ p = silc_mime_decode(line, k - i);
+ if (!p)
+ goto err;
+
+ silc_dlist_add(mime->multiparts, p);
+ i += (k - i);
+ }
+ }
+ }
+ } else {
+ /* Get data area */
+ if (i >= data_len)
+ i = 0;
+ SILC_LOG_DEBUG(("Data len %d", data_len - i));
+ silc_mime_add_data(mime, tmp + i, data_len - i);
+ }
+
+ return mime;
+
+ err:
+ silc_mime_free(mime);
+ return NULL;
+}
+
+unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len)
+{
+ SilcMime part;
+ SilcHashTableList htl;
+ SilcBufferStruct buf;
+ SilcBuffer buffer;
+ char *field, *value, tmp[1024], tmp2[4];
+ unsigned char *ret;
+ int i;
+
+ SILC_LOG_DEBUG(("Encoding MIME message"));
+
+ if (!mime)
+ return NULL;
+
+ memset(&buf, 0, sizeof(buf));
+
+ /* Encode the headers. Order doesn't matter */
+ i = 0;
+ silc_hash_table_list(mime->fields, &htl);
+ while (silc_hash_table_get(&htl, (void **)&field, (void **)&value)) {
+ memset(tmp, 0, sizeof(tmp));
+ SILC_LOG_DEBUG(("Header %s: %s", field, value));
+ snprintf(tmp, sizeof(tmp) - 1, "%s: %s\r\n", field, value);
+ silc_buffer_strformat(&buf, tmp, SILC_STRFMT_END);
+ i++;
+ }
+ silc_hash_table_list_reset(&htl);
+ if (i)
+ silc_buffer_strformat(&buf, "\r\n", SILC_STRFMT_END);
+
+ /* Assemble the whole buffer */
+ buffer = silc_buffer_alloc_size(mime->data_len + buf.len);
+ if (!buffer)
+ return NULL;
+
+ /* Add headers */
+ if (buf.len) {
+ silc_buffer_put(buffer, buf.head, buf.len);
+ silc_buffer_pull(buffer, buf.len);
+ }
+
+ /* Add data */
+ if (mime->data) {
+ SILC_LOG_DEBUG(("Data len %d", mime->data_len));
+ silc_buffer_put(buffer, mime->data, mime->data_len);
+ }
+
+ /* Add multiparts */
+ if (mime->multiparts) {
+ SILC_LOG_DEBUG(("Encoding multiparts"));
+
+ silc_dlist_start(mime->multiparts);
+ i = 0;
+ while ((part = silc_dlist_get(mime->multiparts)) != SILC_LIST_END) {
+ unsigned char *pd;
+ SilcUInt32 pd_len;
+
+ /* Recursive encoding */
+ pd = silc_mime_encode(part, &pd_len);
+ if (!pd)
+ return NULL;
+
+ memset(tmp, 0, sizeof(tmp));
+ memset(tmp2, 0, sizeof(tmp2));
+ if (i == 0) {
+ /* If fields are not present, add extra CRLF */
+ if (!silc_hash_table_count(part->fields))
+ snprintf(tmp2, sizeof(tmp2) - 1, "\r\n");
+ snprintf(tmp, sizeof(tmp) - 1, "--%s\r\n%s", mime->boundary, tmp2);
+ i = 1;
+ } else {
+ /* If fields are not present, add extra CRLF */
+ if (!silc_hash_table_count(part->fields))
+ snprintf(tmp2, sizeof(tmp2) - 1, "\r\n");
+ snprintf(tmp, sizeof(tmp) - 1, "\r\n--%s\r\n%s", mime->boundary, tmp2);
+ }
+
+ buffer = silc_buffer_realloc(buffer, buffer->truelen + pd_len +
+ strlen(tmp));
+ if (!buffer)
+ return NULL;
+ silc_buffer_put_tail(buffer, tmp, strlen(tmp));
+ silc_buffer_pull_tail(buffer, strlen(tmp));
+ silc_buffer_put_tail(buffer, pd, pd_len);
+ silc_buffer_pull_tail(buffer, pd_len);
+ silc_free(pd);
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, "\r\n--%s--\r\n", mime->boundary);
+ buffer = silc_buffer_realloc(buffer, buffer->truelen + strlen(tmp));
+ if (!buffer)
+ return NULL;
+ silc_buffer_put_tail(buffer, tmp, strlen(tmp));
+ silc_buffer_pull_tail(buffer, strlen(tmp));
+ }
+
+ ret = silc_buffer_steal(buffer, encoded_len);
+ silc_buffer_free(buffer);
+
+ return ret;
+}
+
+static void silc_mime_assemble_dest(void *key, void *context,
+ void *user_context)
+{
+ silc_mime_free(context);
+}
+
+void silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial)
+{
+ char *type, *id = NULL, *tmp;
+ SilcHashTable f;
+ SilcMime p, complete;
+ int i, number, total = -1;
+ const unsigned char *data;
+ SilcUInt32 data_len;
+ SilcBuffer compbuf = NULL;
+
+ SILC_LOG_DEBUG(("Assembling MIME fragments"));
+
+ if (!assembler || !partial)
+ goto err;
+
+ type = (char *)silc_mime_get_field(partial, "Content-Type");
+ if (!type)
+ goto err;
+
+ /* Get ID */
+ tmp = strstr(type, "id=");
+ if (!tmp)
+ goto err;
+ if (strlen(tmp) <= 4)
+ goto err;
+ tmp += 3;
+ if (*tmp == '"')
+ tmp++;
+ id = strdup(tmp);
+ if (strchr(id, ';'))
+ *strchr(id, ';') = '\0';
+ if (strrchr(id, '"'))
+ *strrchr(id, '"') = '\0';
+
+ SILC_LOG_DEBUG(("Fragment ID %s", id));
+
+ /* Get fragment number */
+ tmp = strstr(type, "number=");
+ if (!tmp)
+ goto err;
+ tmp = strchr(tmp, '=');
+ if (strlen(tmp) < 2)
+ goto err;
+ tmp++;
+ if (strchr(tmp, ';')) {
+ tmp = strdup(tmp);
+ *strchr(tmp, ';') = '\0';
+ number = atoi(tmp);
+ silc_free(tmp);
+ } else {
+ number = atoi(tmp);
+ }
+
+ SILC_LOG_DEBUG(("Fragment number %d", number));
+
+ /* Find fragments with this ID. */
+ if (!silc_hash_table_find(assembler->fragments, (void *)id,
+ NULL, (void **)&f)) {
+ /* This is new fragment to new message. Add to hash table and return. */
+ f = silc_hash_table_alloc(0, silc_hash_uint, NULL, NULL, NULL,
+ silc_mime_assemble_dest, NULL, TRUE);
+ if (!f)
+ goto err;
+ silc_hash_table_add(f, SILC_32_TO_PTR(number), partial);
+ silc_hash_table_add(assembler->fragments, id, f);
+ return;
+ }
+
+ /* Try to get total number */
+ tmp = strstr(type, "total=");
+ if (tmp) {
+ tmp = strchr(tmp, '=');
+ if (strlen(tmp) < 2)
+ goto err;
+ tmp++;
+ if (strchr(tmp, ';')) {
+ tmp = strdup(tmp);
+ *strchr(tmp, ';') = '\0';
+ total = atoi(tmp);
+ silc_free(tmp);
+ } else {
+ total = atoi(tmp);
+ }
+
+ SILC_LOG_DEBUG(("Fragment total %d", total));
+ }
+
+ /* If more fragments to come, add to hash table */
+ if (number != total) {
+ silc_hash_table_add(f, SILC_32_TO_PTR(number), partial);
+ return;
+ }
+
+ silc_hash_table_add(f, SILC_32_TO_PTR(number), partial);
+
+ /* Verify that we really have all the fragments */
+ if (silc_hash_table_count(f) < total)
+ return;
+
+ /* Assemble the complete MIME message now. We get them in order from
+ the hash table. */
+ for (i = 1; i <= total; i++) {
+ if (!silc_hash_table_find(f, SILC_32_TO_PTR(i), NULL, (void **)&p))
+ goto err;
+
+ /* The fragment is in the data portion of the partial message */
+ data = silc_mime_get_data(p, &data_len);
+ if (!data)
+ goto err;
+
+ /* Assemble */
+ if (!compbuf) {
+ compbuf = silc_buffer_alloc_size(data_len);
+ if (!compbuf)
+ goto err;
+ silc_buffer_put(compbuf, data, data_len);
+ } else {
+ compbuf = silc_buffer_realloc(compbuf, compbuf->truelen + data_len);
+ if (!compbuf)
+ goto err;
+ silc_buffer_put_tail(compbuf, data, data_len);
+ silc_buffer_pull_tail(compbuf, data_len);
+ }
+ }
+
+ /* Now parse the complete MIME message and deliver it */
+ complete = silc_mime_decode((const unsigned char *)compbuf->head,
+ compbuf->truelen);
+ if (!complete)
+ goto err;
+
+ if (assembler->complete)
+ assembler->complete(complete, assembler->complete_context);
+
+ /* Delete the hash table entry. Destructors will free memory */
+ silc_hash_table_del(assembler->fragments, (void *)id);
+
+ silc_free(id);
+ silc_buffer_free(compbuf);
+ return;
+
+ err:
+ silc_free(id);
+ if (compbuf)
+ silc_buffer_free(compbuf);
+ silc_mime_free(partial);
+}
+
+SilcDList silc_mime_encode_partial(SilcMime mime, int max_size)
+{
+ unsigned char *buf, *tmp;
+ SilcUInt32 buf_len, len, tmp_len, off;
+ SilcDList list;
+ SilcBuffer buffer;
+ SilcMime partial;
+ char type[128], id[64];
+ int num;
+
+ SILC_LOG_DEBUG(("Fragmenting MIME message"));
+
+ /* Encode as normal */
+ buf = silc_mime_encode(mime, &buf_len);
+ if (!buf)
+ return NULL;
+
+ list = silc_dlist_init();
+
+ /* Fragment if it is too large */
+ if (buf_len > max_size) {
+ memset(id, 0, sizeof(id));
+ srand((time(NULL) + buf_len) ^ rand());
+ snprintf(id, sizeof(id) - 1, "%X%X%X",
+ (unsigned int)rand(), (unsigned int)time(NULL),
+ (unsigned int)buf_len);
+
+ SILC_LOG_DEBUG(("Fragment ID %s", id));
+
+ partial = silc_mime_alloc();
+ if (!partial)
+ return NULL;
+
+ silc_mime_add_field(partial, "MIME-Version", "1.0");
+ memset(type, 0, sizeof(type));
+ snprintf(type, sizeof(type) - 1,
+ "message/partial; id=\"%s\"; number=1", id);
+ silc_mime_add_field(partial, "Content-Type", type);
+ silc_mime_add_data(partial, buf, max_size);
+
+ tmp = silc_mime_encode(partial, &tmp_len);
+ if (!tmp)
+ return NULL;
+ silc_mime_free(partial);
+
+ /* Add to list */
+ buffer = silc_buffer_alloc_size(tmp_len);
+ if (!buffer)
+ return NULL;
+ silc_buffer_put(buffer, tmp, tmp_len);
+ silc_dlist_add(list, buffer);
+ silc_free(tmp);
+
+ len = buf_len - max_size;
+ off = max_size;
+ num = 2;
+ while (len > 0) {
+ partial = silc_mime_alloc();
+ if (!partial)
+ return NULL;
+
+ memset(type, 0, sizeof(type));
+ silc_mime_add_field(partial, "MIME-Version", "1.0");
+
+ if (len > max_size) {
+ snprintf(type, sizeof(type) - 1,
+ "message/partial; id=\"%s\"; number=%d",
+ id, num++);
+ silc_mime_add_data(partial, buf + off, max_size);
+ off += max_size;
+ len -= max_size;
+ } else {
+ snprintf(type, sizeof(type) - 1,
+ "message/partial; id=\"%s\"; number=%d; total=%d",
+ id, num, num);
+ silc_mime_add_data(partial, buf + off, len);
+ len = 0;
+ }
+
+ silc_mime_add_field(partial, "Content-Type", type);
+
+ tmp = silc_mime_encode(partial, &tmp_len);
+ if (!tmp)
+ return NULL;
+ silc_mime_free(partial);
+
+ /* Add to list */
+ buffer = silc_buffer_alloc_size(tmp_len);
+ if (!buffer)
+ return NULL;
+ silc_buffer_put(buffer, tmp, tmp_len);
+ silc_dlist_add(list, buffer);
+ silc_free(tmp);
+ }
+ } else {
+ /* No need to fragment */
+ buffer = silc_buffer_alloc_size(buf_len);
+ if (!buffer)
+ return NULL;
+ silc_buffer_put(buffer, buf, buf_len);
+ silc_dlist_add(list, buffer);
+ }
+
+ silc_free(buf);
+
+ return list;
+}
+
+void silc_mime_partial_free(SilcDList partials)
+{
+ SilcBuffer buf;
+
+ if (!partials)
+ return;
+
+ silc_dlist_start(partials);
+ while ((buf = silc_dlist_get(partials)) != SILC_LIST_END)
+ silc_buffer_free(buf);
+ silc_dlist_uninit(partials);
+}
+
+void silc_mime_add_field(SilcMime mime, const char *field, const char *value)
+{
+ if (!mime || !field || !value)
+ return;
+
+ silc_hash_table_add(mime->fields, strdup(field), strdup(value));
+}
+
+const char *silc_mime_get_field(SilcMime mime, const char *field)
+{
+ char *value;
+
+ if (!mime || !field)
+ return NULL;
+
+ if (!silc_hash_table_find(mime->fields, (void *)field,
+ NULL, (void **)&value))
+ return NULL;
+
+ return (const char *)value;
+}
+
+void silc_mime_add_data(SilcMime mime, const unsigned char *data,
+ SilcUInt32 data_len)
+{
+ if (!mime || !data)
+ return;
+
+ if (mime->data)
+ silc_free(mime->data);
+
+ mime->data = silc_memdup(data, data_len);
+ mime->data_len = data_len;
+}
+
+const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len)
+{
+ if (!mime)
+ return NULL;
+
+ if (data_len)
+ *data_len = mime->data_len;
+
+ return mime->data;
+}
+
+bool silc_mime_is_partial(SilcMime mime)
+{
+ const char *type = silc_mime_get_field(mime, "Content-Type");
+ if (!type)
+ return FALSE;
+
+ if (strstr(type, "message/partial"))
+ return FALSE;
+
+ return TRUE;
+}
+
+void silc_mime_set_multipart(SilcMime mime, const char *type,
+ const char *boundary)
+{
+ char tmp[1024];
+
+ if (!mime || !type || !boundary)
+ return;
+
+ memset(tmp, 0, sizeof(tmp));
+ snprintf(tmp, sizeof(tmp) - 1, "multipart/%s; boundary=%s", type, boundary);
+ silc_mime_add_field(mime, "Content-Type", tmp);
+ silc_free(mime->boundary);
+ mime->boundary = strdup(boundary);
+
+ if (mime->multiparts)
+ return;
+ mime->multiparts = silc_dlist_init();
+}
+
+bool silc_mime_add_multipart(SilcMime mime, SilcMime part)
+{
+ if (!mime || !mime->multiparts || !part)
+ return FALSE;
+
+ silc_dlist_add(mime->multiparts, part);
+ return TRUE;
+}
+
+bool silc_mime_is_multipart(SilcMime mime)
+{
+ if (!mime)
+ return FALSE;
+
+ return mime->multiparts != NULL;
+}
+
+SilcDList silc_mime_get_multiparts(SilcMime mime)
+{
+ if (!mime)
+ return NULL;
+
+ return mime->multiparts;
+}
--- /dev/null
+/*
+
+ silcmime.h
+
+ Author: Pekka Riikonen <priikone@silcnet.org>
+
+ Copyright (C) 2005 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+/****h* silcutil/SILC MIME Interface
+ *
+ * DESCRIPTION
+ *
+ * Simple implementation of MIME. Supports creation and parsing of simple
+ * MIME messages, multipart MIME messages, including nested multiparts, and
+ * MIME fragmentation and defragmentation.
+ *
+ ***/
+
+#ifndef SILCMIME_H
+#define SILCMIME_H
+
+/****s* silcutil/SILCMIMEAPI/SilcMime
+ *
+ * NAME
+ *
+ * typedef struct SilcMimeStruct *SilcMime;
+ *
+ * DESCRIPTION
+ *
+ * This context is the actual MIME message and is allocated
+ * by silc_mime_alloc and given as argument to all silc_mime_*
+ * functions. It is freed by the silc_mime_free function.
+ *
+ ***/
+typedef struct SilcMimeStruct *SilcMime;
+
+/****s* silcutil/SILCMIMEAPI/SilcMimeAssembler
+ *
+ * NAME
+ *
+ * typedef struct SilcMimeAssemblerStruct *SilcMimeAssembler;
+ *
+ * DESCRIPTION
+ *
+ * This context is a SILC MIME Assembler that is used to assemble partial
+ * MIME messages (fgraments) into complete MIME messages. It is allocated
+ * by silc_mime_assembler_alloc and freed by silc_mime_assembler_free.
+ *
+ ***/
+typedef struct SilcMimeAssemblerStruct *SilcMimeAssembler;
+
+/****f* silcutil/SILCMIMEAPI/SilcMimeComplete
+ *
+ * SYNOPSIS
+ *
+ * typedef void (*SilcMimeComplete)(SilcMime mime, void *context);
+ *
+ * DESCRIPTION
+ *
+ * Callback function that is called by silc_mime_assemble function when
+ * all fragments has been received. The `mime' is the complete MIME
+ * message. It must be freed with silc_mime_free.
+ *
+ ***/
+typedef void (*SilcMimeComplete)(SilcMime mime, void *context);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_alloc
+ *
+ * SYNOPSIS
+ *
+ * SilcMime silc_mime_alloc(void)
+ *
+ * DESCRIPTION
+ *
+ * Allocates SILC Mime message context.
+ *
+ ***/
+SilcMime silc_mime_alloc(void);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_free
+ *
+ * SYNOPSIS
+ *
+ * void silc_mime_alloc(SilcMime mime)
+ *
+ * DESCRIPTION
+ *
+ * Frees `mime' context.
+ *
+ ***/
+void silc_mime_free(SilcMime mime);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_assembler_alloc
+ *
+ * SYNOPSIS
+ *
+ * SilcMimeAssembler silc_mime_assembler_alloc(SilcMimeComplete complete,
+ * void *complete_context);
+ *
+ * DESCRIPTION
+ *
+ * Allocates MIME fragment assembler. The `complete' callback will be
+ * whenever a MIME message has been assembled completely. It delivers
+ * the complete MIME message to the caller.
+ *
+ ***/
+SilcMimeAssembler silc_mime_assembler_alloc(SilcMimeComplete complete,
+ void *complete_context);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_assembler_free
+ *
+ * SYNOPSIS
+ *
+ * void silc_mime_assembler_free(SilcMimeAssembler assembler)
+ *
+ * DESCRIPTION
+ *
+ * Frees `assembler' context.
+ *
+ ***/
+void silc_mime_assembler_free(SilcMimeAssembler assembler);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_decode
+ *
+ * SYNOPSIS
+ *
+ * SilcMime silc_mime_parse(const unsigned char *data,
+ * SilcUInt32 data_len);
+ *
+ * DESCRIPTION
+ *
+ * Decodes a MIME message and returns the parsed message into newly
+ * allocated SilcMime context.
+ *
+ * EXAMPLE
+ *
+ * // Parse MIME message and get its content type
+ * mime = silc_mime_parse(data, data_len);
+ * type = silc_mime_get_field(mime, "Content-Type");
+ * ...
+ *
+ * // Assemble received MIME fragment
+ * mime = silc_mime_parse(data, data_len);
+ * if (silc_mime_is_partial(mime) == TRUE)
+ * silc_mime_assmeble(assembler, mime);
+ *
+ ***/
+SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_encode
+ *
+ * SYNOPSIS
+ *
+ * unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len);
+ *
+ * DESCRIPTION
+ *
+ * Encodes the `mime' context into a raw MIME message (may be human
+ * readable). The caller must free the returned buffer. If the `mime'
+ * is multipart MIME message all parts will be automatically encoded
+ * as well.
+ *
+ * If you want to create fragmented MIME message use the function
+ * silc_mime_encode_partial.
+ *
+ ***/
+unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_assemble
+ *
+ * SYNOPSIS
+ *
+ * void silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial);
+ *
+ * DESCRIPTION
+ *
+ * Processes and attempts to assemble the received MIME fragment `partial'.
+ * To check if a received MIME message is a fragment use the
+ * silc_mime_is_partial function. The callback that was given as argument
+ * to the function silc_mime_assembler_alloc will be called when all
+ * fragments has been received, to deliver the complete MIME message.
+ * Caller must not free the `partial'.
+ *
+ * EXAMPLE
+ *
+ * // Assemble received MIME fragment
+ * mime = silc_mime_parse(data, data_len);
+ * if (silc_mime_is_partial(mime) == TRUE)
+ * silc_mime_assmeble(assembler, mime);
+ *
+ ***/
+void silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_encode_partial
+ *
+ * SYNOPSIS
+ *
+ * SilcDList silc_mime_encode_partial(SilcMime mime, int max_size);
+ *
+ * DESCRIPTION
+ *
+ * Same as silc_mime_encode except fragments the MIME message `mime'
+ * if it is larger than `max_size' in bytes. Returns the MIME fragments
+ * in SilcDList where each entry is SilcBuffer context. The caller must
+ * free the returned list and all SilcBuffer entries in it by calling
+ * silc_mime_partial_free function.
+ *
+ * To assemble the fragments into a complete MIME message the
+ * silc_mime_assemble can be used.
+ *
+ ***/
+SilcDList silc_mime_encode_partial(SilcMime mime, int max_size);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_partial_free
+ *
+ * SYNOPSIS
+ *
+ * void silc_mime_partial_free(SilcDList partials);
+ *
+ * DESCRIPTION
+ *
+ * This function must be called to free the list returned by the
+ * silc_mime_encode_partial function.
+ *
+ ***/
+void silc_mime_partial_free(SilcDList partials);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_add_field
+ *
+ * SYNOPSIS
+ *
+ * void silc_mime_add_field(SilcMime mime,
+ * const char *field, const char *value);
+ *
+ * DESCRIPTION
+ *
+ * Adds a field indicated by `field' to MIME message `mime'. The field
+ * value is `value'.
+ *
+ * EXAMPLE
+ *
+ * silc_mime_add_field(mime, "MIME-Version", "1.0");
+ * silc_mime_add_field(mime, "Content-Type", "image/jpeg");
+ * silc_mime_add_field(mime, "Content-Transfer-Encoding", "binary");
+ *
+ ***/
+void silc_mime_add_field(SilcMime mime, const char *field, const char *value);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_get_field
+ *
+ * SYNOPSIS
+ *
+ * const char *silc_mime_get_field(SilcMime mime, const char *field);
+ *
+ * DESCRIPTION
+ *
+ * Returns the `field' value or NULL if such field does not exist in the
+ * MIME message `mime'.
+ *
+ ***/
+const char *silc_mime_get_field(SilcMime mime, const char *field);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_add_data
+ *
+ * SYNOPSIS
+ *
+ * void silc_mime_add_data(SilcMime mime, const unsigned char *data,
+ * SilcUInt32 data_len);
+ *
+ * DESCRIPTION
+ *
+ * Adds the actual MIME data to the `mime' message.
+ *
+ ***/
+void silc_mime_add_data(SilcMime mime, const unsigned char *data,
+ SilcUInt32 data_len);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_get_data
+ *
+ * SYNOPSIS
+ *
+ * const unsigned char *
+ * silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len);
+ *
+ * DESCRIPTION
+ *
+ * Returns the MIME data from the `mime' message.
+ *
+ ***/
+const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_is_partial
+ *
+ * SYNOPSIS
+ *
+ * bool silc_mime_is_partial(SilcMime mime);
+ *
+ * DESCRIPTION
+ *
+ * Returns TRUE if the MIME message `mime' is a partial MIME fragment.
+ *
+ ***/
+bool silc_mime_is_partial(SilcMime mime);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_set_multipart
+ *
+ * SYNOPSIS
+ *
+ * void silc_mime_set_multipart(SilcMime mime, const char *type,
+ * const char *boundary);
+ *
+ * DESCRIPTION
+ *
+ * Sets the `mime' to be a multipart MIME message. The `type' specifies
+ * the multipart type, usually "mixed", but can be something else too.
+ * The `boundary' specifies the multipart boundary.
+ *
+ ***/
+void silc_mime_set_multipart(SilcMime mime, const char *type,
+ const char *boundary);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_add_multipart
+ *
+ * SYNOPSIS
+ *
+ * bool silc_mime_add_multipart(SilcMime mime, SilcMime part);
+ *
+ * DESCRIPTION
+ *
+ * Adds a multipart `part` to MIME message `mime'. The `part' will be
+ * freed automatically when silc_mime_free is called for `mime'. Returns
+ * TRUE if `part' was added to `mime' and FALSE if `mime' is not marked
+ * as multipart MIME message.
+ *
+ * NOTES
+ *
+ * The silc_mime_set_multipart must be called for `mime' before parts
+ * can be added to it. Otherwise FALSE will be returned.
+ *
+ * EXAMPLE
+ *
+ * part = silc_mime_alloc();
+ * silc_mime_add_field(part, "Content-Type", "image/jpeg");
+ * silc_mime_add_data(part, data, data_len);
+ *
+ * silc_mime_set_multipart(mime, "mixed", "boundary1");
+ * silc_mime_add_multipart(mime, part);
+ *
+ ***/
+bool silc_mime_add_multipart(SilcMime mime, SilcMime part);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_is_multipart
+ *
+ * SYNOPSIS
+ *
+ * bool silc_mime_is_multipart(SilcMime mime);
+ *
+ * DESCRIPTION
+ *
+ * Returns TRUE if the MIME message `mime' is a multipart MIME message.
+ * Its parts can be get by calling silc_mime_get_multiparts.
+ *
+ ***/
+bool silc_mime_is_multipart(SilcMime mime);
+
+/****f* silcutil/SILCMIMEAPI/silc_mime_get_multiparts
+ *
+ * SYNOPSIS
+ *
+ * SilcDList silc_mime_get_multiparts(SilcMime mime);
+ *
+ * DESCRIPTION
+ *
+ * Returns list of the parts from the MIME message `mime'. Each entry
+ * in the list is SilcMime context. The caller must not free the returned
+ * list or the SilcMime contexts in the list. Returns NULL if no parts
+ * exists in the MIME message.
+ *
+ ***/
+SilcDList silc_mime_get_multiparts(SilcMime mime);
+
+#endif /* SILCMIME_H */
SilcUInt32 silc_hash_uint(void *key, void *user_context)
{
- return *(SilcUInt32 *)key;
+ return SILC_PTR_TO_32(key);
}
/* Basic hash funtion to hash pointers. May be used with the SilcHashTable. */
AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
bin_PROGRAMS = test_silcstrutil test_silcstringprep test_silchashtable \
- test_silclist
+ test_silclist test_silcmime
test_silcstrutil_SOURCES = test_silcstrutil.c
test_silcstringprep_SOURCES = test_silcstringprep.c
test_silchashtable_SOURCES = test_silchashtable.c
test_silclist_SOURCES = test_silclist.c
+test_silcmime_SOURCES = test_silcmime.c
LIBS = $(SILC_COMMON_LIBS)
LDADD = -L.. -L../.. -lsilc
int i;
if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_debug = 1;
- silc_debug_hexdump = 1;
+ silc_log_debug(TRUE);
+ silc_log_debug_hexdump(TRUE);
silc_log_set_debug_string("*table*");
}
if (argc > 1 && !strcmp(argv[1], "-D")) {
- silc_debug = 1;
+ silc_log_debug(TRUE);
dump = TRUE;
silc_log_set_debug_string("*table*");
}
struct foo *f, *f1, *f2, *f3;
if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_debug = 1;
- silc_debug_hexdump = 1;
+ silc_log_debug(TRUE);
+ silc_log_debug_hexdump(TRUE);
silc_log_set_debug_string("*list*");
}
--- /dev/null
+/* SilcMime tests */
+
+#include "silcincludes.h"
+#include "silcmime.h"
+
+struct foo {
+ int i;
+ struct foo *next;
+};
+
+static void ass_complete(SilcMime mime, void *context)
+{
+ unsigned char *enc;
+ SilcUInt32 enc_len;
+
+ SILC_LOG_DEBUG(("Defragmentation completed"));
+ SILC_LOG_DEBUG(("Encoding MIME context"));
+ enc = silc_mime_encode(mime, &enc_len);
+ if (!enc)
+ SILC_LOG_DEBUG(("Error encoding"));
+ SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
+ silc_free(enc);
+ silc_mime_free(mime);
+}
+
+int main(int argc, char **argv)
+{
+ bool success = FALSE;
+ SilcMime mime, part, part2;
+ SilcMimeAssembler ass;
+ int i;
+ char tmp[500];
+ unsigned char *enc;
+ SilcUInt32 enc_len;
+ SilcDList frag;
+ SilcBuffer buf;
+
+ if (argc > 1 && !strcmp(argv[1], "-d")) {
+ silc_log_debug(TRUE);
+ silc_log_debug_hexdump(TRUE);
+ silc_log_set_debug_string("*mime*");
+ }
+
+ /* Simple MIME test */
+ SILC_LOG_DEBUG(("Allocating MIME message context"));
+ mime = silc_mime_alloc();
+ if (!mime)
+ goto err;
+ SILC_LOG_DEBUG(("Adding MIME fields"));
+ SILC_LOG_DEBUG(("Adding MIME-Version: 1.0"));
+ silc_mime_add_field(mime, "MIME-Version", "1.0");
+ SILC_LOG_DEBUG(("Adding Content-Type: foo/bar"));
+ silc_mime_add_field(mime, "Content-Type", "foo/bar");
+ SILC_LOG_DEBUG(("Adding Content-Transfer-Encoding: binary"));
+ silc_mime_add_field(mime, "Content-Transfer-Encoding", "binary");
+ SILC_LOG_DEBUG(("Adding FOO: BaR"));
+ silc_mime_add_field(mime, "FOO", "BaR");
+ SILC_LOG_DEBUG(("Adding MIME data, 100 A's + 1 B"));
+ for (i = 0; i < 100; i++)
+ tmp[i] = 'A';
+ tmp[100] = 'B';
+ silc_mime_add_data(mime, tmp, 101);
+ SILC_LOG_DEBUG(("Encoding MIME context"));
+ enc = silc_mime_encode(mime, &enc_len);
+ if (!enc)
+ goto err;
+ SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
+ silc_mime_free(mime);
+ SILC_LOG_DEBUG(("Decoding MIME message"));
+ mime = silc_mime_decode(enc, enc_len);
+ if (!mime)
+ goto err;
+ SILC_LOG_DEBUG(("Re-encoding MIME context"));
+ silc_free(enc);
+ enc = silc_mime_encode(mime, &enc_len);
+ if (!enc)
+ goto err;
+ SILC_LOG_DEBUG(("Re-encoded MIME message: \n%s", enc));
+ silc_free(enc);
+ silc_mime_free(mime);
+
+ /* Multipart test, with nesting */
+ SILC_LOG_DEBUG(("Allocating MIME message context"));
+ mime = silc_mime_alloc();
+ if (!mime)
+ goto err;
+ SILC_LOG_DEBUG(("Adding MIME-Version: 1.0"));
+ silc_mime_add_field(mime, "MIME-Version", "1.0");
+ SILC_LOG_DEBUG(("Adding Content-Transfer-Encoding: binary"));
+ silc_mime_add_field(mime, "Content-Transfer-Encoding", "binary");
+ SILC_LOG_DEBUG(("Marking as multipart MIME message"));
+ silc_mime_set_multipart(mime, "mixed", "boundary");
+ SILC_LOG_DEBUG(("Adding FOO: BaR"));
+ silc_mime_add_field(mime, "FOO", "BaR");
+ SILC_LOG_DEBUG(("Allocating part"));
+ part = silc_mime_alloc();
+ if (!part)
+ goto err;
+ SILC_LOG_DEBUG(("Adding MIME fields"));
+ SILC_LOG_DEBUG(("Adding Content-Type: foo/bar"));
+ silc_mime_add_field(part, "Content-Type", "foo/bar");
+ SILC_LOG_DEBUG(("Adding MIME data, 100 A's + 1 B"));
+ for (i = 0; i < 100; i++)
+ tmp[i] = 'A';
+ tmp[100] = 'B';
+ silc_mime_add_data(part, tmp, 101);
+ SILC_LOG_DEBUG(("Adding part to MIME message"));
+ if (!silc_mime_add_multipart(mime, part))
+ goto err;
+ SILC_LOG_DEBUG(("Allocating part"));
+ part = silc_mime_alloc();
+ if (!part)
+ goto err;
+ SILC_LOG_DEBUG(("Adding Content-Type: image/foobar"));
+ silc_mime_add_field(part, "Content-Type", "image/foobar");
+ SILC_LOG_DEBUG(("Adding MIME data, 50 A's + 1 B"));
+ for (i = 0; i < 50; i++)
+ tmp[i] = 'A';
+ tmp[50] = 'B';
+ silc_mime_add_data(part, tmp, 51);
+ SILC_LOG_DEBUG(("Adding part to MIME message"));
+ if (!silc_mime_add_multipart(mime, part))
+ goto err;
+ SILC_LOG_DEBUG(("Allocating part"));
+ part = silc_mime_alloc();
+ if (!part)
+ goto err;
+ SILC_LOG_DEBUG(("Adding MIME data, 10 A's + 1 B"));
+ for (i = 0; i < 10; i++)
+ tmp[i] = 'A';
+ tmp[10] = 'B';
+ silc_mime_add_data(part, tmp, 11);
+ SILC_LOG_DEBUG(("Adding part to MIME message"));
+ if (!silc_mime_add_multipart(mime, part))
+ goto err;
+ SILC_LOG_DEBUG(("Allocating part"));
+ part = silc_mime_alloc();
+ if (!part)
+ goto err;
+ SILC_LOG_DEBUG(("Adding part to MIME message"));
+ if (!silc_mime_add_multipart(mime, part))
+ goto err;
+ silc_mime_set_multipart(part, "mixed", "booooooooundary");
+ SILC_LOG_DEBUG(("Allocating part for nested multipart"));
+ part2 = silc_mime_alloc();
+ if (!part)
+ goto err;
+ SILC_LOG_DEBUG(("Adding Content-Type: foo/nested"));
+ silc_mime_add_field(part2, "Content-Type", "foo/nested");
+ SILC_LOG_DEBUG(("Adding MIME data, 150 A's + 1 B"));
+ for (i = 0; i < 150; i++)
+ tmp[i] = 'A';
+ tmp[150] = 'B';
+ silc_mime_add_data(part2, tmp, 151);
+ SILC_LOG_DEBUG(("Adding part to another part message"));
+ if (!silc_mime_add_multipart(part, part2))
+ goto err;
+ SILC_LOG_DEBUG(("Encoding MIME context"));
+ enc = silc_mime_encode(mime, &enc_len);
+ if (!enc)
+ goto err;
+ SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
+ silc_mime_free(mime);
+ SILC_LOG_DEBUG(("Decoding MIME message"));
+ mime = silc_mime_decode(enc, enc_len);
+ if (!mime)
+ goto err;
+ SILC_LOG_DEBUG(("Re-encoding MIME context"));
+ silc_free(enc);
+ enc = silc_mime_encode(mime, &enc_len);
+ if (!enc)
+ goto err;
+ SILC_LOG_DEBUG(("Re-encoded MIME message: \n%s", enc));
+ silc_free(enc);
+ SILC_LOG_DEBUG(("Get multiparts"));
+ frag = silc_mime_get_multiparts(mime);
+ if (!frag)
+ goto err;
+ silc_dlist_start(frag);
+ while ((part = silc_dlist_get(frag)) != SILC_LIST_END) {
+ SILC_LOG_DEBUG(("Encoding MIME part"));
+ enc = silc_mime_encode(part, &enc_len);
+ if (!enc)
+ goto err;
+ if (silc_mime_is_multipart(part))
+ SILC_LOG_DEBUG(("Is multipart"));
+ SILC_LOG_DEBUG(("Encoded MIME part: \n%s", enc));
+ silc_free(enc);
+ }
+ silc_mime_free(mime);
+
+ /* Fragmentation test */
+ SILC_LOG_DEBUG(("Allocating MIME assembler"));
+ ass = silc_mime_assembler_alloc(ass_complete, NULL);
+ if (!ass)
+ goto err;
+ SILC_LOG_DEBUG(("Allocating MIME message context"));
+ mime = silc_mime_alloc();
+ if (!mime)
+ goto err;
+ SILC_LOG_DEBUG(("Adding MIME fields"));
+ SILC_LOG_DEBUG(("Adding MIME-Version: 1.0"));
+ silc_mime_add_field(mime, "MIME-Version", "1.0");
+ SILC_LOG_DEBUG(("Adding Content-Type: foo/bar"));
+ silc_mime_add_field(mime, "Content-Type", "foo/bar");
+ SILC_LOG_DEBUG(("Adding Content-Transfer-Encoding: binary"));
+ silc_mime_add_field(mime, "Content-Transfer-Encoding", "binary");
+ SILC_LOG_DEBUG(("Adding FOO: BaR"));
+ silc_mime_add_field(mime, "FOO", "BaR");
+ SILC_LOG_DEBUG(("Adding MIME data, 300 A's + 1 B"));
+ for (i = 0; i < 300; i++)
+ tmp[i] = 'A';
+ tmp[300] = 'B';
+ silc_mime_add_data(mime, tmp, 301);
+ SILC_LOG_DEBUG(("Encoding MIME context"));
+ enc = silc_mime_encode(mime, &enc_len);
+ if (!enc)
+ goto err;
+ SILC_LOG_DEBUG(("Encoded MIME message: \n%s", enc));
+ silc_free(enc);
+ SILC_LOG_DEBUG(("Fragment MIME message in 100 byte chunks"));
+ frag = silc_mime_encode_partial(mime, 100);
+ if (!frag)
+ goto err;
+ silc_dlist_start(frag);
+ while ((buf = silc_dlist_get(frag)) != SILC_LIST_END)
+ SILC_LOG_DEBUG(("Fragment \n%s", buf->data, buf->len));
+ SILC_LOG_DEBUG(("Defragment"));
+ silc_dlist_start(frag);
+ while ((buf = silc_dlist_get(frag)) != SILC_LIST_END) {
+ part = silc_mime_decode(buf->data, buf->len);
+ if (!silc_mime_is_partial(part))
+ goto err;
+ silc_mime_assemble(ass, part);
+ }
+ silc_mime_partial_free(frag);
+ silc_mime_assembler_free(ass);
+
+ success = TRUE;
+
+ err:
+ SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+ fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+ return success;
+}
SilcStringprepStatus ret;
if (argc > 1 && !strcmp(argv[1], "-d")) {
- silc_debug = 1;
- silc_debug_hexdump = 1;
+ silc_log_debug(TRUE);
+ silc_log_debug_hexdump(TRUE);
silc_log_set_debug_string("*stringprep*,*utf8*");
}
exit(0);
break;
case 'd':
- silc_debug = TRUE;
- silc_debug_hexdump = TRUE;
+ silc_log_debug(TRUE);
+ silc_log_debug_hexdump(TRUE);
if (optarg)
silc_log_set_debug_string(optarg);
else