/*
**
** Copyright (C) 1993 Swedish University Network (SUNET)
**
**
** This program is developed by UDAC, Uppsala University by commission
** of the Swedish University Network (SUNET).
**
** 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 of the License, 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 FITTNESS 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., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**
** Martin.Wendel@its.uu.se
** Torbjorn.Wictorin@its.uu.se
**
** ITS
** P.O. Box 887
** S-751 08 Uppsala
** Sweden
**
*/
#include "emil.h"
int do_sibling = FALSE;
/*
* int
* parse_message(inbuf, message)
*
* Parse message and divide into a hierarchical structure of message parts.
*
*/
int
parse_message(struct message *m)
{
struct data *inbuf;
/* Initialize inbuf */
inbuf = (struct data *)m->sd;
/* Exit on empty input */
if (inbuf->size == 0 || (inbuf->end <= inbuf->offset))
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, "*** Empty input (failed).\n");
#endif
logger(LOG_ERR, "parse_message: Empty input");
return(NOK);
}
/* Check header if possible */
if (!m->headerdone && (m->sd->format != RFC822 || m->level == 0))
if (check_header(m) != OK)
return(NOK);
switch(m->sd->format)
{
case MIME:
return(parse_mime_message(m));
break;
case MAILTOOL:
return(parse_sun_message(m));
break;
case RFC822:
return(parse_rfc822_message(m));
break;
default:
break;
}
return(NOK);
}
int
move_past_boundary(struct message *m, char *boundary)
{
int linelen;
struct data *inbuf;
inbuf = (struct data *)m->sd;
/* Find start boundary */
while (is_bound(inbuf, boundary) != TRUE)
{
if ((linelen = getline(inbuf)) == 0)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, "* move_past_boundary failed, EOF.\n");
#endif
return(NOK);
}
inbuf->offset += linelen;
if (inbuf->end <= inbuf->offset)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, "move_past_boundary: cannot find boundary\n");
#endif
sprintf(ebuf, "move_past_boundary: cannot find boundary");
logger(LOG_DEBUG, ebuf);
return(NOK);
}
inbuf->loffset += 1;
}
/* Move past boundary */
inbuf->offset += getline(inbuf);
inbuf->loffset += 1;
#ifdef DEBUG
if (edebug)
fprintf(stderr, "+ Found boundary, moved to %lu\n", inbuf->offset);
#endif
return(OK);
}
int
check_header(struct message *m)
{
m->headerdone = 1;
if (load_header(m) == OK)
/* Offset is updated with size of header! */
{
/* Decode the loaded header */
decode_header(m);
/* Set body lines, if available
* (body length is not trusted)
*/
if (m->sd->bodylines != 0)
m->sd->lineend = m->sd->loffset + m->sd->bodylines;
}
else
{
/* Load header failed */
sprintf(ebuf, "check_header: load header failed: %lu", m->sd->loffset);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "%s\n", ebuf);
#endif
logger(LOG_DEBUG, ebuf);
return(NOK);
}
return(OK);
}
int
check_encoding(struct message *m)
{
struct data *inbuf;
int status;
inbuf = m->sd;
/* Check for encoding */
switch (inbuf->encoding)
{
case 0:
inbuf->encoding = E7BIT;
status = OK;
break;
case EBINHEX:
if (decode_binhex(m) == NOK)
{
sprintf(ebuf, "WARNING: parse_message: BinHex decode failed :%lu",
inbuf->loffset);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "%s\n", ebuf);
#endif
logger(LOG_WARNING, ebuf);
status = NOK;
}
else
status = OK;
break;
case EUUENCODE:
if (decode_uuencode(m) == NOK)
{
sprintf(ebuf, "WARNING: parse_message: UUencode decode failed :%lu",
inbuf->loffset);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "%s\n", ebuf);
#endif
logger(LOG_WARNING, ebuf);
status = NOK;
}
else
status = OK;
break;
case EBASE64:
if (decode_base64(m) == NOK)
{
sprintf(ebuf, "WARNING: parse_message: Base64 decode failed :%lu",
inbuf->loffset);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "%s\n", ebuf);
#endif
logger(LOG_WARNING, ebuf);
status = NOK;
}
else
status = OK;
if (inbuf->bodyend == 0)
inbuf->bodyend = inbuf->end;
break;
case EQP:
if (decode_quoted_printable(m) == NOK)
{
sprintf(ebuf, "WARNING: parse_message: Quoted-Printable decode failed :%lu",
inbuf->loffset);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "%s\n", ebuf);
#endif
logger(LOG_WARNING, ebuf);
status = NOK;
}
else
status = OK;
if (inbuf->bodyend == 0)
inbuf->bodyend = inbuf->end;
break;
default:
status = OK;
break;
}
return(status);
}
int
boundary_check(struct message *m)
{
struct message *parent;
int encoding;
int check;
encoding = m->sd->encoding;
check = m->sd->check;
parent = m->parent;
#ifdef DEBUG
if (edebug)
fprintf(stderr, "checking part %d with check %d and encoding %d\nat offset %lu\n",
m->sd->count, check, encoding, m->sd->offset);
#endif
/* Check a multipart, look for start boundary */
if (parent != NULL && parent->sd->startbound != NULL &&
(strlen(parent->sd->startbound)) != 0)
{
if (is_bound(m->sd, parent->sd->startbound))
{
return(E7BIT); /* Just a precaution */
}
}
/* Check for uuencode */
if (check & EUUENCODE)
{
if (encoding & EUUENCODE)
return(0);
/* Check for binhex and uuencode */
if (strncmp((m->sd->contents + m->sd->offset), "begin ", 6) == 0)
{
return(EUUENCODE);
}
}
/* Check for BinHex */
if (check & EBINHEX)
{
if (encoding & EBINHEX)
return(0);
/* Check for BinHex */
if (strncasecmp((m->sd->contents + m->sd->offset), "(This file ", 11) == 0)
{
return(EBINHEX);
}
}
if (encoding == 0)
return(E7BIT);
return(0);
}
/*
*
*/
int
is_bound(struct data *d, char *boundary)
{
int blen;
if (boundary != NULL &&
(blen = strlen(boundary)) != 0)
{
/*
printf("is_bound: '%20.20s'\n '%20.20'\n",
d->contents+d->offset,
boundary);
*/
if (d->offset + blen < d->end &&
strncmp((d->contents + d->offset), boundary, blen) == 0)
{
return(TRUE);
}
}
return(FALSE);
}
/*
*
*/
struct message *
copy_mstruct(struct message *m, int force)
{
struct data *cbuf, *inbuf;
struct message *cm;
#ifdef DEBUG
if (edebug)
fprintf(stderr, "+ Copying structure\n");
#endif
inbuf = m->sd;
if (force < 2)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, "+ Creating new data structure\n");
#endif
/* Copy data structure */
cbuf = (struct data *) Yalloc(sizeof(struct data));
cbuf->contents = inbuf->contents; /* data */
cbuf->offset = inbuf->offset; /* and offset */
cbuf->check = inbuf->check;
cbuf->size = inbuf->size;
cbuf->count = inbuf->count + 1;
cbuf->loffset = inbuf->loffset;
cbuf->charset = inbuf->charset;
cbuf->format = inbuf->format;
}
else
cbuf = m->sd;
/* Copy message structure */
if (force < 1 && m->sd->format == RFC822)
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, "+ Living with old message structure\n");
#endif
m->sd->next = cbuf;
m->sd = m->sd->next;
m->td = m->sd;
#ifdef DEBUG
if (edebug)
fprintf(stderr, "Reached offset %lu\n", m->sd->offset);
#endif
return(m);
}
else
{
#ifdef DEBUG
if (edebug)
fprintf(stderr, "+ Copying message structure\n");
#endif
cm = (struct message *) Yalloc(sizeof(struct message));
cm->sdl = cbuf;
cm->sd = cm->sdl;
cm->td = cbuf;
return(cm);
}
}
/*
* int
* getline(inbuf)
*
* Move pointer to next line of inbuf. Return line length.
*/
int
getline(struct data *inbuf)
{
unsigned char *tmp;
if (inbuf == NULL || inbuf->contents == NULL ||
inbuf->offset >= inbuf->end)
return(0);
tmp = index(inbuf->contents + inbuf->offset, '\n');
if (tmp == NULL || (tmp - inbuf->contents) >= inbuf->end)
return(inbuf->end - inbuf->offset);
else
return(tmp - inbuf->contents + 1 - inbuf->offset);
}
int
set_end_by_boundary(struct message *m, char *boundary)
{
int linelen, offset, loffset;
struct data *inbuf;
inbuf = (struct data *)m->sd;
#ifdef DEBUG
if (edebug)
fprintf(stderr, "* set_end_by_boundary\n");
#endif
offset = inbuf->offset;
loffset = inbuf->loffset;
while (is_bound(inbuf, boundary) != TRUE)
{
if ((linelen = getline(inbuf)) == 0)
{
if (m->parent)
inbuf->bodyend = m->parent->sd->bodyend;
else
inbuf->bodyend = inbuf->offset;
inbuf->lineend = inbuf->loffset;
inbuf->offset = offset;
inbuf->loffset = loffset;
sprintf(ebuf, "set_end_by_boundary: cannot find boundary, setting end to %lu\n", inbuf->bodyend);
logger(LOG_DEBUG, ebuf);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "set_end_by_boundary: cannot find boundary, setting end to %lu\n", inbuf->bodyend);
#endif
return(NOK);
}
inbuf->offset += linelen;
inbuf->loffset += 1;
}
/* Set bodyend to just before the end boundary */
inbuf->bodyend = inbuf->offset;
inbuf->lineend = inbuf->loffset;
if (m->sd->format == MIME)
inbuf->bodyend -= 1;
inbuf->offset = offset;
inbuf->loffset = loffset;
#ifdef DEBUG
if (edebug)
fprintf(stderr, "+ Found boundary, setting end at %lu.\n", inbuf->bodyend);
#endif
return(OK);
}
int
set_end_by_lines(struct message *m, int lines)
{
int linelen, offset, loffset, lineend;
struct data *inbuf;
inbuf = (struct data *)m->sd;
#ifdef DEBUG
if (edebug)
fprintf(stderr, "* set_end_by_lines\n");
#endif
offset = inbuf->offset;
loffset = inbuf->loffset;
lineend = loffset + lines;
while ((linelen = getline(inbuf)) != 0 && lineend > inbuf->loffset)
{
inbuf->offset += linelen;
inbuf->loffset += 1;
}
/* Set bodyend to just before the end boundary */
inbuf->bodyend = inbuf->offset;
inbuf->lineend = inbuf->loffset;
inbuf->offset = offset;
inbuf->loffset = loffset;
return(OK);
}
syntax highlighted by Code2HTML, v. 0.9.1