Replace minimime with superior GMime library so that the entire contents of an http post are not read into memory.
This does introduce a dependency on the GMime library for handling HTTP POSTs, but it is available in most distros. If the library is present, then the compile flag for ENABLE_UPLOADS is enabled by default in menuselect. git-svn-id: http://svn.digium.com/svn/asterisk/trunk@109229 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
40a42d212f
commit
f12eb74241
|
@ -1,6 +1,10 @@
|
|||
<category name="MENUSELECT_CFLAGS" displayname="Compiler Flags" positive_output="yes" remove_on_change=".lastclean">
|
||||
<member name="DONT_OPTIMIZE" displayname="Disable Optimizations by the Compiler">
|
||||
</member>
|
||||
<member name="ENABLE_UPLOADS" displayname="Enable HTTP uploads">
|
||||
<defaultenabled>yes</defaultenabled>
|
||||
<depend>gmime</depend>
|
||||
</member>
|
||||
<member name="DEBUG_THREADS" displayname="Enable Thread Debugging">
|
||||
</member>
|
||||
<member name="STATIC_BUILD" displayname="Build static binaries">
|
||||
|
|
|
@ -7,11 +7,11 @@ cat << END
|
|||
*/
|
||||
|
||||
END
|
||||
TMP=`${GREP} MENUSELECT_CFLAGS menuselect.makeopts | sed 's/MENUSELECT_CFLAGS\=//g' | sed 's/-D//g'`
|
||||
TMP=`${GREP} -e ^MENUSELECT_CFLAGS menuselect.makeopts | sed 's/MENUSELECT_CFLAGS\=//g' | sed 's/-D//g'`
|
||||
for x in ${TMP}; do
|
||||
echo "#define ${x} 1"
|
||||
done
|
||||
TMP=`${GREP} MENUSELECT_BUILD_DEPS menuselect.makeopts | sed 's/MENUSELECT_BUILD_DEPS\=//g'`
|
||||
TMP=`${GREP} -e ^MENUSELECT_BUILD_DEPS menuselect.makeopts | sed 's/MENUSELECT_BUILD_DEPS\=//g'`
|
||||
for x in ${TMP}; do
|
||||
x2=`echo ${x} | tr a-z A-Z`
|
||||
echo "#define AST_MODULE_${x2} 1"
|
||||
|
|
|
@ -2,6 +2,7 @@ ASOUND=@PBX_ALSA@
|
|||
CRYPTO=@PBX_CRYPTO@
|
||||
CURL=@PBX_CURL@
|
||||
FREETDS=@PBX_FREETDS@
|
||||
GMIME=@PBX_GMIME@
|
||||
GNU_LD=@GNU_LD@
|
||||
GSM=@PBX_GSM@
|
||||
GTK2=@PBX_GTK2@
|
||||
|
|
|
@ -211,6 +211,7 @@ AST_EXT_LIB_SETUP([FFMPEG], [Ffmpeg and avcodec library], [avcodec])
|
|||
AST_EXT_LIB_SETUP([GSM], [External GSM library], [gsm], [, use 'internal' GSM otherwise])
|
||||
AST_EXT_LIB_SETUP([GTK], [gtk libraries], [gtk])
|
||||
AST_EXT_LIB_SETUP([GTK2], [gtk2 libraries], [gtk2])
|
||||
AST_EXT_LIB_SETUP([GMIME], [GMime library], [gmime])
|
||||
AST_EXT_LIB_SETUP([ICONV], [Iconv Library], [iconv])
|
||||
AST_EXT_LIB_SETUP([IKSEMEL], [Iksemel Jabber Library], [iksemel])
|
||||
AST_EXT_LIB_SETUP([IMAP_TK], [UW IMAP Toolkit], [imap])
|
||||
|
@ -1330,6 +1331,8 @@ then
|
|||
AST_EXT_LIB_CHECK([OSPTK], [osptk], [OSPPCryptoDecrypt], [osp/osp.h], [-lcrypto -lssl])
|
||||
fi
|
||||
|
||||
AST_EXT_TOOL_CHECK([GMIME], [gmime])
|
||||
|
||||
AST_EXT_LIB_CHECK([FREETDS], [tds], [tds_version], [tds.h])
|
||||
if test "${PBX_FREETDS}" != "0";
|
||||
then
|
||||
|
|
|
@ -309,6 +309,9 @@
|
|||
/* Define to 1 if you have the `glob' function. */
|
||||
#undef HAVE_GLOB
|
||||
|
||||
/* Define if your system has the GMIME libraries. */
|
||||
#undef HAVE_GMIME
|
||||
|
||||
/* Define to indicate the GSM library */
|
||||
#undef HAVE_GSM
|
||||
|
||||
|
@ -1175,9 +1178,6 @@
|
|||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
|
||||
/* Define like PROTOTYPES; this can be used by system headers. */
|
||||
#undef __PROTOTYPES
|
||||
|
|
|
@ -132,6 +132,11 @@ testexpr2: ast_expr2f.c ast_expr2.c ast_expr2.h
|
|||
|
||||
channel.o: ASTCFLAGS+=$(ZAPTEL_INCLUDE)
|
||||
|
||||
|
||||
ifneq ($(findstring ENABLE_UPLOADS,$(MENUSELECT_CFLAGS)),)
|
||||
http.o: ASTCFLAGS+=$(GMIME_INCLUDE)
|
||||
endif
|
||||
|
||||
stdtime/localtime.o: ASTCFLAGS+=$(AST_NO_STRICT_OVERFLOW)
|
||||
|
||||
AST_EMBED_LDSCRIPTS:=$(sort $(EMBED_LDSCRIPTS))
|
||||
|
@ -146,9 +151,6 @@ else
|
|||
H323LDLIBS=
|
||||
endif
|
||||
|
||||
minimime/libmmime.a: CHECK_SUBDIR
|
||||
@cd minimime && $(MAKE) libmmime.a
|
||||
|
||||
ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
|
||||
MAIN_TGT:=asterisk.dll
|
||||
asterisk: cygload
|
||||
|
@ -159,13 +161,17 @@ else
|
|||
MAIN_TGT:=asterisk
|
||||
endif
|
||||
|
||||
$(MAIN_TGT): $(OBJS) editline/libedit.a db1-ast/libdb1.a minimime/libmmime.a $(AST_EMBED_LDSCRIPTS)
|
||||
ifneq ($(findstring ENABLE_UPLOADS,$(MENUSELECT_CFLAGS)),)
|
||||
GMIMELDFLAGS+=$(GMIME_LIB)
|
||||
endif
|
||||
|
||||
$(MAIN_TGT): $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
|
||||
@$(CC) -c -o buildinfo.o $(ASTCFLAGS) buildinfo.c
|
||||
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
|
||||
ifneq ($(findstring chan_h323,$(MENUSELECT_CHANNELS)),)
|
||||
$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS)
|
||||
$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS)
|
||||
else
|
||||
$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS)
|
||||
$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS) $(GMIMELDFLAGS)
|
||||
endif
|
||||
$(CMD_PREFIX) $(ASTTOPDIR)/build_tools/strip_nonapi $@ || rm $@
|
||||
|
||||
|
@ -175,5 +181,4 @@ clean::
|
|||
@if [ -f editline/Makefile ]; then $(MAKE) -C editline distclean ; fi
|
||||
@$(MAKE) -C db1-ast clean
|
||||
@$(MAKE) -C stdtime clean
|
||||
@$(MAKE) -C minimime clean
|
||||
rm -f libresample/src/*.o
|
||||
|
|
213
main/http.c
213
main/http.c
|
@ -40,7 +40,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#include <sys/signal.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "minimime/mm.h"
|
||||
#ifdef ENABLE_UPLOADS
|
||||
#include <gmime/gmime.h>
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/tcptls.h"
|
||||
|
@ -88,6 +90,7 @@ static struct server_args https_desc = {
|
|||
|
||||
static AST_RWLIST_HEAD_STATIC(uris, ast_http_uri); /*!< list of supported handlers */
|
||||
|
||||
#ifdef ENABLE_UPLOADS
|
||||
struct ast_http_post_mapping {
|
||||
AST_RWLIST_ENTRY(ast_http_post_mapping) entry;
|
||||
char *from;
|
||||
|
@ -96,6 +99,12 @@ struct ast_http_post_mapping {
|
|||
|
||||
static AST_RWLIST_HEAD_STATIC(post_mappings, ast_http_post_mapping);
|
||||
|
||||
struct mime_cbinfo {
|
||||
int count;
|
||||
const char *post_dir;
|
||||
};
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
/* all valid URIs must be prepended by the string in prefix. */
|
||||
static char prefix[MAX_PREFIX];
|
||||
static int enablestatic;
|
||||
|
@ -325,6 +334,7 @@ void ast_http_uri_unlink(struct ast_http_uri *urih)
|
|||
AST_RWLIST_UNLOCK(&uris);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UPLOADS
|
||||
/*! \note This assumes that the post_mappings list is locked */
|
||||
static struct ast_http_post_mapping *find_post_mapping(const char *uri)
|
||||
{
|
||||
|
@ -347,64 +357,115 @@ static struct ast_http_post_mapping *find_post_mapping(const char *uri)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int get_filename(struct mm_mimepart *part, char *fn, size_t fn_len)
|
||||
{
|
||||
const char *filename;
|
||||
|
||||
filename = mm_content_getdispositionparambyname(part->type, "filename");
|
||||
|
||||
if (ast_strlen_zero(filename))
|
||||
return -1;
|
||||
|
||||
ast_copy_string(fn, filename, fn_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void post_raw(struct mm_mimepart *part, const char *post_dir, const char *fn)
|
||||
static void post_raw(GMimePart *part, const char *post_dir, const char *fn)
|
||||
{
|
||||
char filename[PATH_MAX];
|
||||
FILE *f;
|
||||
const char *body;
|
||||
size_t body_len;
|
||||
GMimeDataWrapper *content;
|
||||
GMimeStream *stream;
|
||||
int fd;
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/%s", post_dir, fn);
|
||||
|
||||
ast_debug(1, "Posting raw data to %s\n", filename);
|
||||
|
||||
if (!(f = fopen(filename, "w"))) {
|
||||
if ((fd = open(filename, O_CREAT | O_WRONLY, 0666)) == -1) {
|
||||
ast_log(LOG_WARNING, "Unable to open %s for writing file from a POST!\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(body = mm_mimepart_getbody(part, 0))) {
|
||||
ast_debug(1, "Couldn't get the mimepart body\n");
|
||||
fclose(f);
|
||||
stream = g_mime_stream_fs_new(fd);
|
||||
|
||||
content = g_mime_part_get_content_object(part);
|
||||
g_mime_data_wrapper_write_to_stream(content, stream);
|
||||
g_mime_stream_flush(stream);
|
||||
|
||||
g_object_unref(content);
|
||||
g_object_unref(stream);
|
||||
}
|
||||
|
||||
static GMimeMessage *parse_message(FILE *f)
|
||||
{
|
||||
GMimeMessage *message;
|
||||
GMimeParser *parser;
|
||||
GMimeStream *stream;
|
||||
|
||||
stream = g_mime_stream_file_new(f);
|
||||
|
||||
parser = g_mime_parser_new_with_stream(stream);
|
||||
g_mime_parser_set_respect_content_length(parser, 1);
|
||||
|
||||
g_object_unref(stream);
|
||||
|
||||
message = g_mime_parser_construct_message(parser);
|
||||
|
||||
g_object_unref(parser);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
static void process_message_callback(GMimeObject *part, gpointer user_data)
|
||||
{
|
||||
struct mime_cbinfo *cbinfo = user_data;
|
||||
|
||||
cbinfo->count++;
|
||||
|
||||
/* We strip off the headers before we get here, so should only see GMIME_IS_PART */
|
||||
if (GMIME_IS_MESSAGE_PART(part)) {
|
||||
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PART\n");
|
||||
return;
|
||||
} else if (GMIME_IS_MESSAGE_PARTIAL(part)) {
|
||||
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MESSAGE_PARTIAL\n");
|
||||
return;
|
||||
} else if (GMIME_IS_MULTIPART(part)) {
|
||||
GList *l;
|
||||
|
||||
ast_log(LOG_WARNING, "Got unexpected GMIME_IS_MULTIPART, trying to process subparts\n");
|
||||
l = GMIME_MULTIPART (part)->subparts;
|
||||
while (l) {
|
||||
process_message_callback(l->data, cbinfo);
|
||||
l = l->next;
|
||||
}
|
||||
} else if (GMIME_IS_PART(part)) {
|
||||
const char *filename;
|
||||
|
||||
ast_debug(3, "Got mime part\n");
|
||||
if (ast_strlen_zero(filename = g_mime_part_get_filename(GMIME_PART(part)))) {
|
||||
ast_debug(1, "Skipping part with no filename\n");
|
||||
return;
|
||||
}
|
||||
|
||||
post_raw(GMIME_PART(part), cbinfo->post_dir, filename);
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Encountered unknown MIME part. This should never happen!\n");
|
||||
}
|
||||
body_len = mm_mimepart_getlength(part);
|
||||
}
|
||||
|
||||
ast_debug(1, "Body length is %ld\n", (long int)body_len);
|
||||
static int process_message(GMimeMessage *message, const char *post_dir)
|
||||
{
|
||||
struct mime_cbinfo cbinfo = {
|
||||
.count = 0,
|
||||
.post_dir = post_dir,
|
||||
};
|
||||
|
||||
fwrite(body, 1, body_len, f);
|
||||
g_mime_message_foreach_part(message, process_message_callback, &cbinfo);
|
||||
|
||||
fclose(f);
|
||||
return cbinfo.count;
|
||||
}
|
||||
|
||||
static struct ast_str *handle_post(struct ast_tcptls_session_instance *ser, char *uri,
|
||||
int *status, char **title, int *contentlength, struct ast_variable *headers,
|
||||
struct ast_variable *cookies)
|
||||
{
|
||||
char buf;
|
||||
char buf[4096];
|
||||
FILE *f;
|
||||
size_t res;
|
||||
struct ast_variable *var;
|
||||
int content_len = 0;
|
||||
MM_CTX *ctx;
|
||||
int mm_res, i;
|
||||
struct ast_http_post_mapping *post_map;
|
||||
const char *post_dir;
|
||||
unsigned long ident = 0;
|
||||
GMimeMessage *message;
|
||||
int message_count = 0;
|
||||
|
||||
for (var = cookies; var; var = var->next) {
|
||||
if (strcasecmp(var->name, "mansession_id"))
|
||||
|
@ -445,11 +506,11 @@ static struct ast_str *handle_post(struct ast_tcptls_session_instance *ser, char
|
|||
fprintf(f, "Content-Type: %s\r\n\r\n", var->value);
|
||||
}
|
||||
|
||||
while ((res = fread(&buf, 1, 1, ser->f))) {
|
||||
fwrite(&buf, 1, 1, f);
|
||||
content_len--;
|
||||
if (!content_len)
|
||||
break;
|
||||
for(res = sizeof(buf);content_len;content_len -= res) {
|
||||
if (content_len < res)
|
||||
res = content_len;
|
||||
fread(buf, 1, res, ser->f);
|
||||
fwrite(buf, 1, res, f);
|
||||
}
|
||||
|
||||
if (fseek(f, SEEK_SET, 0)) {
|
||||
|
@ -462,7 +523,6 @@ static struct ast_str *handle_post(struct ast_tcptls_session_instance *ser, char
|
|||
if (!(post_map = find_post_mapping(uri))) {
|
||||
ast_debug(1, "%s is not a valid URI for POST\n", uri);
|
||||
AST_RWLIST_UNLOCK(&post_mappings);
|
||||
fclose(f);
|
||||
*status = 404;
|
||||
*title = ast_strdup("Not Found");
|
||||
return ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
|
||||
|
@ -473,66 +533,27 @@ static struct ast_str *handle_post(struct ast_tcptls_session_instance *ser, char
|
|||
|
||||
ast_debug(1, "Going to post files to dir %s\n", post_dir);
|
||||
|
||||
if (!(ctx = mm_context_new())) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
message = parse_message(f); /* Takes ownership and will close f */
|
||||
|
||||
mm_res = mm_parse_fileptr(ctx, f, MM_PARSE_LOOSE, 0);
|
||||
fclose(f);
|
||||
if (mm_res == -1) {
|
||||
if (!message) {
|
||||
ast_log(LOG_ERROR, "Error parsing MIME data\n");
|
||||
mm_context_free(ctx);
|
||||
*status = 400;
|
||||
*title = ast_strdup("Bad Request");
|
||||
return ast_http_error(400, "Bad Request", NULL, "The was an error parsing the request.");
|
||||
}
|
||||
|
||||
mm_res = mm_context_countparts(ctx);
|
||||
if (!mm_res) {
|
||||
if (!(message_count = process_message(message, post_dir))) {
|
||||
ast_log(LOG_ERROR, "Invalid MIME data, found no parts!\n");
|
||||
mm_context_free(ctx);
|
||||
*status = 400;
|
||||
*title = ast_strdup("Bad Request");
|
||||
return ast_http_error(400, "Bad Request", NULL, "The was an error parsing the request.");
|
||||
}
|
||||
|
||||
if (option_debug) {
|
||||
if (mm_context_iscomposite(ctx))
|
||||
ast_debug(1, "Found %d MIME parts\n", mm_res - 1);
|
||||
else
|
||||
ast_debug(1, "We have a flat (not multi-part) message\n");
|
||||
}
|
||||
|
||||
for (i = 1; i < mm_res; i++) {
|
||||
struct mm_mimepart *part;
|
||||
char fn[PATH_MAX];
|
||||
|
||||
if (!(part = mm_context_getpart(ctx, i))) {
|
||||
ast_debug(1, "Failed to get mime part num %d\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (get_filename(part, fn, sizeof(fn))) {
|
||||
ast_debug(1, "Failed to retrieve a filename for part num %d\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!part->type) {
|
||||
ast_debug(1, "This part has no content struct?\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* XXX This assumes the MIME part body is not encoded! */
|
||||
post_raw(part, post_dir, fn);
|
||||
}
|
||||
|
||||
mm_context_free(ctx);
|
||||
|
||||
*status = 200;
|
||||
*title = ast_strdup("OK");
|
||||
return ast_http_error(200, "OK", NULL, "File successfully uploaded.");
|
||||
}
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
static struct ast_str *handle_uri(struct ast_tcptls_session_instance *ser, char *uri, int *status,
|
||||
char **title, int *contentlength, struct ast_variable **cookies,
|
||||
|
@ -773,15 +794,21 @@ static void *httpd_helper_thread(void *data)
|
|||
}
|
||||
}
|
||||
|
||||
if (!*uri)
|
||||
if (!*uri) {
|
||||
out = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
|
||||
else if (!strcasecmp(buf, "post"))
|
||||
} else if (!strcasecmp(buf, "post")) {
|
||||
#ifdef ENABLE_UPLOADS
|
||||
out = handle_post(ser, uri, &status, &title, &contentlength, headers, vars);
|
||||
else if (strcasecmp(buf, "get"))
|
||||
#else
|
||||
out = ast_http_error(501, "Not Implemented", NULL,
|
||||
"Attempt to use unimplemented / unsupported method");
|
||||
else /* try to serve it */
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
} else if (strcasecmp(buf, "get")) {
|
||||
out = ast_http_error(501, "Not Implemented", NULL,
|
||||
"Attempt to use unimplemented / unsupported method");
|
||||
} else { /* try to serve it */
|
||||
out = handle_uri(ser, uri, &status, &title, &contentlength, &vars, &static_content);
|
||||
}
|
||||
|
||||
/* If they aren't mopped up already, clean up the cookies */
|
||||
if (vars)
|
||||
|
@ -887,6 +914,7 @@ static void add_redirect(const char *value)
|
|||
AST_RWLIST_UNLOCK(&uri_redirects);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UPLOADS
|
||||
static void destroy_post_mapping(struct ast_http_post_mapping *post_map)
|
||||
{
|
||||
if (post_map->from)
|
||||
|
@ -927,6 +955,7 @@ static void add_post_mapping(const char *from, const char *to)
|
|||
AST_RWLIST_INSERT_TAIL(&post_mappings, post_map, entry);
|
||||
AST_RWLIST_UNLOCK(&post_mappings);
|
||||
}
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
static int __ast_http_load(int reload)
|
||||
{
|
||||
|
@ -964,7 +993,9 @@ static int __ast_http_load(int reload)
|
|||
ast_free(redirect);
|
||||
AST_RWLIST_UNLOCK(&uri_redirects);
|
||||
|
||||
#ifdef ENABLE_UPLOADS
|
||||
destroy_post_mappings();
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
if (cfg) {
|
||||
v = ast_variable_browse(cfg, "general");
|
||||
|
@ -1013,8 +1044,10 @@ static int __ast_http_load(int reload)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_UPLOADS
|
||||
for (v = ast_variable_browse(cfg, "post_mappings"); v; v = v->next)
|
||||
add_post_mapping(v->name, v->value);
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
ast_config_destroy(cfg);
|
||||
}
|
||||
|
@ -1036,7 +1069,11 @@ static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_a
|
|||
{
|
||||
struct ast_http_uri *urih;
|
||||
struct http_uri_redirect *redirect;
|
||||
|
||||
#ifdef ENABLE_UPLOADS
|
||||
struct ast_http_post_mapping *post_map;
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "http show status";
|
||||
|
@ -1083,12 +1120,15 @@ static char *handle_show_http(struct ast_cli_entry *e, int cmd, struct ast_cli_a
|
|||
AST_RWLIST_UNLOCK(&uri_redirects);
|
||||
|
||||
|
||||
#ifdef ENABLE_UPLOADS
|
||||
ast_cli(a->fd, "\nPOST mappings:\n");
|
||||
AST_RWLIST_RDLOCK(&post_mappings);
|
||||
AST_LIST_TRAVERSE(&post_mappings, post_map, entry)
|
||||
AST_LIST_TRAVERSE(&post_mappings, post_map, entry) {
|
||||
ast_cli(a->fd, "%s/%s => %s\n", prefix, post_map->from, post_map->to);
|
||||
}
|
||||
ast_cli(a->fd, "%s\n", AST_LIST_EMPTY(&post_mappings) ? "None.\n" : "");
|
||||
AST_RWLIST_UNLOCK(&post_mappings);
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
@ -1104,8 +1144,9 @@ static struct ast_cli_entry cli_http[] = {
|
|||
|
||||
int ast_http_init(void)
|
||||
{
|
||||
mm_library_init();
|
||||
mm_codec_registerdefaultcodecs();
|
||||
#ifdef ENABLE_UPLOADS
|
||||
g_mime_init(0);
|
||||
#endif /* ENABLE_UPLOADS */
|
||||
|
||||
ast_http_uri_link(&statusuri);
|
||||
ast_http_uri_link(&staticuri);
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
CC=gcc
|
||||
PREFIX=/usr
|
||||
LIBNAME=libmmime.so.0.0
|
||||
HAVE_STRLCAT=
|
||||
HAVE_STRLCPY=
|
||||
INSTALL=/usr/bin/install
|
||||
HAVE_DEBUG=1
|
|
@ -1,67 +0,0 @@
|
|||
#
|
||||
# Asterisk -- A telephony toolkit for Linux.
|
||||
#
|
||||
# Makefile for resource modules
|
||||
#
|
||||
# Copyright (C) 2007, Digium, Inc.
|
||||
#
|
||||
# This program is free software, distributed under the terms of
|
||||
# the GNU General Public License
|
||||
#
|
||||
|
||||
-include $(ASTTOPDIR)/menuselect.makeopts $(ASTTOPDIR)/menuselect.makedeps
|
||||
|
||||
include $(ASTTOPDIR)/Makefile.moddir_rules
|
||||
|
||||
LIBMMIME:=libmmime.a
|
||||
MM_SRCS= \
|
||||
mimeparser.tab.c \
|
||||
mimeparser.yy.c \
|
||||
mm_init.c \
|
||||
mm_base64.c \
|
||||
mm_codecs.c \
|
||||
mm_contenttype.c \
|
||||
mm_context.c \
|
||||
mm_envelope.c \
|
||||
mm_error.c \
|
||||
mm_header.c \
|
||||
mm_mem.c \
|
||||
mm_mimepart.c \
|
||||
mm_mimeutil.c \
|
||||
mm_param.c \
|
||||
mm_parse.c \
|
||||
mm_util.c
|
||||
|
||||
MM_OBJS:=$(MM_SRCS:%.c=%.o)
|
||||
MM_HDRS:=mm.h mm_util.h
|
||||
|
||||
# Use weaker error checking because we have some automatically generated
|
||||
# files. However just mask out -Werror, because other warnings below:
|
||||
# -Wundef -Wstrict-prototypes -Wmissing-declarations
|
||||
# -Wmissing-prototypes
|
||||
# may actually be important and spot out real bugs.
|
||||
ASTCFLAGS:=$(filter-out -Werror,$(ASTCFLAGS))
|
||||
|
||||
ASTCFLAGS+=-std=c99
|
||||
|
||||
all: $(LIBMMIME)
|
||||
|
||||
$(LIBMMIME): $(MM_OBJS)
|
||||
$(ECHO_PREFIX) echo " [AR] $^ -> $@"
|
||||
$(CMD_PREFIX) $(AR) cr $@ $^
|
||||
$(CMD_PREFIX) $(RANLIB) $@
|
||||
|
||||
mimeparser.yy.c:
|
||||
flex -Pmimeparser_yy -omimeparser.yy.c mimeparser.l
|
||||
|
||||
mimeparser.tab.c:
|
||||
bison -d -pmimeparser_yy -omimeparser.tab.c mimeparser.y
|
||||
|
||||
clean::
|
||||
rm -f $(LIBMMIME) *.o
|
||||
|
||||
.PHONY: clean all
|
||||
|
||||
ifneq ($(wildcard .*.d),)
|
||||
include .*.d
|
||||
endif
|
|
@ -1,76 +0,0 @@
|
|||
#ifndef _MIMEPARSER_H_INCLUDED
|
||||
#define _MIMEPARSER_H_INCLUDED
|
||||
|
||||
#include "mm.h"
|
||||
|
||||
struct s_position
|
||||
{
|
||||
size_t opaque_start;
|
||||
size_t start;
|
||||
size_t end;
|
||||
};
|
||||
|
||||
struct lexer_state
|
||||
{
|
||||
int header_state;
|
||||
int lineno;
|
||||
size_t current_pos;
|
||||
int condition;
|
||||
|
||||
int is_envelope;
|
||||
|
||||
size_t message_len;
|
||||
size_t buffer_length;
|
||||
|
||||
/* temporary marker variables */
|
||||
size_t body_opaque_start;
|
||||
size_t body_start;
|
||||
size_t body_end;
|
||||
size_t preamble_start;
|
||||
size_t preamble_end;
|
||||
size_t postamble_start;
|
||||
size_t postamble_end;
|
||||
|
||||
char *boundary_string;
|
||||
char *endboundary_string;
|
||||
const char *message_buffer;
|
||||
};
|
||||
|
||||
|
||||
struct parser_state
|
||||
{
|
||||
MM_CTX *ctx;
|
||||
struct mm_mimepart *envelope;
|
||||
struct mm_mimepart *temppart;
|
||||
struct mm_mimepart *current_mimepart;
|
||||
struct mm_content *ctype;
|
||||
int parsemode;
|
||||
int have_contenttype;
|
||||
int debug;
|
||||
int mime_parts;
|
||||
struct lexer_state lstate;
|
||||
};
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
||||
#define YY_TYPEDEF_YY_SCANNER_T
|
||||
typedef void* yyscan_t;
|
||||
#endif
|
||||
|
||||
#include "mimeparser.tab.h"
|
||||
|
||||
/**
|
||||
* Prototypes for functions used by the parser routines
|
||||
*/
|
||||
int count_lines(char *);
|
||||
int dprintf2(struct parser_state *, const char *, ...);
|
||||
int mimeparser_yyparse(struct parser_state *, void *);
|
||||
int mimeparser_yylex(YYSTYPE *, void *);
|
||||
int mimeparser_yyerror(struct parser_state *, void *, const char *);
|
||||
int mimeparser_yylex_init(yyscan_t* scanner);
|
||||
int mimeparser_yylex_destroy(yyscan_t yyscanner);
|
||||
void reset_lexer_state(void *yyscanner, struct parser_state *pstate);
|
||||
int PARSER_initialize(struct parser_state *pstate, yyscan_t scanner);
|
||||
void PARSER_setbuffer(const char *string, yyscan_t scanner);
|
||||
void PARSER_setfp(FILE *fp, yyscan_t scanner);
|
||||
|
||||
#endif /* ! _MIMEPARSER_H_INCLUDED */
|
|
@ -1,484 +0,0 @@
|
|||
%{
|
||||
/*
|
||||
* Copyright (c) 2004 Jann Fischer. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a lexer file for parsing MIME compatible messages. It is intended
|
||||
* to satisfy at least RFC 2045 (Format of Internet Message Bodies). It still
|
||||
* has quite a few problems:
|
||||
*
|
||||
* - The parsing could probably be done in a more elegant way
|
||||
* - I don't know what performance impact REJECT has on the parser
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mimeparser.h"
|
||||
#include "mimeparser.tab.h"
|
||||
|
||||
#define NAMEOF(v) #v
|
||||
/* BC() is a debug wrapper for lex' BEGIN() macro */
|
||||
#define BC(x) do { \
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner); \
|
||||
BEGIN(x); \
|
||||
lstate->condition = x; \
|
||||
} while(0);
|
||||
|
||||
#define ZERO(x) memset(x, '\0', sizeof(x))
|
||||
|
||||
#define PREALLOC_BUFFER 100000
|
||||
#undef YY_BUF_SIZE
|
||||
#define YY_BUF_SIZE 65536
|
||||
|
||||
enum header_states
|
||||
{
|
||||
STATE_MAIL = 0,
|
||||
STATE_CTYPE,
|
||||
STATE_CDISP,
|
||||
STATE_CENC,
|
||||
STATE_MIME
|
||||
};
|
||||
|
||||
|
||||
|
||||
%}
|
||||
|
||||
%option reentrant
|
||||
%option yylineno
|
||||
%option bison-bridge
|
||||
|
||||
%s headers
|
||||
%s header
|
||||
%s headervalue
|
||||
%s tspecialvalue
|
||||
%s comment
|
||||
%s body
|
||||
%s postamble
|
||||
%s preamble
|
||||
%s boundary
|
||||
%s endboundary
|
||||
%s endoffile
|
||||
|
||||
STRING [a-zA-Z0-9\-\.\_]
|
||||
TSPECIAL [a-zA-Z0-9)(<>@,;:/\-.=_\+'? ]
|
||||
TSPECIAL_LITE [a-zA-Z0-9)(<>@,-._+'?\[\]]
|
||||
|
||||
%%
|
||||
|
||||
<INITIAL,headers>^[a-zA-Z]+[a-zA-Z0-9\-\_]* {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
|
||||
yylval_param->string=strdup(yytext);
|
||||
lstate->current_pos += yyleng;
|
||||
BC(header);
|
||||
|
||||
/* Depending on what header we are processing, we enter a different
|
||||
* state and return a different value.
|
||||
*/
|
||||
if (!strcasecmp(yytext, "Content-Type")) {
|
||||
lstate->header_state = STATE_CTYPE;
|
||||
return CONTENTTYPE_HEADER;
|
||||
} else if (!strcasecmp(yytext, "Content-Transfer-Encoding")) {
|
||||
lstate->header_state = STATE_CENC;
|
||||
return CONTENTENCODING_HEADER;
|
||||
} else if (!strcasecmp(yytext, "Content-Disposition")) {
|
||||
lstate->header_state = STATE_CDISP;
|
||||
return CONTENTDISPOSITION_HEADER;
|
||||
} else if (!strcasecmp(yytext, "MIME-Version")) {
|
||||
lstate->header_state = STATE_MAIL;
|
||||
return MIMEVERSION_HEADER;
|
||||
} else {
|
||||
lstate->header_state = STATE_MAIL;
|
||||
return MAIL_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
<INITIAL,headers>. {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
/* dprintf2("Unknown header char: %c\n", *yytext); */
|
||||
lstate->current_pos += yyleng;
|
||||
return ANY;
|
||||
}
|
||||
|
||||
<headers>^(\r\n|\n) {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->lineno++;
|
||||
|
||||
lstate->current_pos += yyleng;
|
||||
|
||||
/* This marks the end of headers. Depending on whether we are in the
|
||||
* envelope currently we need to parse either a body or the preamble
|
||||
* now.
|
||||
*/
|
||||
if (lstate->is_envelope == 0 || lstate->boundary_string == NULL) {
|
||||
BC(body);
|
||||
lstate->body_start = lstate->current_pos;
|
||||
} else {
|
||||
lstate->is_envelope = 0;
|
||||
lstate->preamble_start = lstate->current_pos;
|
||||
BC(preamble);
|
||||
}
|
||||
|
||||
return ENDOFHEADERS;
|
||||
}
|
||||
|
||||
<header>\: {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
BC(headervalue);
|
||||
lstate->current_pos += yyleng;
|
||||
return COLON;
|
||||
}
|
||||
|
||||
<header>(\r\n|\n) {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
BC(headers);
|
||||
/* dprintf2("Invalid header, returning EOL\n"); */
|
||||
lstate->current_pos += yyleng;
|
||||
return EOL;
|
||||
}
|
||||
|
||||
<headervalue>(\n|\r\n)[\ \t]+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
}
|
||||
|
||||
<headervalue>.+|(.+(\n|\r\n)[\ \t]+.+)+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
if (lstate->header_state != STATE_MAIL && lstate->header_state != STATE_CENC) {
|
||||
REJECT;
|
||||
}
|
||||
lstate->current_pos += yyleng;
|
||||
while (*yytext && isspace(*yytext)) yytext++;
|
||||
/* Do we actually have a header value? */
|
||||
if (*yytext == '\0') {
|
||||
yylval_param->string = strdup("");
|
||||
} else {
|
||||
yylval_param->string=strdup(yytext);
|
||||
lstate->lineno += count_lines(yytext);
|
||||
}
|
||||
return WORD;
|
||||
}
|
||||
|
||||
<headervalue,tspecialvalue>(\r\n|\n) {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
/* marks the end of one header line */
|
||||
lstate->lineno++;
|
||||
BC(headers);
|
||||
lstate->current_pos += yyleng;
|
||||
return EOL;
|
||||
}
|
||||
|
||||
<headervalue>;|;(\r\n|\n)[\ \t]+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->lineno += count_lines(yytext);
|
||||
lstate->current_pos += yyleng;
|
||||
return SEMICOLON;
|
||||
}
|
||||
|
||||
<headervalue>\= {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
return EQUAL;
|
||||
}
|
||||
|
||||
<headervalue>\" {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
BC(tspecialvalue);
|
||||
lstate->current_pos += yyleng;
|
||||
return *yytext;
|
||||
}
|
||||
|
||||
<headervalue>{STRING}+|{TSPECIAL_LITE}+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
yylval_param->string=strdup(yytext);
|
||||
lstate->lineno += count_lines(yytext);
|
||||
lstate->current_pos += yyleng;
|
||||
return WORD;
|
||||
}
|
||||
|
||||
<headervalue>[\ |\t]+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
}
|
||||
|
||||
<tspecialvalue>{TSPECIAL}+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->lineno += count_lines(yytext);
|
||||
yylval_param->string=strdup(yytext);
|
||||
lstate->current_pos += yyleng;
|
||||
return TSPECIAL;
|
||||
}
|
||||
|
||||
<tspecialvalue>\" {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
BC(headervalue);
|
||||
lstate->current_pos += yyleng;
|
||||
return *yytext;
|
||||
}
|
||||
|
||||
<body>^\-\-{TSPECIAL}+\-\- {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
/**
|
||||
* Make sure we only catch matching boundaries, and not other lines
|
||||
* that begin and end with two dashes. If we have catched a valid
|
||||
* end boundary, which actually ends a body, we save the current
|
||||
* position, put the token back on the input stream and let the
|
||||
* endboundary condition parse the actual token.
|
||||
*/
|
||||
if (lstate->endboundary_string != NULL) {
|
||||
if (strcmp(lstate->endboundary_string, yytext)) {
|
||||
/* dprintf2("YYTEXT != end_boundary: '%s'\n", yytext); */
|
||||
REJECT;
|
||||
} else {
|
||||
lstate->current_pos += yyleng;
|
||||
/* dprintf2("YYTEXT == lstate->end_boundary: '%s'\n", yytext); */
|
||||
if (lstate->body_start) {
|
||||
yylval_param->position.opaque_start =
|
||||
lstate->body_opaque_start;
|
||||
yylval_param->position.start = lstate->body_start;
|
||||
yylval_param->position.end = lstate->current_pos - yyleng;
|
||||
lstate->body_opaque_start = 0;
|
||||
lstate->body_start = 0;
|
||||
lstate->body_end = 0;
|
||||
yyless(0);
|
||||
BC(endboundary);
|
||||
return BODY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
REJECT;
|
||||
}
|
||||
|
||||
<body,preamble>^\-\-{TSPECIAL}+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
/**
|
||||
* Make sure we only catch matching boundaries, and not other lines
|
||||
* that begin with two dashes.
|
||||
*/
|
||||
if (lstate->boundary_string != NULL) {
|
||||
if (strcmp(lstate->boundary_string, yytext)) {
|
||||
/* dprintf2("YYTEXT != boundary: '%s'\n", yytext);*/
|
||||
REJECT;
|
||||
} else {
|
||||
/* dprintf2("YYTEXT == boundary: '%s'\n", yytext);*/
|
||||
if (lstate->body_start) {
|
||||
yylval_param->position.opaque_start = lstate->body_opaque_start;
|
||||
yylval_param->position.start = lstate->body_start;
|
||||
yylval_param->position.end = lstate->current_pos;
|
||||
lstate->body_opaque_start = 0;
|
||||
lstate->body_start = 0;
|
||||
lstate->body_end = 0;
|
||||
yyless(0);
|
||||
BC(boundary);
|
||||
return BODY;
|
||||
} else if (lstate->preamble_start) {
|
||||
yylval_param->position.start = lstate->preamble_start;
|
||||
yylval_param->position.end = lstate->current_pos;
|
||||
lstate->preamble_start = lstate->preamble_end = 0;
|
||||
yyless(0);
|
||||
BC(boundary);
|
||||
return PREAMBLE;
|
||||
} else {
|
||||
BC(boundary);
|
||||
yylval_param->string = strdup(yytext);
|
||||
lstate->current_pos += yyleng;
|
||||
return(BOUNDARY);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
REJECT;
|
||||
}
|
||||
|
||||
<body>(\r\n|\n) {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
lstate->lineno++;
|
||||
}
|
||||
|
||||
<body>\r {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
/* dprintf2("stray CR in body...\n"); */
|
||||
}
|
||||
|
||||
<body>[^\r\n]+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
}
|
||||
|
||||
<body><<EOF>> {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
if (lstate->boundary_string == NULL && lstate->body_start) {
|
||||
yylval_param->position.opaque_start = 0;
|
||||
yylval_param->position.start = lstate->body_start;
|
||||
yylval_param->position.end = lstate->current_pos;
|
||||
lstate->body_start = 0;
|
||||
return BODY;
|
||||
} else if (lstate->body_start) {
|
||||
return POSTAMBLE;
|
||||
}
|
||||
yyterminate();
|
||||
}
|
||||
|
||||
<preamble,postamble>(\r\n|\n) {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
/* dprintf2("Preamble CR/LF at line %d\n", lineno); */
|
||||
lstate->lineno++;
|
||||
lstate->current_pos += yyleng;
|
||||
}
|
||||
|
||||
<boundary>[^\r\n]+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
yylval_param->string = strdup(yytext);
|
||||
lstate->current_pos += yyleng;
|
||||
return BOUNDARY;
|
||||
}
|
||||
|
||||
<endboundary>[^\r\n]+ {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
yylval_param->string = strdup(yytext);
|
||||
lstate->current_pos += yyleng;
|
||||
return ENDBOUNDARY;
|
||||
}
|
||||
|
||||
<boundary>(\r\n|\n) {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
BC(headers);
|
||||
lstate->lineno++;
|
||||
lstate->current_pos += yyleng;
|
||||
lstate->body_opaque_start = lstate->current_pos;
|
||||
return EOL;
|
||||
}
|
||||
|
||||
<endboundary>(\r\n|\n) {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
BC(postamble);
|
||||
lstate->lineno++;
|
||||
lstate->current_pos += yyleng;
|
||||
}
|
||||
|
||||
<preamble>. {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
}
|
||||
|
||||
|
||||
<postamble>. {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
}
|
||||
|
||||
(\r\n|\n) {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->lineno++;
|
||||
lstate->current_pos += yyleng;
|
||||
return EOL;
|
||||
}
|
||||
|
||||
. {
|
||||
struct lexer_state *lstate = yyget_extra(yyscanner);
|
||||
lstate->current_pos += yyleng;
|
||||
return((int)*yytext);
|
||||
}
|
||||
|
||||
|
||||
%%
|
||||
|
||||
void reset_lexer_state(void *yyscanner, struct parser_state *pstate)
|
||||
{
|
||||
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
|
||||
struct lexer_state *lstate = &(pstate->lstate);
|
||||
|
||||
yyset_extra((void*)lstate, yyscanner);
|
||||
BEGIN(0);
|
||||
lstate->header_state = STATE_MAIL;
|
||||
lstate->lineno = 0;
|
||||
lstate->current_pos = 1;
|
||||
lstate->condition = 0;
|
||||
|
||||
lstate->is_envelope = 1;
|
||||
|
||||
lstate->message_len = 0;
|
||||
lstate->buffer_length = 0;
|
||||
|
||||
/* temporary marker variables */
|
||||
lstate->body_opaque_start = 0;
|
||||
lstate->body_start = 0;
|
||||
lstate->body_end = 0;
|
||||
lstate->preamble_start = 0;
|
||||
lstate->preamble_end = 0;
|
||||
lstate->postamble_start = 0;
|
||||
lstate->postamble_end = 0;
|
||||
}
|
||||
|
||||
void
|
||||
PARSER_setbuffer(const char *string, yyscan_t scanner)
|
||||
{
|
||||
struct lexer_state *lstate = yyget_extra(scanner);
|
||||
lstate->message_buffer = string;
|
||||
yy_scan_string(string, scanner);
|
||||
}
|
||||
|
||||
void
|
||||
PARSER_setfp(FILE *fp, yyscan_t scanner)
|
||||
{
|
||||
/* looks like a bug in bison 2.2a -- the wrong code is generated for yyset_in !! */
|
||||
struct yyguts_t * yyg = (struct yyguts_t*) scanner;
|
||||
yyg->yyin_r = fp;
|
||||
|
||||
if (0) {
|
||||
/* This is just to make a compiler warning go away */
|
||||
yyunput(0, NULL, scanner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts how many lines a given string represents in the message (in case of
|
||||
* folded header values, for example, or a message body).
|
||||
*/
|
||||
int
|
||||
count_lines(char *txt)
|
||||
{
|
||||
char *o;
|
||||
int line;
|
||||
|
||||
line = 0;
|
||||
|
||||
for (o = txt; *o != '\0'; o++)
|
||||
if (*o == '\n')
|
||||
line++;
|
||||
|
||||
return line;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,112 +0,0 @@
|
|||
/* A Bison parser, made by GNU Bison 2.3. */
|
||||
|
||||
/* Skeleton interface for Bison's Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
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; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
ANY = 258,
|
||||
COLON = 259,
|
||||
DASH = 260,
|
||||
DQUOTE = 261,
|
||||
ENDOFHEADERS = 262,
|
||||
EOL = 263,
|
||||
EOM = 264,
|
||||
EQUAL = 265,
|
||||
MIMEVERSION_HEADER = 266,
|
||||
SEMICOLON = 267,
|
||||
CONTENTDISPOSITION_HEADER = 268,
|
||||
CONTENTENCODING_HEADER = 269,
|
||||
CONTENTTYPE_HEADER = 270,
|
||||
MAIL_HEADER = 271,
|
||||
HEADERVALUE = 272,
|
||||
BOUNDARY = 273,
|
||||
ENDBOUNDARY = 274,
|
||||
CONTENTTYPE_VALUE = 275,
|
||||
TSPECIAL = 276,
|
||||
WORD = 277,
|
||||
BODY = 278,
|
||||
PREAMBLE = 279,
|
||||
POSTAMBLE = 280
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
#define ANY 258
|
||||
#define COLON 259
|
||||
#define DASH 260
|
||||
#define DQUOTE 261
|
||||
#define ENDOFHEADERS 262
|
||||
#define EOL 263
|
||||
#define EOM 264
|
||||
#define EQUAL 265
|
||||
#define MIMEVERSION_HEADER 266
|
||||
#define SEMICOLON 267
|
||||
#define CONTENTDISPOSITION_HEADER 268
|
||||
#define CONTENTENCODING_HEADER 269
|
||||
#define CONTENTTYPE_HEADER 270
|
||||
#define MAIL_HEADER 271
|
||||
#define HEADERVALUE 272
|
||||
#define BOUNDARY 273
|
||||
#define ENDBOUNDARY 274
|
||||
#define CONTENTTYPE_VALUE 275
|
||||
#define TSPECIAL 276
|
||||
#define WORD 277
|
||||
#define BODY 278
|
||||
#define PREAMBLE 279
|
||||
#define POSTAMBLE 280
|
||||
|
||||
|
||||
|
||||
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
typedef union YYSTYPE
|
||||
#line 67 "mimeparser.y"
|
||||
{
|
||||
int number;
|
||||
char *string;
|
||||
struct s_position position;
|
||||
}
|
||||
/* Line 1489 of yacc.c. */
|
||||
#line 105 "mimeparser.tab.h"
|
||||
YYSTYPE;
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1,748 +0,0 @@
|
|||
%{
|
||||
/*
|
||||
* Copyright (c) 2004 Jann Fischer. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* These are the grammatic definitions in yacc syntax to parse MIME conform
|
||||
* messages.
|
||||
*
|
||||
* TODO:
|
||||
* - honour parse flags passed to us (partly done)
|
||||
* - parse Content-Disposition header (partly done)
|
||||
* - parse Content-Encoding header
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mimeparser.h"
|
||||
#include "mm.h"
|
||||
#include "mm_internal.h"
|
||||
|
||||
int set_boundary(char *,struct parser_state *);
|
||||
int mimeparser_yywrap(void);
|
||||
void reset_environ(struct parser_state *pstate);
|
||||
int PARSER_initialize(struct parser_state *pstate, void *yyscanner);
|
||||
|
||||
static char *PARSE_readmessagepart(size_t, size_t, size_t, size_t *,yyscan_t, struct parser_state *);
|
||||
FILE *mimeparser_yyget_in (yyscan_t yyscanner );
|
||||
|
||||
%}
|
||||
|
||||
%pure-parser
|
||||
%parse-param {struct parser_state *pstate}
|
||||
%parse-param {void *yyscanner}
|
||||
%lex-param {void *yyscanner}
|
||||
|
||||
%union
|
||||
{
|
||||
int number;
|
||||
char *string;
|
||||
struct s_position position;
|
||||
}
|
||||
|
||||
%token ANY
|
||||
%token COLON
|
||||
%token DASH
|
||||
%token DQUOTE
|
||||
%token ENDOFHEADERS
|
||||
%token EOL
|
||||
%token EOM
|
||||
%token EQUAL
|
||||
%token MIMEVERSION_HEADER
|
||||
%token SEMICOLON
|
||||
|
||||
%token <string> CONTENTDISPOSITION_HEADER
|
||||
%token <string> CONTENTENCODING_HEADER
|
||||
%token <string> CONTENTTYPE_HEADER
|
||||
%token <string> MAIL_HEADER
|
||||
%token <string> HEADERVALUE
|
||||
%token <string> BOUNDARY
|
||||
%token <string> ENDBOUNDARY
|
||||
%token <string> CONTENTTYPE_VALUE
|
||||
%token <string> TSPECIAL
|
||||
%token <string> WORD
|
||||
|
||||
%token <position> BODY
|
||||
%token <position> PREAMBLE
|
||||
%token <position> POSTAMBLE
|
||||
|
||||
%type <string> content_disposition
|
||||
%type <string> contenttype_parameter_value
|
||||
%type <string> mimetype
|
||||
%type <string> body
|
||||
|
||||
%start message
|
||||
|
||||
%%
|
||||
|
||||
/* This is a parser for a MIME-conform message, which is in either single
|
||||
* part or multi part format.
|
||||
*/
|
||||
message :
|
||||
multipart_message
|
||||
|
|
||||
singlepart_message
|
||||
;
|
||||
|
||||
multipart_message:
|
||||
headers preamble
|
||||
{
|
||||
mm_context_attachpart(pstate->ctx, pstate->current_mimepart);
|
||||
pstate->current_mimepart = mm_mimepart_new();
|
||||
pstate->have_contenttype = 0;
|
||||
}
|
||||
mimeparts endboundary postamble
|
||||
{
|
||||
dprintf2(pstate,"This was a multipart message\n");
|
||||
}
|
||||
;
|
||||
|
||||
singlepart_message:
|
||||
headers body
|
||||
{
|
||||
dprintf2(pstate,"This was a single part message\n");
|
||||
mm_context_attachpart(pstate->ctx, pstate->current_mimepart);
|
||||
}
|
||||
;
|
||||
|
||||
headers :
|
||||
header headers
|
||||
|
|
||||
end_headers
|
||||
{
|
||||
/* If we did not find a Content-Type header for the current
|
||||
* MIME part (or envelope), we create one and attach it.
|
||||
* According to the RFC, a type of "text/plain" and a
|
||||
* charset of "us-ascii" can be assumed.
|
||||
*/
|
||||
struct mm_content *ct;
|
||||
struct mm_param *param;
|
||||
|
||||
if (!pstate->have_contenttype) {
|
||||
ct = mm_content_new();
|
||||
mm_content_settype(ct, "text/plain");
|
||||
|
||||
param = mm_param_new();
|
||||
param->name = xstrdup("charset");
|
||||
param->value = xstrdup("us-ascii");
|
||||
|
||||
mm_content_attachtypeparam(ct, param);
|
||||
mm_mimepart_attachcontenttype(pstate->current_mimepart, ct);
|
||||
}
|
||||
pstate->have_contenttype = 0;
|
||||
}
|
||||
|
|
||||
header
|
||||
;
|
||||
|
||||
preamble:
|
||||
PREAMBLE
|
||||
{
|
||||
char *preamble;
|
||||
size_t offset;
|
||||
|
||||
if ($1.start != $1.end) {
|
||||
preamble = PARSE_readmessagepart(0, $1.start, $1.end,
|
||||
&offset,yyscanner,pstate);
|
||||
if (preamble == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
pstate->ctx->preamble = preamble;
|
||||
dprintf2(pstate,"PREAMBLE:\n%s\n", preamble);
|
||||
}
|
||||
}
|
||||
|
|
||||
;
|
||||
|
||||
postamble:
|
||||
POSTAMBLE
|
||||
{
|
||||
}
|
||||
|
|
||||
;
|
||||
|
||||
mimeparts:
|
||||
mimeparts mimepart
|
||||
|
|
||||
mimepart
|
||||
;
|
||||
|
||||
mimepart:
|
||||
boundary headers body
|
||||
{
|
||||
|
||||
if (mm_context_attachpart(pstate->ctx, pstate->current_mimepart) == -1) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
pstate->temppart = mm_mimepart_new();
|
||||
pstate->current_mimepart = pstate->temppart;
|
||||
pstate->mime_parts++;
|
||||
}
|
||||
;
|
||||
|
||||
header :
|
||||
mail_header
|
||||
|
|
||||
contenttype_header
|
||||
{
|
||||
pstate->have_contenttype = 1;
|
||||
if (mm_content_iscomposite(pstate->envelope->type)) {
|
||||
pstate->ctx->messagetype = MM_MSGTYPE_MULTIPART;
|
||||
} else {
|
||||
pstate->ctx->messagetype = MM_MSGTYPE_FLAT;
|
||||
}
|
||||
}
|
||||
|
|
||||
contentdisposition_header
|
||||
|
|
||||
contentencoding_header
|
||||
|
|
||||
mimeversion_header
|
||||
|
|
||||
invalid_header
|
||||
{
|
||||
if (pstate->parsemode != MM_PARSE_LOOSE) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("invalid header encountered");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
} else {
|
||||
/* TODO: attach MM_WARNING_INVHDR */
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
mail_header:
|
||||
MAIL_HEADER COLON WORD EOL
|
||||
{
|
||||
struct mm_mimeheader *hdr;
|
||||
hdr = mm_mimeheader_generate($1, $3);
|
||||
mm_mimepart_attachheader(pstate->current_mimepart, hdr);
|
||||
}
|
||||
|
|
||||
MAIL_HEADER COLON EOL
|
||||
{
|
||||
struct mm_mimeheader *hdr;
|
||||
|
||||
if (pstate->parsemode != MM_PARSE_LOOSE) {
|
||||
mm_errno = MM_ERROR_MIME;
|
||||
mm_error_setmsg("invalid header encountered");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
} else {
|
||||
/* TODO: attach MM_WARNING_INVHDR */
|
||||
}
|
||||
|
||||
hdr = mm_mimeheader_generate($1, xstrdup(""));
|
||||
mm_mimepart_attachheader(pstate->current_mimepart, hdr);
|
||||
}
|
||||
;
|
||||
|
||||
contenttype_header:
|
||||
CONTENTTYPE_HEADER COLON mimetype EOL
|
||||
{
|
||||
mm_content_settype(pstate->ctype, "%s", $3);
|
||||
mm_mimepart_attachcontenttype(pstate->current_mimepart, pstate->ctype);
|
||||
dprintf2(pstate,"Content-Type -> %s\n", $3);
|
||||
pstate->ctype = mm_content_new();
|
||||
}
|
||||
|
|
||||
CONTENTTYPE_HEADER COLON mimetype contenttype_parameters EOL
|
||||
{
|
||||
mm_content_settype(pstate->ctype, "%s", $3);
|
||||
mm_mimepart_attachcontenttype(pstate->current_mimepart, pstate->ctype);
|
||||
dprintf2(pstate,"Content-Type (P) -> %s\n", $3);
|
||||
pstate->ctype = mm_content_new();
|
||||
}
|
||||
;
|
||||
|
||||
contentdisposition_header:
|
||||
CONTENTDISPOSITION_HEADER COLON content_disposition EOL
|
||||
{
|
||||
dprintf2(pstate,"Content-Disposition -> %s\n", $3);
|
||||
pstate->ctype->disposition_type = xstrdup($3);
|
||||
}
|
||||
|
|
||||
CONTENTDISPOSITION_HEADER COLON content_disposition content_disposition_parameters EOL
|
||||
{
|
||||
dprintf2(pstate,"Content-Disposition (P) -> %s; params\n", $3);
|
||||
pstate->ctype->disposition_type = xstrdup($3);
|
||||
}
|
||||
;
|
||||
|
||||
content_disposition:
|
||||
WORD
|
||||
{
|
||||
/*
|
||||
* According to RFC 2183, the content disposition value may
|
||||
* only be "inline", "attachment" or an extension token. We
|
||||
* catch invalid values here if we are not in loose parsing
|
||||
* mode.
|
||||
*/
|
||||
if (strcasecmp($1, "inline") && strcasecmp($1, "attachment")
|
||||
&& strncasecmp($1, "X-", 2)) {
|
||||
if (pstate->parsemode != MM_PARSE_LOOSE) {
|
||||
mm_errno = MM_ERROR_MIME;
|
||||
mm_error_setmsg("invalid content-disposition");
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
/* TODO: attach MM_WARNING_INVHDR */
|
||||
}
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
contentencoding_header:
|
||||
CONTENTENCODING_HEADER COLON WORD EOL
|
||||
{
|
||||
dprintf2(pstate,"Content-Transfer-Encoding -> %s\n", $3);
|
||||
}
|
||||
;
|
||||
|
||||
mimeversion_header:
|
||||
MIMEVERSION_HEADER COLON WORD EOL
|
||||
{
|
||||
dprintf2(pstate,"MIME-Version -> '%s'\n", $3);
|
||||
}
|
||||
;
|
||||
|
||||
invalid_header:
|
||||
any EOL
|
||||
;
|
||||
|
||||
any:
|
||||
any ANY
|
||||
|
|
||||
ANY
|
||||
;
|
||||
|
||||
mimetype:
|
||||
WORD '/' WORD
|
||||
{
|
||||
char type[255];
|
||||
snprintf(type, sizeof(type), "%s/%s", $1, $3);
|
||||
$$ = type;
|
||||
}
|
||||
;
|
||||
|
||||
contenttype_parameters:
|
||||
SEMICOLON contenttype_parameter contenttype_parameters
|
||||
|
|
||||
SEMICOLON contenttype_parameter
|
||||
|
|
||||
SEMICOLON
|
||||
{
|
||||
if (pstate->parsemode != MM_PARSE_LOOSE) {
|
||||
mm_errno = MM_ERROR_MIME;
|
||||
mm_error_setmsg("invalid Content-Type header");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
} else {
|
||||
/* TODO: attach MM_WARNING_INVHDR */
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
content_disposition_parameters:
|
||||
SEMICOLON content_disposition_parameter content_disposition_parameters
|
||||
|
|
||||
SEMICOLON content_disposition_parameter
|
||||
|
|
||||
SEMICOLON
|
||||
{
|
||||
if (pstate->parsemode != MM_PARSE_LOOSE) {
|
||||
mm_errno = MM_ERROR_MIME;
|
||||
mm_error_setmsg("invalid Content-Disposition header");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
} else {
|
||||
/* TODO: attach MM_WARNING_INVHDR */
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
contenttype_parameter:
|
||||
WORD EQUAL contenttype_parameter_value
|
||||
{
|
||||
struct mm_param *param;
|
||||
param = mm_param_new();
|
||||
|
||||
dprintf2(pstate,"Param: '%s', Value: '%s'\n", $1, $3);
|
||||
|
||||
/* Catch an eventual boundary identifier */
|
||||
if (!strcasecmp($1, "boundary")) {
|
||||
if (pstate->lstate.boundary_string == NULL) {
|
||||
set_boundary($3,pstate);
|
||||
} else {
|
||||
if (pstate->parsemode != MM_PARSE_LOOSE) {
|
||||
mm_errno = MM_ERROR_MIME;
|
||||
mm_error_setmsg("duplicate boundary "
|
||||
"found");
|
||||
return -1;
|
||||
} else {
|
||||
/* TODO: attach MM_WARNING_DUPPARAM */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
param->name = xstrdup($1);
|
||||
param->value = xstrdup($3);
|
||||
|
||||
mm_content_attachtypeparam(pstate->ctype, param);
|
||||
}
|
||||
;
|
||||
|
||||
content_disposition_parameter:
|
||||
WORD EQUAL contenttype_parameter_value
|
||||
{
|
||||
struct mm_param *param;
|
||||
param = mm_param_new();
|
||||
|
||||
param->name = xstrdup($1);
|
||||
param->value = xstrdup($3);
|
||||
|
||||
mm_content_attachdispositionparam(pstate->ctype, param);
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
contenttype_parameter_value:
|
||||
WORD
|
||||
{
|
||||
dprintf2(pstate,"contenttype_param_val: WORD=%s\n", $1);
|
||||
$$ = $1;
|
||||
}
|
||||
|
|
||||
TSPECIAL
|
||||
{
|
||||
dprintf2(pstate,"contenttype_param_val: TSPECIAL\n");
|
||||
/* For broken MIME implementation */
|
||||
if (pstate->parsemode != MM_PARSE_LOOSE) {
|
||||
mm_errno = MM_ERROR_MIME;
|
||||
mm_error_setmsg("tspecial without quotes");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
} else {
|
||||
/* TODO: attach MM_WARNING_INVAL */
|
||||
}
|
||||
$$ = $1;
|
||||
}
|
||||
|
|
||||
'"' TSPECIAL '"'
|
||||
{
|
||||
dprintf2(pstate,"contenttype_param_val: \"TSPECIAL\"\n" );
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
end_headers :
|
||||
ENDOFHEADERS
|
||||
{
|
||||
dprintf2(pstate,"End of headers at line %d\n", pstate->lstate.lineno);
|
||||
}
|
||||
;
|
||||
|
||||
boundary :
|
||||
BOUNDARY EOL
|
||||
{
|
||||
if (pstate->lstate.boundary_string == NULL) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("internal incosistency");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
}
|
||||
if (strcmp(pstate->lstate.boundary_string, $1)) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("invalid boundary: '%s' (%d)", $1, strlen($1));
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
}
|
||||
dprintf2(pstate,"New MIME part... (%s)\n", $1);
|
||||
}
|
||||
;
|
||||
|
||||
endboundary :
|
||||
ENDBOUNDARY
|
||||
{
|
||||
if (pstate->lstate.endboundary_string == NULL) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("internal incosistency");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
}
|
||||
if (strcmp(pstate->lstate.endboundary_string, $1)) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("invalid end boundary: %s", $1);
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(-1);
|
||||
}
|
||||
dprintf2(pstate,"End of MIME message\n");
|
||||
}
|
||||
;
|
||||
|
||||
body:
|
||||
BODY
|
||||
{
|
||||
char *body;
|
||||
size_t offset;
|
||||
|
||||
dprintf2(pstate,"BODY (%d/%d), SIZE %d\n", $1.start, $1.end, $1.end - $1.start);
|
||||
|
||||
body = PARSE_readmessagepart($1.opaque_start, $1.start, $1.end,
|
||||
&offset,yyscanner,pstate);
|
||||
|
||||
if (body == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
pstate->current_mimepart->opaque_body = body;
|
||||
pstate->current_mimepart->body = body + offset;
|
||||
pstate->current_mimepart->opaque_length = $1.end - $1.start - 2 + offset;
|
||||
pstate->current_mimepart->length = pstate->current_mimepart->opaque_length - offset;
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
/*
|
||||
* This function gets the specified part from the currently parsed message.
|
||||
*/
|
||||
static char *
|
||||
PARSE_readmessagepart(size_t opaque_start, size_t real_start, size_t end,
|
||||
size_t *offset, yyscan_t yyscanner, struct parser_state *pstate)
|
||||
{
|
||||
size_t body_size;
|
||||
size_t current;
|
||||
size_t start;
|
||||
char *body;
|
||||
|
||||
/* calculate start and offset markers for the opaque and
|
||||
* header stripped body message.
|
||||
*/
|
||||
if (opaque_start > 0) {
|
||||
/* Multipart message */
|
||||
if (real_start) {
|
||||
if (real_start < opaque_start) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("internal incosistency (S:%d/O:%d)",
|
||||
real_start,
|
||||
opaque_start);
|
||||
return(NULL);
|
||||
}
|
||||
start = opaque_start;
|
||||
*offset = real_start - start;
|
||||
/* Flat message */
|
||||
} else {
|
||||
start = opaque_start;
|
||||
*offset = 0;
|
||||
}
|
||||
} else {
|
||||
start = real_start;
|
||||
*offset = 0;
|
||||
}
|
||||
|
||||
/* The next three cases should NOT happen anytime */
|
||||
if (end <= start) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("internal incosistency,2");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(NULL);
|
||||
}
|
||||
if (start < *offset) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("internal incosistency, S:%d,O:%d,L:%d", start, offset, pstate->lstate.lineno);
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(NULL);
|
||||
}
|
||||
if (start < 0 || end < 0) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("internal incosistency,4");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* XXX: do we want to enforce a maximum body size? make it a
|
||||
* parser option? */
|
||||
|
||||
/* Read in the body message */
|
||||
body_size = end - start;
|
||||
|
||||
if (body_size < 1) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("size of body cannot be < 1");
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
body = (char *)malloc(body_size + 1);
|
||||
if (body == NULL) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Get the message body either from a stream or a memory
|
||||
* buffer.
|
||||
*/
|
||||
if (mimeparser_yyget_in(yyscanner) != NULL) {
|
||||
FILE *x = mimeparser_yyget_in(yyscanner);
|
||||
current = ftell(x);
|
||||
fseek(x, start - 1, SEEK_SET);
|
||||
fread(body, body_size - 1, 1, x);
|
||||
fseek(x, current, SEEK_SET);
|
||||
} else if (pstate->lstate.message_buffer != NULL) {
|
||||
strlcpy(body, pstate->lstate.message_buffer + start - 1, body_size);
|
||||
}
|
||||
|
||||
return(body);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
yyerror(struct parser_state *pstate, void *yyscanner, const char *str)
|
||||
{
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("%s", str);
|
||||
mm_error_setlineno(pstate->lstate.lineno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
mimeparser_yywrap(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the boundary value for the current message
|
||||
*/
|
||||
int
|
||||
set_boundary(char *str, struct parser_state *pstate)
|
||||
{
|
||||
size_t blen;
|
||||
|
||||
blen = strlen(str);
|
||||
|
||||
pstate->lstate.boundary_string = (char *)malloc(blen + 3);
|
||||
pstate->lstate.endboundary_string = (char *)malloc(blen + 5);
|
||||
|
||||
if (pstate->lstate.boundary_string == NULL || pstate->lstate.endboundary_string == NULL) {
|
||||
if (pstate->lstate.boundary_string != NULL) {
|
||||
free(pstate->lstate.boundary_string);
|
||||
}
|
||||
if (pstate->lstate.endboundary_string != NULL) {
|
||||
free(pstate->lstate.endboundary_string);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
pstate->ctx->boundary = xstrdup(str);
|
||||
|
||||
snprintf(pstate->lstate.boundary_string, blen + 3, "--%s", str);
|
||||
snprintf(pstate->lstate.endboundary_string, blen + 5, "--%s--", str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug printf()
|
||||
*/
|
||||
int
|
||||
dprintf2(struct parser_state *pstate, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *msg;
|
||||
if (pstate->debug == 0) return 1;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vasprintf(&msg, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr, "%s", msg);
|
||||
free(msg);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void reset_environ(struct parser_state *pstate)
|
||||
{
|
||||
pstate->lstate.lineno = 0;
|
||||
pstate->lstate.boundary_string = NULL;
|
||||
pstate->lstate.endboundary_string = NULL;
|
||||
pstate->lstate.message_buffer = NULL;
|
||||
pstate->mime_parts = 0;
|
||||
pstate->debug = 0;
|
||||
pstate->envelope = NULL;
|
||||
pstate->temppart = NULL;
|
||||
pstate->ctype = NULL;
|
||||
pstate->current_mimepart = NULL;
|
||||
|
||||
pstate->have_contenttype = 0;
|
||||
}
|
||||
/**
|
||||
* Initializes the parser engine.
|
||||
*/
|
||||
int
|
||||
PARSER_initialize(struct parser_state *pstate, void *yyscanner)
|
||||
{
|
||||
void reset_lexer_state(void *yyscanner, struct parser_state *);
|
||||
#if 0
|
||||
if (pstate->ctx != NULL) {
|
||||
xfree(pstate->ctx);
|
||||
pstate->ctx = NULL;
|
||||
}
|
||||
if (pstate->envelope != NULL) {
|
||||
xfree(pstate->envelope);
|
||||
pstate->envelope = NULL;
|
||||
}
|
||||
if (pstate->ctype != NULL) {
|
||||
xfree(pstate->ctype);
|
||||
pstate->ctype = NULL;
|
||||
}
|
||||
#endif
|
||||
/* yydebug = 1; */
|
||||
reset_environ(pstate);
|
||||
reset_lexer_state(yyscanner,pstate);
|
||||
|
||||
pstate->envelope = mm_mimepart_new();
|
||||
pstate->current_mimepart = pstate->envelope;
|
||||
pstate->ctype = mm_content_new();
|
||||
|
||||
pstate->have_contenttype = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,244 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2004 Jann Fischer. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MiniMIME test program
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "mm.h"
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"MiniMIME test suite\n"
|
||||
"Usage: ./minimime [-m] <filename>\n\n"
|
||||
" -m : use memory based scanning\n\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
MM_CTX *ctx;
|
||||
struct mm_mimeheader *header, *lastheader;
|
||||
struct mm_warning *lastwarning;
|
||||
struct mm_mimepart *part;
|
||||
struct mm_content *ct;
|
||||
int parts, i;
|
||||
struct stat st;
|
||||
int fd;
|
||||
char *buf;
|
||||
int scan_mode = 0;
|
||||
|
||||
lastheader = NULL;
|
||||
|
||||
while ((i = getopt(argc, argv, "m")) != -1) {
|
||||
switch(i) {
|
||||
case 'm':
|
||||
scan_mode = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
#ifdef __HAVE_LEAK_DETECTION
|
||||
/* Initialize memory leak detection if compiled in */
|
||||
MM_leakd_init();
|
||||
#endif
|
||||
|
||||
/* Initialize MiniMIME library */
|
||||
mm_library_init();
|
||||
|
||||
/* Register all default codecs (base64/qp) */
|
||||
mm_codec_registerdefaultcodecs();
|
||||
|
||||
do {
|
||||
/* Create a new context */
|
||||
ctx = mm_context_new();
|
||||
|
||||
/* Parse a file into our context */
|
||||
if (scan_mode == 0) {
|
||||
i = mm_parse_file(ctx, argv[0], MM_PARSE_LOOSE, 0);
|
||||
} else {
|
||||
if (stat(argv[0], &st) == -1) {
|
||||
fprintf(stderr, "INFO: stat");
|
||||
}
|
||||
|
||||
if ((fd = open(argv[0], O_RDONLY)) == -1) {
|
||||
fdprintf(stderr, "INFO: open");
|
||||
}
|
||||
|
||||
buf = (char *)malloc(st.st_size);
|
||||
if (buf == NULL) {
|
||||
fdprintf(stderr, "INFO: malloc");
|
||||
}
|
||||
|
||||
if (read(fd, buf, st.st_size) != st.st_size) {
|
||||
fdprintf(stderr, "INFO: read");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
buf[st.st_size] = '\0';
|
||||
|
||||
i = mm_parse_mem(ctx, buf, MM_PARSE_LOOSE, 0);
|
||||
}
|
||||
|
||||
if (i == -1 || mm_errno != MM_ERROR_NONE) {
|
||||
printf("ERROR: %s at line %d\n", mm_error_string(), mm_error_lineno());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the number of MIME parts */
|
||||
parts = mm_context_countparts(ctx);
|
||||
if (parts == 0) {
|
||||
printf("ERROR: got zero MIME parts, huh\n");
|
||||
exit(1);
|
||||
} else {
|
||||
if (mm_context_iscomposite(ctx)) {
|
||||
printf("Got %d MIME parts\n", parts - 1);
|
||||
} else {
|
||||
printf("Flat message (not multipart)\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the main MIME part */
|
||||
part = mm_context_getpart(ctx, 0);
|
||||
if (part == NULL) {
|
||||
fprintf(stderr, "Could not get envelope part\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Printing envelope headers:\n");
|
||||
/* Print all headers */
|
||||
if (mm_mimepart_headers_start(part, &lastheader) == -1) {
|
||||
fprintf(stderr, "No headers in envelope\n");
|
||||
exit(1);
|
||||
}
|
||||
while ((header = mm_mimepart_headers_next(part, &lastheader)) != NULL) {
|
||||
printf("%s: %s\n", header->name, header->value);
|
||||
}
|
||||
|
||||
printf("%s\n", mm_content_tostring(part->type));
|
||||
printf("\n");
|
||||
|
||||
ct = part->type;
|
||||
assert(ct != NULL);
|
||||
|
||||
if (mm_context_iscomposite(ctx) == 0) {
|
||||
printf("Printing body part for FLAT message:\n");
|
||||
part = mm_context_getpart(ctx, 0);
|
||||
printf("%s", part->body);
|
||||
}
|
||||
|
||||
/* Loop through all MIME parts beginning with 1 */
|
||||
for (i = 1; i < mm_context_countparts(ctx); i++) {
|
||||
char *decoded;
|
||||
|
||||
printf("Printing headers for MIME part %d\n", i);
|
||||
|
||||
/* Get the current MIME entity */
|
||||
part = mm_context_getpart(ctx, i);
|
||||
if (part == NULL) {
|
||||
fprintf(stderr, "Should have %d parts but "
|
||||
"couldn't retrieve part %d",
|
||||
mm_context_countparts(ctx), i);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Print all headers */
|
||||
if (mm_mimepart_headers_start(part, &lastheader) == -1) {
|
||||
printf("Ups no headers\n");
|
||||
}
|
||||
while ((header = mm_mimepart_headers_next(part, &lastheader)) != NULL) {
|
||||
printf("%s: %s\n", header->name, header->value);
|
||||
}
|
||||
|
||||
printf("Part Type: %s\n", mm_content_tostring(part->type));
|
||||
|
||||
/* Print MIME part body */
|
||||
printf("\nPrinting message BODY:\n%s\n", (char *)part->opaque_body);
|
||||
decoded = mm_mimepart_decode(part);
|
||||
if (decoded != NULL) {
|
||||
printf("DECODED:\n%s\n", decoded);
|
||||
free(decoded);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print out all warnings that we might have received */
|
||||
if (mm_context_haswarnings(ctx) > 0) {
|
||||
lastwarning = NULL;
|
||||
fprintf(stderr, "WARNINGS:\n");
|
||||
#if 0
|
||||
while ((warning = mm_warning_next(ctx, &lastwarning))
|
||||
!= NULL) {
|
||||
fprintf(stderr, " -> %s\n", warning->message);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
printf("ENVELOPE:\n");
|
||||
|
||||
do {
|
||||
char *env;
|
||||
size_t env_len;
|
||||
|
||||
mm_context_flatten(ctx, &env, &env_len, 0);
|
||||
printf("%s", env);
|
||||
|
||||
} while (0);
|
||||
|
||||
mm_context_free(ctx);
|
||||
ctx = NULL;
|
||||
|
||||
#ifdef __HAVE_LEAK_DETECTION
|
||||
MM_leakd_printallocated();
|
||||
#endif
|
||||
|
||||
} while (0);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,367 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _MM_H_INCLUDED
|
||||
#define _MM_H_INCLUDED
|
||||
|
||||
#include "asterisk.h"
|
||||
#include "mm_queue.h"
|
||||
#include "mm_mem.h"
|
||||
|
||||
#define MM_MIME_LINELEN 998
|
||||
#define MM_BASE64_LINELEN 76
|
||||
|
||||
TAILQ_HEAD(mm_mimeheaders, mm_mimeheader);
|
||||
TAILQ_HEAD(mm_mimeparts, mm_mimepart);
|
||||
TAILQ_HEAD(mm_params, mm_param);
|
||||
SLIST_HEAD(mm_codecs, mm_codec);
|
||||
SLIST_HEAD(mm_warnings, mm_warning);
|
||||
|
||||
/*
|
||||
* Parser modes
|
||||
*/
|
||||
enum mm_parsemodes
|
||||
{
|
||||
/** Parse loosely, accept some MIME quirks */
|
||||
MM_PARSE_LOOSE = 0,
|
||||
/** Parse as strict as possible */
|
||||
MM_PARSE_STRICT
|
||||
};
|
||||
|
||||
/*
|
||||
* Available parser flags
|
||||
*/
|
||||
enum mm_parseflags
|
||||
{
|
||||
MM_PARSE_NONE = (1L << 0),
|
||||
MM_PARSE_STRIPCOMMENTS = (1L << 1)
|
||||
};
|
||||
|
||||
/*
|
||||
* Enumeration of MIME encodings
|
||||
*/
|
||||
enum mm_encoding
|
||||
{
|
||||
MM_ENCODING_NONE = 0,
|
||||
MM_ENCODING_BASE64,
|
||||
MM_ENCODING_QUOTEDPRINTABLE,
|
||||
MM_ENCODING_UNKNOWN
|
||||
};
|
||||
|
||||
/*
|
||||
* Message type
|
||||
*/
|
||||
enum mm_messagetype
|
||||
{
|
||||
/** Flat message */
|
||||
MM_MSGTYPE_FLAT = 0,
|
||||
/** Composite message */
|
||||
MM_MSGTYPE_MULTIPART
|
||||
};
|
||||
|
||||
/*
|
||||
* Enumeration of error categories
|
||||
*/
|
||||
enum mm_errors
|
||||
{
|
||||
MM_ERROR_NONE = 0,
|
||||
MM_ERROR_UNDEF,
|
||||
MM_ERROR_ERRNO,
|
||||
MM_ERROR_PARSE,
|
||||
MM_ERROR_MIME,
|
||||
MM_ERROR_CODEC,
|
||||
MM_ERROR_PROGRAM
|
||||
};
|
||||
|
||||
enum mm_warning_ids
|
||||
{
|
||||
MM_WARN_NONE = 0,
|
||||
MM_WARN_PARSE,
|
||||
MM_WARN_MIME,
|
||||
MM_WARN_CODEC
|
||||
};
|
||||
|
||||
enum mm_addressfields {
|
||||
MM_ADDR_TO = 0,
|
||||
MM_ADDR_CC,
|
||||
MM_ADDR_BCC,
|
||||
MM_ADDR_FROM,
|
||||
MM_ADDR_SENDER,
|
||||
MM_ADDR_REPLY_TO
|
||||
};
|
||||
|
||||
enum mm_flatten_flags {
|
||||
MM_FLATTEN_NONE = 0,
|
||||
MM_FLATTEN_SKIPENVELOPE = (1L << 1),
|
||||
MM_FLATTEN_OPAQUE = (1L << 2),
|
||||
MM_FLATTEN_NOPREAMBLE = (1L << 3)
|
||||
};
|
||||
|
||||
/*
|
||||
* More information about an error
|
||||
*/
|
||||
struct mm_error_data
|
||||
{
|
||||
int error_id;
|
||||
int error_where;
|
||||
int lineno;
|
||||
char error_msg[128];
|
||||
};
|
||||
|
||||
extern int mm_errno;
|
||||
extern struct mm_error_data mm_error;
|
||||
|
||||
enum mm_warning_code
|
||||
{
|
||||
MM_WARNING_NONE = 0,
|
||||
MM_WARNING_INVHDR,
|
||||
};
|
||||
|
||||
/*
|
||||
* A parser warning
|
||||
*/
|
||||
struct mm_warning
|
||||
{
|
||||
enum mm_warning_code warning;
|
||||
uint32_t lineno;
|
||||
SLIST_ENTRY(mm_warning) next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Representation of a MiniMIME codec object
|
||||
*/
|
||||
struct mm_codec
|
||||
{
|
||||
enum mm_encoding id;
|
||||
char *encoding;
|
||||
|
||||
char *(*encoder)(char *, uint32_t);
|
||||
char *(*decoder)(char *);
|
||||
|
||||
SLIST_ENTRY(mm_codec) next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Representation of a MIME Content-Type parameter
|
||||
*/
|
||||
struct mm_param
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
|
||||
TAILQ_ENTRY(mm_param) next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Representation of a mail or MIME header field
|
||||
*/
|
||||
struct mm_mimeheader
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
|
||||
struct mm_params params;
|
||||
|
||||
TAILQ_ENTRY(mm_mimeheader) next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Representation of a MIME Content-Type object
|
||||
*/
|
||||
struct mm_content
|
||||
{
|
||||
char *maintype;
|
||||
char *subtype;
|
||||
char *disposition_type;
|
||||
|
||||
struct mm_params type_params;
|
||||
struct mm_params disposition_params;
|
||||
|
||||
char *encstring;
|
||||
enum mm_encoding encoding;
|
||||
};
|
||||
|
||||
/*
|
||||
* Representation of a MIME part
|
||||
*/
|
||||
struct mm_mimepart
|
||||
{
|
||||
struct mm_mimeheaders headers;
|
||||
|
||||
size_t opaque_length;
|
||||
char *opaque_body;
|
||||
|
||||
size_t length;
|
||||
char *body;
|
||||
|
||||
struct mm_content *type;
|
||||
|
||||
TAILQ_ENTRY(mm_mimepart) next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Represantation of a MiniMIME context
|
||||
*/
|
||||
struct mm_context
|
||||
{
|
||||
struct mm_mimeparts parts;
|
||||
enum mm_messagetype messagetype;
|
||||
struct mm_warnings warnings;
|
||||
struct mm_codecs codecs;
|
||||
char *boundary;
|
||||
char *preamble;
|
||||
size_t max_message_size;
|
||||
};
|
||||
|
||||
typedef struct mm_context MM_CTX;
|
||||
typedef struct mm_context mm_ctx_t;
|
||||
|
||||
char *mm_unquote(const char *);
|
||||
char *mm_uncomment(const char *);
|
||||
char *mm_stripchars(char *, char *);
|
||||
char *mm_addchars(char *, char *, uint16_t);
|
||||
int mm_gendate(char **);
|
||||
void mm_striptrailing(char **, const char *);
|
||||
int mm_mimeutil_genboundary(char *, size_t, char **);
|
||||
|
||||
int mm_library_init(void);
|
||||
int mm_library_isinitialized(void);
|
||||
|
||||
int mm_parse_mem(MM_CTX *, const char *, int, int);
|
||||
int mm_parse_file(MM_CTX *, const char *, int, int);
|
||||
int mm_parse_fileptr(MM_CTX *, FILE *, int, int);
|
||||
|
||||
MM_CTX *mm_context_new(void);
|
||||
void mm_context_free(MM_CTX *);
|
||||
int mm_context_attachpart(MM_CTX *, struct mm_mimepart *);
|
||||
int mm_context_deletepart(MM_CTX *, int, int);
|
||||
int mm_context_countparts(MM_CTX *);
|
||||
struct mm_mimepart *mm_context_getpart(MM_CTX *, int);
|
||||
int mm_context_iscomposite(MM_CTX *);
|
||||
int mm_context_haswarnings(MM_CTX *);
|
||||
int mm_context_flatten(MM_CTX *, char **, size_t *, int);
|
||||
|
||||
int mm_envelope_getheaders(MM_CTX *, char **, size_t *);
|
||||
int mm_envelope_setheader(MM_CTX *, const char *, const char *, ...);
|
||||
|
||||
struct mm_mimeheader *mm_mimeheader_new(void);
|
||||
void mm_mimeheader_free(struct mm_mimeheader *);
|
||||
struct mm_mimeheader *mm_mimeheader_generate(const char *, const char *);
|
||||
int mm_mimeheader_uncomment(struct mm_mimeheader *);
|
||||
int mm_mimeheader_uncommentbyname(struct mm_mimepart *, const char *);
|
||||
int mm_mimeheader_uncommentall(struct mm_mimepart *);
|
||||
int mm_mimeheader_tostring(struct mm_mimeheader *);
|
||||
char *mm_mimeheader_getparambyname(struct mm_mimeheader *hdr, const char *name);
|
||||
int mm_mimeheader_attachparam(struct mm_mimeheader *hdr, struct mm_param *param);
|
||||
|
||||
struct mm_mimepart *mm_mimepart_new(void);
|
||||
void mm_mimepart_free(struct mm_mimepart *);
|
||||
int mm_mimepart_attachheader(struct mm_mimepart *, struct mm_mimeheader *);
|
||||
int mm_mimepart_countheaders(struct mm_mimepart *part);
|
||||
int mm_mimepart_countheaderbyname(struct mm_mimepart *, const char *);
|
||||
struct mm_mimeheader *mm_mimepart_getheaderbyname(struct mm_mimepart *, const char *, int);
|
||||
const char *mm_mimepart_getheadervalue(struct mm_mimepart *, const char *, int);
|
||||
int mm_mimepart_headers_start(struct mm_mimepart *, struct mm_mimeheader **);
|
||||
struct mm_mimeheader *mm_mimepart_headers_next(struct mm_mimepart *, struct mm_mimeheader **);
|
||||
char *mm_mimepart_decode(struct mm_mimepart *);
|
||||
struct mm_content *mm_mimepart_getcontent(struct mm_mimepart *);
|
||||
size_t mm_mimepart_getlength(struct mm_mimepart *);
|
||||
char *mm_mimepart_getbody(struct mm_mimepart *, int);
|
||||
void mm_mimepart_attachcontenttype(struct mm_mimepart *, struct mm_content *);
|
||||
int mm_mimepart_setdefaultcontenttype(struct mm_mimepart *, int);
|
||||
int mm_mimepart_flatten(struct mm_mimepart *, char **, size_t *, int);
|
||||
struct mm_mimepart *mm_mimepart_fromfile(const char *);
|
||||
|
||||
struct mm_content *mm_content_new(void);
|
||||
void mm_content_free(struct mm_content *);
|
||||
int mm_content_attachtypeparam(struct mm_content *, struct mm_param *);
|
||||
int mm_content_attachdispositionparam(struct mm_content *, struct mm_param *);
|
||||
struct mm_content *mm_content_parse(const char *, int);
|
||||
char *mm_content_gettypeparambyname(struct mm_content *, const char *);
|
||||
char *mm_content_getdispositionparambyname(struct mm_content *, const char *);
|
||||
struct mm_param *mm_content_gettypeparamobjbyname(struct mm_content *, const char *);
|
||||
struct mm_param *mm_content_getdispositionparamobjbyname(struct mm_content *, const char *);
|
||||
int mm_content_setmaintype(struct mm_content *, char *, int);
|
||||
int mm_content_setsubtype(struct mm_content *, char *, int);
|
||||
int mm_content_settype(struct mm_content *, const char *, ...);
|
||||
int mm_content_setdispositiontype(struct mm_content *ct, char *value, int copy);
|
||||
char *mm_content_getmaintype(struct mm_content *);
|
||||
char *mm_content_getsubtype(struct mm_content *);
|
||||
char *mm_content_gettype(struct mm_content *);
|
||||
char *mm_content_getdispositiontype(struct mm_content *ct);
|
||||
int mm_content_iscomposite(struct mm_content *);
|
||||
int mm_content_isvalidencoding(const char *);
|
||||
int mm_content_setencoding(struct mm_content *, const char *);
|
||||
char *mm_content_typeparamstostring(struct mm_content *);
|
||||
char *mm_content_dispositionparamstostring(struct mm_content *);
|
||||
char *mm_content_tostring(struct mm_content *);
|
||||
|
||||
struct mm_param *mm_param_new(void);
|
||||
void mm_param_free(struct mm_param *);
|
||||
|
||||
char *mm_flatten_mimepart(struct mm_mimepart *);
|
||||
char *mm_flatten_context(MM_CTX *);
|
||||
|
||||
int mm_codec_isregistered(const char *);
|
||||
int mm_codec_hasdecoder(const char *);
|
||||
int mm_codec_hasencoder(const char *);
|
||||
int mm_codec_register(const char *, char *(*encoder)(char *, uint32_t), char *(*decoder)(char *));
|
||||
int mm_codec_unregister(const char *);
|
||||
int mm_codec_unregisterall(void);
|
||||
void mm_codec_registerdefaultcodecs(void);
|
||||
|
||||
char *mm_base64_decode(char *);
|
||||
char *mm_base64_encode(char *, uint32_t);
|
||||
|
||||
void mm_error_init(void);
|
||||
void mm_error_setmsg(const char *, ...);
|
||||
void mm_error_setlineno(int lineno);
|
||||
char *mm_error_string(void);
|
||||
int mm_error_lineno(void);
|
||||
|
||||
void mm_warning_add(MM_CTX *, int, const char *, ...);
|
||||
struct mm_warning *mm_warning_next(MM_CTX *, struct mm_warning **);
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy(char *, const char *, size_t);
|
||||
#endif /* ! HAVE_STRLCPY */
|
||||
#ifndef HAVE_STRLCAT
|
||||
size_t strlcat(char *, const char *, size_t);
|
||||
#endif /* ! HAVE_STRLCAT */
|
||||
|
||||
#define MM_ISINIT() do { \
|
||||
assert(mm_library_isinitialized() == 1); \
|
||||
} while (0);
|
||||
|
||||
#endif /* ! _MM_H_INCLUDED */
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003 Jann Fischer <jfi@openbsd.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* XXX: This piece of software is not nearly MIME compatible as it should be.
|
||||
*
|
||||
* This is based on third-party code, see the copyright notice below.
|
||||
*
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/***********************************************************
|
||||
Copyright 1998 by Carnegie Mellon University
|
||||
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of Carnegie Mellon
|
||||
University not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
|
||||
ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
******************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
#define XX 127
|
||||
|
||||
static int _mm_base64_decode(char *);
|
||||
static char *_mm_base64_encode(char *, uint32_t);
|
||||
|
||||
/*
|
||||
* Tables for encoding/decoding base64
|
||||
*/
|
||||
static const char basis_64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char index_64[256] = {
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
|
||||
52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX,
|
||||
XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||
15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
|
||||
XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
|
||||
};
|
||||
#define CHAR64(c) (index_64[(unsigned char)(c)])
|
||||
|
||||
/*
|
||||
* mm_base64_decode()
|
||||
*
|
||||
* Decodes the data pointed to by 'data' from the BASE64 encoding to the data
|
||||
* format it was encoded from. Returns a pointer to a string on success or
|
||||
* NULL on error. The string returned needs to be freed by the caller at some
|
||||
* later point.
|
||||
*
|
||||
*/
|
||||
char *
|
||||
mm_base64_decode(char *data)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
assert(data != NULL);
|
||||
|
||||
buf = mm_stripchars(data, "\r\n");
|
||||
assert(buf != NULL);
|
||||
|
||||
_mm_base64_decode(buf);
|
||||
assert(buf != NULL);
|
||||
return(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* mm_base64_encode()
|
||||
*
|
||||
* Encodes the data pointed to by 'data', which is of the length specified in
|
||||
* 'len' to the BASE64 format. Returns a pointer to a string containing the
|
||||
* BASE64 encoding, whose lines are broken at the MIME recommended linelength
|
||||
* of 76 characters. If an error occured, returns NULL. The string returned
|
||||
* needs to be freed by the caller at some later point.
|
||||
*
|
||||
*/
|
||||
char *
|
||||
mm_base64_encode(char *data, uint32_t len) {
|
||||
char *buf;
|
||||
char *ret;
|
||||
|
||||
assert(data != NULL);
|
||||
|
||||
buf = _mm_base64_encode(data, len);
|
||||
assert(buf != NULL);
|
||||
|
||||
ret = mm_addchars(buf, "\r\n", MM_BASE64_LINELEN);
|
||||
xfree(buf);
|
||||
assert(ret != NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode in-place the base64 data in 'input'. Returns the length
|
||||
* of the decoded data, or -1 if there was an error.
|
||||
*/
|
||||
static int
|
||||
_mm_base64_decode(char *input)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
unsigned char *output = (unsigned char *)input;
|
||||
int c1, c2, c3, c4;
|
||||
|
||||
while (*input) {
|
||||
c1 = *input++;
|
||||
if (CHAR64(c1) == XX) return -1;
|
||||
c2 = *input++;
|
||||
if (CHAR64(c2) == XX) return -1;
|
||||
c3 = *input++;
|
||||
if (c3 != '=' && CHAR64(c3) == XX) return -1;
|
||||
c4 = *input++;
|
||||
if (c4 != '=' && CHAR64(c4) == XX) return -1;
|
||||
*output++ = (CHAR64(c1) << 2) | (CHAR64(c2) >> 4);
|
||||
++len;
|
||||
if (c3 == '=') break;
|
||||
*output++ = ((CHAR64(c2) << 4) & 0xf0) | (CHAR64(c3) >> 2);
|
||||
++len;
|
||||
if (c4 == '=') break;
|
||||
*output++ = ((CHAR64(c3) << 6) & 0xc0) | CHAR64(c4);
|
||||
++len;
|
||||
}
|
||||
*output = 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode the given binary string of length 'len' and return Base64
|
||||
* in a char buffer. It allocates the space for buffer.
|
||||
* caller must free the space.
|
||||
*/
|
||||
static char *
|
||||
_mm_base64_encode(char *data, uint32_t len)
|
||||
{
|
||||
char *buf;
|
||||
uint32_t buflen;
|
||||
int c1;
|
||||
int c2;
|
||||
int c3;
|
||||
uint32_t maxbuf;
|
||||
|
||||
buflen = 0;
|
||||
|
||||
#ifdef RUBBISH
|
||||
maxbuf = len*4/3 + 1; /* size after expantion */
|
||||
#endif
|
||||
maxbuf = len*2 + 20; /* size after expantion */
|
||||
|
||||
buf = (char *)xmalloc(maxbuf);
|
||||
|
||||
while (len && buflen < (maxbuf - 6)) {
|
||||
|
||||
c1 = (unsigned char)*data++;
|
||||
buf[buflen++] = basis_64[c1>>2];
|
||||
|
||||
if (--len == 0) c2 = 0;
|
||||
else c2 = (unsigned char)*data++;
|
||||
buf[buflen++] = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
|
||||
|
||||
if (len == 0) {
|
||||
buf[buflen++] = '=';
|
||||
buf[buflen++] = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
if (--len == 0) c3 = 0;
|
||||
else c3 = (unsigned char)*data++;
|
||||
|
||||
buf[buflen++] = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
||||
if (len == 0) {
|
||||
buf[buflen++] = '=';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
--len;
|
||||
buf[buflen++] = basis_64[c3 & 0x3F];
|
||||
}
|
||||
|
||||
buf[buflen]=0;
|
||||
return buf;
|
||||
}
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
#include "mm_util.h"
|
||||
|
||||
extern struct mm_codecs codecs;
|
||||
|
||||
/** @file mm_codecs.c
|
||||
*
|
||||
* This module contains functions to manipulate MiniMIME codecs
|
||||
*
|
||||
*/
|
||||
|
||||
/** @defgroup codecs Manipulating MiniMIME codecs */
|
||||
|
||||
/** @{
|
||||
* @name Codec manipulation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Looks up whether a context has an decoder installed for a given encoding
|
||||
*
|
||||
* @param encoding The encoding specifier to look up
|
||||
* @return 1 if a decoder is installed or 0 if not
|
||||
* @ingroup codecs
|
||||
*/
|
||||
int
|
||||
mm_codec_hasdecoder(const char *encoding)
|
||||
{
|
||||
struct mm_codec *codec;
|
||||
|
||||
assert(encoding != NULL);
|
||||
|
||||
SLIST_FOREACH(codec, &codecs, next) {
|
||||
assert(codec->encoding != NULL);
|
||||
if (!strcasecmp(codec->encoding, encoding)) {
|
||||
if (codec->decoder != NULL)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up whether a context has an encoder installed for a given encoding
|
||||
*
|
||||
* @param ctx A valid MIME context
|
||||
* @param encoding The encoding specifier to look up
|
||||
* @return 1 if an encoder is installed or 0 if not
|
||||
* @ingroup codecs
|
||||
*/
|
||||
int
|
||||
mm_codec_hasencoder(const char *encoding)
|
||||
{
|
||||
struct mm_codec *codec;
|
||||
|
||||
assert(encoding != NULL);
|
||||
|
||||
SLIST_FOREACH(codec, &codecs, next) {
|
||||
assert(codec->encoding != NULL);
|
||||
if (!strcasecmp(codec->encoding, encoding)) {
|
||||
if (codec->encoder != NULL)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up whether a codec for a given encoding is installed to a context
|
||||
*
|
||||
* @param encoding The encoding specifier to look up
|
||||
* @return 1 if a codec was found or 0 if not
|
||||
* @ingroup codecs
|
||||
*/
|
||||
int
|
||||
mm_codec_isregistered(const char *encoding)
|
||||
{
|
||||
struct mm_codec *codec;
|
||||
|
||||
assert(encoding != NULL);
|
||||
|
||||
SLIST_FOREACH(codec, &codecs, next) {
|
||||
if (!strcasecmp(codec->encoding, encoding)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a codec with the MiniMIME library
|
||||
*
|
||||
* @param encoding The encoding specifier for which to register the codec
|
||||
* @param encoder The encoder function for this encoding
|
||||
* @param decoder The decoder function for this encoding
|
||||
* @return 1 if successfull or 0 if not
|
||||
* @ingroup codecs
|
||||
*
|
||||
* This function registers a codec for a given MiniMIME context. The codec
|
||||
* may provide an decoder, an encoder or both (but not none). If there is
|
||||
* a codec already installed for this encoding, the function will puke.
|
||||
*/
|
||||
int
|
||||
mm_codec_register(const char *encoding,
|
||||
char *(*encoder)(char *data, uint32_t i),
|
||||
char *(*decoder)(char *data))
|
||||
{
|
||||
struct mm_codec *codec;
|
||||
|
||||
assert(encoding != NULL);
|
||||
|
||||
assert(mm_codec_isregistered(encoding) != 1);
|
||||
|
||||
codec = (struct mm_codec *)xmalloc(sizeof(struct mm_codec));
|
||||
|
||||
codec->encoding = xstrdup(encoding);
|
||||
codec->encoder = encoder;
|
||||
codec->decoder = decoder;
|
||||
|
||||
if (SLIST_EMPTY(&codecs)) {
|
||||
SLIST_INSERT_HEAD(&codecs, codec, next);
|
||||
return 1;
|
||||
} else {
|
||||
struct mm_codec *lcodec, *tcodec;
|
||||
tcodec = NULL;
|
||||
SLIST_FOREACH(lcodec, &codecs, next) {
|
||||
if (lcodec != NULL)
|
||||
tcodec = lcodec;
|
||||
}
|
||||
assert(tcodec != NULL);
|
||||
SLIST_INSERT_AFTER(tcodec, codec, next);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a MiniMIME codec
|
||||
*
|
||||
* @param encoding The encoding specifier which to unregister
|
||||
* @return 0 if unregistered successfully, or -1 if there was no such codec
|
||||
* @ingroup codecs
|
||||
*/
|
||||
int
|
||||
mm_codec_unregister(const char *encoding)
|
||||
{
|
||||
struct mm_codec *codec;
|
||||
|
||||
assert(encoding != NULL);
|
||||
|
||||
SLIST_FOREACH(codec, &codecs, next) {
|
||||
if (!strcasecmp(codec->encoding, encoding)) {
|
||||
xfree(codec->encoding);
|
||||
xfree(codec);
|
||||
codec = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all codecs within a context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @return 0 if all codecs were unregistered successfully or -1 if an error
|
||||
* occured.
|
||||
* @note Foobar
|
||||
*/
|
||||
int
|
||||
mm_codec_unregisterall(void)
|
||||
{
|
||||
struct mm_codec *codec;
|
||||
|
||||
SLIST_FOREACH(codec, &codecs, next) {
|
||||
if (mm_codec_unregister(codec->encoding) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the default codecs to a MiniMIME context
|
||||
*
|
||||
* This functions registers the codecs for the following encodings to a
|
||||
* MiniMIME context:
|
||||
*
|
||||
* - Base64
|
||||
* - (TODO:) Quoted-Printable
|
||||
*/
|
||||
void
|
||||
mm_codec_registerdefaultcodecs(void)
|
||||
{
|
||||
mm_codec_register("base64", mm_base64_encode, mm_base64_decode);
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
|
@ -1,759 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
#include "mm_util.h"
|
||||
|
||||
/* This file is documented using Doxygen */
|
||||
|
||||
/**
|
||||
* @file mm_contenttype.c
|
||||
*
|
||||
* This module contains functions for manipulating Content-Type objects.
|
||||
*/
|
||||
|
||||
/** @defgroup contenttype Accessing and manipulating Content-Type objects */
|
||||
|
||||
struct mm_encoding_mappings {
|
||||
const char *idstring;
|
||||
int type;
|
||||
};
|
||||
|
||||
static struct mm_encoding_mappings mm_content_enctypes[] = {
|
||||
{ "Base64", MM_ENCODING_BASE64 },
|
||||
{ "Quoted-Printable", MM_ENCODING_QUOTEDPRINTABLE },
|
||||
{ NULL, - 1},
|
||||
};
|
||||
|
||||
static const char *mm_composite_maintypes[] = {
|
||||
"multipart",
|
||||
"message",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char *mm_composite_encodings[] = {
|
||||
"7bit",
|
||||
"8bit",
|
||||
"binary",
|
||||
NULL,
|
||||
};
|
||||
|
||||
/** @{
|
||||
* @name Functions for manipulating Content objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new object to hold a Content representation.
|
||||
* The allocated memory must later be freed using mm_content_free()
|
||||
*
|
||||
* @return An object representing a MIME Content-Type
|
||||
* @see mm_content_free
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
struct mm_content *
|
||||
mm_content_new(void)
|
||||
{
|
||||
struct mm_content *ct;
|
||||
|
||||
ct = (struct mm_content *)xmalloc(sizeof(struct mm_content));
|
||||
|
||||
ct->maintype = NULL;
|
||||
ct->subtype = NULL;
|
||||
|
||||
TAILQ_INIT(&ct->type_params);
|
||||
TAILQ_INIT(&ct->disposition_params);
|
||||
|
||||
ct->encoding = MM_ENCODING_NONE;
|
||||
ct->encstring = NULL;
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all memory associated with an Content object
|
||||
*
|
||||
* @param ct A Content-Type object
|
||||
* @return Nothing
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
void
|
||||
mm_content_free(struct mm_content *ct)
|
||||
{
|
||||
struct mm_param *param;
|
||||
|
||||
assert(ct != NULL);
|
||||
|
||||
if (ct->maintype != NULL) {
|
||||
xfree(ct->maintype);
|
||||
ct->maintype = NULL;
|
||||
}
|
||||
if (ct->subtype != NULL) {
|
||||
xfree(ct->subtype);
|
||||
ct->subtype = NULL;
|
||||
}
|
||||
if (ct->encstring != NULL) {
|
||||
xfree(ct->encstring);
|
||||
ct->encstring = NULL;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(param, &ct->type_params, next) {
|
||||
TAILQ_REMOVE(&ct->type_params, param, next);
|
||||
mm_param_free(param);
|
||||
}
|
||||
TAILQ_FOREACH(param, &ct->disposition_params, next) {
|
||||
TAILQ_REMOVE(&ct->disposition_params, param, next);
|
||||
mm_param_free(param);
|
||||
}
|
||||
|
||||
xfree(ct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a content-type parameter to a Content object
|
||||
*
|
||||
* @param ct The target Content object
|
||||
* @param param The Content-Type parameter which to attach
|
||||
* @return 0 on success and -1 on failure
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
int
|
||||
mm_content_attachtypeparam(struct mm_content *ct, struct mm_param *param)
|
||||
{
|
||||
assert(ct != NULL);
|
||||
assert(param != NULL);
|
||||
|
||||
if (TAILQ_EMPTY(&ct->type_params)) {
|
||||
TAILQ_INSERT_HEAD(&ct->type_params, param, next);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&ct->type_params, param, next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attaches a content-disposition parameter to a Content-Disposition object
|
||||
*
|
||||
* @param ct The target Content object
|
||||
* @param param The Content-Type parameter which to attach
|
||||
* @return 0 on success and -1 on failure
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
int
|
||||
mm_content_attachdispositionparam(struct mm_content *ct, struct mm_param *param)
|
||||
{
|
||||
assert(ct != NULL);
|
||||
assert(param != NULL);
|
||||
|
||||
if (TAILQ_EMPTY(&ct->disposition_params)) {
|
||||
TAILQ_INSERT_HEAD(&ct->disposition_params, param, next);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&ct->disposition_params, param, next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a Content-Type parameter value from a Content object.
|
||||
*
|
||||
* @param ct the Content object
|
||||
* @param name the name of the parameter to retrieve
|
||||
* @return The value of the parameter on success or a NULL pointer on failure
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
char *
|
||||
mm_content_gettypeparambyname(struct mm_content *ct, const char *name)
|
||||
{
|
||||
struct mm_param *param;
|
||||
|
||||
assert(ct != NULL);
|
||||
|
||||
TAILQ_FOREACH(param, &ct->type_params, next) {
|
||||
if (!strcasecmp(param->name, name)) {
|
||||
return param->value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Content-Disposition parameter value from a Content object.
|
||||
*
|
||||
* @param ct the Content object
|
||||
* @param name the name of the parameter to retrieve
|
||||
* @return The value of the parameter on success or a NULL pointer on failure
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
char *
|
||||
mm_content_getdispositionparambyname(struct mm_content *ct, const char *name)
|
||||
{
|
||||
struct mm_param *param;
|
||||
|
||||
assert(ct != NULL);
|
||||
|
||||
TAILQ_FOREACH(param, &ct->disposition_params, next) {
|
||||
if (!strcasecmp(param->name, name)) {
|
||||
return param->value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mm_param *
|
||||
mm_content_gettypeparamobjbyname(struct mm_content *ct, const char *name)
|
||||
{
|
||||
struct mm_param *param;
|
||||
|
||||
assert(ct != NULL);
|
||||
|
||||
TAILQ_FOREACH(param, &ct->type_params, next) {
|
||||
if (!strcasecmp(param->name, name)) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mm_param *
|
||||
mm_content_getdispositionparamobjbyname(struct mm_content *ct, const char *name)
|
||||
{
|
||||
struct mm_param *param;
|
||||
|
||||
assert(ct != NULL);
|
||||
|
||||
TAILQ_FOREACH(param, &ct->disposition_params, next) {
|
||||
if (!strcasecmp(param->name, name)) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the MIME main Content-Type for a MIME Content object
|
||||
*
|
||||
* @param ct The MIME Content object
|
||||
* @param value The value which to set the main type to
|
||||
* @param copy Whether to make a copy of the value (original value must be
|
||||
* freed afterwards to prevent memory leaks).
|
||||
*/
|
||||
int
|
||||
mm_content_setmaintype(struct mm_content *ct, char *value, int copy)
|
||||
{
|
||||
assert(ct != NULL);
|
||||
assert(value != NULL);
|
||||
|
||||
if (copy) {
|
||||
/**
|
||||
* @bug The xfree() call could lead to undesirable results.
|
||||
* Do we really need it?
|
||||
*/
|
||||
if (ct->maintype != NULL) {
|
||||
xfree(ct->maintype);
|
||||
}
|
||||
ct->maintype = xstrdup(value);
|
||||
} else {
|
||||
ct->maintype = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the main MIME Content-Type stored in a Content object
|
||||
*
|
||||
* @param ct A valid Content object
|
||||
* @returns A pointer to the string representing the main type
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
char *
|
||||
mm_content_getmaintype(struct mm_content *ct)
|
||||
{
|
||||
assert(ct != NULL);
|
||||
assert(ct->maintype != NULL);
|
||||
|
||||
return ct->maintype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the MIME Content-Disposition type for a MIME Content object
|
||||
*
|
||||
* @param ct The MIME Content object
|
||||
* @param value The value which to set the main type to
|
||||
* @param copy Whether to make a copy of the value (original value must be
|
||||
* freed afterwards to prevent memory leaks).
|
||||
*/
|
||||
int
|
||||
mm_content_setdispositiontype(struct mm_content *ct, char *value, int copy)
|
||||
{
|
||||
assert(ct != NULL);
|
||||
assert(value != NULL);
|
||||
|
||||
if (copy) {
|
||||
/**
|
||||
* @bug The xfree() call could lead to undesirable results.
|
||||
* Do we really need it?
|
||||
*/
|
||||
if (ct->disposition_type != NULL) {
|
||||
xfree(ct->disposition_type);
|
||||
}
|
||||
ct->disposition_type = xstrdup(value);
|
||||
} else {
|
||||
ct->disposition_type = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the Content-Disposition MIME type stored in a Content object
|
||||
*
|
||||
* @param ct A valid Content-Type object
|
||||
* @returns A pointer to the string representing the main type
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
char *
|
||||
mm_content_getdispositiontype(struct mm_content *ct)
|
||||
{
|
||||
assert(ct != NULL);
|
||||
assert(ct->disposition_type != NULL);
|
||||
|
||||
return ct->disposition_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the sub MIME Content-Type stored in a Content object
|
||||
*
|
||||
* @param ct A valid Content-Type object
|
||||
* @return A pointer to the string holding the current sub MIME type
|
||||
* @ingroup contenttype
|
||||
*/
|
||||
char *
|
||||
mm_content_getsubtype(struct mm_content *ct)
|
||||
{
|
||||
assert(ct != NULL);
|
||||
assert(ct->subtype != NULL);
|
||||
|
||||
return ct->subtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the MIME sub Content-Type for a MIME Content object
|
||||
*
|
||||
* @param ct The MIME Content-Type object
|
||||
* @param value The value which to set the sub type to
|
||||
* @param copy Whether to make a copy of the value (original value must be
|
||||
* freed afterwards to prevent memory leaks).
|
||||
*/
|
||||
int
|
||||
mm_content_setsubtype(struct mm_content *ct, char *value, int copy)
|
||||
{
|
||||
assert(ct != NULL);
|
||||
assert(value != NULL);
|
||||
|
||||
if (copy) {
|
||||
/**
|
||||
* @bug The xfree() call could lead to undesirable results.
|
||||
* Do we really need it?
|
||||
*/
|
||||
if (ct->subtype != NULL) {
|
||||
xfree(ct->subtype);
|
||||
}
|
||||
ct->subtype = xstrdup(value);
|
||||
} else {
|
||||
ct->subtype = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mm_content_settype(struct mm_content *ct, const char *fmt, ...)
|
||||
{
|
||||
char *maint, *subt;
|
||||
char buf[512], *parse;
|
||||
va_list ap;
|
||||
|
||||
mm_errno = MM_ERROR_NONE;
|
||||
|
||||
va_start(ap, fmt);
|
||||
/* Make sure no truncation occurs */
|
||||
if (vsnprintf(buf, sizeof buf, fmt, ap) > sizeof buf) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
mm_error_setmsg("Input string too long");
|
||||
return -1;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
parse = buf;
|
||||
maint = strsep(&parse, "/");
|
||||
if (maint == NULL) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("Invalid type specifier: %s", buf);
|
||||
return -1;
|
||||
}
|
||||
ct->maintype = xstrdup(maint);
|
||||
|
||||
subt = strsep(&parse, "");
|
||||
if (subt == NULL) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("Invalid type specifier: %s", buf);
|
||||
return -1;
|
||||
}
|
||||
ct->subtype = xstrdup(subt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the Content-Type represents a composite message or not
|
||||
*
|
||||
* @param ct A valid Content-Type object
|
||||
* @returns 1 if the Content-Type object represents a composite message or
|
||||
* 0 if not.
|
||||
*/
|
||||
int
|
||||
mm_content_iscomposite(struct mm_content *ct)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mm_composite_maintypes[i] != NULL; i++) {
|
||||
if (!strcasecmp(ct->maintype, mm_composite_maintypes[i])) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether a string represents a valid encoding or not.
|
||||
*
|
||||
* @param encoding The string to verify
|
||||
* @return 1 if the encoding string is valid or 0 if not
|
||||
*
|
||||
*/
|
||||
int
|
||||
mm_content_isvalidencoding(const char *encoding)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mm_composite_encodings[i] != NULL; i++) {
|
||||
if (!strcasecmp(encoding, mm_composite_encodings[i])) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the encoding of a MIME entitity according to a mapping table
|
||||
*
|
||||
* @param ct A valid content type object
|
||||
* @param encoding A string representing the content encoding
|
||||
* @return 0 if successfull or -1 if not (i.e. unknown content encoding)
|
||||
*/
|
||||
int
|
||||
mm_content_setencoding(struct mm_content *ct, const char *encoding)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(ct != NULL);
|
||||
assert(encoding != NULL);
|
||||
|
||||
for (i = 0; mm_content_enctypes[i].idstring != NULL; i++) {
|
||||
if (!strcasecmp(mm_content_enctypes[i].idstring, encoding)) {
|
||||
ct->encoding = mm_content_enctypes[i].type;
|
||||
ct->encstring = xstrdup(encoding);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we didn't find a mapping, set the encoding to unknown */
|
||||
ct->encoding = MM_ENCODING_UNKNOWN;
|
||||
ct->encstring = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the numerical ID of a content encoding identifier
|
||||
*
|
||||
* @param ct A valid Content Type object
|
||||
* @param encoding A string representing the content encoding identifier
|
||||
* @return The numerical ID of the content encoding
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
mm_content_getencoding(struct mm_content *ct, const char *encoding)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(ct != NULL);
|
||||
|
||||
for (i = 0; mm_content_enctypes[i].idstring != NULL; i++) {
|
||||
if (!strcasecmp(mm_content_enctypes[i].idstring, encoding)) {
|
||||
return mm_content_enctypes[i].type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return MM_ENCODING_UNKNOWN;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Constructs a MIME conform string of Content-Type parameters.
|
||||
*
|
||||
* @param ct A valid Content Type object
|
||||
* @return A pointer to a string representing the Content-Type parameters
|
||||
* in MIME terminology, or NULL if either the Content-Type object
|
||||
* is invalid, has no parameters or no memory could be allocated.
|
||||
*
|
||||
* This function constructs a MIME conform string including all the parameters
|
||||
* associated with the given Content-Type object. It should NOT be used if
|
||||
* you need an opaque copy of the current MIME part (e.g. for PGP purposes).
|
||||
*/
|
||||
char *
|
||||
mm_content_typeparamstostring(struct mm_content *ct)
|
||||
{
|
||||
size_t size, new_size;
|
||||
struct mm_param *param;
|
||||
char *param_string, *cur_param;
|
||||
char *buf;
|
||||
|
||||
size = 1;
|
||||
param_string = NULL;
|
||||
cur_param = NULL;
|
||||
|
||||
param_string = (char *) xmalloc(size);
|
||||
*param_string = '\0';
|
||||
|
||||
/* Concatenate all Content-Type parameters attached to the current
|
||||
* Content-Type object to a single string.
|
||||
*/
|
||||
TAILQ_FOREACH(param, &ct->type_params, next) {
|
||||
if (asprintf(&cur_param, "; %s=\"%s\"", param->name,
|
||||
param->value) == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
new_size = size + strlen(cur_param) + 1;
|
||||
|
||||
if (new_size < 0 || new_size > 1000) {
|
||||
size = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
buf = (char *) xrealloc(param_string, new_size);
|
||||
if (buf == NULL) {
|
||||
size = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
param_string = buf;
|
||||
size = new_size;
|
||||
strlcat(param_string, cur_param, size);
|
||||
|
||||
xfree(cur_param);
|
||||
cur_param = NULL;
|
||||
}
|
||||
|
||||
return param_string;
|
||||
|
||||
cleanup:
|
||||
if (param_string != NULL) {
|
||||
xfree(param_string);
|
||||
param_string = NULL;
|
||||
}
|
||||
if (cur_param != NULL) {
|
||||
xfree(cur_param);
|
||||
cur_param = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MIME conformant string of Content-Disposition parameters.
|
||||
*
|
||||
* @param ct A valid Content object
|
||||
* @return A pointer to a string representing the Content-Disposition parameters
|
||||
* in MIME terminology, or NULL if either the Content object
|
||||
* is invalid, has no Disposition parameters or no memory could be allocated.
|
||||
*
|
||||
* This function constructs a MIME conforming string including all the parameters
|
||||
* associated with the given Content-Disposition object. It should NOT be used if
|
||||
* you need an opaque copy of the current MIME part (e.g. for PGP purposes).
|
||||
*/
|
||||
char *
|
||||
mm_content_dispositionparamstostring(struct mm_content *ct)
|
||||
{
|
||||
size_t size, new_size;
|
||||
struct mm_param *param;
|
||||
char *param_string, *cur_param;
|
||||
char *buf;
|
||||
|
||||
size = 1;
|
||||
param_string = NULL;
|
||||
cur_param = NULL;
|
||||
|
||||
param_string = (char *) xmalloc(size);
|
||||
*param_string = '\0';
|
||||
|
||||
/* Concatenate all Content-Disposition parameters attached to the current
|
||||
* Content object to a single string.
|
||||
*/
|
||||
TAILQ_FOREACH(param, &ct->disposition_params, next) {
|
||||
if (asprintf(&cur_param, "; %s=\"%s\"", param->name,
|
||||
param->value) == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
new_size = size + strlen(cur_param) + 1;
|
||||
|
||||
if (new_size < 0 || new_size > 1000) {
|
||||
size = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
buf = (char *) xrealloc(param_string, new_size);
|
||||
if (buf == NULL) {
|
||||
size = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
param_string = buf;
|
||||
size = new_size;
|
||||
strlcat(param_string, cur_param, size);
|
||||
|
||||
xfree(cur_param);
|
||||
cur_param = NULL;
|
||||
}
|
||||
|
||||
return param_string;
|
||||
|
||||
cleanup:
|
||||
if (param_string != NULL) {
|
||||
xfree(param_string);
|
||||
param_string = NULL;
|
||||
}
|
||||
if (cur_param != NULL) {
|
||||
xfree(cur_param);
|
||||
cur_param = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Content-Type header according to the object given
|
||||
*
|
||||
* @param ct A valid Content-Type object
|
||||
*
|
||||
*/
|
||||
char *
|
||||
mm_content_tostring(struct mm_content *ct)
|
||||
{
|
||||
char *paramstring;
|
||||
char *buf;
|
||||
char *headerstring;
|
||||
size_t size;
|
||||
|
||||
paramstring = NULL;
|
||||
headerstring = NULL;
|
||||
buf = NULL;
|
||||
|
||||
if (ct == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (ct->maintype == NULL || ct->subtype == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = strlen(ct->maintype) + strlen(ct->subtype) + 2;
|
||||
headerstring = (char *)xmalloc(size);
|
||||
snprintf(headerstring, size, "%s/%s", ct->maintype, ct->subtype);
|
||||
|
||||
paramstring = mm_content_typeparamstostring(ct);
|
||||
if (paramstring == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
size += strlen(paramstring) + strlen("Content-Type: ") + 1;
|
||||
buf = (char *)malloc(size);
|
||||
if (buf == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
snprintf(buf, size, "Content-Type: %s%s", headerstring, paramstring);
|
||||
|
||||
xfree(headerstring);
|
||||
xfree(paramstring);
|
||||
|
||||
headerstring = NULL;
|
||||
paramstring = NULL;
|
||||
|
||||
return buf;
|
||||
|
||||
cleanup:
|
||||
if (paramstring != NULL) {
|
||||
xfree(paramstring);
|
||||
paramstring = NULL;
|
||||
}
|
||||
if (headerstring != NULL) {
|
||||
xfree(headerstring);
|
||||
headerstring = NULL;
|
||||
}
|
||||
if (buf != NULL) {
|
||||
xfree(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,614 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
/** @file mm_context.c
|
||||
*
|
||||
* Modules for manipulating MiniMIME contexts
|
||||
*/
|
||||
|
||||
/** @defgroup context Accessing and manipulating MIME contexts
|
||||
*
|
||||
* Each message in MiniMIME is represented by a so called ``context''. A
|
||||
* context holds all necessary information given about a MIME message, such
|
||||
* as the envelope, all MIME parts etc.
|
||||
*/
|
||||
|
||||
/** @{
|
||||
* @name Manipulating MiniMIME contexts
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new MiniMIME context object.
|
||||
*
|
||||
* @return a new MiniMIME context object
|
||||
* @see mm_context_free
|
||||
*
|
||||
* This function creates a new MiniMIME context, which will hold a message.
|
||||
* The memory needed is allocated dynamically and should later be free'd
|
||||
* using mm_context_free().
|
||||
*
|
||||
* Before a context can be created, the MiniMIME library needs to be
|
||||
* initialized properly using mm_library_init().
|
||||
*
|
||||
*/
|
||||
MM_CTX *
|
||||
mm_context_new(void)
|
||||
{
|
||||
MM_CTX *ctx;
|
||||
|
||||
MM_ISINIT();
|
||||
|
||||
ctx = (MM_CTX *)xmalloc(sizeof(MM_CTX));
|
||||
ctx->messagetype = MM_MSGTYPE_FLAT; /* This is the default */
|
||||
ctx->boundary = NULL;
|
||||
ctx->preamble = xstrdup("This is a message in MIME format, generated "
|
||||
"by MiniMIME 0.1");
|
||||
|
||||
TAILQ_INIT(&ctx->parts);
|
||||
SLIST_INIT(&ctx->warnings);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a MiniMIME context object
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @see mm_context_new
|
||||
*
|
||||
* This function releases all memory associated with MiniMIME context object
|
||||
* that was created using mm_context_new(). It will also release all memory
|
||||
* used for the MIME parts attached, and their specific properties (such as
|
||||
* Content-Type information, headers, and the body data).
|
||||
*/
|
||||
void
|
||||
mm_context_free(MM_CTX *ctx)
|
||||
{
|
||||
struct mm_mimepart *part;
|
||||
struct mm_warning *warning, *nxt;
|
||||
|
||||
assert(ctx != NULL);
|
||||
|
||||
TAILQ_FOREACH(part, &ctx->parts, next) {
|
||||
TAILQ_REMOVE(&ctx->parts, part, next);
|
||||
mm_mimepart_free(part);
|
||||
}
|
||||
|
||||
if (ctx->boundary != NULL) {
|
||||
xfree(ctx->boundary);
|
||||
ctx->boundary = NULL;
|
||||
}
|
||||
|
||||
if (ctx->preamble != NULL) {
|
||||
xfree(ctx->preamble);
|
||||
ctx->preamble = NULL;
|
||||
}
|
||||
|
||||
for (warning = SLIST_FIRST(&ctx->warnings);
|
||||
warning != SLIST_END(&ctx->warnings);
|
||||
warning = nxt) {
|
||||
nxt = SLIST_NEXT(warning, next);
|
||||
SLIST_REMOVE(&ctx->warnings, warning, mm_warning, next);
|
||||
xfree(warning);
|
||||
warning = NULL;
|
||||
}
|
||||
|
||||
xfree(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a MIME part object to a MiniMIME context.
|
||||
*
|
||||
* @param ctx the MiniMIME context
|
||||
* @param part the MIME part object to attach
|
||||
* @return 0 on success or -1 on failure. Sets mm_errno on failure.
|
||||
*
|
||||
* This function attaches a MIME part to a context, appending it to the end
|
||||
* of the message.
|
||||
*
|
||||
* The MIME part should be initialized before attaching it using
|
||||
* mm_mimepart_new().
|
||||
*/
|
||||
int
|
||||
mm_context_attachpart(MM_CTX *ctx, struct mm_mimepart *part)
|
||||
{
|
||||
assert(ctx != NULL);
|
||||
assert(part != NULL);
|
||||
|
||||
if (TAILQ_EMPTY(&ctx->parts)) {
|
||||
TAILQ_INSERT_HEAD(&ctx->parts, part, next);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&ctx->parts, part, next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a MIME part object to a MiniMIME context at a given position
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @param part The MIME part object to attach
|
||||
* @param pos After which part to attach the object
|
||||
* @return 0 on success or -1 if the given position is invalid
|
||||
* @see mm_context_attachpart
|
||||
*
|
||||
* This function attaches a MIME part object after a given position in the
|
||||
* specified context. If the position is invalid (out of range), the part
|
||||
* will not get attached to the message and the function returns -1. If
|
||||
* the index was in range, the MIME part will get attached after the MIME
|
||||
* part at the given position, moving any possible following MIME parts one
|
||||
* down the hierarchy.
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
mm_context_attachpart_after(MM_CTX *ctx, struct mm_mimepart *part, int pos)
|
||||
{
|
||||
struct mm_mimepart *p;
|
||||
int where;
|
||||
|
||||
where = 0;
|
||||
p = NULL;
|
||||
|
||||
TAILQ_FOREACH(part, &ctx->parts, next) {
|
||||
if (where == pos) {
|
||||
p = part;
|
||||
}
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
TAILQ_INSERT_AFTER(&ctx->parts, p, part, next);
|
||||
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Deletes a MIME part object from a MiniMIME context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context object
|
||||
* @param which The number of the MIME part object to delete
|
||||
* @param freemem Whether to free the memory associated with the MIME part
|
||||
* object
|
||||
* @return 0 on success or -1 on failure. Sets mm_errno on failure.
|
||||
*
|
||||
* This function deletes a MIME part from a given context. The MIME part to
|
||||
* delete is specified as numerical index by the parameter ``which''. If the
|
||||
* parameter ``freemem'' is set to anything greater than 0, the memory that
|
||||
* is associated will be free'd by using mm_mimepart_free(), otherwise the
|
||||
* memory is left untouched (if you still have a pointer to the MIME part
|
||||
* around).
|
||||
*/
|
||||
int
|
||||
mm_context_deletepart(MM_CTX *ctx, int which, int freemem)
|
||||
{
|
||||
struct mm_mimepart *part;
|
||||
int cur;
|
||||
|
||||
assert(ctx != NULL);
|
||||
assert(which >= 0);
|
||||
|
||||
cur = 0;
|
||||
|
||||
TAILQ_FOREACH(part, &ctx->parts, next) {
|
||||
if (cur == which) {
|
||||
TAILQ_REMOVE(&ctx->parts, part, next);
|
||||
if (freemem)
|
||||
mm_mimepart_free(part);
|
||||
return 0;
|
||||
}
|
||||
cur++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of attached MIME part objects in a given MiniMIME context
|
||||
*
|
||||
* @param ctx The MiniMIME context
|
||||
* @returns The number of attached MIME part objects
|
||||
*/
|
||||
int
|
||||
mm_context_countparts(MM_CTX *ctx)
|
||||
{
|
||||
int count;
|
||||
struct mm_mimepart *part;
|
||||
|
||||
assert(ctx != NULL);
|
||||
|
||||
count = 0;
|
||||
|
||||
if (TAILQ_EMPTY(&ctx->parts)) {
|
||||
return 0;
|
||||
} else {
|
||||
TAILQ_FOREACH(part, &ctx->parts, next) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
assert(count > -1);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specified MIME part object from a MimeMIME context
|
||||
*
|
||||
* @param ctx The MiniMIME context
|
||||
* @param which The number of the MIME part object to retrieve
|
||||
* @returns The requested MIME part object on success or a NULL pointer if
|
||||
* there is no such part.
|
||||
*/
|
||||
struct mm_mimepart *
|
||||
mm_context_getpart(MM_CTX *ctx, int which)
|
||||
{
|
||||
struct mm_mimepart *part;
|
||||
int cur;
|
||||
|
||||
assert(ctx != NULL);
|
||||
|
||||
cur = 0;
|
||||
|
||||
TAILQ_FOREACH(part, &ctx->parts, next) {
|
||||
if (cur == which) {
|
||||
return part;
|
||||
}
|
||||
cur++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given context represents a composite (multipart) message
|
||||
*
|
||||
* @param ctx A valid MiniMIME context object
|
||||
* @return 1 if the context is a composite message or 0 if it's flat
|
||||
*
|
||||
*/
|
||||
int
|
||||
mm_context_iscomposite(MM_CTX *ctx)
|
||||
{
|
||||
if (ctx->messagetype == MM_MSGTYPE_MULTIPART) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether there are any warnings associated with a given context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @return 1 if there are warnings associated with the context, otherwise 0
|
||||
*/
|
||||
int
|
||||
mm_context_haswarnings(MM_CTX *ctx)
|
||||
{
|
||||
if (SLIST_EMPTY(&ctx->warnings)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a generic boundary string for a given context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @return 0 on success or -1 on failure
|
||||
*
|
||||
* This function generates a default boundary string for the given context.
|
||||
* If there is already a boundary for the context, the memory will be free()'d.
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
mm_context_generateboundary(MM_CTX *ctx)
|
||||
{
|
||||
char *boundary;
|
||||
struct mm_mimepart *part;
|
||||
struct mm_param *param;
|
||||
|
||||
if (mm_mimeutil_genboundary("++MiniMIME++", 20, &boundary) == -1) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (ctx->boundary != NULL) {
|
||||
xfree(ctx->boundary);
|
||||
ctx->boundary = NULL;
|
||||
}
|
||||
|
||||
/* If we already have an envelope, make sure that we also justify the
|
||||
* "boundary" parameter of the envelope.
|
||||
*/
|
||||
part = mm_context_getpart(ctx, 0);
|
||||
if (part == NULL) {
|
||||
return(0);
|
||||
}
|
||||
if (part->type != NULL) {
|
||||
param = mm_content_gettypeparamobjbyname(part->type, "boundary");
|
||||
if (param == NULL) {
|
||||
param = mm_param_new();
|
||||
param->name = xstrdup("boundary");
|
||||
param->value = xstrdup(boundary);
|
||||
mm_content_attachtypeparam(part->type, param);
|
||||
} else {
|
||||
if (param->value != NULL) {
|
||||
xfree(param->value);
|
||||
param->value = NULL;
|
||||
}
|
||||
param->value = xstrdup(boundary);
|
||||
}
|
||||
}
|
||||
|
||||
ctx->boundary = boundary;
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets a preamble for the given MiniMIME context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @param preamble The preamble to set
|
||||
* @return 0 on success or -1 on failure
|
||||
*
|
||||
* This function sets the MIME preamble (the text between the end of envelope
|
||||
* headers and the beginning of the first MIME part) for a given context
|
||||
* object. If preamble is a NULL-pointer then the preamble will be deleted,
|
||||
* and the currently associated memory will be free automagically.
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
mm_context_setpreamble(MM_CTX *ctx, char *preamble)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return(-1);
|
||||
|
||||
if (preamble == NULL) {
|
||||
if (ctx->preamble != NULL) {
|
||||
xfree(ctx->preamble);
|
||||
}
|
||||
ctx->preamble = NULL;
|
||||
} else {
|
||||
ctx->preamble = xstrdup(preamble);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
char *
|
||||
mm_context_getpreamble(MM_CTX *ctx)
|
||||
{
|
||||
if (ctx == NULL)
|
||||
return(NULL);
|
||||
|
||||
return(ctx->preamble);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates an ASCII message of the specified context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context object
|
||||
* @param flat Where to store the message
|
||||
* @param flags Flags that affect the flattening process
|
||||
*
|
||||
* This function ``flattens'' a MiniMIME context, that is, it creates an ASCII
|
||||
* represantation of the message the context contains. The flags can be a
|
||||
* bitwise combination of the following constants:
|
||||
*
|
||||
* - MM_FLATTEN_OPAQUE : use opaque MIME parts when flattening
|
||||
* - MM_FLATTEN_SKIPENVELOPE : do not flatten the envelope part
|
||||
*
|
||||
* Great care is taken to not produce invalid MIME output.
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
mm_context_flatten(MM_CTX *ctx, char **flat, size_t *length, int flags)
|
||||
{
|
||||
struct mm_mimepart *part;
|
||||
char *message;
|
||||
char *flatpart;
|
||||
char *buf;
|
||||
char *envelope_headers;
|
||||
size_t message_size;
|
||||
size_t tmp_size;
|
||||
char envelope;
|
||||
|
||||
mm_errno = MM_ERROR_NONE;
|
||||
envelope = 1;
|
||||
|
||||
message = NULL;
|
||||
message_size = 0;
|
||||
|
||||
if (ctx->boundary == NULL) {
|
||||
if (mm_context_iscomposite(ctx)) {
|
||||
mm_context_generateboundary(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(part, &ctx->parts, next) {
|
||||
if (envelope) {
|
||||
if (flags & MM_FLATTEN_SKIPENVELOPE) {
|
||||
envelope = 0;
|
||||
if ((message = (char *) malloc(1)) == NULL) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
goto cleanup;
|
||||
}
|
||||
*message = '\0';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part->type == NULL && mm_context_countparts(ctx) > 1) {
|
||||
if (mm_mimepart_setdefaultcontenttype(part, 1)
|
||||
== -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mm_context_generateboundary(ctx) == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
ctx->messagetype = MM_MSGTYPE_MULTIPART;
|
||||
}
|
||||
|
||||
if (mm_envelope_getheaders(ctx, &envelope_headers,
|
||||
&tmp_size) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
message = envelope_headers;
|
||||
message_size = tmp_size;
|
||||
envelope = 0;
|
||||
|
||||
if (ctx->preamble != NULL
|
||||
&& mm_context_iscomposite(ctx)
|
||||
&& !(flags & MM_FLATTEN_NOPREAMBLE)) {
|
||||
tmp_size += strlen(ctx->preamble)
|
||||
+ (strlen("\r\n") * 2);
|
||||
buf = (char *)xrealloc(message, tmp_size);
|
||||
if (buf == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
message_size += tmp_size;
|
||||
message = buf;
|
||||
strlcat(message, "\r\n", message_size);
|
||||
strlcat(message, ctx->preamble, message_size);
|
||||
strlcat(message, "\r\n", message_size);
|
||||
}
|
||||
} else {
|
||||
/* Enforce Content-Type if none exist */
|
||||
if (part->type == NULL) {
|
||||
if (mm_mimepart_setdefaultcontenttype(part, 0)
|
||||
== -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append a boundary if necessary */
|
||||
if (ctx->boundary != NULL) {
|
||||
tmp_size = strlen(ctx->boundary) +
|
||||
(strlen("\r\n") * 2) + strlen("--");
|
||||
|
||||
if (tmp_size < 1) {
|
||||
return(-1);
|
||||
}
|
||||
if (message_size + tmp_size < 1) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
buf = (char *)xrealloc(message, message_size
|
||||
+ tmp_size);
|
||||
if (buf == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
message_size += tmp_size;
|
||||
message = buf;
|
||||
strlcat(message, "\r\n", message_size);
|
||||
strlcat(message, "--", message_size);
|
||||
strlcat(message, ctx->boundary, message_size);
|
||||
strlcat(message, "\r\n", message_size);
|
||||
}
|
||||
|
||||
if (mm_mimepart_flatten(part, &flatpart, &tmp_size,
|
||||
(flags & MM_FLATTEN_OPAQUE)) == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (tmp_size < 1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
buf = (char *) xrealloc(message, message_size
|
||||
+ tmp_size);
|
||||
if (buf == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
message_size += tmp_size;
|
||||
message = buf;
|
||||
|
||||
strlcat(message, flatpart, message_size);
|
||||
xfree(flatpart);
|
||||
flatpart = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append end boundary */
|
||||
if (ctx->boundary != NULL && mm_context_iscomposite(ctx)) {
|
||||
tmp_size = strlen(ctx->boundary) + (strlen("\r\n") * 2)
|
||||
+ (strlen("--") * 2);
|
||||
buf = (char *)xrealloc(message, message_size + tmp_size);
|
||||
if (buf == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
message_size += tmp_size;
|
||||
message = buf;
|
||||
if (message[strlen(message)-1] != 13)
|
||||
strlcat(message, "\r", message_size);
|
||||
strlcat(message, "\n", message_size);
|
||||
strlcat(message, "--", message_size);
|
||||
strlcat(message, ctx->boundary, message_size);
|
||||
strlcat(message, "--", message_size);
|
||||
strlcat(message, "\r\n", message_size);
|
||||
}
|
||||
|
||||
*flat = message;
|
||||
*length = message_size;
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (message != NULL) {
|
||||
xfree(message);
|
||||
message = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
|
@ -1,271 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
#include "mm_util.h"
|
||||
|
||||
/** @file mm_envelope.c
|
||||
*
|
||||
* This module contains functions for accessing a message's envelope. This
|
||||
* are mainly wrapper functions for easy access.
|
||||
*/
|
||||
|
||||
/** @defgroup envelope Accessing and manipulating a message's envelope
|
||||
*/
|
||||
|
||||
/** @{
|
||||
* @name Accessing and manipulating a message's envelope
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets an ASCII representation of all envelope headers
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @param result Where to store the resulting ASCII headers
|
||||
* @param length Where to store the length of the result
|
||||
* @returns 0 on success or -1 on failure.
|
||||
* @note Sets mm_errno on failure
|
||||
*
|
||||
* This is mainly a convinience function. It constructs an ASCII representation
|
||||
* from all of the message's envelope headers and stores the result in headers.
|
||||
* Memory is allocated dynamically, and the total length of the result is
|
||||
* stored in length. This function takes care that the output is MIME conform,
|
||||
* and folds long lines according to the MIME standard at position 78 of the
|
||||
* string. It also nicely formats all MIME related header fields, such as
|
||||
* the Content-Type header.
|
||||
*
|
||||
* Since the memory needed to store the result is allocated dynamically, one
|
||||
* should take care of freeing it again when it's not needed anymore. If an
|
||||
* error occurs, *result will be set to NULL, *length will be set to zero
|
||||
* and mm_errno will be set to a reasonable value.
|
||||
*
|
||||
*/
|
||||
int
|
||||
mm_envelope_getheaders(MM_CTX *ctx, char **result, size_t *length)
|
||||
{
|
||||
struct mm_mimepart *part;
|
||||
struct mm_mimeheader *hdr;
|
||||
char *buf, *hdrbuf;
|
||||
size_t headers_length, tmp_length;
|
||||
|
||||
headers_length = 1;
|
||||
buf = NULL;
|
||||
|
||||
part = mm_context_getpart(ctx, 0);
|
||||
if (part == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize our buffer */
|
||||
if ((buf = (char *)xmalloc(headers_length)) == NULL) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
goto cleanup;
|
||||
}
|
||||
*buf = '\0';
|
||||
|
||||
/* Store each envelope header */
|
||||
TAILQ_FOREACH(hdr, &part->headers, next) {
|
||||
tmp_length = strlen(hdr->name) + strlen(hdr->value)
|
||||
+ strlen(": \r\n");
|
||||
hdrbuf = (char *) xrealloc(buf, headers_length + tmp_length);
|
||||
if (hdrbuf == NULL) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
headers_length += tmp_length;
|
||||
buf = hdrbuf;
|
||||
|
||||
strlcat(buf, hdr->name, headers_length);
|
||||
strlcat(buf, ": ", headers_length);
|
||||
strlcat(buf, hdr->value, headers_length);
|
||||
strlcat(buf, "\r\n", headers_length);
|
||||
}
|
||||
|
||||
/* Construct and store MIME headers */
|
||||
if (part->type != NULL) {
|
||||
char *typebuf;
|
||||
typebuf = mm_content_tostring(part->type);
|
||||
if (typebuf == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
tmp_length = strlen(typebuf) + strlen("\r\n");
|
||||
|
||||
hdrbuf = (char *) xrealloc(buf, headers_length + tmp_length);
|
||||
if (hdrbuf == NULL) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
headers_length += tmp_length;
|
||||
buf = hdrbuf;
|
||||
|
||||
strlcat(buf, typebuf, headers_length);
|
||||
strlcat(buf, "\r\n", headers_length);
|
||||
}
|
||||
|
||||
*result = buf;
|
||||
*length = headers_length;
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (buf != NULL) {
|
||||
xfree(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
*result = NULL;
|
||||
*length = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a header field in the envelope
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @param name The name of the header field to set
|
||||
* @param fmt A format string specifying the value of the header field
|
||||
* @return 0 on success or -1 on failure
|
||||
*
|
||||
* This function generates a new MIME header and attaches it to the first
|
||||
* MIME part (the envelope) found in the given context. If no part is
|
||||
* attached already, the function will return an error. The function will
|
||||
* store a copy of ``name'' as the header's name field, and dynamically
|
||||
* allocate the memory needed to build the format string.
|
||||
*/
|
||||
int
|
||||
mm_envelope_setheader(MM_CTX *ctx, const char *name, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *buf;
|
||||
struct mm_mimeheader *hdr;
|
||||
struct mm_mimepart *part;
|
||||
|
||||
part = mm_context_getpart(ctx, 0);
|
||||
if (part == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
hdr = mm_mimeheader_new();
|
||||
if (hdr == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
hdr->name = xstrdup(name);
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (vasprintf(&buf, fmt, ap) == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
hdr->value = buf;
|
||||
|
||||
if (mm_mimepart_attachheader(part, hdr) == -1) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return(0);
|
||||
|
||||
cleanup:
|
||||
if (hdr != NULL) {
|
||||
if (hdr->name != NULL) {
|
||||
xfree(hdr->name);
|
||||
hdr->name = NULL;
|
||||
}
|
||||
if (hdr->value != NULL) {
|
||||
xfree(hdr->value);
|
||||
hdr->value = NULL;
|
||||
}
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of recipients for a MIME message
|
||||
*
|
||||
* @param ctx A valid MiniMIME context
|
||||
* @param result Where to store the result
|
||||
* @param length Where to store the length of the result
|
||||
* @returns 0 on success or -1 on error
|
||||
* @note Sets mm_errno on error
|
||||
*
|
||||
* This functions gets the list of recipients for a given MIME message. It
|
||||
* does so by concatenating the "From" and "Cc" header fields, and storing
|
||||
* the results in recipients. The memory needed to store the result is
|
||||
* allocated dynamically, and the total length of the result is stored in
|
||||
* length.
|
||||
*
|
||||
* One should take care to free() the result once it's not needed anymore.
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
mm_envelope_getrecipients(MM_CTX *ctx, char **result, size_t *length)
|
||||
{
|
||||
struct mm_mimepart *part;
|
||||
struct mm_mimeheader *to, *cc;
|
||||
size_t recipients_length = 0;
|
||||
|
||||
part = mm_context_getpart(ctx, 0);
|
||||
if (part == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
to = mm_mimepart_getheaderbyname(part, "From", 0);
|
||||
cc = mm_mimepart_getheaderbyname(part, "Cc", 0);
|
||||
|
||||
if (to == NULL || cc == NULL) {
|
||||
*result = NULL;
|
||||
*length = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (to != NULL) {
|
||||
recipients_length += strlen(to->value);
|
||||
}
|
||||
if (cc != NULL) {
|
||||
recipients_length += strlen(cc->value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
#include "mm_util.h"
|
||||
|
||||
/** @file mm_error.c
|
||||
*
|
||||
* This module contains functions for MiniMIME error information/manipulation
|
||||
*/
|
||||
|
||||
/** @defgroup error MiniMIME error functions */
|
||||
|
||||
/**
|
||||
* Initializes the global error object
|
||||
*
|
||||
* @ingroup error
|
||||
*
|
||||
* This function initializes the global error object mm_error. This must be
|
||||
* done when the library is initialized, and is automatically called from
|
||||
* mm_init_library().
|
||||
*/
|
||||
void
|
||||
mm_error_init(void)
|
||||
{
|
||||
mm_error.error_id = 0;
|
||||
mm_error.error_where = 0;
|
||||
mm_error.lineno = 0;
|
||||
memset(&mm_error.error_msg, '\0', sizeof(mm_error.error_msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a descriptive error message
|
||||
*
|
||||
* @param fmt The error message as format string
|
||||
* @ingroup error
|
||||
*
|
||||
* This function is called from the various MiniMIME modules in case an
|
||||
* error occured. Should never be called by the user.
|
||||
*/
|
||||
void
|
||||
mm_error_setmsg(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(mm_error.error_msg, sizeof(mm_error.error_msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
mm_error_setlineno(int lineno)
|
||||
{
|
||||
mm_error.lineno = lineno;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current error message
|
||||
*
|
||||
* @return The currently set error message
|
||||
* @ingroup error
|
||||
*
|
||||
* This function can be used to retrieve a descriptive error message for the
|
||||
* current error, much like strerror() function of libc. When this function
|
||||
* is called without an error being set, it returns the string "No error".
|
||||
* The string returned does not need to be freed, since it is not dynamically
|
||||
* allocated by the library.
|
||||
*/
|
||||
char *
|
||||
mm_error_string(void)
|
||||
{
|
||||
if (mm_errno != MM_ERROR_ERRNO && mm_error.error_msg[0] == '\0') {
|
||||
return "No error";
|
||||
} else if (mm_errno == MM_ERROR_ERRNO) {
|
||||
return strerror(errno);
|
||||
} else {
|
||||
return mm_error.error_msg;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mm_error_lineno(void)
|
||||
{
|
||||
return mm_error.lineno;
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
#include "mm_util.h"
|
||||
|
||||
/** @file mm_header.c
|
||||
*
|
||||
* This module contains functions for manipulating MIME headers
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new MIME header object
|
||||
*
|
||||
* @return A new and initialized MIME header object
|
||||
* @see mm_mimeheader_free
|
||||
*
|
||||
* This function creates and initializes a new MIME header object, which must
|
||||
* later be freed using mm_mimeheader_free()
|
||||
*/
|
||||
struct mm_mimeheader *
|
||||
mm_mimeheader_new(void)
|
||||
{
|
||||
struct mm_mimeheader *header;
|
||||
|
||||
header = (struct mm_mimeheader *)xmalloc(sizeof(struct mm_mimeheader));
|
||||
|
||||
header->name = NULL;
|
||||
header->value = NULL;
|
||||
TAILQ_INIT(&header->params);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a MIME header object
|
||||
*
|
||||
* @param header The MIME header object which to free
|
||||
*/
|
||||
void
|
||||
mm_mimeheader_free(struct mm_mimeheader *header)
|
||||
{
|
||||
struct mm_param *param;
|
||||
assert(header != NULL);
|
||||
|
||||
if (header->name != NULL) {
|
||||
xfree(header->name);
|
||||
header->name = NULL;
|
||||
}
|
||||
if (header->value != NULL) {
|
||||
xfree(header->value);
|
||||
header->value = NULL;
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(param, &header->params, next) {
|
||||
TAILQ_REMOVE(&header->params, param, next);
|
||||
mm_param_free(param);
|
||||
}
|
||||
xfree(header);
|
||||
header = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MIME header, but does no checks whatsoever (create as-is)
|
||||
*/
|
||||
struct mm_mimeheader *
|
||||
mm_mimeheader_generate(const char *name, const char *value)
|
||||
{
|
||||
struct mm_mimeheader *header;
|
||||
|
||||
header = mm_mimeheader_new();
|
||||
|
||||
header->name = xstrdup(name);
|
||||
header->value = xstrdup(value);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a parameter to a MimeHeader object
|
||||
*
|
||||
* @param hdr The target MimeHeader object
|
||||
* @param param The parameter to attach
|
||||
* @return 0 on success and -1 on failure
|
||||
* @ingroup mimeheader
|
||||
*/
|
||||
int
|
||||
mm_mimeheader_attachparam(struct mm_mimeheader *hdr, struct mm_param *param)
|
||||
{
|
||||
assert(hdr != NULL);
|
||||
assert(param != NULL);
|
||||
|
||||
if (TAILQ_EMPTY(&hdr->params)) {
|
||||
TAILQ_INSERT_HEAD(&hdr->params, param, next);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&hdr->params, param, next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets a parameter value from a MimeHeader object.
|
||||
*
|
||||
* @param hdr the MimeHeader object
|
||||
* @param name the name of the parameter to retrieve
|
||||
* @return The value of the parameter on success or a NULL pointer on failure
|
||||
* @ingroup mimeheader
|
||||
*/
|
||||
char *
|
||||
mm_mimeheader_getparambyname(struct mm_mimeheader *hdr, const char *name)
|
||||
{
|
||||
struct mm_param *param;
|
||||
|
||||
assert(hdr != NULL);
|
||||
|
||||
TAILQ_FOREACH(param, &hdr->params, next) {
|
||||
if (!strcasecmp(param->name, name)) {
|
||||
return param->value;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
mm_mimeheader_uncomment(struct mm_mimeheader *header)
|
||||
{
|
||||
char *new;
|
||||
|
||||
assert(header != NULL);
|
||||
assert(header->name != NULL);
|
||||
assert(header->value != NULL);
|
||||
|
||||
new = mm_uncomment(header->value);
|
||||
if (new == NULL)
|
||||
return -1;
|
||||
|
||||
xfree(header->value);
|
||||
header->value = new;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mm_mimeheader_uncommentbyname(struct mm_mimepart *part, const char *name)
|
||||
{
|
||||
struct mm_mimeheader *header;
|
||||
|
||||
TAILQ_FOREACH(header, &part->headers, next) {
|
||||
if (!strcasecmp(header->name, name)) {
|
||||
return mm_mimeheader_uncomment(header);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
mm_mimeheader_uncommentall(struct mm_mimepart *part)
|
||||
{
|
||||
struct mm_mimeheader *header;
|
||||
int ret, r;
|
||||
|
||||
ret = 0;
|
||||
|
||||
TAILQ_FOREACH(header, &part->headers, next) {
|
||||
if ((r = mm_mimeheader_uncomment(header)) == -1) {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
int mm_errno;
|
||||
struct mm_error_data mm_error;
|
||||
static int mm_initialized;
|
||||
struct mm_codecs codecs;
|
||||
|
||||
int
|
||||
mm_library_init(void)
|
||||
{
|
||||
assert(mm_initialized != 1);
|
||||
|
||||
mm_errno = MM_ERROR_NONE;
|
||||
mm_initialized = 1;
|
||||
|
||||
SLIST_INIT(&codecs);
|
||||
|
||||
mm_error_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mm_library_isinitialized(void)
|
||||
{
|
||||
return mm_initialized;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** @file mm_internal.h
|
||||
* Data definitions for MiniMIME
|
||||
*/
|
||||
#ifndef _MM_INTERNAL_H_INCLUDED
|
||||
#define _MM_INTERNAL_H_INCLUDED
|
||||
|
||||
#include "mm.h"
|
||||
|
||||
#define debugp(m, ...) do { \
|
||||
fprintf(stderr, "%s:%d:: ", __FILE__, __LINE__); \
|
||||
fprintf(stderr, m, ## __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
fflush(stderr); \
|
||||
} while (0);
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @name Utility functions
|
||||
*/
|
||||
#ifndef __HAVE_LEAK_DETECTION
|
||||
void *xmalloc(size_t);
|
||||
void *xrealloc(void *, size_t);
|
||||
void xfree(void *);
|
||||
char *xstrdup(const char *);
|
||||
#endif
|
||||
|
||||
char *xstrsep(char **, const char *);
|
||||
|
||||
/* THIS FILE IS INTENTIONALLY LEFT BLANK */
|
||||
|
||||
#endif /* ! _MM_INTERNAL_H_INCLUDED */
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
#ifdef __HAVE_LEAK_DETECTION
|
||||
# include "mm_mem.h"
|
||||
|
||||
static struct MM_chunks chunks;
|
||||
|
||||
void *
|
||||
MM_malloc(size_t size, char *filename, int line)
|
||||
{
|
||||
struct MM_mem_chunk *chunk;
|
||||
void *pointer;
|
||||
|
||||
pointer = malloc(size);
|
||||
if (pointer == NULL)
|
||||
fdprintf(stderr, "INFO: malloc");
|
||||
|
||||
chunk = (struct MM_mem_chunk *)malloc(sizeof(struct MM_mem_chunk));
|
||||
if (chunk == NULL)
|
||||
fdprintf(stderr, "INFO: malloc");
|
||||
|
||||
chunk->address = pointer;
|
||||
chunk->size = size;
|
||||
chunk->filename = filename;
|
||||
chunk->line = line;
|
||||
|
||||
TAILQ_INSERT_TAIL(&chunks, chunk, next);
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
char *
|
||||
MM_strdup(const char *s, char *filename, int line)
|
||||
{
|
||||
char *r;
|
||||
|
||||
r = (char *)MM_malloc(strlen(s)+1, filename, line);
|
||||
strlcpy(r, s, strlen(s) + 1);
|
||||
if (strlen(r) != strlen(s)) {
|
||||
debugp("%d:%d", strlen(s), strlen(r));
|
||||
}
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
void *
|
||||
MM_realloc(void *p, size_t new_size, char *filename, int line)
|
||||
{
|
||||
void *r;
|
||||
void *a;
|
||||
struct MM_mem_chunk *chunk;
|
||||
struct MM_mem_chunk *last;
|
||||
|
||||
a = p;
|
||||
chunk = NULL;
|
||||
last = NULL;
|
||||
|
||||
assert(new_size > 0);
|
||||
|
||||
TAILQ_FOREACH(chunk, &chunks, next) {
|
||||
if (chunk->address == p) {
|
||||
last = chunk;
|
||||
}
|
||||
}
|
||||
|
||||
if (last == NULL) {
|
||||
debugp("MM_realloc: did not find chunk at %p (%s:%d) "
|
||||
", creating new", p, filename, line);
|
||||
return MM_malloc(new_size, filename, line);
|
||||
}
|
||||
|
||||
r = realloc(p, new_size);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
last->address = r;
|
||||
last->size = new_size;
|
||||
last->filename = filename;
|
||||
last->line = line;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
MM_free(void *pointer, char *filename, int line, char *name)
|
||||
{
|
||||
struct MM_mem_chunk *chunk, *nxt;
|
||||
|
||||
for (chunk = TAILQ_FIRST(&chunks); chunk != TAILQ_END(&chunks);
|
||||
chunk = nxt) {
|
||||
nxt = TAILQ_NEXT(&chunks, next);
|
||||
if (chunk->address == pointer) {
|
||||
TAILQ_REMOVE(&chunks, chunk, next);
|
||||
free(chunk->address);
|
||||
free(chunk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
debugp("FREE: did not find storage %s (at %p), %s:%d", name, pointer,
|
||||
filename, line);
|
||||
}
|
||||
|
||||
void
|
||||
MM_leakd_flush(void)
|
||||
{
|
||||
debugp("flushing memory informations");
|
||||
while (!TAILQ_EMPTY(&chunks))
|
||||
SLIST_REMOVE_HEAD(&chunks, next);
|
||||
}
|
||||
|
||||
void
|
||||
MM_leakd_printallocated(void)
|
||||
{
|
||||
struct MM_mem_chunk *chunk;
|
||||
debugp("printing dynamic memory allocations");
|
||||
TAILQ_FOREACH(chunk, &chunks, next) {
|
||||
debugp(" chunk: %p (alloc'ed at %s:%d, size %d)\n",
|
||||
chunk->address, chunk->filename, chunk->line, chunk->size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MM_leakd_init(void)
|
||||
{
|
||||
TAILQ_INIT(&chunks);
|
||||
}
|
||||
|
||||
#endif /* !__HAVE_LEAK_DETECTOR */
|
|
@ -1,32 +0,0 @@
|
|||
#ifndef __MEM_H
|
||||
#define __MEM_H
|
||||
|
||||
#ifdef __HAVE_LEAK_DETECTION
|
||||
|
||||
#define NAMEOF(v) #v
|
||||
#define xmalloc(x) MM_malloc(x, __FILE__, __LINE__)
|
||||
#define xfree(x) MM_free(x, __FILE__, __LINE__, NAMEOF(x))
|
||||
#define xstrdup(x) MM_strdup(x, __FILE__, __LINE__)
|
||||
#define xrealloc(x, y) MM_realloc(x, y, __FILE__, __LINE__)
|
||||
|
||||
TAILQ_HEAD(MM_chunks, MM_mem_chunk);
|
||||
|
||||
struct MM_mem_chunk {
|
||||
void *address;
|
||||
const char *filename;
|
||||
uint32_t line;
|
||||
size_t size;
|
||||
|
||||
TAILQ_ENTRY(MM_mem_chunk) next;
|
||||
};
|
||||
|
||||
void *MM_malloc(size_t, char *, int);
|
||||
void *MM_realloc(void *, size_t, char *, int);
|
||||
void MM_free(void *, char *, int, char *);
|
||||
char *MM_strdup(const char *, char *, int);
|
||||
void MM_leakd_init(void);
|
||||
void MM_leakd_printallocated(void);
|
||||
void MM_leakd_flush(void);
|
||||
|
||||
#endif /* __HAVE_LEAK_DETECTION */
|
||||
#endif /* ! HAVE_MEM_H */
|
|
@ -1,659 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
/** @file mm_mimepart.c
|
||||
*
|
||||
* This module contains functions for manipulating MIME header objects.
|
||||
*/
|
||||
|
||||
/** @defgroup mimepart Accessing and manipulating MIME parts
|
||||
*
|
||||
* MIME parts, also called entities, represent the structure of a MIME
|
||||
* message. ``Normal'' internet messages have only a single part, and
|
||||
* are called ``flat'' messages. Multipart messages have more then one
|
||||
* part, and each MIME part can have it's own subset of headers.
|
||||
*
|
||||
* Provided here are functions to easily access all informations from
|
||||
* a MIME part, including their specific headers and bodies.
|
||||
*/
|
||||
|
||||
/** @{
|
||||
* @name Creating and destroying MIME parts
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocates memory for a new mm_mimepart structure and initializes it.
|
||||
*
|
||||
* @return A pointer to a struct of type mm_mimeheader or NULL on failure
|
||||
* @see mm_mimepart_free
|
||||
* @note The memory must be freed by using mm_mimepart_free() later on.
|
||||
*/
|
||||
struct mm_mimepart *
|
||||
mm_mimepart_new(void)
|
||||
{
|
||||
struct mm_mimepart *part;
|
||||
|
||||
part = (struct mm_mimepart *)xmalloc(sizeof(struct mm_mimepart));
|
||||
|
||||
TAILQ_INIT(&part->headers);
|
||||
|
||||
part->opaque_length = 0;
|
||||
part->opaque_body = NULL;
|
||||
|
||||
part->length = 0;
|
||||
part->body = NULL;
|
||||
|
||||
part->type = NULL;
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MIME part from a file
|
||||
*
|
||||
* @param filename The name of the file to create the MIME part from
|
||||
* @return A pointer to a new MIME part object
|
||||
*
|
||||
* This function creates a new MIME part object from a file. The object should
|
||||
* be freed using mm_mimepart_free() later on. This function does NOT set the
|
||||
* Content-Type and neither does any encoding work.
|
||||
*/
|
||||
struct mm_mimepart *
|
||||
mm_mimepart_fromfile(const char *filename)
|
||||
{
|
||||
int fd;
|
||||
char *data;
|
||||
size_t r;
|
||||
struct stat st;
|
||||
struct mm_mimepart *part;
|
||||
|
||||
mm_errno = MM_ERROR_NONE;
|
||||
|
||||
if ((fd = open(filename, O_RDONLY)) == -1) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((stat(filename, &st)) == -1) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = xmalloc(st.st_size);
|
||||
r = read(fd, data, st.st_size);
|
||||
if (r != st.st_size) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
close(fd);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
data[r] = '\0';
|
||||
close(fd);
|
||||
|
||||
part = mm_mimepart_new();
|
||||
part->length = r;
|
||||
part->body = data;
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Frees all memory allocated by a mm_mimepart object.
|
||||
*
|
||||
* @param part A pointer to an allocated mm_mimepart object
|
||||
* @see mm_mimepart_new
|
||||
*/
|
||||
void
|
||||
mm_mimepart_free(struct mm_mimepart *part)
|
||||
{
|
||||
struct mm_mimeheader *header;
|
||||
|
||||
assert(part != NULL);
|
||||
|
||||
TAILQ_FOREACH(header, &part->headers, next) {
|
||||
mm_mimeheader_free(header);
|
||||
TAILQ_REMOVE(&part->headers, header, next);
|
||||
}
|
||||
|
||||
if (part->opaque_body != NULL) {
|
||||
xfree(part->opaque_body);
|
||||
part->opaque_body = NULL;
|
||||
part->body = NULL;
|
||||
} else if (part->body != NULL) {
|
||||
xfree(part->body);
|
||||
part->body = NULL;
|
||||
}
|
||||
|
||||
if (part->type != NULL) {
|
||||
mm_content_free(part->type);
|
||||
part->type = NULL;
|
||||
}
|
||||
|
||||
xfree(part);
|
||||
part = NULL;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @{
|
||||
* @name Accessing the MIME part's mail header
|
||||
*/
|
||||
|
||||
/**
|
||||
* Attaches a mm_mimeheader object to a MIME part
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param header A valid MIME header object
|
||||
* @return 0 if successfull or -1 if the header could not be attached
|
||||
*/
|
||||
int
|
||||
mm_mimepart_attachheader(struct mm_mimepart *part, struct mm_mimeheader *header)
|
||||
{
|
||||
assert(part != NULL);
|
||||
assert(header != NULL);
|
||||
|
||||
if (TAILQ_EMPTY(&part->headers)) {
|
||||
TAILQ_INSERT_HEAD(&part->headers, header, next);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&part->headers, header, next);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of MIME headers available in a MIME part
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @return The number of MIME headers within the MIME part
|
||||
*/
|
||||
int
|
||||
mm_mimepart_countheaders(struct mm_mimepart *part)
|
||||
{
|
||||
int found;
|
||||
struct mm_mimeheader *header;
|
||||
|
||||
assert(part != NULL);
|
||||
|
||||
found = 0;
|
||||
|
||||
TAILQ_FOREACH(header, &part->headers, next) {
|
||||
found++;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the number of MIME headers with a given name in a MIME part
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param name The name of the MIME header which to count for
|
||||
* @return The number of MIME headers within the MIME part
|
||||
*/
|
||||
int
|
||||
mm_mimepart_countheaderbyname(struct mm_mimepart *part, const char *name)
|
||||
{
|
||||
int found;
|
||||
struct mm_mimeheader *header;
|
||||
|
||||
assert(part != NULL);
|
||||
|
||||
found = 0;
|
||||
|
||||
TAILQ_FOREACH(header, &part->headers, next) {
|
||||
if (strcasecmp(header->name, name) == 0) {
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a MIME header object from a MIME part
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param name The name of the MIME header which to retrieve
|
||||
* @param idx Which header field to get (in case of multiple headers of the
|
||||
* same name).
|
||||
* @return A pointer to the requested MIME header on success, or NULL if there
|
||||
* either isn't a header with the requested name or idx is out of
|
||||
* range.
|
||||
*/
|
||||
struct mm_mimeheader *
|
||||
mm_mimepart_getheaderbyname(struct mm_mimepart *part, const char *name, int idx)
|
||||
{
|
||||
struct mm_mimeheader *header;
|
||||
int curidx;
|
||||
|
||||
curidx = 0;
|
||||
|
||||
TAILQ_FOREACH(header, &part->headers, next) {
|
||||
if (!strcasecmp(header->name, name)) {
|
||||
if (curidx == idx)
|
||||
return header;
|
||||
else
|
||||
curidx++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a MIME header object
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param name The name of the header field to get the value from
|
||||
* @param idx The index of the header field to get, in case there are multiple
|
||||
* headers with the same name.
|
||||
* @return A pointer to the requested value on success, or NULL if there either
|
||||
* isn't a header with the requested name or idx is out of range.
|
||||
*
|
||||
*/
|
||||
const char *
|
||||
mm_mimepart_getheadervalue(struct mm_mimepart *part, const char *name, int idx)
|
||||
{
|
||||
struct mm_mimeheader *header;
|
||||
|
||||
header = mm_mimepart_getheaderbyname(part, name, idx);
|
||||
if (header == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return header->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a header loop for a given MIME part
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param id The address of a MIME header object (to allow reentrance)
|
||||
* @return 0 on success or -1 on failure
|
||||
* @see mm_mimepart_headers_next
|
||||
*
|
||||
* Looping through headers can be done in the following way:
|
||||
*
|
||||
* @code
|
||||
* struct mm_mimeheader *header, *lheader;
|
||||
*
|
||||
* mm_mimepart_headers_start(part, &lheader);
|
||||
*
|
||||
* while ((header = mm_mimepart_headers_next(part, &lheader)) != NULL) {
|
||||
* printf("%s: %s\n", header->name, header->value);
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* For convienience, the macro mm_mimepart_headers_foreach() can be used to
|
||||
* loop through headers in a one-shot manner.
|
||||
*/
|
||||
int
|
||||
mm_mimepart_headers_start(struct mm_mimepart *part, struct mm_mimeheader **id)
|
||||
{
|
||||
assert(part != NULL);
|
||||
|
||||
if (TAILQ_EMPTY(&part->headers)) {
|
||||
return -1;
|
||||
}
|
||||
*id = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next MIME header of a given MIME part object
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param id A previously initialized MIME header object
|
||||
* @return A pointer to the MIME header object or NULL if end of headers was
|
||||
* reached.
|
||||
* @see mm_mimepart_headers_start
|
||||
*/
|
||||
struct mm_mimeheader *
|
||||
mm_mimepart_headers_next(struct mm_mimepart *part, struct mm_mimeheader **id)
|
||||
{
|
||||
struct mm_mimeheader *header;
|
||||
|
||||
assert(part != NULL);
|
||||
|
||||
if (*id == NULL) {
|
||||
header = TAILQ_FIRST(&part->headers);
|
||||
} else {
|
||||
header = TAILQ_NEXT(*id, next);
|
||||
}
|
||||
*id = header;
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @{
|
||||
* @name Accessing and manipulating the MIME part's body
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the pointer to the MIME part's body data
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param opaque Whether to get the opaque part or not
|
||||
* @return A pointer to the MIME part's body
|
||||
* @see mm_mimepart_setbody
|
||||
*
|
||||
*/
|
||||
char *
|
||||
mm_mimepart_getbody(struct mm_mimepart *part, int opaque)
|
||||
{
|
||||
assert(part != NULL);
|
||||
|
||||
if (opaque)
|
||||
return part->opaque_body;
|
||||
else
|
||||
return part->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the MIME part's body data
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param data A pointer to the data which to set
|
||||
* @see mm_mimepart_getbody
|
||||
*
|
||||
* This functions sets the body data for a given MIME part. The string pointed
|
||||
* to by data must be NUL-terminated. The data is copied into the MIME part's
|
||||
* body, and thus, the memory pointed to by data can be freed after the
|
||||
* operation.
|
||||
*/
|
||||
#if 0
|
||||
void
|
||||
mm_mimepart_setbody(struct mm_mimepart *part, const char *data, int opaque)
|
||||
{
|
||||
assert(part != NULL);
|
||||
assert(data != NULL);
|
||||
|
||||
if (opaque) {
|
||||
part->opaque_body = xstrdup(data);
|
||||
part->body = part->opaque_body;
|
||||
} else {
|
||||
part->body = xstrdup(data);
|
||||
}
|
||||
part->length = strlen(data);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the length of a given MIME part object
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @returns The size of the part's body in byte.
|
||||
*
|
||||
* This function returns the total length of the given MIME part's body. The
|
||||
* length does not include the headers of the MIME parts. If the function
|
||||
* returns 0, no body part is set currently.
|
||||
*/
|
||||
size_t
|
||||
mm_mimepart_getlength(struct mm_mimepart *part)
|
||||
{
|
||||
assert(part != NULL);
|
||||
|
||||
return part->length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a MIME part according to it's encoding using MiniMIME codecs
|
||||
*
|
||||
* @param A valid MIME part object
|
||||
* @return 0 if the MIME part could be successfully decoded or -1 if not
|
||||
* @note Sets mm_errno on error
|
||||
*
|
||||
* This function decodes the body of a MIME part with a registered decoder
|
||||
* according to it's Content-Transfer-Encoding header field.
|
||||
*/
|
||||
char *
|
||||
mm_mimepart_decode(struct mm_mimepart *part)
|
||||
{
|
||||
extern struct mm_codecs codecs;
|
||||
struct mm_codec *codec;
|
||||
void *decoded;
|
||||
|
||||
assert(part != NULL);
|
||||
assert(part->type != NULL);
|
||||
|
||||
decoded = NULL;
|
||||
|
||||
/* No encoding associated */
|
||||
if (part->type->encstring == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Loop through codecs and find a suitable one */
|
||||
SLIST_FOREACH(codec, &codecs, next) {
|
||||
if (!strcasecmp(part->type->encstring, codec->encoding)) {
|
||||
decoded = codec->decoder((char *)part->body);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASCII representation of the given MIME part
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param result Where to store the result
|
||||
* @param length Where to store the length of the result
|
||||
* @param opaque Whether to use the opaque MIME part
|
||||
* @returtn 0 on success or -1 on error.
|
||||
* @see mm_context_flatten
|
||||
*
|
||||
* This function creates an ASCII representation of a given MIME part. It will
|
||||
* dynamically allocate the memory needed and stores the result in the memory
|
||||
* region pointed to by result. The length of the result will be stored in
|
||||
* length. If opaque is set to 1, mm_mimepart_flatten will store an opaque
|
||||
* version of the MIME part in result, which means no headers will be created
|
||||
* or sanitized. This is particulary useful if the part is digitally signed by
|
||||
* e.g. PGP, and the signature spans the header fields of the part in question.
|
||||
*
|
||||
*/
|
||||
int
|
||||
mm_mimepart_flatten(struct mm_mimepart *part, char **result, size_t *length,
|
||||
int opaque)
|
||||
{
|
||||
size_t part_length;
|
||||
char *buf;
|
||||
char *ct_hdr;
|
||||
|
||||
*result = NULL;
|
||||
*length = 0;
|
||||
buf = NULL;
|
||||
ct_hdr = NULL;
|
||||
part_length = 0;
|
||||
|
||||
if (opaque && part->opaque_body != NULL) {
|
||||
part_length = strlen(part->opaque_body);
|
||||
*result = xstrdup(part->opaque_body);
|
||||
*length = part_length;
|
||||
return(0);
|
||||
} else {
|
||||
if (part->type == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
ct_hdr = mm_content_tostring(part->type);
|
||||
if (ct_hdr == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
part_length += strlen(ct_hdr) + 2;
|
||||
part_length += strlen("\r\n") * 2;
|
||||
part_length += strlen(part->body);
|
||||
|
||||
if (part_length < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
buf = (char *) xmalloc(part_length);
|
||||
if (buf == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
snprintf(buf, part_length,
|
||||
"%s\r\n\r\n%s\r\n",
|
||||
ct_hdr,
|
||||
part->body);
|
||||
|
||||
xfree(ct_hdr);
|
||||
ct_hdr = NULL;
|
||||
|
||||
*result = buf;
|
||||
*length = part_length;
|
||||
}
|
||||
|
||||
return(0);
|
||||
|
||||
cleanup:
|
||||
if (ct_hdr != NULL) {
|
||||
xfree(ct_hdr);
|
||||
ct_hdr = NULL;
|
||||
}
|
||||
if (buf != NULL) {
|
||||
xfree(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
*result = NULL;
|
||||
*length = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default Content-Type for a given MIME part
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param part Whether the Content-Type should be for composite or not
|
||||
* @return 0 on success or -1 on failure
|
||||
*
|
||||
* This function sets a default Content-Type according to RFC 2045 with a value
|
||||
* of "text/plain; charset="us-ascii"". This function should only be used if
|
||||
* the MIME part in question does not have a valid Content-Type specification.
|
||||
*/
|
||||
int
|
||||
mm_mimepart_setdefaultcontenttype(struct mm_mimepart *part, int composite)
|
||||
{
|
||||
struct mm_content *type;
|
||||
struct mm_param *param;
|
||||
|
||||
if (part == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (part->type != NULL) {
|
||||
mm_content_free(part->type);
|
||||
part->type = NULL;
|
||||
}
|
||||
|
||||
type = mm_content_new();
|
||||
if (composite) {
|
||||
type->maintype = xstrdup("multipart");
|
||||
type->subtype = xstrdup("mixed");
|
||||
} else {
|
||||
type->maintype = xstrdup("text");
|
||||
type->subtype = xstrdup("plain");
|
||||
param = mm_param_new();
|
||||
param->name = xstrdup("charset");
|
||||
param->value = xstrdup("us-ascii");
|
||||
mm_content_attachtypeparam(type, param);
|
||||
}
|
||||
|
||||
mm_mimepart_attachcontenttype(part, type);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/** @{
|
||||
* @name Accessing the MIME part's Content-Type information
|
||||
*/
|
||||
|
||||
/**
|
||||
* Attaches a context type object to a MIME part
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @param ct The content type object to attach
|
||||
* @return Nothing
|
||||
*
|
||||
* This function attaches a Content-Type object to a MIME part. It does not
|
||||
* care whether the Content-Type suites the actual content in the MIME part,
|
||||
* so the programmer should take care of that.
|
||||
*/
|
||||
void
|
||||
mm_mimepart_attachcontenttype(struct mm_mimepart *part, struct mm_content *ct)
|
||||
{
|
||||
part->type = ct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Content-Type of a given MIME part object
|
||||
*
|
||||
* @param part A valid MIME part object
|
||||
* @return The Content-Type object of the specified MIME part
|
||||
*
|
||||
* This function returns a pointer to the Content-Type object of the given
|
||||
* MIME part. This pointer might be set to NULL, indicating that there is
|
||||
* no Content-Type object for the given MIME part currently.
|
||||
*/
|
||||
struct mm_content *
|
||||
mm_mimepart_getcontent(struct mm_mimepart *part)
|
||||
{
|
||||
assert(part != NULL);
|
||||
|
||||
return part->type;
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2004 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
#define MM_DATE_LENGTH 50
|
||||
|
||||
static const char boundary_charset[] =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.=";
|
||||
|
||||
/** @file mm_mimeutil.c
|
||||
*
|
||||
* This module contains various MIME related utility functions.
|
||||
*/
|
||||
|
||||
/** @defgroup mimeutil MIME related utility functions */
|
||||
|
||||
/**
|
||||
* Generates an RFC 2822 conform date string
|
||||
*
|
||||
* @param timezone Whether to include timezone information
|
||||
* @returns A pointer to the actual date string
|
||||
* @note The pointer returned must be freed some time
|
||||
*
|
||||
* This function generates an RFC 2822 conform date string to use in message
|
||||
* headers. It allocates memory to hold the string and returns a pointer to
|
||||
* it. The generated date is in the format (example):
|
||||
*
|
||||
* Thu, 25 December 2003 16:35:22 +0100 (CET)
|
||||
*
|
||||
* This function dynamically allocates memory and returns a pointer to it.
|
||||
* This memory should be released with free() once not needed anymore.
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
mm_mimeutil_gendate(char **result)
|
||||
{
|
||||
time_t curtime;
|
||||
struct tm *curtm;
|
||||
|
||||
if (result != NULL) {
|
||||
curtime = time(NULL);
|
||||
curtm = localtime(&curtime);
|
||||
if ((*result = (char *) malloc(MM_DATE_LENGTH)) == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
return(strftime(*result, MM_DATE_LENGTH,
|
||||
"%a, %d %b %G %T %z (%Z)", curtm));
|
||||
} else {
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
mm_mimeutil_genboundary(char *prefix, size_t length, char **result)
|
||||
{
|
||||
size_t total;
|
||||
size_t preflen;
|
||||
struct timeval curtm;
|
||||
int i;
|
||||
int pos;
|
||||
|
||||
total = 0;
|
||||
preflen = 0;
|
||||
|
||||
if (result == NULL) {
|
||||
return(-1);
|
||||
}
|
||||
*result = NULL;
|
||||
|
||||
gettimeofday(&curtm, NULL);
|
||||
srandom(curtm.tv_usec);
|
||||
|
||||
if (prefix != NULL) {
|
||||
total = strlen(prefix);
|
||||
preflen = total;
|
||||
}
|
||||
|
||||
total += length;
|
||||
|
||||
if ((*result = (char *) xmalloc(total + 1)) == NULL) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
*result = '\0';
|
||||
|
||||
if (prefix != NULL) {
|
||||
strlcat(*result, prefix, total);
|
||||
}
|
||||
|
||||
for (i = 0; i < length - 1; i++) {
|
||||
pos = random() % strlen(boundary_charset);
|
||||
*result[i + preflen] = boundary_charset[pos];
|
||||
}
|
||||
*result[total] = '\0';
|
||||
|
||||
return (0);
|
||||
}
|
|
@ -1,225 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
#include "mm_util.h"
|
||||
|
||||
/**
|
||||
* @file mm_param.c
|
||||
*
|
||||
* Functions to manipulate MIME parameters
|
||||
*/
|
||||
|
||||
/** @defgroup param Accessing and manipulating MIME parameters */
|
||||
|
||||
/** @{
|
||||
*
|
||||
* @name Functions for manipulating MIME parameters
|
||||
*
|
||||
* MIME parameters are properties attached to certain MIME headers, such as
|
||||
* Content-Type and Content-Disposition. MIME parameters have a textual
|
||||
* representations as in <i>name=value</i>. They contain important information
|
||||
* about the MIME structure of a message, such as the boundary string used,
|
||||
* which charset was used to encode the message and so on. This module
|
||||
* provides simple to use functions to query or set MIME parameters.
|
||||
*
|
||||
* Each MIME header may hold an arbitrary amount of such parameters, which
|
||||
* are delimeted by each other with a semicolon.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a new object to hold a MIME parameter.
|
||||
*
|
||||
* @return An object representing a MIME parameter
|
||||
* @see mm_param_free
|
||||
* @note The allocated memory must later be freed using mm_param_free()
|
||||
*/
|
||||
struct mm_param *
|
||||
mm_param_new(void)
|
||||
{
|
||||
struct mm_param *param;
|
||||
|
||||
param = (struct mm_param *)xmalloc(sizeof(struct mm_param));
|
||||
|
||||
param->name = NULL;
|
||||
param->value = NULL;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all memory associated with a MIME parameter object.
|
||||
*
|
||||
* @param param A valid MIME parameter object to be freed
|
||||
* @return Nothing
|
||||
* @see mm_param_new
|
||||
*/
|
||||
void
|
||||
mm_param_free(struct mm_param *param)
|
||||
{
|
||||
assert(param != NULL);
|
||||
|
||||
if (param->name != NULL) {
|
||||
xfree(param->name);
|
||||
param->name = NULL;
|
||||
}
|
||||
if (param->value != NULL) {
|
||||
xfree(param->value);
|
||||
param->value = NULL;
|
||||
}
|
||||
xfree(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Content-Type parameter with the given name and value
|
||||
*
|
||||
* @param name The name of the MIME parameter
|
||||
* @param value The value of the MIME parameter
|
||||
* @returns A new MIME parameter object
|
||||
* @see mm_param_free
|
||||
* @see mm_param_new
|
||||
*
|
||||
* This function generates a new MIME parameter, with the name
|
||||
* and value given as the arguments. The needed memory for the operation
|
||||
* is allocated dynamically. It stores a copy of name and value in the
|
||||
* actual object, so the memory holding the arguments can safely be
|
||||
* freed after successfull return of this function.
|
||||
*/
|
||||
#if 0
|
||||
struct mm_param *
|
||||
mm_param_generate(const char *name, const char *value)
|
||||
{
|
||||
struct mm_param *param;
|
||||
|
||||
param = mm_param_new();
|
||||
|
||||
param->name = xstrdup(name);
|
||||
param->value = xstrdup(value);
|
||||
|
||||
return param;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets the name of the given MIME parameter
|
||||
*
|
||||
* @param param A valid MIME parameter object
|
||||
* @param name The new name of the parameter
|
||||
* @param copy If set to > 0, copy the value stored in name
|
||||
* @returns The address of the previous name for passing to free()
|
||||
*/
|
||||
#if 0
|
||||
char *
|
||||
mm_param_setname(struct mm_param *param, const char *name, int copy)
|
||||
{
|
||||
char *retadr;
|
||||
assert(param != NULL);
|
||||
|
||||
retadr = param->name;
|
||||
|
||||
if (copy)
|
||||
param->name = xstrdup(name);
|
||||
else
|
||||
param->name = (char *)name;
|
||||
|
||||
return retadr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets the value of the given MIME parameter
|
||||
*
|
||||
* @param param A valid MIME parameter object
|
||||
* @param name The new value for the parameter
|
||||
* @param copy If set to > 0, copy the value stored in value
|
||||
* @returns The address of the previous value for passing to free()
|
||||
*/
|
||||
#if 0
|
||||
char *
|
||||
mm_param_setvalue(struct mm_param *param, const char *value, int copy)
|
||||
{
|
||||
char *retadr;
|
||||
assert(param != NULL);
|
||||
|
||||
retadr = param->value;
|
||||
|
||||
if (copy)
|
||||
param->value = xstrdup(value);
|
||||
else
|
||||
param->value = (char *)value;
|
||||
|
||||
return retadr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the name of a MIME parameter object
|
||||
*
|
||||
* @param param A valid MIME parameter object
|
||||
* @returns The name of the MIME parameter
|
||||
*/
|
||||
#if 0
|
||||
const char *
|
||||
mm_param_getname(struct mm_param *param)
|
||||
{
|
||||
assert(param != NULL);
|
||||
return param->name;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the value of a MIME parameter object
|
||||
*
|
||||
* @param param A valid MIME parameter object
|
||||
* @returns The value of the MIME parameter
|
||||
*/
|
||||
#if 0
|
||||
const char *
|
||||
mm_param_getvalue(struct mm_param *param)
|
||||
{
|
||||
assert(param != NULL);
|
||||
return param->value;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
#include "mm_util.h"
|
||||
|
||||
#include "mimeparser.h"
|
||||
#include "mimeparser.tab.h"
|
||||
|
||||
/** @file mm_parse.c
|
||||
*
|
||||
* Functions to parse MIME messages
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parses a NUL-terminated string into a MiniMIME context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context object
|
||||
* @param text The NUL-terminated string to parse
|
||||
* @param parsemode The parsemode
|
||||
* @param flags The flags to pass to the parser
|
||||
* @returns 0 on success or -1 on failure
|
||||
* @note Sets mm_errno if an error occurs
|
||||
*
|
||||
* This function parses a MIME message, stored in the memory region pointed to
|
||||
* by text (must be NUL-terminated) according to the parseflags and stores the
|
||||
* results in the MiniMIME context specified by ctx.
|
||||
*
|
||||
* The following modes can be used to specify how the message should be
|
||||
* parsed:
|
||||
*
|
||||
* - MM_PARSE_STRICT: Do not tolerate MIME violations
|
||||
* - MM_PARSE_LOOSE: Tolerate as much MIME violations as possible
|
||||
*
|
||||
* The context needs to be initialized before using mm_context_new() and may
|
||||
* be freed using mm_context_free().
|
||||
*/
|
||||
int
|
||||
mm_parse_mem(MM_CTX *ctx, const char *text, int parsemode, int flags)
|
||||
{
|
||||
void *yyscanner;
|
||||
int res;
|
||||
struct parser_state pstate;
|
||||
|
||||
pstate.ctx = ctx;
|
||||
pstate.parsemode = parsemode;
|
||||
|
||||
mimeparser_yylex_init(&yyscanner);
|
||||
PARSER_initialize(&pstate, yyscanner);
|
||||
|
||||
PARSER_setbuffer(text, yyscanner);
|
||||
PARSER_setfp(NULL, yyscanner);
|
||||
|
||||
res = mimeparser_yyparse(&pstate,yyscanner);
|
||||
mimeparser_yylex_destroy(yyscanner);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a file into a MiniMIME context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context object
|
||||
* @param filename The name of the file to parse
|
||||
* @param parsemode The parsemode
|
||||
* @param flags The flags to pass to the parser
|
||||
* @returns 0 on success or -1 on failure
|
||||
* @note Sets mm_errno if an error occurs
|
||||
*
|
||||
* This function parses a MIME message, stored in the filesystem according to
|
||||
* the parseflags and stores the results in the MiniMIME context specified by
|
||||
* ctx.
|
||||
*
|
||||
* The following modes can be used to specify how the message should be
|
||||
* parsed:
|
||||
*
|
||||
* - MM_PARSE_STRICT: Do not tolerate MIME violations
|
||||
* - MM_PARSE_LOOSE: Tolerate as much MIME violations as possible
|
||||
*
|
||||
* The context needs to be initialized before using mm_context_new() and may
|
||||
* be freed using mm_context_free().
|
||||
*/
|
||||
int
|
||||
mm_parse_file(MM_CTX *ctx, const char *filename, int parsemode, int flags)
|
||||
{
|
||||
FILE *fp;
|
||||
int res;
|
||||
void *yyscanner;
|
||||
struct parser_state pstate;
|
||||
|
||||
mimeparser_yylex_init(&yyscanner);
|
||||
|
||||
if ((fp = fopen(filename, "r")) == NULL) {
|
||||
mm_errno = MM_ERROR_ERRNO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PARSER_setfp(fp,yyscanner);
|
||||
PARSER_initialize(&pstate, yyscanner);
|
||||
|
||||
pstate.ctx = ctx;
|
||||
pstate.parsemode = parsemode;
|
||||
|
||||
res = mimeparser_yyparse(&pstate,yyscanner);
|
||||
mimeparser_yylex_destroy(yyscanner);
|
||||
fclose(fp);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
mm_parse_fileptr(MM_CTX *ctx, FILE *f, int parsemode, int flags)
|
||||
{
|
||||
int res;
|
||||
void *yyscanner;
|
||||
struct parser_state pstate;
|
||||
|
||||
mimeparser_yylex_init(&yyscanner);
|
||||
|
||||
PARSER_setfp(f, yyscanner);
|
||||
PARSER_initialize(&pstate, yyscanner);
|
||||
|
||||
pstate.ctx = ctx;
|
||||
pstate.parsemode = parsemode;
|
||||
|
||||
res = mimeparser_yyparse(&pstate,yyscanner);
|
||||
mimeparser_yylex_destroy(yyscanner);
|
||||
|
||||
return res;
|
||||
}
|
|
@ -1,508 +0,0 @@
|
|||
/* $OpenBSD: queue.h,v 1.25 2004/04/08 16:08:21 henning Exp $ */
|
||||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* lists, simple queues, tail queues, and circular queues.
|
||||
*
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
#define SLIST_END(head) NULL
|
||||
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for((var) = SLIST_FIRST(head); \
|
||||
(var) != SLIST_END(head); \
|
||||
(var) = SLIST_NEXT(var, field))
|
||||
|
||||
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||
for ((varp) = &SLIST_FIRST((head)); \
|
||||
((var) = *(varp)) != SLIST_END(head); \
|
||||
(varp) = &SLIST_NEXT((var), field))
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_INIT(head) { \
|
||||
SLIST_FIRST(head) = SLIST_END(head); \
|
||||
}
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->slh_first == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = (head)->slh_first; \
|
||||
while( curelm->field.sle_next != (elm) ) \
|
||||
curelm = curelm->field.sle_next; \
|
||||
curelm->field.sle_next = \
|
||||
curelm->field.sle_next->field.sle_next; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List access methods
|
||||
*/
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
#define LIST_END(head) NULL
|
||||
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for((var) = LIST_FIRST(head); \
|
||||
(var)!= LIST_END(head); \
|
||||
(var) = LIST_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST(head) = LIST_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REPLACE(elm, elm2, field) do { \
|
||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||
(elm2)->field.le_next->field.le_prev = \
|
||||
&(elm2)->field.le_next; \
|
||||
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||
*(elm2)->field.le_prev = (elm2); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define SIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define SIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define SIMPLEQ_END(head) NULL
|
||||
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||
for((var) = SIMPLEQ_FIRST(head); \
|
||||
(var) != SIMPLEQ_END(head); \
|
||||
(var) = SIMPLEQ_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define SIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \
|
||||
if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* tail queue access methods
|
||||
*/
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_END(head) NULL
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
/* XXX */
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
#define TAILQ_EMPTY(head) \
|
||||
(TAILQ_FIRST(head) == TAILQ_END(head))
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for((var) = TAILQ_FIRST(head); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_NEXT(var, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for((var) = TAILQ_LAST(head, headname); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm2)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
*(elm2)->field.tqe_prev = (elm2); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue access methods
|
||||
*/
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define CIRCLEQ_END(head) ((void *)(head))
|
||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
#define CIRCLEQ_EMPTY(head) \
|
||||
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for((var) = CIRCLEQ_FIRST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_NEXT(var, field))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for((var) = CIRCLEQ_LAST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_PREV(var, field))
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_last = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_first = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
|
@ -1,412 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
/** @file mm_util.c
|
||||
*
|
||||
* This module contains utility functions for the MiniMIME library
|
||||
*/
|
||||
|
||||
/** @defgroup util General purpose utility functions */
|
||||
|
||||
#ifndef __HAVE_LEAK_DETECTION
|
||||
/**
|
||||
* Allocates a block of memory
|
||||
*
|
||||
* @param size The size of the memory region to allocate
|
||||
* @return A pointer to the allocated memory region
|
||||
* @ingroup util
|
||||
*
|
||||
* xmalloc() calls abort() if either the size argument is negative or the
|
||||
* requested memory amount could not be allocated via an assert() call.
|
||||
*/
|
||||
void *
|
||||
xmalloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
assert(size > 0);
|
||||
p = malloc(size);
|
||||
assert(p != NULL);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* realloc() wrapper
|
||||
*
|
||||
* @param p Pointer to a memory region which should be reallocated
|
||||
* @param size The new size of the memory region
|
||||
* @return A pointer to the reallocated memory region
|
||||
* @ingroup util
|
||||
*
|
||||
* xrealloc() is a wrapper around realloc() which calls abort() if either the
|
||||
* size argument is negative or the requested memory amount could not be
|
||||
* allocated.
|
||||
*/
|
||||
void *
|
||||
xrealloc(void *p, size_t size)
|
||||
{
|
||||
void *n;
|
||||
|
||||
assert(size > 0);
|
||||
n = realloc(p, size);
|
||||
assert(n != NULL);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *str)
|
||||
{
|
||||
char *p;
|
||||
|
||||
assert(str != NULL);
|
||||
p = strdup(str);
|
||||
assert(p != NULL);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
xfree(void *p)
|
||||
{
|
||||
assert(p != NULL);
|
||||
free(p);
|
||||
p = NULL;
|
||||
assert(p == NULL);
|
||||
}
|
||||
#endif /* ! __HAVE_LEAK_DETECTION */
|
||||
|
||||
/**
|
||||
* Unquotes a string
|
||||
*
|
||||
* @param string The quoted string to unquote
|
||||
* @return A pointer to the unquoted string
|
||||
* @ingroup util
|
||||
*
|
||||
* This function unquotes a string. That is, it returns a pointer to a newly
|
||||
* allocated memory region in which the unquoted string is stored. Only
|
||||
* leading and trailing double-qoutes are removed. The string needs to be
|
||||
* freed when it is not needed anymore.
|
||||
*/
|
||||
char *
|
||||
mm_unquote(const char *string)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (string[0] != '\"' || string[strlen(string)-1] != '\"')
|
||||
return xstrdup(string);
|
||||
|
||||
ret = xstrdup(string + 1);
|
||||
ret[strlen(ret)-1] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes MIME comments from a string
|
||||
*
|
||||
* @param string The string to uncomment
|
||||
* @return A pointer to the uncommented string or NULL on error. Sets mm_errno.
|
||||
* @ingroup util
|
||||
*
|
||||
* This function removes MIME comments from a string (included in parantheses).
|
||||
* It returns a pointer to a newly allocated memory region in which the
|
||||
* uncommented string is stored. The returned string needs to be freed when
|
||||
* it's not used anymore.
|
||||
*/
|
||||
char *
|
||||
mm_uncomment(const char *string)
|
||||
{
|
||||
char *buf, *new, *orig, *token;
|
||||
size_t new_size;
|
||||
int found;
|
||||
int open;
|
||||
|
||||
assert(string != NULL);
|
||||
|
||||
new_size = strlen(string) + 1;
|
||||
new = NULL;
|
||||
buf = NULL;
|
||||
orig = NULL;
|
||||
found = 0;
|
||||
open = 0;
|
||||
mm_errno = MM_ERROR_NONE;
|
||||
|
||||
buf = xstrdup(string);
|
||||
orig = buf;
|
||||
|
||||
while (*buf != '\0') {
|
||||
if (*buf == '(') {
|
||||
open++;
|
||||
new_size--;
|
||||
found++;
|
||||
} else if (*buf == ')') {
|
||||
open--;
|
||||
new_size--;
|
||||
} else {
|
||||
if (open)
|
||||
new_size--;
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
|
||||
if (open != 0) {
|
||||
mm_errno = MM_ERROR_PARSE;
|
||||
mm_error_setmsg("Uncommenting: parantheses are unbalanced");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
new = orig;
|
||||
return orig;
|
||||
}
|
||||
|
||||
new = xmalloc(new_size + 1);
|
||||
*new = '\0';
|
||||
buf = orig;
|
||||
token = buf;
|
||||
|
||||
/* Tokenize our string by parentheses, and copy the portions which are
|
||||
* not commented to our destination.
|
||||
*/
|
||||
open = 0;
|
||||
while (*buf != '\0') {
|
||||
if (*buf == '(') {
|
||||
if (!open) {
|
||||
*buf = '\0';
|
||||
strlcat(new, token, new_size);
|
||||
token = buf+1;
|
||||
}
|
||||
open++;
|
||||
}
|
||||
if (*buf == ')') {
|
||||
open--;
|
||||
token = buf + 1;
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
|
||||
strlcat(new, token, new_size);
|
||||
|
||||
cleanup:
|
||||
if (orig != NULL) {
|
||||
xfree(orig);
|
||||
orig = NULL;
|
||||
}
|
||||
|
||||
if (mm_errno != MM_ERROR_NONE) {
|
||||
if (new != NULL) {
|
||||
xfree(new);
|
||||
new = NULL;
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
return new;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* separate strings
|
||||
*
|
||||
* @param stringp A pointer to the string being splitted
|
||||
* @param delim The delimeter string
|
||||
* @ingroup util
|
||||
*
|
||||
* This function works similar to strsep(), with the difference that delim is
|
||||
* treated as a whole.
|
||||
*/
|
||||
char *
|
||||
xstrsep(char **stringp, const char *delim)
|
||||
{
|
||||
char *p;
|
||||
char *s;
|
||||
char *r;
|
||||
|
||||
if (*stringp == NULL || *stringp == '\0')
|
||||
return NULL;
|
||||
|
||||
p = *stringp;
|
||||
|
||||
if ((s = strstr(p, delim)) == NULL) {
|
||||
r = p;
|
||||
while (*p != '\0')
|
||||
p++;
|
||||
*stringp = NULL;
|
||||
return r;
|
||||
} else {
|
||||
r = p;
|
||||
p += strlen(p) - strlen(s);
|
||||
*p = '\0';
|
||||
*stringp = p + strlen(delim);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips a given character set from a string
|
||||
*
|
||||
* @param input The string which to strip
|
||||
* @param strip The character set to strip off
|
||||
* @return A copy of the original string with all chars stripped
|
||||
* @ingroup util
|
||||
*/
|
||||
char *
|
||||
mm_stripchars(char *input, char *strip)
|
||||
{
|
||||
char *output, *orig;
|
||||
int i, j, chars;
|
||||
|
||||
assert(input != NULL);
|
||||
assert(strip != '\0');
|
||||
|
||||
chars = 0;
|
||||
orig = input;
|
||||
|
||||
while (*orig != '\0') {
|
||||
for (i = 0; i < strlen(strip); i++) {
|
||||
if (*orig == strip[i]) {
|
||||
chars++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
orig++;
|
||||
}
|
||||
|
||||
/* If we have not found any char in the input, return a dup of the orig
|
||||
string */
|
||||
if (chars == 0)
|
||||
return(xstrdup(input));
|
||||
|
||||
output = (char *)xmalloc(strlen(input) - chars);
|
||||
orig = output;
|
||||
|
||||
for (i = 0; i < strlen(input); i++) {
|
||||
int stripc;
|
||||
stripc = 0;
|
||||
for (j = 0; j < strlen(strip); j++) {
|
||||
if (input[i] == strip[j]) {
|
||||
stripc = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stripc == 0) {
|
||||
*output = input[i];
|
||||
output++;
|
||||
}
|
||||
}
|
||||
|
||||
*output = '\0';
|
||||
|
||||
return(orig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds characters to a string at given positions
|
||||
*
|
||||
* @param input The string to which to add characters
|
||||
* @param add The character string to add
|
||||
* @param linelength The position where to add the character
|
||||
* @return A copy of the string with characters added
|
||||
* @ingroup util
|
||||
*
|
||||
* This function adds the characters add at each linelength positions and
|
||||
* returns this new string.
|
||||
*/
|
||||
char *
|
||||
mm_addchars(char *input, char *add, uint16_t linelength)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t i;
|
||||
uint32_t l;
|
||||
uint32_t j;
|
||||
uint16_t addcrlf;
|
||||
char *output;
|
||||
char *orig;
|
||||
|
||||
len = strlen(input);
|
||||
if (len <= linelength)
|
||||
return(xstrdup(input));
|
||||
|
||||
addcrlf = len / linelength;
|
||||
|
||||
output = (char *)xmalloc(len + (addcrlf * strlen(add)));
|
||||
orig = output;
|
||||
|
||||
for (i = 0, l = 0; i < len; i++, l++) {
|
||||
if (l == linelength) {
|
||||
for (j = 0; j < strlen(add); j++) {
|
||||
*output = add[j];
|
||||
output++;
|
||||
}
|
||||
l = 0;
|
||||
}
|
||||
*output = input[i];
|
||||
output++;
|
||||
}
|
||||
|
||||
*output = '\0';
|
||||
output = orig;
|
||||
|
||||
return(orig);
|
||||
}
|
||||
|
||||
void
|
||||
mm_striptrailing(char **what, const char *charset)
|
||||
{
|
||||
size_t eos, i, hit;
|
||||
char *str;
|
||||
|
||||
str = *what;
|
||||
for (eos = strlen(str)-1; eos >= 0; eos--) {
|
||||
hit = 0;
|
||||
for (i = 0; i < strlen(charset); i++) {
|
||||
if (str[eos] == charset[i]) {
|
||||
str[eos] = '\0';
|
||||
hit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hit)
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __MM_UTIL_H
|
||||
#define __MM_UTIL_H
|
||||
|
||||
#define STRIP_TRAILING(str, charset) do { \
|
||||
size_t eos, i, hit; \
|
||||
for (eos = strlen(str); eos > 0; eos--) { \
|
||||
hit = 0; \
|
||||
for (i = 0; i <= strlen(charset); i++) { \
|
||||
if (str[eos] == charset[i]) {\
|
||||
str[eos] = '\0'; \
|
||||
hit = 1; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (!hit) \
|
||||
break; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#endif /* ! __MM_UTIL_H */
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* MiniMIME - a library for handling MIME messages
|
||||
*
|
||||
* Copyright (C) 2003 Jann Fischer <rezine@mistrust.net>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the author nor the names of the contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY JANN FISCHER AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL JANN FISCHER OR THE VOICES IN HIS HEAD
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
||||
/**
|
||||
* Attaches a warning message to a context
|
||||
*
|
||||
* @param ctx A valid MiniMIME context object
|
||||
* @param type The type of the warning
|
||||
* @param fmt The warning message as format string
|
||||
*/
|
||||
void
|
||||
mm_warning_add(MM_CTX *ctx, int type, const char *fmt, ...)
|
||||
{
|
||||
struct mm_warning *warning;
|
||||
char buf[1024];
|
||||
va_list ap;
|
||||
|
||||
assert(ctx != NULL);
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
warning = (struct mm_warning *)xmalloc(sizeof(struct mm_warning));
|
||||
warning->message = xstrdup(buf);
|
||||
warning->type = type;
|
||||
|
||||
if (SLIST_EMPTY(&ctx->warnings)) {
|
||||
SLIST_INSERT_HEAD(&ctx->warnings, warning, next);
|
||||
} else {
|
||||
struct mm_warning *last, *after;
|
||||
|
||||
after = NULL;
|
||||
|
||||
SLIST_FOREACH(last, &ctx->warnings, next) {
|
||||
if (last != NULL) {
|
||||
after = last;
|
||||
}
|
||||
}
|
||||
|
||||
assert(after != NULL);
|
||||
|
||||
SLIST_INSERT_AFTER(after, warning, next);
|
||||
}
|
||||
}
|
||||
|
||||
struct mm_warning *
|
||||
mm_warning_next(MM_CTX *ctx, struct mm_warning **last)
|
||||
{
|
||||
struct mm_warning *warning;
|
||||
|
||||
if (*last == NULL) {
|
||||
warning = SLIST_FIRST(&ctx->warnings);
|
||||
} else {
|
||||
warning = SLIST_NEXT(*last, next);
|
||||
}
|
||||
|
||||
*last = warning;
|
||||
return warning;
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/* $OpenBSD: strlcat.c,v 1.9 2003/03/14 14:35:29 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char *rcsid = "$OpenBSD: strlcat.c,v 1.9 2003/03/14 14:35:29 millert Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/* $OpenBSD: strlcpy.c,v 1.6 2003/03/14 14:35:29 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char *rcsid = "$OpenBSD: strlcpy.c,v 1.6 2003/03/14 14:35:29 millert Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0 && --n != 0) {
|
||||
do {
|
||||
if ((*d++ = *s++) == 0)
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
|
@ -1,503 +0,0 @@
|
|||
/* $OpenBSD: queue.h,v 1.22 2001/06/23 04:39:35 angelos Exp $ */
|
||||
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* lists, simple queues, tail queues, and circular queues.
|
||||
*
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A simple queue is headed by a pair of pointers, one the head of the
|
||||
* list and the other to the tail of the list. The elements are singly
|
||||
* linked to save space, so elements can only be removed from the
|
||||
* head of the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the
|
||||
* list. A simple queue may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Singly-linked List definitions.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List access methods.
|
||||
*/
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
#define SLIST_END(head) NULL
|
||||
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for((var) = SLIST_FIRST(head); \
|
||||
(var) != SLIST_END(head); \
|
||||
(var) = SLIST_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_INIT(head) { \
|
||||
SLIST_FIRST(head) = SLIST_END(head); \
|
||||
}
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
(elm)->field.sle_next = (slistelm)->field.sle_next; \
|
||||
(slistelm)->field.sle_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.sle_next = (head)->slh_first; \
|
||||
(head)->slh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
(head)->slh_first = (head)->slh_first->field.sle_next; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->slh_first == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = (head)->slh_first; \
|
||||
while( curelm->field.sle_next != (elm) ) \
|
||||
curelm = curelm->field.sle_next; \
|
||||
curelm->field.sle_next = \
|
||||
curelm->field.sle_next->field.sle_next; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* List definitions.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List access methods
|
||||
*/
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
#define LIST_END(head) NULL
|
||||
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for((var) = LIST_FIRST(head); \
|
||||
(var)!= LIST_END(head); \
|
||||
(var) = LIST_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST(head) = LIST_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
|
||||
(listelm)->field.le_next->field.le_prev = \
|
||||
&(elm)->field.le_next; \
|
||||
(listelm)->field.le_next = (elm); \
|
||||
(elm)->field.le_prev = &(listelm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
(elm)->field.le_next = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &(elm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
|
||||
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
|
||||
(head)->lh_first = (elm); \
|
||||
(elm)->field.le_prev = &(head)->lh_first; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
if ((elm)->field.le_next != NULL) \
|
||||
(elm)->field.le_next->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = (elm)->field.le_next; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_REPLACE(elm, elm2, field) do { \
|
||||
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
|
||||
(elm2)->field.le_next->field.le_prev = \
|
||||
&(elm2)->field.le_next; \
|
||||
(elm2)->field.le_prev = (elm)->field.le_prev; \
|
||||
*(elm2)->field.le_prev = (elm2); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Simple queue definitions.
|
||||
*/
|
||||
#define SIMPLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *sqh_first; /* first element */ \
|
||||
struct type **sqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define SIMPLEQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).sqh_first }
|
||||
|
||||
#define SIMPLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple queue access methods.
|
||||
*/
|
||||
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
|
||||
#define SIMPLEQ_END(head) NULL
|
||||
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
|
||||
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
|
||||
|
||||
#define SIMPLEQ_FOREACH(var, head, field) \
|
||||
for((var) = SIMPLEQ_FIRST(head); \
|
||||
(var) != SIMPLEQ_END(head); \
|
||||
(var) = SIMPLEQ_NEXT(var, field))
|
||||
|
||||
/*
|
||||
* Simple queue functions.
|
||||
*/
|
||||
#define SIMPLEQ_INIT(head) do { \
|
||||
(head)->sqh_first = NULL; \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(head)->sqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.sqe_next = NULL; \
|
||||
*(head)->sqh_last = (elm); \
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
|
||||
(head)->sqh_last = &(elm)->field.sqe_next; \
|
||||
(listelm)->field.sqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \
|
||||
if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \
|
||||
(head)->sqh_last = &(head)->sqh_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue definitions.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* tail queue access methods
|
||||
*/
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
#define TAILQ_END(head) NULL
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
/* XXX */
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
#define TAILQ_EMPTY(head) \
|
||||
(TAILQ_FIRST(head) == TAILQ_END(head))
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for((var) = TAILQ_FIRST(head); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_NEXT(var, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, field, headname) \
|
||||
for((var) = TAILQ_LAST(head, headname); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_INIT(head) do { \
|
||||
(head)->tqh_first = NULL; \
|
||||
(head)->tqh_last = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
|
||||
(head)->tqh_first->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(head)->tqh_first = (elm); \
|
||||
(elm)->field.tqe_prev = &(head)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.tqe_next = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm)->field.tqe_next; \
|
||||
(listelm)->field.tqe_next = (elm); \
|
||||
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
(elm)->field.tqe_next = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if (((elm)->field.tqe_next) != NULL) \
|
||||
(elm)->field.tqe_next->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
|
||||
(elm2)->field.tqe_next->field.tqe_prev = \
|
||||
&(elm2)->field.tqe_next; \
|
||||
else \
|
||||
(head)->tqh_last = &(elm2)->field.tqe_next; \
|
||||
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
|
||||
*(elm2)->field.tqe_prev = (elm2); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Circular queue definitions.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue access methods
|
||||
*/
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
#define CIRCLEQ_END(head) ((void *)(head))
|
||||
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
|
||||
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
|
||||
#define CIRCLEQ_EMPTY(head) \
|
||||
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for((var) = CIRCLEQ_FIRST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_NEXT(var, field))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for((var) = CIRCLEQ_LAST(head); \
|
||||
(var) != CIRCLEQ_END(head); \
|
||||
(var) = CIRCLEQ_PREV(var, field))
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
(head)->cqh_first = CIRCLEQ_END(head); \
|
||||
(head)->cqh_last = CIRCLEQ_END(head); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
|
||||
(elm)->field.cqe_prev = (listelm); \
|
||||
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
|
||||
(listelm)->field.cqe_next = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
(elm)->field.cqe_next = (listelm); \
|
||||
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
|
||||
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
|
||||
(listelm)->field.cqe_prev = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = (head)->cqh_first; \
|
||||
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
|
||||
if ((head)->cqh_last == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm); \
|
||||
else \
|
||||
(head)->cqh_first->field.cqe_prev = (elm); \
|
||||
(head)->cqh_first = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.cqe_next = CIRCLEQ_END(head); \
|
||||
(elm)->field.cqe_prev = (head)->cqh_last; \
|
||||
if ((head)->cqh_first == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm); \
|
||||
else \
|
||||
(head)->cqh_last->field.cqe_next = (elm); \
|
||||
(head)->cqh_last = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_last = (elm)->field.cqe_prev; \
|
||||
else \
|
||||
(elm)->field.cqe_next->field.cqe_prev = \
|
||||
(elm)->field.cqe_prev; \
|
||||
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
|
||||
(head)->cqh_first = (elm)->field.cqe_next; \
|
||||
else \
|
||||
(elm)->field.cqe_prev->field.cqe_next = \
|
||||
(elm)->field.cqe_next; \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
|
||||
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_last = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
|
||||
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
|
||||
CIRCLEQ_END(head)) \
|
||||
(head).cqh_first = (elm2); \
|
||||
else \
|
||||
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
|
@ -1,54 +0,0 @@
|
|||
#!/bin/sh
|
||||
# MiniMIME test cases
|
||||
|
||||
[ ! -x ./tests/parse -o ! -x ./tests/create ] && {
|
||||
echo "You need to compile the test suite first to accomplish tests"
|
||||
exit 1
|
||||
}
|
||||
|
||||
LD_LIBRARY_PATH=${PWD}
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
DIRECTORY=${1:-tests/messages}
|
||||
FILES=${2:-"*"}
|
||||
|
||||
TESTS=0
|
||||
F_ERRORS=0
|
||||
F_INVALID=""
|
||||
M_ERRORS=0
|
||||
M_INVALID=""
|
||||
for f in ${DIRECTORY}/${FILES}; do
|
||||
if [ -f "${f}" ]; then
|
||||
TESTS=$((TESTS + 2))
|
||||
echo -n "Running PARSER test for $f (file)... "
|
||||
output=`./tests/parse $f 2>&1`
|
||||
[ $? != 0 ] && {
|
||||
echo "FAILED ($output)"
|
||||
F_ERRORS=$((F_ERRORS + 1))
|
||||
F_INVALID="${F_INVALID} ${f} "
|
||||
} || {
|
||||
echo "PASSED"
|
||||
}
|
||||
echo -n "Running PARSER test for $f (memory)... "
|
||||
output=`./tests/parse -m $f 2>&1`
|
||||
[ $? != 0 ] && {
|
||||
echo "FAILED ($output)"
|
||||
M_ERRORS=$((M_ERRORS + 1))
|
||||
M_INVALID="${M_INVALID} ${f} "
|
||||
} || {
|
||||
echo "PASSED"
|
||||
}
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Ran a total of ${TESTS} tests"
|
||||
|
||||
if [ ${F_ERRORS} -gt 0 ]; then
|
||||
echo "!! ${F_ERRORS} messages had errors in file based parsing"
|
||||
echo "-> ${F_INVALID}"
|
||||
fi
|
||||
if [ ${M_ERRORS} -gt 0 ]; then
|
||||
echo "!! ${F_ERRORS} messages had errors in memory based parsing"
|
||||
fi
|
||||
|
||||
unset LD_LIBRARY_PATH
|
|
@ -1,18 +0,0 @@
|
|||
BINARIES=parse create
|
||||
CFLAGS=-Wall -ggdb -g3 -I..
|
||||
LDFLAGS=-L..
|
||||
LIBS=-lmmime
|
||||
CC=gcc
|
||||
|
||||
all: parse create
|
||||
|
||||
parse: parse.o
|
||||
$(CC) -o parse parse.o $(LDFLAGS) $(LIBS)
|
||||
|
||||
create: create.o
|
||||
$(CC) -o create create.o $(LDFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(BINARIES)
|
||||
rm -f *.o
|
||||
rm -f *.core
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2004 Jann Fischer. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MiniMIME test program - create.c
|
||||
*
|
||||
* Creates a MIME message of the given MIME parts
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "mm.h"
|
||||
|
||||
const char *progname;
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"MiniMIME test suite\n"
|
||||
"USAGE: %s <part> [<part_2>[<part_N>[...]]]\n",
|
||||
progname
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
print_error(void)
|
||||
{
|
||||
fprintf(stderr, "ERROR: %s\n", mm_error_string());
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
MM_CTX *ctx;
|
||||
struct mm_mimepart *part;
|
||||
char *data;
|
||||
size_t length;
|
||||
int i;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mm_library_init();
|
||||
|
||||
ctx = mm_context_new();
|
||||
|
||||
part = mm_mimepart_new();
|
||||
mm_context_attachpart(ctx, part);
|
||||
mm_envelope_setheader(ctx, "From", "foo@bar.com");
|
||||
|
||||
for (i=1; i < argc; i++) {
|
||||
part = mm_mimepart_fromfile(argv[i]);
|
||||
if (part == NULL) {
|
||||
print_error();
|
||||
exit(1);
|
||||
}
|
||||
mm_context_attachpart(ctx, part);
|
||||
}
|
||||
|
||||
if (mm_context_flatten(ctx, &data, &length, 0) == -1) {
|
||||
print_error();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("%s", data);
|
||||
|
||||
exit(0);
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
Return-Path: <rezine@hannover.ccc.de>
|
||||
X-Original-To: test@mistrust.net
|
||||
Delivered-To: rezine@hannover.ccc.de
|
||||
Received: from thinktank.niedersachsen.de (thinktank.niedersachsen.de [195.37.192.218])
|
||||
(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
|
||||
(Client did not present a certificate)
|
||||
by gost.hannover.ccc.de (Postfix) with ESMTP id 90EDEBBF2
|
||||
for <test@mistrust.net>; Sun, 24 Aug 2003 16:05:29 +0200 (CEST)
|
||||
Date: Sun, 24 Aug 2003 15:49:15 +0200
|
||||
From: Jann Fischer <rezine@hannover.ccc.de>
|
||||
To: test@mistrust.net
|
||||
Subject: Test
|
||||
Message-Id: <20030824154915.12cb3f85.rezine@hannover.ccc.de>
|
||||
Organization: Chaos Computer Club Hannover
|
||||
X-Mailer: Who-Cares 5.23
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";
|
||||
boundary="=.2S1ZDSX8ir3lbt"
|
||||
|
||||
--=.2S1ZDSX8ir3lbt
|
||||
Content-Type: application/pgp-encrypted
|
||||
|
||||
Version: 1
|
||||
|
||||
--=.2S1ZDSX8ir3lbt
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
Version: GnuPG v1.2.2 (OpenBSD)
|
||||
|
||||
hQEOA3TvLJ6KBZLBEAP/cl4DiRH5+8S7/kP2BIVdDavHJ9cwHh8awGoyddhMKPJ3
|
||||
2558r8MKT0Etjpo649O5WUvT5Z2Jcp12+dTPlAC1kvoIjNNk8+Oe3JCREz/pXYnm
|
||||
5ANSCThVYSS34jppgT3NsqiV8sQK3e+Nq/NY7SoKVAV37L0fU4HHozcDZfXqOLsE
|
||||
AJgfxjRjjEazPHmgTTu8Pnt5gmlxyP35Yy0pl+gJmboG3Cn5WBcD/rrQf8oiwrB6
|
||||
Vak2Hk9TNU7hDO2IRolz4wUfkId47SK31PdhDLBnNPWn6LNWHd+G4hI97e+xeqLW
|
||||
dpG7Li5CdP0gfuHx2ux9Y5buWVVtqPhdDUlRaIBfM7Fu0sENAeREANAtdPHn0yTf
|
||||
V4T5NvImY3gXgLST5wNm3Ft+4nIDZrcnSy04x4faTLFBOcY95W0O1omILHyN5Ste
|
||||
Le5NhXhQRKyl6ebXtIvEOsJOK4NT6JaUF20l4yvgf0AnetG9Pbzc37mRqmE6Fb8O
|
||||
h/De3iqw7dexaQc+LaD3XTmvPyyDK2aI4cXOdc9WOzrWR7+9iEiY32SFsQWMRMZJ
|
||||
GdKkGk22K2p7MPFaU3MHQ3Af+WCN4mRW8SurFxH1379Y5e1IPfTeL6OBkj8hHilX
|
||||
Y+Y7523ADiStJsONIZPBXJVhZ/VAJ+jL+T1/Xht10VsJcWAY8A9tP+jNgyg8dh+J
|
||||
JgWVchQOZipdftYwR7w5GkhL2Nc5NYBJBg4DFd9g2nnwuzaAKYO5kMTzEmm9KOYq
|
||||
0DC5ukok4SGDwWPUIogNHmaSnFr723hYuJC7DwSxHXVG3VxxF78u1gzEnImOWRsf
|
||||
1RzGb7b8Lf7Rj98H5cNiZ55BXAmidjm7WghCLsT2GvxviqQoRIJ2h/WHM0Bl2v3F
|
||||
Dpa3N01p2NIIgQLRoXXyBCZTwGOH4y9nBj5PU7vzzSrMweHHt1BwHXcqItCyWFXX
|
||||
2tj4//Dyw3Lw/L5xGxYRP1Q=
|
||||
=fSLd
|
||||
-----END PGP MESSAGE-----
|
||||
|
||||
--=.2S1ZDSX8ir3lbt--
|
|
@ -1,50 +0,0 @@
|
|||
Return-Path: <rezine@hannover.ccc.de>
|
||||
X-Original-To: test@mistrust.net
|
||||
Delivered-To: rezine@hannover.ccc.de
|
||||
Received: from thinktank.niedersachsen.de (thinktank.niedersachsen.de [195.37.192.218])
|
||||
(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
|
||||
(Client did not present a certificate)
|
||||
by gost.hannover.ccc.de (Postfix) with ESMTP id 90EDEBBF2
|
||||
for <test@mistrust.net>; Sun, 24 Aug 2003 16:05:29 +0200 (CEST)
|
||||
Date: Sun, 24 Aug 2003 15:49:15 +0200
|
||||
From: Jann Fischer <rezine@hannover.ccc.de>
|
||||
To: test@mistrust.net
|
||||
Subject: Test
|
||||
Message-Id: <20030824154915.12cb3f85.rezine@hannover.ccc.de>
|
||||
Organization: Chaos Computer Club Hannover
|
||||
X-Mailer: Who-Cares 5.23
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";
|
||||
boundary="=.2S1ZDSX8ir3lbt"
|
||||
|
||||
--=.2S1ZDSX8ir3lbt
|
||||
Content-Type: application/pgp-encrypted
|
||||
|
||||
Version: 1
|
||||
|
||||
--=.2S1ZDSX8ir3lbt
|
||||
Content-Type: application/octet-stream
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
Version: GnuPG v1.2.2 (OpenBSD)
|
||||
|
||||
hQEOA3TvLJ6KBZLBEAP/cl4DiRH5+8S7/kP2BIVdDavHJ9cwHh8awGoyddhMKPJ3
|
||||
2558r8MKT0Etjpo649O5WUvT5Z2Jcp12+dTPlAC1kvoIjNNk8+Oe3JCREz/pXYnm
|
||||
5ANSCThVYSS34jppgT3NsqiV8sQK3e+Nq/NY7SoKVAV37L0fU4HHozcDZfXqOLsE
|
||||
AJgfxjRjjEazPHmgTTu8Pnt5gmlxyP35Yy0pl+gJmboG3Cn5WBcD/rrQf8oiwrB6
|
||||
Vak2Hk9TNU7hDO2IRolz4wUfkId47SK31PdhDLBnNPWn6LNWHd+G4hI97e+xeqLW
|
||||
dpG7Li5CdP0gfuHx2ux9Y5buWVVtqPhdDUlRaIBfM7Fu0sENAeREANAtdPHn0yTf
|
||||
V4T5NvImY3gXgLST5wNm3Ft+4nIDZrcnSy04x4faTLFBOcY95W0O1omILHyN5Ste
|
||||
Le5NhXhQRKyl6ebXtIvEOsJOK4NT6JaUF20l4yvgf0AnetG9Pbzc37mRqmE6Fb8O
|
||||
h/De3iqw7dexaQc+LaD3XTmvPyyDK2aI4cXOdc9WOzrWR7+9iEiY32SFsQWMRMZJ
|
||||
GdKkGk22K2p7MPFaU3MHQ3Af+WCN4mRW8SurFxH1379Y5e1IPfTeL6OBkj8hHilX
|
||||
Y+Y7523ADiStJsONIZPBXJVhZ/VAJ+jL+T1/Xht10VsJcWAY8A9tP+jNgyg8dh+J
|
||||
JgWVchQOZipdftYwR7w5GkhL2Nc5NYBJBg4DFd9g2nnwuzaAKYO5kMTzEmm9KOYq
|
||||
0DC5ukok4SGDwWPUIogNHmaSnFr723hYuJC7DwSxHXVG3VxxF78u1gzEnImOWRsf
|
||||
1RzGb7b8Lf7Rj98H5cNiZ55BXAmidjm7WghCLsT2GvxviqQoRIJ2h/WHM0Bl2v3F
|
||||
Dpa3N01p2NIIgQLRoXXyBCZTwGOH4y9nBj5PU7vzzSrMweHHt1BwHXcqItCyWFXX
|
||||
2tj4//Dyw3Lw/L5xGxYRP1Q=
|
||||
=fSLd
|
||||
-----END PGP MESSAGE-----
|
||||
|
||||
--=.2S1ZDSX8ir3lbt--
|
|
@ -1,12 +0,0 @@
|
|||
From: Jann Fischer <rezine@criminology.de>
|
||||
To: cipherlist <cipherlist@mistrust.net>
|
||||
Subject: Foobar
|
||||
Date: blahblah
|
||||
MIME-Version: 1.0 (MiniMIME)
|
||||
Content-Type: multipart/mixed; boundary="abcd"
|
||||
|
||||
--abcd
|
||||
Content-Type: plain/text;
|
||||
|
||||
This is a test :->
|
||||
--abcd--
|
|
@ -1,168 +0,0 @@
|
|||
X-Envelope-From: <511-bounces@hannover.ccc.de>
|
||||
X-Envelope-To: <rezine@criminology.de>
|
||||
X-Delivery-Time: 1070263752
|
||||
Received: from gost.hannover.ccc.de (hannover.ccc.de [62.48.71.164])
|
||||
by mailin.webmailer.de (8.12.10/8.12.10) with ESMTP id hB17TAUR020052
|
||||
for <rezine@criminology.de>; Mon, 1 Dec 2003 08:29:10 +0100 (MET)
|
||||
Received: from localhost.hannover.ccc.de (unknown [127.0.0.1])
|
||||
by gost.hannover.ccc.de (Postfix) with ESMTP
|
||||
id 092C8BC81; Mon, 1 Dec 2003 08:29:23 +0100 (CET)
|
||||
X-Original-To: 511@hannover.ccc.de
|
||||
Delivered-To: 511@hannover.ccc.de
|
||||
Received: from sbapp3 (unknown [211.157.36.9])
|
||||
by gost.hannover.ccc.de (Postfix) with ESMTP id 3F93ABC7C
|
||||
for <511@hannover.ccc.de>; Mon, 1 Dec 2003 08:29:12 +0100 (CET)
|
||||
From: "Vanessa Lintner" <reply@seekercenter.net>
|
||||
To: 511@hannover.ccc.de
|
||||
Date: Mon, 1 Dec 2003 15:30:57 +0800
|
||||
X-Priority: 3
|
||||
X-Library: Indy 8.0.25
|
||||
Message-Id: <20031201072912.3F93ABC7C@gost.hannover.ccc.de>
|
||||
Subject: [CCC511] http://lists.hannover.ccc.de
|
||||
X-BeenThere: 511@hannover.ccc.de
|
||||
X-Mailman-Version: 2.1.2
|
||||
Precedence: list
|
||||
Reply-To: Vanessa Lintner <vanessa@seekercenter.net>,
|
||||
Oeffentliche Mailingliste des C3H <511@hannover.ccc.de>
|
||||
List-Id: Oeffentliche Mailingliste des C3H <511.hannover.ccc.de>
|
||||
List-Unsubscribe: <http://hannover.ccc.de/mailman/listinfo/511>,
|
||||
<mailto:511-request@hannover.ccc.de?subject=unsubscribe>
|
||||
List-Post: <mailto:511@hannover.ccc.de>
|
||||
List-Help: <mailto:511-request@hannover.ccc.de?subject=help>
|
||||
List-Subscribe: <http://hannover.ccc.de/mailman/listinfo/511>,
|
||||
<mailto:511-request@hannover.ccc.de?subject=subscribe>
|
||||
Content-Type: multipart/mixed; boundary="===============14807035762661644=="
|
||||
Sender: 511-bounces@hannover.ccc.de
|
||||
Errors-To: 511-bounces@hannover.ccc.de
|
||||
|
||||
--===============14807035762661644==
|
||||
Content-Type: text/html;
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<style type="text/css">
|
||||
.stbtm {
|
||||
BACKGROUND-COLOR:#cecbde; BORDER-BOTTOM: #665b8e 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-RIGHT: #665b8e 1px solid; BORDER-TOP: #ffffff 1px solid; COLOR: #000000; FONT-SIZE: 12pt; HEIGHT: 26px; WIDTH: 120px; clip: rect( )}
|
||||
.stedit {
|
||||
background-color:#484C68; white-space: nowrap; border: #000000; BORDER-BOTTOM: #ffffff 1px solid; BORDER-LEFT: #ffffff 1px solid; BORDER-RIGHT: #ffffff 1px solid; BORDER-TOP: #ffffff 1px solid; FONT-SIZE: 10pt; color: #CCCCCC; font-weight: bold}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<BODY leftMargin=0 onload="" topMargin=0 marginheight="0" marginwidth="0" bgcolor="#FFFFFF">
|
||||
<table border="0" cellspacing="0" cellpadding="0" width="580">
|
||||
<tr>
|
||||
<td width="20" rowspan="2"> </td>
|
||||
<td colspan="3">
|
||||
<table border="0" cellspacing="0" cellpadding="0" align="left" width="560">
|
||||
<tr>
|
||||
<td width="330" height="307">
|
||||
<table width="330" border="0" cellspacing="0" cellpadding="0" background="http://www.imagespool.com/skbmp/letter_01.gif" height="307">
|
||||
<tr>
|
||||
<td>
|
||||
<p> <font face=Arial size=2> </font> <font face=Arial size=2><font face="Verdana, Arial, Helvetica, sans-serif" color="#000000">Hello,<br>
|
||||
<br>
|
||||
I have visited <a href='http://lists.hannover.ccc.de'>lists.hannover.ccc.de</a>
|
||||
and noticed that your website is not listed on some search
|
||||
engines. I am sure that through our service the number of
|
||||
people who visit your website will definitely increase.
|
||||
<a target=_blank href="http://www.seekercenter.net/index.php">SeekerCenter</a>
|
||||
is a unique technology that instantly submits your website
|
||||
to over 500,000 search engines and directories -- a really
|
||||
low-cost and effective way to advertise your site. For more
|
||||
details please go to <a target=_blank href="http://www.seekercenter.net/index.php">SeekerCenter.net</a>.<br>
|
||||
<br>
|
||||
Give your website maximum exposure today!<br>
|
||||
Looking forward to hearing from you.<br>
|
||||
<br>
|
||||
</font></font>
|
||||
<table border=0 width=100%>
|
||||
<tr>
|
||||
<td width=50%> <font face="Arial" color="#000000" size="2">Best
|
||||
Regards,<br>
|
||||
Vanessa Lintner<br>
|
||||
Sales & Marketing <br>
|
||||
<a target=_blank href="http://www.seekercenter.net/index.php">www.SeekerCenter.net</a></font>
|
||||
<TD><td width=50%>
|
||||
<div align="center" valign=middle>
|
||||
<form target=_blank action=http://www.seekercenter.net method=POST>
|
||||
<input type="submit" name="Submit" value="Signup Now!!!" class="stbtm">
|
||||
</form>
|
||||
</div>
|
||||
</TD>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td width="250" height="64" valign="middle">
|
||||
<table width="230" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td colspan="3" height="2"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3"><img src="http://report.imagespool.com/report_email.php?s=1&e=511@hannover.ccc.de" border=0 width=0 height=0>
|
||||
<p><img src="http://www.imagespool.com/skbmp/letter_04.gif" height="12"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3"><img src="http://www.imagespool.com/skbmp/letter_05.gif" height="127"><img src="http://ww2.imagespool.com/1/9/b/0r066.jpg" width="177" height="127"><img src="http://www.imagespool.com/skbmp/letter_07.gif" width="33" height="127"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" height="92" background="http://www.imagespool.com/skbmp/letter_08.gif" valign="bottom">
|
||||
<table width="230" border="0" cellspacing="0" cellpadding="0" height="92">
|
||||
<tr>
|
||||
<td width="36" height="43"> </td>
|
||||
<td width="157" height="43"> </td>
|
||||
<td width="134" height="43"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="36" height="2"> </td>
|
||||
<td width="157" height="2"> </td>
|
||||
<td width="134" height="2"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr> </tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<table width="560" border="0" cellspacing="0" cellpadding="1" bordercolor="0">
|
||||
<tr>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor="#EFEFEF"><font face="Verdana, Arial, Helvetica, sans-serif" size="1">You
|
||||
are receiving this email because you opted-in to receive special
|
||||
offers through a partner website. If you feel that you received
|
||||
this email in error or do not wish to receive additional special
|
||||
offers, please enter your email address here and click the button
|
||||
of "Remove Me": <a href="http://www.seekercenter.net/remove.php?email=511@hannover.ccc.de">
|
||||
<img src="http://www.imagespool.com/skbmp/removeme.gif" width="73" height="17" border="0"></a>
|
||||
</font></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
--===============14807035762661644==
|
||||
Content-Type: text/plain; charset="iso-8859-1"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Disposition: inline
|
||||
|
||||
_______________________________________________
|
||||
511 mailing list
|
||||
511@hannover.ccc.de
|
||||
--===============14807035762661644==--
|
|
@ -1,44 +0,0 @@
|
|||
Return-Path: <rezine@criminology.de>
|
||||
X-Original-To: rezine@mistrust.net
|
||||
Delivered-To: rezine@hannover.ccc.de
|
||||
Received: from thinktank.niedersachsen.de (thinktank.niedersachsen.de [195.37.192.218])
|
||||
(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
|
||||
(Client did not present a certificate)
|
||||
by gost.hannover.ccc.de (Postfix) with ESMTP id 79E9BBC7C
|
||||
for <rezine@mistrust.net>; Wed, 24 Dec 2003 13:35:36 +0100 (CET)
|
||||
Received: from thinktank.niedersachsen.de (localhost [127.0.0.1])
|
||||
by thinktank.niedersachsen.de (8.12.9/8.12.2) with SMTP id hBOCZBFU029588
|
||||
for <rezine@mistrust.net>; Wed, 24 Dec 2003 13:35:11 +0100 (CET)
|
||||
Date: Wed, 24 Dec 2003 13:35:11 +0100
|
||||
From: Jann Fischer <rezine@criminology.de>
|
||||
To: rezine@mistrust.net
|
||||
Subject: Test
|
||||
Message-Id: <20031224133511.5f4b6d9b.rezine@criminology.de>
|
||||
X-Mailer: Who Cares 5.23
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="Multipart_Wed__24_Dec_2003_13:35:11_+0100_00148800"
|
||||
|
||||
This is a multi-part message in MIME format.
|
||||
|
||||
--Multipart_Wed__24_Dec_2003_13:35:11_+0100_00148800
|
||||
Content-Type: text/plain; charset=US-ASCII
|
||||
Content-Transfer-Encoding: 7bit
|
||||
|
||||
Test
|
||||
|
||||
--
|
||||
Be careful who you follow.
|
||||
0x6D839821 | FA8C 3663 9906 D8C3 AC16 F7C4 66E0 F351 6D83 9821
|
||||
|
||||
--Multipart_Wed__24_Dec_2003_13:35:11_+0100_00148800
|
||||
Content-Type: application/octet-stream;
|
||||
name="bar.c"
|
||||
Content-Disposition: attachment;
|
||||
filename="bar.c"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
I2luY2x1ZGUgPHN0ZGlvLmg+Cgp2b2lkCm1haW4oaW50IGFyZ2MsIGNoYXIgKiphcmd2KQp7CgkJ
|
||||
cHJpbnRmKCIlc1xuIiwgYXJndlswXSk7Cn0K
|
||||
|
||||
--Multipart_Wed__24_Dec_2003_13:35:11_+0100_00148800--
|
|
@ -1,12 +0,0 @@
|
|||
From: Me
|
||||
Date: Foobar
|
||||
To: There
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="abcde"
|
||||
|
||||
--abcde
|
||||
Content-Type: text/plain
|
||||
|
||||
Blah blah
|
||||
Blah
|
||||
--abcde--
|
|
@ -1,64 +0,0 @@
|
|||
Return-Path: MAILER-DAEMON
|
||||
Received: from chaos.verfassungsschutz.de (localhost [IPv6:::1])
|
||||
by chaos.verfassungsschutz.de (8.12.7/8.12.2) with ESMTP id h2EKV1oM031761
|
||||
for <jfi@chaos.verfassungsschutz.de>; Fri, 14 Mar 2003 21:31:18 +0100 (CET)
|
||||
Received: from localhost (localhost)
|
||||
by chaos.verfassungsschutz.de (8.12.7/8.12.2/Submit) id h2BNU1vr029177;
|
||||
Wed, 12 Mar 2003 00:35:01 +0100 (CET)
|
||||
Date: Wed, 12 Mar 2003 00:35:01 +0100 (CET)
|
||||
From: Mail Delivery Subsystem <MAILER-DAEMON@chaos.verfassungsschutz.de>
|
||||
Message-Id: <200303112335.h2BNU1vr029177@chaos.verfassungsschutz.de>
|
||||
To: jfi@chaos.verfassungsschutz.de
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/report; report-type=delivery-status;
|
||||
boundary="h2BNU1vr029177.1047425701/chaos.verfassungsschutz.de"
|
||||
Subject: Warning: could not send message for past 4 hours
|
||||
Auto-Submitted: auto-generated (warning-timeout)
|
||||
|
||||
This is a MIME-encapsulated message
|
||||
|
||||
--h2BNU1vr029177.1047425701/chaos.verfassungsschutz.de
|
||||
|
||||
**********************************************
|
||||
** THIS IS A WARNING MESSAGE ONLY **
|
||||
** YOU DO NOT NEED TO RESEND YOUR MESSAGE **
|
||||
**********************************************
|
||||
|
||||
The original message was received at Tue, 11 Mar 2003 20:18:36 +0100 (CET)
|
||||
from jfi@localhost
|
||||
|
||||
----- Transcript of session follows -----
|
||||
451 4.4.1 reply: read error from localhost
|
||||
rezine@kommunism.us... Deferred: Connection timed out with localhost
|
||||
Warning: message still undelivered after 4 hours
|
||||
Will keep trying until message is 5 days old
|
||||
|
||||
--h2BNU1vr029177.1047425701/chaos.verfassungsschutz.de
|
||||
Content-Type: message/delivery-status
|
||||
|
||||
Reporting-MTA: dns; chaos.verfassungsschutz.de
|
||||
Arrival-Date: Tue, 11 Mar 2003 20:18:36 +0100 (CET)
|
||||
|
||||
Final-Recipient: RFC822; rezine@kommunism.us
|
||||
Action: delayed
|
||||
Status: 4.4.2
|
||||
Last-Attempt-Date: Wed, 12 Mar 2003 00:35:01 +0100 (CET)
|
||||
Will-Retry-Until: Sun, 16 Mar 2003 20:18:36 +0100 (CET)
|
||||
|
||||
--h2BNU1vr029177.1047425701/chaos.verfassungsschutz.de
|
||||
Content-Type: message/rfc822
|
||||
|
||||
Return-Path: <jfi>
|
||||
Received: (from jfi@localhost)
|
||||
by chaos.verfassungsschutz.de (8.12.7/8.12.2/Submit) id h2BJIawm025679
|
||||
for rezine@kommunism.us; Tue, 11 Mar 2003 20:18:36 +0100 (CET)
|
||||
Date: Tue, 11 Mar 2003 20:18:36 +0100 (CET)
|
||||
From: Jann Fischer <jfi>
|
||||
Message-Id: <200303111918.h2BJIawm025679@chaos.verfassungsschutz.de>
|
||||
To: rezine@kommunism.us
|
||||
Subject: Test
|
||||
|
||||
Test
|
||||
|
||||
--h2BNU1vr029177.1047425701/chaos.verfassungsschutz.de--
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2004 Jann Fischer. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MiniMIME test program - parse.c
|
||||
*
|
||||
* Parses any given messages
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "mm.h"
|
||||
|
||||
const char *progname;
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"MiniMIME test suite\n"
|
||||
"Usage: %s [-m] <filename>\n\n"
|
||||
" -m : use memory based scanning\n\n",
|
||||
progname
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
MM_CTX *ctx;
|
||||
struct mm_mimeheader *header, *lastheader = NULL;
|
||||
struct mm_mimepart *part;
|
||||
struct mm_content *ct;
|
||||
int parts, i;
|
||||
struct stat st;
|
||||
int fd;
|
||||
char *buf;
|
||||
int scan_mode = 0;
|
||||
|
||||
progname = strdup(argv[0]);
|
||||
|
||||
while ((i = getopt(argc, argv, "m")) != -1) {
|
||||
switch(i) {
|
||||
case 'm':
|
||||
scan_mode = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
#ifdef __HAVE_LEAK_DETECTION
|
||||
/* Initialize memory leak detection if compiled in */
|
||||
MM_leakd_init();
|
||||
#endif
|
||||
|
||||
/* Initialize MiniMIME library */
|
||||
mm_library_init();
|
||||
|
||||
/* Register all default codecs (base64/qp) */
|
||||
mm_codec_registerdefaultcodecs();
|
||||
|
||||
do {
|
||||
/* Create a new context */
|
||||
ctx = mm_context_new();
|
||||
|
||||
/* Parse a file into our context */
|
||||
if (scan_mode == 0) {
|
||||
i = mm_parse_file(ctx, argv[0], MM_PARSE_LOOSE, 0);
|
||||
} else {
|
||||
if (stat(argv[0], &st) == -1) {
|
||||
err(1, "stat");
|
||||
}
|
||||
|
||||
if ((fd = open(argv[0], O_RDONLY)) == -1) {
|
||||
err(1, "open");
|
||||
}
|
||||
|
||||
buf = (char *)malloc(st.st_size);
|
||||
if (buf == NULL) {
|
||||
err(1, "malloc");
|
||||
}
|
||||
|
||||
if (read(fd, buf, st.st_size) != st.st_size) {
|
||||
err(1, "read");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
buf[st.st_size] = '\0';
|
||||
|
||||
i = mm_parse_mem(ctx, buf, MM_PARSE_LOOSE, 0);
|
||||
}
|
||||
|
||||
if (i == -1 || mm_errno != MM_ERROR_NONE) {
|
||||
printf("ERROR: %s at line %d\n", mm_error_string(), mm_error_lineno());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Get the number of MIME parts */
|
||||
parts = mm_context_countparts(ctx);
|
||||
if (parts == 0) {
|
||||
printf("ERROR: got zero MIME parts, huh\n");
|
||||
exit(1);
|
||||
} else {
|
||||
if (mm_context_iscomposite(ctx)) {
|
||||
printf("Got %d MIME parts\n", parts - 1);
|
||||
} else {
|
||||
printf("Flat message (not multipart)\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the main MIME part */
|
||||
part = mm_context_getpart(ctx, 0);
|
||||
if (part == NULL) {
|
||||
fprintf(stderr, "Could not get envelope part\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Printing envelope headers:\n");
|
||||
/* Print all headers */
|
||||
lastheader = NULL;
|
||||
while ((header = mm_mimepart_headers_next(part, &lastheader)) != NULL)
|
||||
printf("%s: %s\n", header->name, header->value);
|
||||
|
||||
printf("%s\n", mm_content_tostring(part->type));
|
||||
printf("\n");
|
||||
|
||||
ct = part->type;
|
||||
assert(ct != NULL);
|
||||
|
||||
if (mm_context_iscomposite(ctx) == 0) {
|
||||
printf("Printing body part for FLAT message:\n");
|
||||
part = mm_context_getpart(ctx, 0);
|
||||
printf("%s", part->body);
|
||||
}
|
||||
|
||||
/* Loop through all MIME parts beginning with 1 */
|
||||
for (i = 1; i < mm_context_countparts(ctx); i++) {
|
||||
char *decoded;
|
||||
|
||||
printf("Printing headers for MIME part %d\n", i);
|
||||
|
||||
/* Get the current MIME entity */
|
||||
part = mm_context_getpart(ctx, i);
|
||||
if (part == NULL) {
|
||||
fprintf(stderr, "Should have %d parts but "
|
||||
"couldn't retrieve part %d",
|
||||
mm_context_countparts(ctx), i);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Print all headers */
|
||||
lastheader = NULL;
|
||||
while ((header = mm_mimepart_headers_next(part, &lastheader)) != NULL)
|
||||
printf("%s: %s\n", header->name, header->value);
|
||||
|
||||
printf("%s\n", mm_content_tostring(part->type));
|
||||
|
||||
/* Print MIME part body */
|
||||
printf("\nPRINTING MESSAGE BODY (%d):\n%s\n", i, part->opaque_body);
|
||||
decoded = mm_mimepart_decode(part);
|
||||
if (decoded != NULL) {
|
||||
printf("DECODED:\n%s\n", decoded);
|
||||
free(decoded);
|
||||
}
|
||||
}
|
||||
|
||||
printf("RECONSTRUCTED MESSAGE:\n");
|
||||
|
||||
do {
|
||||
char *env;
|
||||
size_t env_len;
|
||||
|
||||
mm_context_flatten(ctx, &env, &env_len, 0);
|
||||
printf("%s", env);
|
||||
free(env);
|
||||
|
||||
} while (0);
|
||||
|
||||
mm_context_free(ctx);
|
||||
ctx = NULL;
|
||||
|
||||
#ifdef __HAVE_LEAK_DETECTION
|
||||
MM_leakd_printallocated();
|
||||
#endif
|
||||
|
||||
} while (0);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -81,6 +81,9 @@ EDITLINE_LIB=@EDITLINE_LIB@
|
|||
FREETDS_INCLUDE=@FREETDS_INCLUDE@
|
||||
FREETDS_LIB=@FREETDS_LIB@
|
||||
|
||||
GMIME_INCLUDE=@GMIME_INCLUDE@
|
||||
GMIME_LIB=@GMIME_LIB@
|
||||
|
||||
GSM_INTERNAL=@GSM_INTERNAL@
|
||||
GSM_INCLUDE=@GSM_INCLUDE@
|
||||
GSM_LIB=@GSM_LIB@
|
||||
|
|
Reference in New Issue