X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcmime.c;h=c0817ec0f594d1eaed43c27d1f88fac673929116;hb=e9374395ec9747bddd3ea0bfd3e5a17717e97b31;hp=d347d7350490f4f9a8b967d24c5b6aa0045abe71;hpb=0f0340b9fbce9704cc7171f8f0104ce9103d2de6;p=silc.git diff --git a/lib/silcutil/silcmime.c b/lib/silcutil/silcmime.c index d347d735..c0817ec0 100644 --- a/lib/silcutil/silcmime.c +++ b/lib/silcutil/silcmime.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2005 Pekka Riikonen + Copyright (C) 2005 - 2007 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 @@ -17,21 +17,11 @@ */ -#include "silcincludes.h" -#include "silcmime.h" +#include "silc.h" -struct SilcMimeStruct { - SilcHashTable fields; - unsigned char *data; - SilcUInt32 data_len; - SilcDList multiparts; - char *boundary; - char *multitype; -}; +/************************ Static utility functions **************************/ -struct SilcMimeAssemblerStruct { - SilcHashTable fragments; -}; +/* MIME fields destructor */ static void silc_mime_field_dest(void *key, void *context, void *user_context) { @@ -39,6 +29,28 @@ static void silc_mime_field_dest(void *key, void *context, void *user_context) silc_free(context); } +/* Assembler fragment destructor */ + +static void silc_mime_assembler_dest(void *key, void *context, + void *user_context) +{ + silc_free(key); + silc_hash_table_free(context); +} + +/* Assembler partial MIME destructor */ + +static void silc_mime_assemble_dest(void *key, void *context, + void *user_context) +{ + silc_mime_free(context); +} + + +/******************************* Public API *********************************/ + +/* Allocate MIME context */ + SilcMime silc_mime_alloc(void) { SilcMime mime; @@ -58,6 +70,8 @@ SilcMime silc_mime_alloc(void) return mime; } +/* Free MIME context */ + void silc_mime_free(SilcMime mime) { SilcMime m; @@ -77,12 +91,7 @@ void silc_mime_free(SilcMime mime) silc_free(mime); } -static void silc_mime_assembler_dest(void *key, void *context, - void *user_context) -{ - silc_free(key); - silc_hash_table_free(context); -} +/* Allocate MIME assembler */ SilcMimeAssembler silc_mime_assembler_alloc(void) { @@ -104,15 +113,20 @@ SilcMimeAssembler silc_mime_assembler_alloc(void) return assembler; } +/* Free MIME 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) +/* Decode MIME message */ + +SilcMime silc_mime_decode(SilcMime mime, const unsigned char *data, + SilcUInt32 data_len) { - SilcMime mime; + SilcMime m = NULL; int i, k; char *tmp, *field, *value, *line; @@ -121,9 +135,12 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len) if (!data) return NULL; - mime = silc_mime_alloc(); - if (!mime) - return NULL; + if (!mime) { + mime = silc_mime_alloc(); + if (!mime) + return NULL; + m = mime; + } /* Parse the fields */ line = tmp = (char *)data; @@ -181,6 +198,7 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len) if (field && strstr(field, "multipart")) { char b[1024]; SilcMime p; + unsigned int len; mime->multiparts = silc_dlist_init(); if (!mime->multiparts) @@ -196,7 +214,10 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len) if (!strchr(field, ';')) goto err; memset(b, 0, sizeof(b)); - strncat(b, value, strchr(field, ';') - value); + len = (unsigned int)(strchr(field, ';') - value); + if (len > sizeof(b) - 1) + goto err; + strncpy(b, value, len); if (strchr(b, '"')) *strchr(b, '"') = '\0'; mime->multitype = silc_memdup(b, strlen(b)); @@ -212,10 +233,10 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len) line = strdup(value); if (strrchr(line, '"')) { *strrchr(line, '"') = '\0'; - snprintf(b, sizeof(b) - 1, "--%s", line + 1); + silc_snprintf(b, sizeof(b) - 1, "--%s", line + 1); mime->boundary = strdup(line + 1); } else { - snprintf(b, sizeof(b) - 1, "--%s", line); + silc_snprintf(b, sizeof(b) - 1, "--%s", line); mime->boundary = strdup(line); } silc_free(line); @@ -255,7 +276,7 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len) k -= 2; /* Parse the part */ - p = silc_mime_decode(line, k - i); + p = silc_mime_decode(NULL, line, k - i); if (!p) goto err; @@ -265,20 +286,26 @@ SilcMime silc_mime_decode(const unsigned char *data, SilcUInt32 data_len) } } } else { - /* Get data area */ - if (i >= data_len) + /* Get data area. If we are at the end and we have fields present + there is no data area present, but, if fields are not present we + only have data area. */ + if (i >= data_len && !silc_hash_table_count(mime->fields)) i = 0; SILC_LOG_DEBUG(("Data len %d", data_len - i)); - silc_mime_add_data(mime, tmp + i, data_len - i); + if (data_len - i) + silc_mime_add_data(mime, tmp + i, data_len - i); } return mime; err: - silc_mime_free(mime); + if (m) + silc_mime_free(m); return NULL; } +/* Encode MIME message */ + unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len) { SilcMime part; @@ -299,10 +326,10 @@ unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len) /* 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)) { + 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_snprintf(tmp, sizeof(tmp) - 1, "%s: %s\r\n", field, value); silc_buffer_strformat(&buf, tmp, SILC_STRFMT_END); i++; } @@ -319,6 +346,7 @@ unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len) if (silc_buffer_len(&buf)) { silc_buffer_put(buffer, buf.head, silc_buffer_len(&buf)); silc_buffer_pull(buffer, silc_buffer_len(&buf)); + silc_buffer_purge(&buf); } /* Add data */ @@ -347,8 +375,8 @@ unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len) /* 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--%s\r\n%s", + silc_snprintf(tmp2, sizeof(tmp2) - 1, "\r\n"); + silc_snprintf(tmp, sizeof(tmp) - 1, "%s--%s\r\n%s", i != 0 ? "\r\n" : "", mime->boundary, tmp2); i = 1; @@ -364,7 +392,7 @@ unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len) } memset(tmp, 0, sizeof(tmp)); - snprintf(tmp, sizeof(tmp) - 1, "\r\n--%s--\r\n", mime->boundary); + silc_snprintf(tmp, sizeof(tmp) - 1, "\r\n--%s--\r\n", mime->boundary); buffer = silc_buffer_realloc(buffer, silc_buffer_truelen(buffer) + strlen(tmp)); if (!buffer) @@ -379,11 +407,7 @@ unsigned char *silc_mime_encode(SilcMime mime, SilcUInt32 *encoded_len) return ret; } -static void silc_mime_assemble_dest(void *key, void *context, - void *user_context) -{ - silc_mime_free(context); -} +/* Assembles MIME message from partial MIME messages */ SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial) { @@ -442,7 +466,7 @@ SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial) /* Find fragments with this ID. */ if (!silc_hash_table_find(assembler->fragments, (void *)id, - NULL, (void **)&f)) { + 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); @@ -487,7 +511,7 @@ SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial) /* 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)) + 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 */ @@ -512,7 +536,7 @@ SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial) } /* Now parse the complete MIME message and deliver it */ - complete = silc_mime_decode((const unsigned char *)compbuf->head, + complete = silc_mime_decode(NULL, (const unsigned char *)compbuf->head, silc_buffer_truelen(compbuf)); if (!complete) goto err; @@ -532,6 +556,8 @@ SilcMime silc_mime_assemble(SilcMimeAssembler assembler, SilcMime partial) return NULL; } +/* Encodes partial MIME messages */ + SilcDList silc_mime_encode_partial(SilcMime mime, int max_size) { unsigned char *buf, *tmp; @@ -557,7 +583,7 @@ SilcDList silc_mime_encode_partial(SilcMime mime, int max_size) memset(type, 0, sizeof(type)); gethostname(type, sizeof(type) - 1); srand((time(NULL) + buf_len) ^ rand()); - snprintf(id, sizeof(id) - 1, "%X%X%X%s", + silc_snprintf(id, sizeof(id) - 1, "%X%X%X%s", (unsigned int)rand(), (unsigned int)time(NULL), (unsigned int)buf_len, type); @@ -569,7 +595,7 @@ SilcDList silc_mime_encode_partial(SilcMime mime, int max_size) silc_mime_add_field(partial, "MIME-Version", "1.0"); memset(type, 0, sizeof(type)); - snprintf(type, sizeof(type) - 1, + silc_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); @@ -599,14 +625,14 @@ SilcDList silc_mime_encode_partial(SilcMime mime, int max_size) silc_mime_add_field(partial, "MIME-Version", "1.0"); if (len > max_size) { - snprintf(type, sizeof(type) - 1, + silc_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, + silc_snprintf(type, sizeof(type) - 1, "message/partial; id=\"%s\"; number=%d; total=%d", id, num, num); silc_mime_add_data(partial, buf + off, len); @@ -642,6 +668,8 @@ SilcDList silc_mime_encode_partial(SilcMime mime, int max_size) return list; } +/* Free partial MIME list */ + void silc_mime_partial_free(SilcDList partials) { SilcBuffer buf; @@ -655,6 +683,8 @@ void silc_mime_partial_free(SilcDList partials) silc_dlist_uninit(partials); } +/* Add field */ + void silc_mime_add_field(SilcMime mime, const char *field, const char *value) { if (!mime || !field || !value) @@ -663,6 +693,8 @@ void silc_mime_add_field(SilcMime mime, const char *field, const char *value) silc_hash_table_add(mime->fields, strdup(field), strdup(value)); } +/* Get field */ + const char *silc_mime_get_field(SilcMime mime, const char *field) { char *value; @@ -671,12 +703,14 @@ const char *silc_mime_get_field(SilcMime mime, const char *field) return NULL; if (!silc_hash_table_find(mime->fields, (void *)field, - NULL, (void **)&value)) + NULL, (void *)&value)) return NULL; return (const char *)value; } +/* Add data */ + void silc_mime_add_data(SilcMime mime, const unsigned char *data, SilcUInt32 data_len) { @@ -690,6 +724,8 @@ void silc_mime_add_data(SilcMime mime, const unsigned char *data, mime->data_len = data_len; } +/* Get data */ + const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len) { if (!mime) @@ -701,7 +737,29 @@ const unsigned char *silc_mime_get_data(SilcMime mime, SilcUInt32 *data_len) return mime->data; } -bool silc_mime_is_partial(SilcMime mime) +/* Steal data */ + +unsigned char *silc_mime_steal_data(SilcMime mime, SilcUInt32 *data_len) +{ + unsigned char *data; + + if (!mime) + return NULL; + + if (data_len) + *data_len = mime->data_len; + + data = mime->data; + + mime->data = NULL; + mime->data_len = 0; + + return data; +} + +/* Returns TRUE if partial message */ + +SilcBool silc_mime_is_partial(SilcMime mime) { const char *type = silc_mime_get_field(mime, "Content-Type"); if (!type) @@ -713,6 +771,8 @@ bool silc_mime_is_partial(SilcMime mime) return TRUE; } +/* Set as multipart message */ + void silc_mime_set_multipart(SilcMime mime, const char *type, const char *boundary) { @@ -722,7 +782,7 @@ void silc_mime_set_multipart(SilcMime mime, const char *type, return; memset(tmp, 0, sizeof(tmp)); - snprintf(tmp, sizeof(tmp) - 1, "multipart/%s; boundary=%s", type, boundary); + silc_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); @@ -732,7 +792,9 @@ void silc_mime_set_multipart(SilcMime mime, const char *type, mime->multiparts = silc_dlist_init(); } -bool silc_mime_add_multipart(SilcMime mime, SilcMime part) +/* Add multipart */ + +SilcBool silc_mime_add_multipart(SilcMime mime, SilcMime part) { if (!mime || !mime->multiparts || !part) return FALSE; @@ -741,7 +803,9 @@ bool silc_mime_add_multipart(SilcMime mime, SilcMime part) return TRUE; } -bool silc_mime_is_multipart(SilcMime mime) +/* Return TRUE if has multiparts */ + +SilcBool silc_mime_is_multipart(SilcMime mime) { if (!mime) return FALSE; @@ -749,6 +813,8 @@ bool silc_mime_is_multipart(SilcMime mime) return mime->multiparts != NULL; } +/* Returns multiparts */ + SilcDList silc_mime_get_multiparts(SilcMime mime, const char **type) { if (!mime)