masqmail-0.2

annotate src/header.c @ 179:ec3fe72a3e99

Fixed an important bug with folded headers! g_strconcat() returns a *copy* of the string, but hdr->value still pointed to the old header (which probably was a memory leak, too). If the folded part had been quite small it was likely that the new string was at the same position as the old one, thus making everything go well. But if pretty long headers were folded several times it was likely that the new string was allocated somewhere else in memory, thus breaking things. In result mails to lots of recipients (folded header) were frequently only sent to the ones in the first line. Sorry for the inconvenience.
author meillo@marmaro.de
date Fri, 03 Jun 2011 09:52:17 +0200
parents 26e34ae9a3e3
children
rev   line source
meillo@0 1 /* MasqMail
meillo@0 2 Copyright (C) 2000 Oliver Kurth
meillo@0 3
meillo@0 4 This program is free software; you can redistribute it and/or modify
meillo@0 5 it under the terms of the GNU General Public License as published by
meillo@0 6 the Free Software Foundation; either version 2 of the License, or
meillo@0 7 (at your option) any later version.
meillo@0 8
meillo@0 9 This program is distributed in the hope that it will be useful,
meillo@0 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@0 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
meillo@0 12 GNU General Public License for more details.
meillo@0 13
meillo@0 14 You should have received a copy of the GNU General Public License
meillo@0 15 along with this program; if not, write to the Free Software
meillo@0 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
meillo@0 17 */
meillo@0 18 #include "masqmail.h"
meillo@0 19
meillo@10 20 header_name header_names[] = {
meillo@15 21 {"From", HEAD_FROM,},
meillo@15 22 {"Sender", HEAD_SENDER,},
meillo@15 23 {"To", HEAD_TO,},
meillo@15 24 {"Cc", HEAD_CC,},
meillo@15 25 {"Bcc", HEAD_BCC,},
meillo@15 26 {"Date", HEAD_DATE,},
meillo@15 27 {"Message-Id", HEAD_MESSAGE_ID,},
meillo@15 28 {"Reply-To", HEAD_REPLY_TO,},
meillo@15 29 {"Subject", HEAD_SUBJECT,},
meillo@15 30 {"Return-Path", HEAD_RETURN_PATH,},
meillo@15 31 {"Envelope-To", HEAD_ENVELOPE_TO,},
meillo@15 32 {"Received", HEAD_RECEIVED},
meillo@0 33 };
meillo@0 34
meillo@0 35 /* this was borrowed from exim and slightly changed */
meillo@10 36 gchar*
meillo@10 37 rec_timestamp()
meillo@0 38 {
meillo@10 39 static gchar buf[64];
meillo@10 40 int len;
meillo@0 41
meillo@10 42 time_t now = time(NULL);
meillo@10 43 struct tm *t = localtime(&now);
meillo@0 44
meillo@10 45 int diff_hour, diff_min;
meillo@10 46 struct tm local;
meillo@10 47 struct tm *gmt;
meillo@0 48
meillo@10 49 memcpy(&local, t, sizeof(struct tm));
meillo@10 50 gmt = gmtime(&now);
meillo@10 51 diff_min = 60 * (local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
meillo@10 52 if (local.tm_year != gmt->tm_year)
meillo@10 53 diff_min += (local.tm_year > gmt->tm_year) ? 1440 : -1440;
meillo@10 54 else if (local.tm_yday != gmt->tm_yday)
meillo@10 55 diff_min += (local.tm_yday > gmt->tm_yday) ? 1440 : -1440;
meillo@10 56 diff_hour = diff_min / 60;
meillo@10 57 diff_min = abs(diff_min - diff_hour * 60);
meillo@0 58
meillo@10 59 len = strftime(buf, sizeof(buf), "%a, ", &local);
meillo@10 60 g_snprintf(buf + len, sizeof(buf) - len, "%02d ", local.tm_mday);
meillo@10 61 len += strlen(buf + len);
meillo@10 62 len += strftime(buf + len, sizeof(buf) - len, "%b %Y %H:%M:%S", &local);
meillo@10 63 g_snprintf(buf + len, sizeof(buf) - len, " %+03d%02d", diff_hour, diff_min);
meillo@10 64
meillo@10 65 return buf;
meillo@0 66 }
meillo@0 67
meillo@0 68 /* finds list of headers matching id
meillo@0 69 if id == HEAD_UNKNOWN and header == NULL finds all unknown headers
meillo@0 70 else finds all headers matching header
meillo@0 71 */
meillo@10 72 GList*
meillo@10 73 find_header(GList * hdr_list, header_id id, gchar * hdr_str)
meillo@0 74 {
meillo@10 75 GList *found_list = NULL;
meillo@10 76 GList *node;
meillo@0 77
meillo@10 78 if ((id != HEAD_UNKNOWN) || (hdr_str == NULL)) {
meillo@10 79 foreach(hdr_list, node) {
meillo@10 80 header *hdr = (header *) (node->data);
meillo@10 81 if (hdr->id == id)
meillo@10 82 found_list = g_list_append(found_list, hdr);
meillo@10 83 }
meillo@10 84 } else {
meillo@10 85 foreach(hdr_list, node) {
meillo@10 86 header *hdr = (header *) (node->data);
meillo@10 87 gchar buf[64], *q = buf, *p = hdr->header;
meillo@10 88
meillo@10 89 while (*p != ':' && q < buf + 63 && *p)
meillo@10 90 *(q++) = *(p++);
meillo@15 91 *q = '\0';
meillo@10 92
meillo@10 93 if (strcasecmp(buf, hdr_str) == 0)
meillo@10 94 found_list = g_list_append(found_list, hdr);
meillo@10 95 }
meillo@10 96 }
meillo@10 97 return found_list;
meillo@0 98 }
meillo@0 99
meillo@10 100 void
meillo@10 101 header_unfold(header * hdr)
meillo@0 102 {
meillo@10 103 gchar *tmp_hdr = g_malloc(strlen(hdr->header));
meillo@10 104 gchar *p = hdr->header, *q = tmp_hdr;
meillo@10 105 gboolean flag = FALSE;
meillo@0 106
meillo@10 107 while (*p) {
meillo@10 108 if (*p != '\n')
meillo@10 109 *(q++) = *p;
meillo@10 110 else
meillo@10 111 flag = TRUE;
meillo@10 112 p++;
meillo@10 113 }
meillo@10 114 *(q++) = '\n';
meillo@0 115
meillo@10 116 if (flag) {
meillo@10 117 gchar *new_hdr;
meillo@0 118
meillo@10 119 g_free(hdr->header);
meillo@10 120 new_hdr = g_strdup(tmp_hdr);
meillo@10 121 g_free(tmp_hdr);
meillo@10 122 hdr->value = new_hdr + (hdr->value - hdr->header);
meillo@10 123 hdr->header = new_hdr;
meillo@10 124 }
meillo@0 125 }
meillo@0 126
meillo@0 127 #define MAX_HDR_LEN 72
meillo@10 128 void
meillo@10 129 header_fold(header * hdr)
meillo@0 130 {
meillo@10 131 gint len = strlen(hdr->header);
meillo@10 132 gchar *p, *q;
meillo@10 133 /* size is probably overestimated, but so we are on the safe side */
meillo@10 134 gchar *tmp_hdr = g_malloc(len + 2 * len / MAX_HDR_LEN);
meillo@0 135
meillo@10 136 p = hdr->header;
meillo@10 137 q = tmp_hdr;
meillo@0 138
meillo@10 139 if (p[len - 1] == '\n')
meillo@15 140 p[len - 1] = '\0';
meillo@0 141
meillo@10 142 while (*p) {
meillo@10 143 gint i, l;
meillo@10 144 gchar *pp;
meillo@0 145
meillo@10 146 /* look forward and find potential break points */
meillo@10 147 i = 0;
meillo@10 148 l = -1;
meillo@10 149 pp = p;
meillo@10 150 while (*pp && (i < MAX_HDR_LEN)) {
meillo@10 151 if ((*pp == ' ') || (*pp == '\t'))
meillo@10 152 l = i;
meillo@10 153 pp++;
meillo@10 154 i++;
meillo@10 155 }
meillo@10 156 if (!*pp)
meillo@10 157 l = pp - p; /* take rest, if EOS found */
meillo@0 158
meillo@10 159 if (l == -1) {
meillo@10 160 /* no potential break point was found within MAX_HDR_LEN so advance further until the next */
meillo@10 161 while (*pp && *pp != ' ' && *pp != '\t') {
meillo@10 162 pp++;
meillo@10 163 i++;
meillo@10 164 }
meillo@10 165 l = i;
meillo@10 166 }
meillo@10 167
meillo@10 168 /* copy */
meillo@10 169 i = 0;
meillo@10 170 while (i < l) {
meillo@10 171 *(q++) = *(p++);
meillo@10 172 i++;
meillo@10 173 }
meillo@10 174 *(q++) = '\n';
meillo@15 175 *(q++) = *(p++); /* this is either space, tab or 0 */
meillo@10 176 }
meillo@10 177 {
meillo@10 178 gchar *new_hdr;
meillo@10 179
meillo@10 180 g_free(hdr->header);
meillo@10 181 new_hdr = g_strdup(tmp_hdr);
meillo@10 182 g_free(tmp_hdr);
meillo@10 183 hdr->value = new_hdr + (hdr->value - hdr->header);
meillo@10 184 hdr->header = new_hdr;
meillo@10 185 }
meillo@0 186 }
meillo@0 187
meillo@10 188 header*
meillo@10 189 create_header(header_id id, gchar * fmt, ...)
meillo@0 190 {
meillo@10 191 gchar *p;
meillo@10 192 header *hdr;
meillo@10 193 va_list args;
meillo@10 194 va_start(args, fmt);
meillo@0 195
meillo@10 196 if ((hdr = g_malloc(sizeof(header)))) {
meillo@0 197
meillo@10 198 hdr->id = id;
meillo@10 199 hdr->header = g_strdup_vprintf(fmt, args);
meillo@10 200 hdr->value = NULL;
meillo@0 201
meillo@10 202 p = hdr->header;
meillo@10 203 while (*p && *p != ':')
meillo@10 204 p++;
meillo@10 205 if (*p)
meillo@10 206 hdr->value = p + 1;
meillo@10 207 }
meillo@0 208
meillo@10 209 va_end(args);
meillo@10 210 return hdr;
meillo@0 211 }
meillo@0 212
meillo@10 213 void
meillo@10 214 destroy_header(header * hdr)
meillo@0 215 {
meillo@10 216 if (hdr) {
meillo@10 217 if (hdr->header)
meillo@10 218 g_free(hdr->header);
meillo@10 219 g_free(hdr);
meillo@10 220 }
meillo@0 221 }
meillo@0 222
meillo@10 223 header*
meillo@10 224 copy_header(header * hdr)
meillo@0 225 {
meillo@10 226 header *new_hdr = NULL;
meillo@0 227
meillo@10 228 if (hdr) {
meillo@10 229 if ((new_hdr = g_malloc(sizeof(header)))) {
meillo@10 230 new_hdr->id = hdr->id;
meillo@10 231 new_hdr->header = g_strdup(hdr->header);
meillo@10 232 new_hdr->value = new_hdr->header + (hdr->value - hdr->header);
meillo@10 233 }
meillo@10 234 }
meillo@10 235 return new_hdr;
meillo@0 236 }
meillo@0 237
meillo@10 238 header*
meillo@10 239 get_header(gchar * line)
meillo@0 240 {
meillo@10 241 gchar *p = line;
meillo@10 242 gchar buf[64], *q = buf;
meillo@10 243 gint i;
meillo@10 244 header *hdr;
meillo@0 245
meillo@10 246 while (*p && (*p != ':') && (q < buf + 63))
meillo@10 247 *(q++) = *(p++);
meillo@15 248 *q = '\0';
meillo@0 249
meillo@10 250 if (*p != ':')
meillo@10 251 return NULL;
meillo@0 252
meillo@10 253 hdr = g_malloc(sizeof(header));
meillo@0 254
meillo@10 255 hdr->value = NULL;
meillo@10 256 p++;
meillo@0 257
meillo@10 258 while (*p && (*p == ' ' || *p == '\t'))
meillo@10 259 p++;
meillo@10 260 hdr->value = p;
meillo@0 261
meillo@10 262 for (i = 0; i < HEAD_NUM_IDS; i++) {
meillo@10 263 if (strcasecmp(header_names[i].header, buf) == 0)
meillo@10 264 break;
meillo@10 265 }
meillo@10 266 hdr->id = (header_id) i;
meillo@10 267 hdr->header = g_strdup(line);
meillo@10 268 hdr->value = hdr->header + (hdr->value - line);
meillo@10 269
meillo@10 270 DEBUG(4) debugf("header: %d = %s", hdr->id, hdr->header);
meillo@10 271
meillo@10 272 return hdr;
meillo@0 273 }