Added SilcMime API.
authorPekka Riikonen <priikone@silcnet.org>
Sat, 19 Nov 2005 16:26:20 +0000 (16:26 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 19 Nov 2005 16:26:20 +0000 (16:26 +0000)
lib/silcutil/Makefile.ad
lib/silcutil/silcmime.c [new file with mode: 0644]
lib/silcutil/silcmime.h [new file with mode: 0644]
lib/silcutil/silcutil.c
lib/silcutil/tests/Makefile.am
lib/silcutil/tests/test_silchashtable.c
lib/silcutil/tests/test_silclist.c
lib/silcutil/tests/test_silcmime.c [new file with mode: 0644]
lib/silcutil/tests/test_silcstringprep.c
lib/silcutil/tests/test_silcstrutil.c

index 027525a6d4822cbba8d0a9d0a60999f27e1b3210..115e0b261087916525bee9efd865974a4b71a5b9 100644 (file)
@@ -60,6 +60,7 @@ libsilcutil_la_SOURCES = \
        silcprotocol.c  \
        silcvcard.c     \
        silcapputil.c   \
+       silcmime.c      \
        silcutf8.c      \
        silcstringprep.c
 
@@ -86,6 +87,7 @@ include_HEADERS =     \
        silcstrutil.h   \
        silcvcard.h     \
        silcapputil.h   \
+       silcmime.h      \
        silcutf8.h      \
        silcstringprep.h        \
        silctypes.h
diff --git a/lib/silcutil/silcmime.c b/lib/silcutil/silcmime.c
new file mode 100644 (file)
index 0000000..8ccc891
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+
+  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;
+}
diff --git a/lib/silcutil/silcmime.h b/lib/silcutil/silcmime.h
new file mode 100644 (file)
index 0000000..10ede17
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+
+  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 */
index a3746f92ff8bf9f745c731cc17f99bfae5bdfb97..b1f09b7b5a5ffa05dc34733dae97b0f7fc923ed4 100644 (file)
@@ -490,7 +490,7 @@ SilcUInt32 silc_hash_utf8_string(void *key, void *user_context)
 
 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. */
index 8462ffbda05b2777e484fbc866b449f90db1c1a7..96cebf4d92528af7e70f951bf6b1b127376b6195 100644 (file)
 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
index 47326c0db6cbc83cd057654c3cfa7a5298e5d396..bf75e7f5abef28acfd357b268688611d45a80a46 100644 (file)
@@ -211,13 +211,13 @@ int main(int argc, char **argv)
   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*");
   }
index 93aad06eba620f2138edd6d0a3d5bfebc7cb6ee3..b873af1d9160511c552222c8fe89b125cff8447e 100644 (file)
@@ -14,8 +14,8 @@ int main(int argc, char **argv)
   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*");
   }
 
diff --git a/lib/silcutil/tests/test_silcmime.c b/lib/silcutil/tests/test_silcmime.c
new file mode 100644 (file)
index 0000000..01e7fdd
--- /dev/null
@@ -0,0 +1,246 @@
+/* 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;
+}
index 26ff2aaf9f5f9d6b5cec87d2b6c9b8c90808f743..3c48c52eebfeeb31e3fd388e407f4bcdeb5b3d00 100644 (file)
@@ -77,8 +77,8 @@ int main(int argc, char **argv)
   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*");
   }
 
index dcf9466273040b88205fb2f287ca565101e954d2..821bc89802a1d8131918e9d382626460220f5452 100644 (file)
@@ -65,8 +65,8 @@ int main(int argc, char **argv)
           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