/* ** ** 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" #define HQUOTE -1 /* Function definitions */ void process_header_line(struct header *, char *); void save_header(struct message *, struct data *, short, int); void clear_end(struct data *); void add_header_item(); void add_header_delimiter(); static void code_header(struct header *); static void code_hvalue(struct hprs *, struct data *); int isheader(char *); /* * */ int load_header(struct message *m) { struct data *line_buf; struct data *indata; int linelen; long startoffset; long startline; char *buf; indata = m->sd; line_buf = (struct data *)Yalloc(sizeof (struct data)); /* * Make sure there is data to process, else exit. */ if (indata->end <= indata->offset) return(OK); startoffset = indata->offset; startline = indata->loffset; /* * If current header is not empty, look for folded header lines. */ while (1) { buf = indata->contents + indata->offset; if ((linelen = getline(indata)) == 0) { /* End of data, illegal header */ indata->offset = startoffset; /* Rewind */ indata->loffset = startline; /* Rewind */ m->h = NULL; return(NOK); } #ifdef DEBUG if (edebug) { fprintf(stderr, "Read: "); fwrite(indata->contents + indata->offset, 1, linelen, stderr); } #endif indata->loffset += 1; if ((*buf == ' ' || *buf == '\t') && line_buf->end != 0) { /* Unfold header line and append to previos line */ /* clear_end(line_buf); */ append_data(line_buf, buf, linelen, HEAD_BUF); } else /* Not folded yet */ { if (line_buf->end != 0) /* If no header line yet, append header line */ /* Already got header line */ { if (strncasecmp(line_buf->contents, "from ", 5) == 0 || strncasecmp(line_buf->contents,">from ", 6) == 0) { /* Process folded UNIX from line */ save_header(m, line_buf, (short) UNIXFROM, RFC822); line_buf->end = 0; *(line_buf->contents) = '\0'; } else { if (isheader(line_buf->contents)) { save_header(m, line_buf, (short) EMHEADER, m->sd->format); line_buf->end = 0; *(line_buf->contents) = '\0'; } else { /* Syntax error or end of header */ indata->offset = startoffset; /* Rewind */ sprintf(ebuf, "load_header: illegal end of header: %s", line_buf->contents); logger(LOG_ERR, ebuf); m->h = NULL; return(NOK); } } } } if((linelen == 1 && *buf == '\n') || (linelen == 2 && *buf == '\r')) { /* End of header */ indata->offset++; return(OK); } if (line_buf->end == 0) { append_data(line_buf, buf, linelen, HEAD_BUF); } indata->offset += linelen; } /* Not reached */ } /* * */ void clear_end(struct data *d) { if (*(d->contents + d->end - 1) == '\n') { if (*(d->contents + d->end - 2) == '\r') { *(d->contents + d->end - 2) = '\0'; d->end -= 2; } else { *(d->contents + d->end - 1) = '\0'; d->end -= 1; } } } /* * save_header() * * Save the header field and header value in a list of header structures. * */ void save_header(struct message *mess, struct data *line, short type, int format) { struct header *hdr, *thdr; char *value; hdr = (struct header *)Yalloc(sizeof(struct header)); hdr->type = type; hdr->format = format; clear_end(line); #ifdef DEBUG if (edebug) fprintf(stderr, "+ Save header: %s\n", line->contents); #endif hdr->field = (struct data *)Yalloc(sizeof(struct data )); if (type == UNIXFROM) append_data(hdr->field, line->contents, line->end, HEAD_BUF); else { hdr->value = (struct data *)Yalloc(sizeof(struct data )); value = index(line->contents, ':'); assert(value); *value = '\0'; value++; while(isspace(*value)) value++; append_data(hdr->field, line->contents, strlen(line->contents), HEAD_BUF); append_data(hdr->value, value, strlen(value), HEAD_BUF); } if (mess->h == NULL) mess->h = hdr; else { for (thdr = mess->h; thdr->next != NULL; thdr = thdr->next) ; thdr->next = hdr; } code_header(hdr); } void add_header(struct message *mess, char *field, char *value, int format) { struct header *hdr, *thdr; #ifdef DEBUG if (edebug) fprintf(stderr, "+ Add header: %s: %s\n", field, value); #endif if (mess->h != NULL) for (thdr = mess->h; thdr != NULL; thdr = thdr->next) { if (thdr->field->end != 0 && cmatch(thdr->field->contents, field) == TRUE) { thdr->value->offset = 0; thdr->value->end = 0; thdr->value->bodyend = 0; append_data(thdr->value, value, strlen(value), HEAD_BUF); append_char(thdr->value, '\0', HEAD_BUF); /* NULL terminate */ thdr->format = format; thdr->hvalue = NULL; return; } hdr = thdr; } thdr = hdr; hdr = (struct header *)Yalloc(sizeof(struct header)); hdr->type = EMHEADER; hdr->format = format; hdr->field = (struct data *)Yalloc(sizeof(struct data )); hdr->value = (struct data *)Yalloc(sizeof(struct data )); append_data(hdr->field, field, strlen(field), HEAD_BUF); if (value != NULL) append_data(hdr->value, value, strlen(value), HEAD_BUF); if (mess->h == NULL) mess->h = hdr; else thdr->next = hdr; } void rm_header(struct message *mess, char *field) { struct header *hdr, *thdr; #ifdef DEBUG if (edebug) fprintf(stderr, "+ Remove header: %s: **\n", field); #endif if (mess->h != NULL) for (thdr = mess->h; thdr != NULL; thdr = thdr->next) { if (thdr->field->end != 0 && cmatch(thdr->field->contents, field) == TRUE) { if (thdr != NULL && thdr == mess->h) mess->h = thdr->next; else hdr->next = thdr->next; break; } hdr = thdr; } } int isheader(char *string) { char *t, *p; if ((t = index(string, ':')) == NULL || t == string) return(0); if ((p = index(string, ' ')) != NULL && p < t) return(0); return(1); } static void code_header(struct header *th) { struct data *outbuf; #ifdef DEBUG if (edebug) fprintf(stderr, "+ code_header.\n"); #endif parse_rfc1522(th); if (th->hvalue != NULL) { outbuf = (struct data *)Yalloc(sizeof(struct data)); (void)code_hvalue(th->hvalue, outbuf); th->value = outbuf; } } static void code_hvalue(struct hprs *h, struct data *outbuf) { #ifdef DEBUG if (edebug) fprintf(stderr, "+ code_hvalue.\n"); #endif switch (h->type) { case ATOM: case DELIMITER: case RFC1522: append_data(outbuf, h->td->contents + h->td->bodystart, h->td->bodyend - h->td->bodystart, HEAD_BUF); break; case DLITERAL: append_char(outbuf, '[', HEAD_BUF); break; case COMMENT: append_char(outbuf, '(', HEAD_BUF); break; case HQSTRING: append_char(outbuf, '"', HEAD_BUF); break; case RADDR: append_char(outbuf, '<', HEAD_BUF); break; default: break; } if (h->child != NULL) code_hvalue(h->child, outbuf); switch(h->type) { case DLITERAL: append_char(outbuf, ']', HEAD_BUF); break; case COMMENT: append_char(outbuf, ')', HEAD_BUF); break; case HQSTRING: append_char(outbuf, '"', HEAD_BUF); break; case RADDR: append_char(outbuf, '>', HEAD_BUF); break; default: break; } if (h->sibling != NULL) code_hvalue(h->sibling, outbuf); } char * clear_end_space(char *c) { char *d; d = c + strlen(c) -1; while (isspace(*d)) { *d = '\0'; d--; } return(c); }