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