/* $Id: decode.c,v 1.30 2006/05/13 01:12:59 jonz Exp $ */
/*
DSPAM
COPYRIGHT (C) 2002-2006 JONATHAN A. ZDZIARSKI
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* decode.c - message decoding and parsing
*
* DESCRIPTION
* This set of functions performs parsing and decoding of a message and
* embeds its components into a ds_message_t structure, suitable for
* logical access.
*/
#ifdef HAVE_CONFIG_H
#include <auto-config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "decode.h"
#include "error.h"
#include "util.h"
#include "language.h"
#include "buffer.h"
#include "base64.h"
#include "libdspam.h"
#ifdef NCORE
#include "ncore_adp.h"
#endif
/*
* _ds_actualize_message (const char *message)
*
* DESCRIPTION
* primary message parser
*
* this function performs all decoding and actualization of the message
* into the message structures defined in the .h
*
* INPUT ARGUMENTS
* message message to decode
*
* RETURN VALUES
* pointer to an allocated message structure (ds_message_t), NULL on failure
*/
ds_message_t
_ds_actualize_message (const char *message)
{
char *line, *in = strdup (message), *m_in;
ds_message_part_t current_block;
ds_header_t current_heading = NULL;
struct nt *boundaries = nt_create (NT_CHAR);
ds_message_t out = (ds_message_t) calloc (1, sizeof (struct _ds_message));
int block_position = BP_HEADER;
int in_content = 0;
m_in = in;
if (!in || !boundaries || !out)
goto MEMFAIL;
out->components = nt_create (NT_PTR);
if (!out->components)
goto MEMFAIL;
current_block = _ds_create_message_part ();
if (!current_block)
goto MEMFAIL;
if (nt_add (out->components, (void *) current_block) == NULL)
LOG (LOG_CRIT, ERR_MEM_ALLOC);
/* Read the message from memory */
line = strsep (&in, "\n");
while (line)
{
/* Header processing */
if (block_position == BP_HEADER)
{
/* If we see two boundaries converged on top of one another */
if (_ds_match_boundary (boundaries, line))
{
/* Add the boundary as the terminating boundary */
current_block->terminating_boundary = strdup (line + 2);
current_block->original_encoding = current_block->encoding;
_ds_decode_headers(current_block);
current_block = _ds_create_message_part ();
if (!current_block)
{
LOG (LOG_CRIT, ERR_MEM_ALLOC);
goto MEMFAIL;
}
if (nt_add (out->components, (void *) current_block) == NULL)
goto MEMFAIL;
block_position = BP_HEADER;
}
/* Concatenate multiline headers to the original header field data */
else if (line[0] == 32 || line[0] == '\t')
{
if (current_heading)
{
char *eow, *ptr;
ptr = realloc (current_heading->data,
strlen (current_heading->data) + strlen (line) + 2);
if (ptr)
{
current_heading->data = ptr;
strcat (current_heading->data, "\n");
strcat (current_heading->data, line);
} else {
goto MEMFAIL;
}
/* Our concatenated data doesn't have any whitespace between lines */
for(eow=line;eow[0] && isspace((int) eow[0]);eow++) { }
ptr =
realloc (current_heading->concatenated_data,
strlen (current_heading->concatenated_data) + strlen (eow) + 1);
if (ptr)
{
current_heading->concatenated_data = ptr;
strcat (current_heading->concatenated_data, eow);
} else {
goto MEMFAIL;
}
if (current_heading->original_data) {
ptr =
realloc (current_heading->original_data,
strlen (current_heading->original_data) +
strlen (line) + 2);
if (ptr) {
current_heading->original_data = ptr;
strcat (current_heading->original_data, "\n");
strcat (current_heading->original_data, line);
} else {
goto MEMFAIL;
}
}
_ds_analyze_header (current_block, current_heading, boundaries);
}
}
/* New header field */
else if (line[0] != 0)
{
ds_header_t header = _ds_create_header_field (line);
if (header != NULL)
{
_ds_analyze_header (current_block, header, boundaries);
current_heading = header;
nt_add (current_block->headers, header);
}
/* line[0] == 0; switch to body */
} else {
block_position = BP_BODY;
}
}
/* Body processing */
else if (block_position == BP_BODY)
{
/* Look for a boundary in the header of a part */
if (!strncasecmp (line, "Content-Type", 12)
|| ((line[0] == 32 || line[0] == 9) && in_content))
{
char boundary[128];
in_content = 1;
if (!_ds_extract_boundary(boundary, sizeof(boundary), line)) {
if (!_ds_match_boundary (boundaries, boundary)) {
_ds_push_boundary (boundaries, boundary);
free(current_block->boundary);
current_block->boundary = strdup (boundary);
}
} else {
_ds_push_boundary (boundaries, "");
}
} else {
in_content = 0;
}
/* Multipart boundary was reached; move onto next block */
if (_ds_match_boundary (boundaries, line))
{
/* Add the boundary as the terminating boundary */
current_block->terminating_boundary = strdup (line + 2);
current_block->original_encoding = current_block->encoding;
_ds_decode_headers(current_block);
current_block = _ds_create_message_part ();
if (!current_block)
goto MEMFAIL;
if (nt_add (out->components, (void *) current_block) == NULL)
goto MEMFAIL;
block_position = BP_HEADER;
}
/* Plain old message (or part) body */
else {
buffer_cat (current_block->body, line);
/* Don't add extra \n at the end of message's body */
if (in != NULL)
buffer_cat (current_block->body, "\n");
}
}
line = strsep (&in, "\n");
} /* while (line) */
_ds_decode_headers(current_block);
free (m_in);
nt_destroy (boundaries);
return out;
MEMFAIL:
free(m_in);
nt_destroy (boundaries);
_ds_destroy_message(out);
LOG (LOG_CRIT, ERR_MEM_ALLOC);
return NULL;
}
/*
* _ds_create_message_part
*
* DESCRIPTION
* create and initialize a new message block component
*
* RETURN VALUES
* pointer to an allocated message block (ds_message_part_t), NULL on failure
*
*/
ds_message_part_t
_ds_create_message_part (void)
{
ds_message_part_t block =
(ds_message_part_t) calloc (1, sizeof (struct _ds_message_part));
if (!block)
goto MEMFAIL;
block->headers = nt_create (NT_PTR);
if (!block->headers)
goto MEMFAIL;
block->body = buffer_create (NULL);
if (!block->body)
goto MEMFAIL;
block->encoding = EN_UNKNOWN;
block->media_type = MT_TEXT;
block->media_subtype = MST_PLAIN;
block->original_encoding = EN_UNKNOWN;
block->content_disposition = PCD_UNKNOWN;
/* Not really necessary, but.. */
block->boundary = NULL;
block->terminating_boundary = NULL;
block->original_signed_body = NULL;
return block;
MEMFAIL:
if (block) {
buffer_destroy(block->body);
nt_destroy(block->headers);
free(block);
}
LOG (LOG_CRIT, ERR_MEM_ALLOC);
return NULL;
}
/*
* _ds_create_header_field(const char *heading)
*
* DESCRIPTION
* create and initialize a new header structure
*
* INPUT ARGUMENTS
* heading plain text heading (e.g. "To: Mom")
*
* RETURN VALUES
* pointer to an allocated header structure (ds_header_t), NULL on failure
*/
ds_header_t
_ds_create_header_field (const char *heading)
{
char *in = strdup(heading);
char *ptr, *m = in, *data;
ds_header_t header =
(ds_header_t) calloc (1, sizeof (struct _ds_header_field));
if (!header || !in)
goto MEMFAIL;
ptr = strsep (&in, ":");
if (ptr) {
header->heading = strdup (ptr);
if (!header->heading)
goto MEMFAIL;
else
{
if (!in)
{
LOGDEBUG("%s:%u: unexpected data: header string '%s' doesn't "
"contains `:' character", __FILE__, __LINE__, header->heading);
/* Use empty string as data as fallback for comtinue processing. */
in = "";
}
else
{
/* Skip white space */
while (*in == 32 || *in == 9)
++in;
}
data = strdup (in);
if (!data)
goto MEMFAIL;
header->data = data;
header->concatenated_data = strdup(data);
}
}
free (m);
return header;
MEMFAIL:
free(header);
free(m);
LOG (LOG_CRIT, ERR_MEM_ALLOC);
return NULL;
}
/*
* _ds_decode_headers (ds_message_part_t block)
*
* DESCRIPTION
* decodes in-line encoded headers
*
* RETURN VALUES
* returns 0 on success
*/
int
_ds_decode_headers (ds_message_part_t block) {
char *ptr, *dptr, *rest, *enc;
ds_header_t header;
struct nt_node *node_nt;
struct nt_c c_nt;
long decoded_len;
node_nt = c_nt_first(block->headers, &c_nt);
while(node_nt != NULL) {
long enc_offset;
header = (ds_header_t) node_nt->ptr;
for(enc_offset = 0; header->concatenated_data[enc_offset]; enc_offset++)
{
enc = header->concatenated_data + enc_offset;
if (!strncmp(enc, "=?", 2)) {
int was_null = 0;
char *ptrptr, *decoded = NULL;
long offset = (long) enc - (long) header->concatenated_data;
if (header->original_data == NULL) {
header->original_data = strdup(header->data);
was_null = 1;
}
ptr = strtok_r (enc, "?", &ptrptr);
ptr = strtok_r (NULL, "?", &ptrptr);
ptr = strtok_r (NULL, "?", &ptrptr);
dptr = strtok_r (NULL, "?", &ptrptr);
if (!dptr) {
if (was_null)
header->original_data = NULL;
continue;
}
rest = dptr + strlen (dptr) + 1;
if (rest[0]!=0)
rest++;
if (ptr != NULL && (ptr[0] == 'b' || ptr[0] == 'B'))
decoded = _ds_decode_base64 (dptr);
else if (ptr != NULL && (ptr[0] == 'q' || ptr[0] == 'Q'))
decoded = _ds_decode_quoted (dptr);
decoded_len = 0;
/* Append the rest of the message */
if (decoded)
{
char *new_alloc;
decoded_len = strlen(decoded);
new_alloc = calloc (1, offset + decoded_len + strlen (rest) + 2);
if (new_alloc == NULL) {
LOG (LOG_CRIT, ERR_MEM_ALLOC);
}
else
{
if (offset)
strncpy(new_alloc, header->concatenated_data, offset);
strcat(new_alloc, decoded);
strcat(new_alloc, rest);
free(decoded);
decoded = new_alloc;
}
}
if (decoded) {
enc_offset += (decoded_len-1);
free(header->concatenated_data);
header->concatenated_data = decoded;
}
else if (was_null) {
header->original_data = NULL;
}
}
}
if (header->original_data != NULL) {
free(header->data);
header->data = strdup(header->concatenated_data);
}
node_nt = c_nt_next(block->headers, &c_nt);
}
return 0;
}
/*
* _ds_analyze_header (ds_message_part_t block, ds_header_t header,
* struct nt *boundaries)
*
* DESCRIPTION
* analyzes the header passed in and performs various operations including:
* - setting media type and subtype
* - setting transfer encoding
* - adding newly discovered boundaries
*
* based on the heading specified. essentially all headers should be
* analyzed for future expansion
*
* INPUT ARGUMENTS
* block the message block to which the header belongs
* header the header to analyze
* boundaries a list of known boundaries found within the block
*/
void
_ds_analyze_header (
ds_message_part_t block,
ds_header_t header,
struct nt *boundaries)
{
if (!header || !block || !header->data)
return;
/* Content-Type header */
if (!strcasecmp (header->heading, "Content-Type"))
{
int len = strlen(header->data);
if (!strncasecmp (header->data, "text", 4)) {
block->media_type = MT_TEXT;
if (len >= 5 && !strncasecmp (header->data + 5, "plain", 5))
block->media_subtype = MST_PLAIN;
else if (len >= 5 && !strncasecmp (header->data + 5, "html", 4))
block->media_subtype = MST_HTML;
else
block->media_subtype = MST_OTHER;
}
else if (!strncasecmp (header->data, "application", 11))
{
block->media_type = MT_APPLICATION;
if (len >= 12 && !strncasecmp (header->data + 12, "dspam-signature", 15))
block->media_subtype = MST_DSPAM_SIGNATURE;
else
block->media_subtype = MST_OTHER;
}
else if (!strncasecmp (header->data, "message", 7))
{
block->media_type = MT_MESSAGE;
if (len >= 8 && !strncasecmp (header->data + 8, "rfc822", 6))
block->media_subtype = MST_RFC822;
else if (len >= 8 && !strncasecmp (header->data + 8, "inoculation", 11))
block->media_subtype = MST_INOCULATION;
else
block->media_subtype = MST_OTHER;
}
else if (!strncasecmp (header->data, "multipart", 9))
{
char boundary[128];
block->media_type = MT_MULTIPART;
if (len >= 10 && !strncasecmp (header->data + 10, "mixed", 5))
block->media_subtype = MST_MIXED;
else if (len >= 10 && !strncasecmp (header->data + 10, "alternative", 11))
block->media_subtype = MST_ALTERNATIVE;
else if (len >= 10 && !strncasecmp (header->data + 10, "signed", 6))
block->media_subtype = MST_SIGNED;
else if (len >= 10 && !strncasecmp (header->data + 10, "encrypted", 9))
block->media_subtype = MST_ENCRYPTED;
else
block->media_subtype = MST_OTHER;
if (!_ds_extract_boundary(boundary, sizeof(boundary), header->data)) {
if (!_ds_match_boundary (boundaries, boundary)) {
_ds_push_boundary (boundaries, boundary);
free(block->boundary);
block->boundary = strdup (boundary);
}
} else {
_ds_push_boundary (boundaries, "");
}
}
else {
block->media_type = MT_OTHER;
block->media_subtype = MST_OTHER;
}
}
/* Content-Transfer-Encoding */
else if (!strcasecmp (header->heading, "Content-Transfer-Encoding"))
{
if (!strncasecmp (header->data, "7bit", 4))
block->encoding = EN_7BIT;
else if (!strncasecmp (header->data, "8bit", 4))
block->encoding = EN_8BIT;
else if (!strncasecmp (header->data, "quoted-printable", 16))
block->encoding = EN_QUOTED_PRINTABLE;
else if (!strncasecmp (header->data, "base64", 6))
block->encoding = EN_BASE64;
else if (!strncasecmp (header->data, "binary", 6))
block->encoding = EN_BINARY;
else
block->encoding = EN_OTHER;
}
if (!strcasecmp (header->heading, "Content-Disposition"))
{
if (!strncasecmp (header->data, "inline", 6))
block->content_disposition = PCD_INLINE;
else if (!strncasecmp (header->data, "attachment", 10))
block->content_disposition = PCD_ATTACHMENT;
else
block->content_disposition = PCD_OTHER;
}
return;
}
/*
* _ds_destroy_message (ds_message_t message)
*
* DESCRIPTION
* destroys a message structure (ds_message_t)
*
* INPUT ARGUMENTS
* message the message structure to be destroyed
*/
void
_ds_destroy_message (ds_message_t message)
{
struct nt_node *node_nt;
struct nt_c c;
int i = 0;
if (message == NULL)
return;
if (message->components) {
node_nt = c_nt_first (message->components, &c);
while (node_nt != NULL)
{
ds_message_part_t block = (ds_message_part_t) node_nt->ptr;
_ds_destroy_block(block);
node_nt = c_nt_next (message->components, &c);
i++;
}
nt_destroy (message->components);
}
free (message);
return;
}
/*
* _ds_destroy_headers (ds_message_part_t block)
*
* DESCRIPTION
* destroys a message block's header pairs
* does not free the structures themselves; these are freed at nt_destroy
*
* INPUT ARGUMENTS
* block the message block containing the headers to destsroy
*/
void
_ds_destroy_headers (ds_message_part_t block)
{
struct nt_node *node_nt;
struct nt_c c;
if (!block || !block->headers)
return;
node_nt = c_nt_first (block->headers, &c);
while (node_nt != NULL)
{
ds_header_t field = (ds_header_t) node_nt->ptr;
if (field)
{
free (field->original_data);
free (field->heading);
free (field->concatenated_data);
free (field->data);
}
node_nt = c_nt_next (block->headers, &c);
}
return;
}
/*
* _ds_destroy_block (ds_message_part_t block)
*
* DESCRIPTION
* destroys a message block
*
* INPUT ARGUMENTS
* block the message block to destroy
*/
void
_ds_destroy_block (ds_message_part_t block)
{
if (!block)
return;
if (block->headers)
{
_ds_destroy_headers (block);
nt_destroy (block->headers);
}
buffer_destroy (block->body);
buffer_destroy (block->original_signed_body);
free (block->boundary);
free (block->terminating_boundary);
// free (block);
return;
}
/*
* _ds_decode_block (ds_message_part_t block)
*
* DESCRIPTION
* decodes a message block
*
* INPUT ARGUMENTS
* block the message block to decode
*
* RETURN VALUES
* a pointer to the allocated character array containing the decoded message
* NULL on failure
*/
char *
_ds_decode_block (ds_message_part_t block)
{
if (block->encoding == EN_BASE64)
return _ds_decode_base64 (block->body->data);
else if (block->encoding == EN_QUOTED_PRINTABLE)
return _ds_decode_quoted (block->body->data);
LOG (LOG_WARNING, "decoding of block encoding type %d not supported",
block->encoding);
return NULL;
}
/*
* _ds_decode_{base64,quoted}
*
* DESCRIPTION
* supporting block decoder functions
* these function call (or perform) specific decoding functions
*
* INPUT ARGUMENTS
* body encoded message body
*
* RETURN VALUES
* a pointer to the allocated character array containing the decoded body
*/
#ifndef NCORE
char *
_ds_decode_base64 (const char *body)
{
if (body == NULL)
return NULL;
return base64decode (body);
}
char *
_ds_decode_quoted (const char *body)
{
char *out, *x;
char hex[3];
int val;
size_t len;
if (!body)
return NULL;
out = strdup (body);
if (!out)
{
LOG (LOG_CRIT, ERR_MEM_ALLOC);
return NULL;
}
len = strlen(out) + 1;
hex[2] = 0;
x = strchr (out, '=');
while (x != NULL)
{
hex[0] = x[1];
hex[1] = x[2];
if (x[1] == '\n')
{
memmove(x, x+2, len-((x+2)-out)); //strlen(x+2)+1);
len -= 2;
x = strchr (x, '=');
}
else
{
if (((hex[0] >= 'A' && hex[0] <= 'F')
|| (hex[0] >= 'a' && hex[0] <= 'f')
|| (hex[0] >= '0' && hex[0] <= '9'))
&& ((hex[1] >= 'A' && hex[1] <= 'F')
|| (hex[1] >= 'a' && hex[1] <= 'f')
|| (hex[1] >= '0' && hex[1] <= '9')))
{
val = (int) strtol (hex, NULL, 16);
if (val) {
x[0] = val;
memmove(x+1, x+3, len-((x+3)-out)); //strlen(x+3)+1);
len -= 2;
}
}
x = strchr (x + 1, '=');
}
}
return out;
}
#endif /* NCORE */
/*
* _ds_encode_block (ds_message_part_t block, int encoding)
*
* DESCRIPTION
* encodes a message block using the encoding specified and replaces the
* block's message body with the encoded data
*
* INPUT ARGUMENTS
* block the message block to encode
* encoding encoding to use (EN_)
*
* RETURN VALUES
* returns 0 on success
*/
int
_ds_encode_block (ds_message_part_t block, int encoding)
{
/* we can't encode a block with the same encoding */
if (block->encoding == encoding)
return EINVAL;
/* we can't encode a block that's already encoded */
if (block->encoding == EN_BASE64 || block->encoding == EN_QUOTED_PRINTABLE)
return EFAILURE;
if (encoding == EN_BASE64) {
char *encoded = _ds_encode_base64 (block->body->data);
buffer_destroy (block->body);
block->body = buffer_create (encoded);
free (encoded);
block->encoding = EN_BASE64;
}
else if (encoding == EN_QUOTED_PRINTABLE) {
/* TODO */
return 0;
}
LOGDEBUG("unsupported encoding: %d", encoding);
return 0;
}
/*
* _ds_encode_{base64,quoted}
*
* DESCRIPTION
* supporting block encoder functions
* these function call (or perform) specific encoding functions
*
* INPUT ARGUMENTS
* body decoded message body
*
* RETURN VALUES
* a pointer to the allocated character array containing the encoded body
*/
char *
_ds_encode_base64 (const char *body)
{
return base64encode (body);
}
/*
* _ds_assemble_message (ds_message_t message)
*
* DESCRIPTION
* assembles a message structure into a flat text message
*
* INPUT ARGUMENTS
* message the message structure (ds_message_t) to assemble
*
* RETURN VALUES
* a pointer to the allocated character array containing the text message
*/
char *
_ds_assemble_message (ds_message_t message)
{
buffer *out = buffer_create (NULL);
struct nt_node *node_nt, *node_header;
struct nt_c c_nt, c_nt2;
char *heading;
char *copyback;
int i = 0;
if (!out) {
LOG (LOG_CRIT, ERR_MEM_ALLOC);
return NULL;
}
node_nt = c_nt_first (message->components, &c_nt);
while (node_nt != NULL && node_nt->ptr != NULL)
{
ds_message_part_t block =
(ds_message_part_t) node_nt->ptr;
#ifdef VERBOSE
LOGDEBUG ("assembling component %d", i);
#endif
/* Assemble headers */
if (block->headers != NULL && block->headers->items > 0)
{
node_header = c_nt_first (block->headers, &c_nt2);
while (node_header != NULL)
{
char *data;
ds_header_t current_header =
(ds_header_t) node_header->ptr;
data = (current_header->original_data == NULL) ? current_header->data :
current_header->original_data;
heading = malloc(
((current_header->heading) ? strlen(current_header->heading) : 0)
+ ((data) ? strlen(data) : 0)
+ 4);
if (current_header->heading != NULL &&
(!strncmp (current_header->heading, "From ", 5) ||
!strncmp (current_header->heading, "--", 2)))
sprintf (heading, "%s:%s\n",
(current_header->heading) ? current_header->heading : "",
(data) ? data: "");
else
sprintf (heading, "%s: %s\n",
(current_header->heading) ? current_header->heading : "",
(data) ? data : "");
buffer_cat (out, heading);
free(heading);
node_header = c_nt_next (block->headers, &c_nt2);
}
}
buffer_cat (out, "\n");
/* Assemble bodies */
if (block->original_signed_body != NULL && message->protect)
buffer_cat (out, block->original_signed_body->data);
else
buffer_cat (out, block->body->data);
if (block->terminating_boundary != NULL)
{
buffer_cat (out, "--");
buffer_cat (out, block->terminating_boundary);
}
node_nt = c_nt_next (message->components, &c_nt);
i++;
if (node_nt != NULL && node_nt->ptr != NULL)
buffer_cat (out, "\n");
}
copyback = out->data;
out->data = NULL;
buffer_destroy (out);
return copyback;
}
/*
* _ds_{push,pop,match,extract}_boundary
*
* DESCRIPTION
* these functions maintain and service a boundary "stack" on the message
*/
int
_ds_push_boundary (struct nt *stack, const char *boundary)
{
char *y;
if (boundary == NULL || boundary[0] == 0)
return EINVAL;
y = malloc (strlen (boundary) + 3);
if (y == NULL)
return EUNKNOWN;
sprintf (y, "--%s", boundary);
nt_add (stack, (char *) y);
free(y);
return 0;
}
char *
_ds_pop_boundary (struct nt *stack)
{
struct nt_node *node, *last_node = NULL, *parent_node = NULL;
struct nt_c c;
char *boundary = NULL;
node = c_nt_first (stack, &c);
while (node != NULL)
{
parent_node = last_node;
last_node = node;
node = c_nt_next (stack, &c);
}
if (parent_node != NULL)
parent_node->next = NULL;
else
stack->first = NULL;
if (last_node == NULL)
return NULL;
boundary = strdup (last_node->ptr);
free (last_node->ptr);
free (last_node);
return boundary;
}
int
_ds_match_boundary (struct nt *stack, const char *buff)
{
struct nt_node *node;
struct nt_c c;
node = c_nt_first (stack, &c);
while (node != NULL)
{
if (!strncmp (buff, node->ptr, strlen (node->ptr)))
{
return 1;
}
node = c_nt_next (stack, &c);
}
return 0;
}
int
_ds_extract_boundary (char *buf, size_t size, char *mem)
{
char *data, *ptr, *ptrptr;
if (mem == NULL)
return EINVAL;
data = strdup(mem);
if (data == NULL) {
LOG(LOG_CRIT, ERR_MEM_ALLOC);
return EUNKNOWN;
}
for(ptr=data;ptr<(data+strlen(data));ptr++) {
if (!strncasecmp(ptr, "boundary", 8)) {
ptr = strchr(ptr, '=');
if (ptr == NULL) {
free(data);
return EFAILURE;
}
ptr++;
while(isspace((int) ptr[0]))
ptr++;
if (ptr[0] == '"')
ptr++;
strtok_r(ptr, " \";\n\t", &ptrptr);
strlcpy(buf, ptr, size);
free(data);
return 0;
}
}
free(data);
return EFAILURE;
}
/*
* _ds_find_header (ds_message_t message, consr char *heading, int flags) {
*
* DESCRIPTION
* finds a header and returns its value
*
* INPUT ARGUMENTS
* message the message structure to search
* heading the heading to search for
* flags optional search flags
*
* FLAGS
* DDF_ICASE case insensitive search
*
* RETURN VALUES
* a pointer to the header structure's value
*
*/
char *
_ds_find_header (ds_message_t message, const char *heading, int flags) {
ds_message_part_t block;
ds_header_t head;
struct nt_node *node_nt;
if (message->components->first) {
if ((block = message->components->first->ptr)==NULL)
return NULL;
if (block->headers == NULL)
return NULL;
} else {
return NULL;
}
node_nt = block->headers->first;
while(node_nt != NULL) {
head = (ds_header_t) node_nt->ptr;
if (flags & DDF_ICASE) {
if (head && !strcasecmp(head->heading, heading))
return head->data;
} else {
if (head && !strcmp(head->heading, heading))
return head->data;
}
node_nt = node_nt->next;
}
return NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1