meillo@367: /* meillo@367: ** MasqMail meillo@367: ** Copyright (C) 2000 Oliver Kurth meillo@367: ** meillo@367: ** This program is free software; you can redistribute it and/or modify meillo@367: ** it under the terms of the GNU General Public License as published by meillo@367: ** the Free Software Foundation; either version 2 of the License, or meillo@367: ** (at your option) any later version. meillo@367: ** meillo@367: ** This program is distributed in the hope that it will be useful, meillo@367: ** but WITHOUT ANY WARRANTY; without even the implied warranty of meillo@367: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the meillo@367: ** GNU General Public License for more details. meillo@367: ** meillo@367: ** You should have received a copy of the GNU General Public License meillo@367: ** along with this program; if not, write to the Free Software meillo@367: ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. meillo@0: */ meillo@0: #include "masqmail.h" meillo@0: meillo@10: header_name header_names[] = { meillo@15: {"From", HEAD_FROM,}, meillo@15: {"Sender", HEAD_SENDER,}, meillo@15: {"To", HEAD_TO,}, meillo@15: {"Cc", HEAD_CC,}, meillo@15: {"Bcc", HEAD_BCC,}, meillo@15: {"Date", HEAD_DATE,}, meillo@15: {"Message-Id", HEAD_MESSAGE_ID,}, meillo@15: {"Reply-To", HEAD_REPLY_TO,}, meillo@15: {"Subject", HEAD_SUBJECT,}, meillo@15: {"Return-Path", HEAD_RETURN_PATH,}, meillo@15: {"Envelope-To", HEAD_ENVELOPE_TO,}, meillo@15: {"Received", HEAD_RECEIVED}, meillo@0: }; meillo@0: meillo@0: /* this was borrowed from exim and slightly changed */ meillo@10: gchar* meillo@10: rec_timestamp() meillo@0: { meillo@10: static gchar buf[64]; meillo@10: int len; meillo@0: meillo@10: time_t now = time(NULL); meillo@10: struct tm *t = localtime(&now); meillo@0: meillo@10: int diff_hour, diff_min; meillo@10: struct tm local; meillo@10: struct tm *gmt; meillo@0: meillo@10: memcpy(&local, t, sizeof(struct tm)); meillo@10: gmt = gmtime(&now); meillo@10: diff_min = 60 * (local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min; meillo@301: if (local.tm_year != gmt->tm_year) { meillo@10: diff_min += (local.tm_year > gmt->tm_year) ? 1440 : -1440; meillo@301: } else if (local.tm_yday != gmt->tm_yday) { meillo@10: diff_min += (local.tm_yday > gmt->tm_yday) ? 1440 : -1440; meillo@301: } meillo@10: diff_hour = diff_min / 60; meillo@10: diff_min = abs(diff_min - diff_hour * 60); meillo@0: meillo@10: len = strftime(buf, sizeof(buf), "%a, ", &local); meillo@10: g_snprintf(buf + len, sizeof(buf) - len, "%02d ", local.tm_mday); meillo@10: len += strlen(buf + len); meillo@10: len += strftime(buf + len, sizeof(buf) - len, "%b %Y %H:%M:%S", &local); meillo@10: g_snprintf(buf + len, sizeof(buf) - len, " %+03d%02d", diff_hour, diff_min); meillo@10: meillo@10: return buf; meillo@0: } meillo@0: meillo@367: /* meillo@367: ** finds list of headers matching id meillo@367: ** if id == HEAD_UNKNOWN and header == NULL finds all unknown headers meillo@367: ** else finds all headers matching header meillo@0: */ meillo@10: GList* meillo@366: find_header(GList *hdr_list, header_id id, gchar *hdr_str) meillo@0: { meillo@10: GList *found_list = NULL; meillo@10: GList *node; meillo@0: meillo@301: if ((id != HEAD_UNKNOWN) || !hdr_str) { meillo@10: foreach(hdr_list, node) { meillo@10: header *hdr = (header *) (node->data); meillo@301: if (hdr->id == id) { meillo@10: found_list = g_list_append(found_list, hdr); meillo@301: } meillo@10: } meillo@301: return found_list; meillo@301: } meillo@10: meillo@301: foreach(hdr_list, node) { meillo@301: header *hdr = (header *) (node->data); meillo@301: gchar buf[64], *q = buf, *p = hdr->header; meillo@10: meillo@301: while (*p != ':' && q < buf+sizeof(buf)-1 && *p) { meillo@301: *(q++) = *(p++); meillo@301: } meillo@301: *q = '\0'; meillo@301: meillo@301: if (strcasecmp(buf, hdr_str) == 0) { meillo@301: found_list = g_list_append(found_list, hdr); meillo@10: } meillo@10: } meillo@10: return found_list; meillo@0: } meillo@0: meillo@10: void meillo@366: header_unfold(header *hdr) meillo@0: { meillo@302: char *src = hdr->header; meillo@302: char *dest = src; meillo@302: char *p; meillo@0: meillo@302: p = strchr(src, '\n'); meillo@302: if (!p || !p[1]) { meillo@302: /* no folded header */ meillo@302: return; meillo@302: } meillo@0: meillo@302: while (*src) { meillo@302: if (*src == '\n') { meillo@302: /* ignore */ meillo@302: src++; meillo@302: } else { meillo@302: /* copy */ meillo@302: *(dest++) = *(src++); meillo@302: } meillo@302: } meillo@302: *(dest++) = '\n'; meillo@302: *(dest++) = '\0'; meillo@0: } meillo@0: meillo@303: /* meillo@367: ** fold the header at maxlen chars (newline excluded) meillo@367: ** (We exclude the newline because the RFCs deal with it this way) meillo@303: */ meillo@10: void meillo@366: header_fold(header *hdr, unsigned int maxlen) meillo@0: { meillo@303: int len = strlen(hdr->header); meillo@366: char *src = hdr->header; meillo@366: char *dest; meillo@366: char *tmp; meillo@366: char *p; meillo@301: int valueoffset; meillo@301: meillo@303: if (len <= maxlen) { meillo@301: /* we don't need to do anything */ meillo@301: return; meillo@301: } meillo@301: meillo@303: /* strip trailing whitespace */ meillo@303: for (p=src+len-1; *p==' '||*p=='\t'||*p=='\n'; p--) { meillo@303: *p = '\0'; meillo@303: len--; meillo@303: printf(" trailing whitespace\n"); meillo@303: } meillo@303: printf("stripped len: %d\n", len); meillo@303: meillo@367: /* meillo@367: ** FIXME: would be nice to have a better size calculation meillo@367: ** (the current size + what we insert as break, twice as often as meillo@367: ** we have breaks in the optimal case) meillo@367: */ meillo@303: tmp = malloc(len + 2 * (len/maxlen) * strlen("\n\t")); meillo@303: dest = tmp; meillo@303: meillo@303: /* the position in hdr->header where the value part start */ meillo@301: valueoffset = hdr->value - hdr->header; meillo@301: meillo@303: while (strlen(src) > maxlen) { meillo@303: char *pp; meillo@0: meillo@303: for (pp=src+maxlen; pp>src; pp--) { meillo@303: if (*pp==' ' || *pp=='\t' || *p=='\n') { meillo@303: break; meillo@303: } meillo@303: } meillo@303: meillo@303: if (src == pp) { meillo@303: /* no potential break point was found within meillo@303: maxlen so advance further until the next */ meillo@303: for (pp=src+maxlen; *pp; pp++) { meillo@303: if (*pp==' ' || *pp=='\t' || *p=='\n') { meillo@303: break; meillo@303: } meillo@303: } meillo@303: } meillo@303: if (!*pp) { meillo@303: break; meillo@303: } meillo@0: meillo@303: memcpy(dest, src, pp-src); meillo@303: dest += pp-src; meillo@303: *(dest++) = '\n'; meillo@303: *(dest++) = '\t'; meillo@303: while (*pp == ' ' || *pp == '\t' || *p=='\n') { meillo@303: pp++; meillo@303: } meillo@303: src = pp; meillo@303: } meillo@303: memcpy(dest, src, strlen(src)); meillo@303: dest += strlen(src); meillo@303: meillo@303: if (*(dest-1) != '\n') { meillo@303: *dest = '\n'; meillo@303: *(dest+1) = '\0'; meillo@301: } meillo@0: meillo@303: hdr->header = tmp; meillo@301: hdr->value = hdr->header + valueoffset; meillo@0: } meillo@0: meillo@10: header* meillo@366: create_header(header_id id, gchar *fmt, ...) meillo@0: { meillo@10: gchar *p; meillo@10: header *hdr; meillo@10: va_list args; meillo@10: va_start(args, fmt); meillo@0: meillo@301: /* g_malloc() calls exit on failure */ meillo@301: hdr = g_malloc(sizeof(header)); meillo@0: meillo@301: hdr->id = id; meillo@301: hdr->header = g_strdup_vprintf(fmt, args); meillo@301: hdr->value = NULL; meillo@0: meillo@367: /* meillo@367: ** value shall point to the first non-whitespace char in the meillo@367: ** value part of the header line (i.e. after the first colon) meillo@367: */ meillo@301: p = strchr(hdr->header, ':'); meillo@301: if (p) { meillo@301: p++; meillo@301: while (*p == ' ' || *p == '\t' || *p == '\n') { meillo@10: p++; meillo@301: } meillo@301: hdr->value = (*p) ? p : NULL; meillo@10: } meillo@0: meillo@415: DEBUG(3) debugf("create_header(): %s", hdr->header); meillo@415: /* DEBUG(3) debugf("create_header(): val: `%s'\n", hdr->value); */ meillo@301: meillo@10: va_end(args); meillo@10: return hdr; meillo@0: } meillo@0: meillo@10: void meillo@366: destroy_header(header *hdr) meillo@0: { meillo@10: if (hdr) { meillo@301: if (hdr->header) { meillo@10: g_free(hdr->header); meillo@301: } meillo@10: g_free(hdr); meillo@10: } meillo@0: } meillo@0: meillo@10: header* meillo@366: copy_header(header *hdr) meillo@0: { meillo@10: header *new_hdr = NULL; meillo@0: meillo@10: if (hdr) { meillo@301: new_hdr = g_malloc(sizeof(header)); meillo@301: new_hdr->id = hdr->id; meillo@301: new_hdr->header = g_strdup(hdr->header); meillo@301: new_hdr->value = new_hdr->header + (hdr->value - hdr->header); meillo@10: } meillo@10: return new_hdr; meillo@0: } meillo@0: meillo@10: header* meillo@366: get_header(gchar *line) meillo@0: { meillo@10: gchar *p = line; meillo@10: gchar buf[64], *q = buf; meillo@10: gint i; meillo@10: header *hdr; meillo@0: meillo@301: while (*p && (*p != ':') && (q < buf+sizeof(buf)-1)) { meillo@10: *(q++) = *(p++); meillo@301: } meillo@15: *q = '\0'; meillo@0: meillo@301: if (*p != ':') { meillo@10: return NULL; meillo@301: } meillo@0: meillo@10: hdr = g_malloc(sizeof(header)); meillo@0: meillo@10: hdr->value = NULL; meillo@10: p++; meillo@0: meillo@301: while (*p && (*p == ' ' || *p == '\t')) { meillo@10: p++; meillo@301: } meillo@10: hdr->value = p; meillo@367: /* meillo@367: ** Note: an empty value can also mean that it's only the first part meillo@367: ** of a folded header line meillo@367: */ meillo@0: meillo@10: for (i = 0; i < HEAD_NUM_IDS; i++) { meillo@301: if (strcasecmp(header_names[i].header, buf) == 0) { meillo@10: break; meillo@301: } meillo@10: } meillo@10: hdr->id = (header_id) i; meillo@10: hdr->header = g_strdup(line); meillo@10: hdr->value = hdr->header + (hdr->value - line); meillo@10: meillo@415: DEBUG(4) debugf("header: %d = %s", hdr->id, hdr->header); meillo@301: /* Note: This only outputs the first line if the header is folded */ meillo@10: meillo@10: return hdr; meillo@0: }