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"
20 
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 };
35 
36 /* this was borrowed from exim and slightly changed */
37 gchar*
rec_timestamp()38 rec_timestamp()
39 {
40 	static gchar buf[64];
41 	int len;
42 
43 	time_t now = time(NULL);
44 	struct tm *t = localtime(&now);
45 
46 	int diff_hour, diff_min;
47 	struct tm local;
48 	struct tm *gmt;
49 
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);
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);
66 
67 	return buf;
68 }
69 
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*
find_header(GList * hdr_list,header_id id,gchar * hdr_str)76 find_header(GList *hdr_list, header_id id, gchar *hdr_str)
77 {
78 	GList *found_list = NULL;
79 	GList *node;
80 
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 	}
90 
91 	foreach(hdr_list, node) {
92 		header *hdr = (header *) (node->data);
93 		gchar buf[64], *q = buf, *p = hdr->header;
94 
95 		while (*p != ':' && q < buf+sizeof(buf)-1 && *p) {
96 			*(q++) = *(p++);
97 		}
98 		*q = '\0';
99 
100 		if (strcasecmp(buf, hdr_str) == 0) {
101 			found_list = g_list_append(found_list, hdr);
102 		}
103 	}
104 	return found_list;
105 }
106 
107 void
header_unfold(header * hdr)108 header_unfold(header *hdr)
109 {
110         char *src = hdr->header;
111         char *dest = src;
112         char *p;
113 
114         p = strchr(src, '\n');
115         if (!p || !p[1]) {
116                 /* no folded header */
117                 return;
118         }
119 
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 }
132 
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
header_fold(header * hdr,unsigned int maxlen)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;
146 
147 	if (len <= maxlen) {
148 		/* we don't need to do anything */
149 		return;
150 	}
151 
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);
159 
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;
167 
168 	/* the position in hdr->header where the value part start */
169 	valueoffset = hdr->value - hdr->header;
170 
171 	while (strlen(src) > maxlen) {
172 		char *pp;
173 
174 		for (pp=src+maxlen; pp>src; pp--) {
175 			if (*pp==' ' || *pp=='\t' || *p=='\n') {
176 				break;
177 			}
178 		}
179 
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 		}
192 
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);
204 
205 	if (*(dest-1) != '\n') {
206 		*dest = '\n';
207 		*(dest+1) = '\0';
208 	}
209 
210 	hdr->header = tmp;
211 	hdr->value = hdr->header + valueoffset;
212 }
213 
214 header*
create_header(header_id id,gchar * fmt,...)215 create_header(header_id id, gchar *fmt, ...)
216 {
217 	gchar *p;
218 	header *hdr;
219 	va_list args;
220 	va_start(args, fmt);
221 
222 	/* g_malloc() calls exit on failure */
223 	hdr = g_malloc(sizeof(header));
224 
225 	hdr->id = id;
226 	hdr->header = g_strdup_vprintf(fmt, args);
227 	hdr->value = NULL;
228 
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 	}
241 
242 	DEBUG(3) debugf("create_header():  %s", hdr->header);
243 	/* DEBUG(3) debugf("create_header(): val: `%s'\n", hdr->value); */
244 
245 	va_end(args);
246 	return hdr;
247 }
248 
249 void
destroy_header(header * hdr)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 }
259 
260 header*
copy_header(header * hdr)261 copy_header(header *hdr)
262 {
263 	header *new_hdr = NULL;
264 
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 }
273 
274 header*
get_header(gchar * line)275 get_header(gchar *line)
276 {
277 	gchar *p = line;
278 	gchar buf[64], *q = buf;
279 	gint i;
280 	header *hdr;
281 
282 	while (*p && (*p != ':') && (q < buf+sizeof(buf)-1)) {
283 		*(q++) = *(p++);
284 	}
285 	*q = '\0';
286 
287 	if (*p != ':') {
288 		return NULL;
289 	}
290 
291 	hdr = g_malloc(sizeof(header));
292 
293 	hdr->value = NULL;
294 	p++;
295 
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 	*/
304 
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);
313 
314 	DEBUG(4) debugf("header: %d = %s", hdr->id, hdr->header);
315 	/* Note: This only outputs the first line if the header is folded */
316 
317 	return hdr;
318 }
319