masqmail
view src/header.c @ 323:29de6a1c4538
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:47:27 +0200 |
parents | 3e3c280ca5b2 |
children | 41958685480d |
line source
1 /* MasqMail
2 Copyright (C) 2000 Oliver Kurth
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 #include "masqmail.h"
20 header_name header_names[] = {
21 {"From", HEAD_FROM,},
22 {"Sender", HEAD_SENDER,},
23 {"To", HEAD_TO,},
24 {"Cc", HEAD_CC,},
25 {"Bcc", HEAD_BCC,},
26 {"Date", HEAD_DATE,},
27 {"Message-Id", HEAD_MESSAGE_ID,},
28 {"Reply-To", HEAD_REPLY_TO,},
29 {"Subject", HEAD_SUBJECT,},
30 {"Return-Path", HEAD_RETURN_PATH,},
31 {"Envelope-To", HEAD_ENVELOPE_TO,},
32 {"Received", HEAD_RECEIVED},
33 };
35 /* this was borrowed from exim and slightly changed */
36 gchar*
37 rec_timestamp()
38 {
39 static gchar buf[64];
40 int len;
42 time_t now = time(NULL);
43 struct tm *t = localtime(&now);
45 int diff_hour, diff_min;
46 struct tm local;
47 struct tm *gmt;
49 memcpy(&local, t, sizeof(struct tm));
50 gmt = gmtime(&now);
51 diff_min = 60 * (local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
52 if (local.tm_year != gmt->tm_year) {
53 diff_min += (local.tm_year > gmt->tm_year) ? 1440 : -1440;
54 } else if (local.tm_yday != gmt->tm_yday) {
55 diff_min += (local.tm_yday > gmt->tm_yday) ? 1440 : -1440;
56 }
57 diff_hour = diff_min / 60;
58 diff_min = abs(diff_min - diff_hour * 60);
60 len = strftime(buf, sizeof(buf), "%a, ", &local);
61 g_snprintf(buf + len, sizeof(buf) - len, "%02d ", local.tm_mday);
62 len += strlen(buf + len);
63 len += strftime(buf + len, sizeof(buf) - len, "%b %Y %H:%M:%S", &local);
64 g_snprintf(buf + len, sizeof(buf) - len, " %+03d%02d", diff_hour, diff_min);
66 return buf;
67 }
69 /* finds list of headers matching id
70 if id == HEAD_UNKNOWN and header == NULL finds all unknown headers
71 else finds all headers matching header
72 */
73 GList*
74 find_header(GList * hdr_list, header_id id, gchar * hdr_str)
75 {
76 GList *found_list = NULL;
77 GList *node;
79 if ((id != HEAD_UNKNOWN) || !hdr_str) {
80 foreach(hdr_list, node) {
81 header *hdr = (header *) (node->data);
82 if (hdr->id == id) {
83 found_list = g_list_append(found_list, hdr);
84 }
85 }
86 return found_list;
87 }
89 foreach(hdr_list, node) {
90 header *hdr = (header *) (node->data);
91 gchar buf[64], *q = buf, *p = hdr->header;
93 while (*p != ':' && q < buf+sizeof(buf)-1 && *p) {
94 *(q++) = *(p++);
95 }
96 *q = '\0';
98 if (strcasecmp(buf, hdr_str) == 0) {
99 found_list = g_list_append(found_list, hdr);
100 }
101 }
102 return found_list;
103 }
105 void
106 header_unfold(header * hdr)
107 {
108 char *src = hdr->header;
109 char *dest = src;
110 char *p;
112 p = strchr(src, '\n');
113 if (!p || !p[1]) {
114 /* no folded header */
115 return;
116 }
118 while (*src) {
119 if (*src == '\n') {
120 /* ignore */
121 src++;
122 } else {
123 /* copy */
124 *(dest++) = *(src++);
125 }
126 }
127 *(dest++) = '\n';
128 *(dest++) = '\0';
129 }
131 /*
132 fold the header at maxlen chars (newline excluded)
133 (We exclude the newline because the RFCs deal with it this way)
134 */
135 void
136 header_fold(header* hdr, unsigned int maxlen)
137 {
138 int len = strlen(hdr->header);
139 char* src = hdr->header;
140 char* dest;
141 char* tmp;
142 char* p;
143 int valueoffset;
145 if (len <= maxlen) {
146 /* we don't need to do anything */
147 return;
148 }
150 /* strip trailing whitespace */
151 for (p=src+len-1; *p==' '||*p=='\t'||*p=='\n'; p--) {
152 *p = '\0';
153 len--;
154 printf(" trailing whitespace\n");
155 }
156 printf("stripped len: %d\n", len);
158 /* FIXME: would be nice to have a better size calculation */
159 /* (the current size + what we insert as break, twice as often as
160 we have breaks in the optimal case) */
161 tmp = malloc(len + 2 * (len/maxlen) * strlen("\n\t"));
162 dest = tmp;
164 /* the position in hdr->header where the value part start */
165 valueoffset = hdr->value - hdr->header;
167 while (strlen(src) > maxlen) {
168 int i, l;
169 char *pp;
171 for (pp=src+maxlen; pp>src; pp--) {
172 if (*pp==' ' || *pp=='\t' || *p=='\n') {
173 break;
174 }
175 }
177 if (src == pp) {
178 /* no potential break point was found within
179 maxlen so advance further until the next */
180 for (pp=src+maxlen; *pp; pp++) {
181 if (*pp==' ' || *pp=='\t' || *p=='\n') {
182 break;
183 }
184 }
185 }
186 if (!*pp) {
187 break;
188 }
190 memcpy(dest, src, pp-src);
191 dest += pp-src;
192 *(dest++) = '\n';
193 *(dest++) = '\t';
194 while (*pp == ' ' || *pp == '\t' || *p=='\n') {
195 pp++;
196 }
197 src = pp;
198 }
199 memcpy(dest, src, strlen(src));
200 dest += strlen(src);
202 if (*(dest-1) != '\n') {
203 *dest = '\n';
204 *(dest+1) = '\0';
205 }
207 hdr->header = tmp;
208 hdr->value = hdr->header + valueoffset;
209 }
211 header*
212 create_header(header_id id, gchar * fmt, ...)
213 {
214 gchar *p;
215 header *hdr;
216 va_list args;
217 va_start(args, fmt);
219 /* g_malloc() calls exit on failure */
220 hdr = g_malloc(sizeof(header));
222 hdr->id = id;
223 hdr->header = g_strdup_vprintf(fmt, args);
224 hdr->value = NULL;
226 /* value shall point to the first non-whitespace char in the
227 value part of the header line (i.e. after the first colon) */
228 p = strchr(hdr->header, ':');
229 if (p) {
230 p++;
231 while (*p == ' ' || *p == '\t' || *p == '\n') {
232 p++;
233 }
234 hdr->value = (*p) ? p : NULL;
235 }
237 DEBUG(3) debugf("create_header(): hdr: `%s'\n", hdr->header);
238 DEBUG(3) debugf("create_header(): val: `%s'\n", hdr->value);
240 va_end(args);
241 return hdr;
242 }
244 void
245 destroy_header(header * hdr)
246 {
247 if (hdr) {
248 if (hdr->header) {
249 g_free(hdr->header);
250 }
251 g_free(hdr);
252 }
253 }
255 header*
256 copy_header(header * hdr)
257 {
258 header *new_hdr = NULL;
260 if (hdr) {
261 new_hdr = g_malloc(sizeof(header));
262 new_hdr->id = hdr->id;
263 new_hdr->header = g_strdup(hdr->header);
264 new_hdr->value = new_hdr->header + (hdr->value - hdr->header);
265 }
266 return new_hdr;
267 }
269 header*
270 get_header(gchar * line)
271 {
272 gchar *p = line;
273 gchar buf[64], *q = buf;
274 gint i;
275 header *hdr;
277 while (*p && (*p != ':') && (q < buf+sizeof(buf)-1)) {
278 *(q++) = *(p++);
279 }
280 *q = '\0';
282 if (*p != ':') {
283 return NULL;
284 }
286 hdr = g_malloc(sizeof(header));
288 hdr->value = NULL;
289 p++;
291 while (*p && (*p == ' ' || *p == '\t')) {
292 p++;
293 }
294 hdr->value = p;
295 /* Note: an empty value can also mean that it's only the first part
296 of a folded header line */
298 for (i = 0; i < HEAD_NUM_IDS; i++) {
299 if (strcasecmp(header_names[i].header, buf) == 0) {
300 break;
301 }
302 }
303 hdr->id = (header_id) i;
304 hdr->header = g_strdup(line);
305 hdr->value = hdr->header + (hdr->value - line);
307 DEBUG(4) debugf("header: %d = %s[...]", hdr->id, hdr->header);
308 /* Note: This only outputs the first line if the header is folded */
310 return hdr;
311 }