Commit 985d3a58 985d3a580a54ded105a5616ae7ce206ef846fd37 by Alain Magloire

header.c header0.h rfc822.c

collpase everything in header.c
1 parent 920daf3b
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
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 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <header0.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27
28 int
29 header_init (header_t *ph, const char *blurb, size_t len,
30 int flag, void *owner)
31 {
32 if (flag != MU_HEADER_RFC822)
33 return ENOTSUP;
34 return rfc822_init (ph, blurb, len, owner);
35 }
36
37 void
38 header_destroy (header_t *ph, void *owner)
39 {
40 if (ph && *ph)
41 (*ph)->_destroy (ph, owner);
42 }
43
44 /* stub functions */
45 int
46 header_set_value (header_t h, const char *fn, const char *fb, size_t n,
47 int replace)
48 {
49 if (h == NULL || h->_set_value == NULL)
50 return EINVAL;
51 return h->_set_value (h, fn, fb, n, replace);
52 }
53
54 int
55 header_get_value (header_t h, const char *fn, char *fb,
56 size_t len, size_t *n)
57 {
58 if (h == NULL || h->_get_value == NULL )
59 return EINVAL;
60 return h->_get_value (h, fn, fb, len, n);
61 }
62
63 int
64 header_entry_name (header_t h, size_t num, char *buf, size_t len, size_t *n)
65 {
66 if (h == NULL || h->_entry_name == NULL)
67 return EINVAL;
68
69 return h->_entry_name (h, num, buf, len, n);
70 }
71
72 int
73 header_entry_value (header_t h, size_t num, char *buf, size_t len, size_t *n)
74 {
75 if (h == NULL || h->_entry_value == NULL)
76 return EINVAL;
77
78 return h->_entry_value (h, num, buf, len, n);
79 }
80
81 int
82 header_entry_count (header_t h, size_t *num)
83 {
84 if (h == NULL || h->_entry_count)
85 return EINVAL;
86 return h->_entry_count (h, num);
87 }
88
89 int
90 header_get_istream (header_t h, istream_t *pis)
91 {
92 if (h == NULL || pis == NULL || h->_get_istream == NULL)
93 return EINVAL;
94 return h->_get_istream (h, pis);
95 }
96
97 int
98 header_get_ostream (header_t h, ostream_t *pos)
99 {
100 if (h == NULL || pos == NULL || h->_get_ostream == NULL)
101 return EINVAL;
102 return h->_get_ostream (h, pos);
103 }
...@@ -33,8 +33,6 @@ ...@@ -33,8 +33,6 @@
33 extern "C" { 33 extern "C" {
34 #endif 34 #endif
35 35
36 #define MU_HEADER_RFC822 0
37
38 #define MU_HEADER_UNIX_FROM "From " 36 #define MU_HEADER_UNIX_FROM "From "
39 #define MU_HEADER_RETURN_PATH "Return-Path" 37 #define MU_HEADER_RETURN_PATH "Return-Path"
40 #define MU_HEADER_RECEIVED "Received" 38 #define MU_HEADER_RECEIVED "Received"
...@@ -69,7 +67,7 @@ struct _header; ...@@ -69,7 +67,7 @@ struct _header;
69 typedef struct _header * header_t; 67 typedef struct _header * header_t;
70 68
71 extern int header_init __P ((header_t *, const char *blurb, 69 extern int header_init __P ((header_t *, const char *blurb,
72 size_t ln, int flag, void *owner)); 70 size_t ln, void *owner));
73 extern void header_destroy __P ((header_t *, void *owner)); 71 extern void header_destroy __P ((header_t *, void *owner));
74 72
75 extern int header_set_value __P ((header_t, const char *fn, 73 extern int header_set_value __P ((header_t, const char *fn,
......
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
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.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #ifndef _HEADER0_H
19 #define _HEADER0_H
20
21 #include <sys/types.h>
22 #include <header.h>
23 #include <io0.h>
24
25 #ifndef __P
26 #ifdef __STDC__
27 #define __P(args) args
28 #else
29 #define __P(args) ()
30 #endif
31 #endif /*__P */
32
33 #ifdef _cpluscplus
34 extern "C" {
35 #endif
36
37 struct _hdr
38 {
39 char *fn;
40 char *fn_end;
41 char *fv;
42 char *fv_end;
43 };
44 typedef struct _hdr *hdr_t;
45
46 struct _header
47 {
48 size_t num;
49 /* Data */
50 void *data;
51 /* streams */
52 istream_t is;
53 ostream_t os;
54
55 /* owner ? */
56 void *owner;
57 int ref_count;
58
59 /* Functions */
60 int (*_init) __P ((header_t *, const char *, size_t, void *owner));
61 void (*_destroy) __P ((header_t *, void *owner));
62 int (*_set_value) __P ((header_t, const char *fn, const char *fv,
63 size_t n, int replace));
64 int (*_get_value) __P ((header_t, const char *fn, char *fv,
65 size_t len, size_t *n));
66 int (*_entry_count) __P ((header_t, size_t *));
67 int (*_entry_name) __P ((header_t, size_t num, char *buf,
68 size_t buflen, size_t *nwritten));
69 int (*_entry_value) __P ((header_t, size_t num, char *buf,
70 size_t buflen, size_t *nwritten));
71 int (*_get_istream) __P ((header_t h, istream_t *is));
72 int (*_get_ostream) __P ((header_t h, ostream_t *os));
73 int (*_parse) __P ((header_t, const char *blurb, size_t len));
74 };
75
76 /* rfc822 */
77 extern int rfc822_init __P ((header_t *ph, const char *blurb,
78 size_t len, void *owner));
79 extern void rfc822_destroy __P ((header_t *ph, void *owner));
80
81 #ifdef _cpluscplus
82 }
83 #endif
84
85 #endif /* HEADER0_H */
...@@ -1318,8 +1318,7 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg) ...@@ -1318,8 +1318,7 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
1318 } 1318 }
1319 1319
1320 /* set the header */ 1320 /* set the header */
1321 if ((status = header_init (&header, pbuf, 1321 if ((status = header_init (&header, pbuf, offset, mum)) != 0 ||
1322 offset, MU_HEADER_RFC822, mum)) != 0 ||
1323 (status = message_set_header (msg, header, mum)) != 0) 1322 (status = message_set_header (msg, header, mum)) != 0)
1324 { 1323 {
1325 free (pbuf); 1324 free (pbuf);
......
...@@ -74,7 +74,7 @@ int message_clone (message_t omsg, message_t *pmsg) ...@@ -74,7 +74,7 @@ int message_clone (message_t omsg, message_t *pmsg)
74 } while (nread > 0); 74 } while (nread > 0);
75 75
76 76
77 status = header_init (&header, pbuf, offset, MU_HEADER_RFC822, NULL); 77 status = header_init (&header, pbuf, offset, NULL);
78 if (status != 0) 78 if (status != 0)
79 { 79 {
80 free (pbuf); 80 free (pbuf);
......
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
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 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <header0.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27
28 static int rfc822_parse (header_t h, const char *blurb, size_t len);
29 static int rfc822_set_value (header_t h, const char *fn, const char *fb,
30 size_t n, int replace);
31 static int rfc822_get_value (header_t h, const char *fn, char *fb,
32 size_t len, size_t *n);
33 static int rfc822_entry_count (header_t, size_t *num);
34 static int rfc822_entry_name (header_t h, size_t num, char *buf,
35 size_t buflen, size_t *total);
36 static int rfc822_entry_value (header_t h, size_t num, char *buf,
37 size_t buflen, size_t *total);
38 static int rfc822_get_istream (header_t h, istream_t *pis);
39 static int rfc822_get_ostream (header_t h, ostream_t *pos);
40 static int rfc822_read (istream_t is, char *buf, size_t buflen,
41 off_t off, ssize_t *pnread);
42
43 struct _rfc822
44 {
45 char *blurb;
46 size_t blurb_len;
47 size_t hdr_count;
48 struct _hdr *hdr;
49 };
50
51 typedef struct _rfc822 * rfc822_t;
52
53
54 int
55 rfc822_init (header_t *ph, const char *blurb, size_t len, void *owner)
56 {
57 header_t h;
58 int status;
59 h = calloc (1, sizeof (*h));
60 if (h == NULL)
61 return ENOMEM;
62 h->owner = owner;
63 h->_init = rfc822_init;
64 h->_destroy = rfc822_destroy;
65 h->_parse = rfc822_parse;
66 h->_get_value = rfc822_get_value;
67 h->_set_value = rfc822_set_value;
68 h->_entry_count = rfc822_entry_count;
69 h->_entry_name = rfc822_entry_name;
70 h->_entry_value = rfc822_entry_value;
71 h->_get_istream = rfc822_get_istream;
72 h->_get_ostream = rfc822_get_ostream;
73
74 status = h->_parse (h, blurb, len);
75 if (status != 0)
76 free (h);
77 *ph = h;
78 return status;
79 }
80
81 void
82 rfc822_destroy (header_t *ph, void *owner)
83 {
84 if (ph && *ph)
85 {
86 header_t h = *ph;
87
88 /* if destroy is call always decremente */
89 h->ref_count--;
90
91 /* can we destroy ? */
92 if ((h->owner && h->owner == owner) ||
93 (h->owner == NULL && h->ref_count <= 0))
94 {
95 /* io */
96 istream_destroy (&(h->is), owner);
97 ostream_destroy (&(h->os), owner);
98
99 if (h->data)
100 {
101 rfc822_t rfc = (rfc822_t)h->data;
102 free (rfc->hdr);
103 free (rfc->blurb);
104 free (rfc);
105 }
106 free (h);
107 }
108 *ph = NULL;
109 }
110 }
111
112 /*
113 * Parsing is done in a rather simple fashion.
114 * meaning we just consider an entry to be
115 * a field-name an a field-value. So they
116 * maybe duplicate of field-name like "Received"
117 * they are just put in the array, see _get_value()
118 * on how to handle the case.
119 */
120 static int
121 rfc822_parse (header_t h, const char *blurb, size_t len)
122 {
123 rfc822_t rfc;
124 char *header_end;
125 char *header_start;
126 char *header_start2;
127 struct _hdr *hdr;
128
129 if (h == NULL || blurb == NULL || len == 0)
130 return EINVAL;
131
132 rfc = calloc (1, sizeof (*rfc));
133 if (rfc == NULL)
134 return ENOMEM;
135
136 rfc->blurb = calloc (1, len);
137 if (rfc->blurb == NULL)
138 {
139 free (rfc);
140 return ENOMEM;
141 }
142 rfc->blurb_len = len;
143 memcpy (rfc->blurb, blurb, len);
144
145 for (header_start = rfc->blurb;; header_start = ++header_end)
146 {
147 /* get a header, a header is :
148 * field-name ':' ' ' field-value '\r' '\n'
149 * [ (' ' | '\t') field-value '\r' '\n' ]
150 */
151 for (header_start2 = header_start;;header_start2 = ++header_end)
152 {
153 header_end = memchr (header_start2, '\n', len);
154 if (header_end == NULL)
155 break;
156 else
157 {
158 len -= (header_end - header_start2 + 1);
159 if (len == 0)
160 {
161 header_end = NULL;
162 break;
163 }
164 if (header_end[1] != ' '
165 && header_end[1] != '\t')
166 break; /* new header break the inner for */
167 }
168 /* *header_end = ' '; smash LF */
169 }
170
171 if (header_end == NULL)
172 break; /* bail out */
173
174 hdr = realloc (rfc->hdr, (rfc->hdr_count + 1) * sizeof (*hdr));
175 if (hdr == NULL)
176 {
177 free (rfc->blurb);
178 free (rfc->hdr);
179 free (rfc);
180 return ENOMEM;
181 }
182 rfc->hdr = hdr;
183 rfc->hdr_count++;
184 /* Treats unix "From " specially */
185 if ((header_end - header_start >= 5)
186 && strncmp (header_start, "From ", 5) == 0)
187 {
188 rfc->hdr[rfc->hdr_count - 1].fn = header_start;
189 rfc->hdr[rfc->hdr_count - 1].fn_end = header_start + 6;
190 rfc->hdr[rfc->hdr_count - 1].fv = header_start + 6;
191 rfc->hdr[rfc->hdr_count - 1].fv_end = header_end;
192 }
193 else
194 {
195 char *colon = memchr (header_start, ':', header_end - header_start);
196 if (colon == NULL)
197 {
198 /* Houston we have a problem */
199 free (rfc->blurb);
200 free (rfc->hdr);
201 free (rfc);
202 return EINVAL;
203 }
204 rfc->hdr[rfc->hdr_count - 1].fn = header_start;
205 rfc->hdr[rfc->hdr_count - 1].fn_end = colon;
206 /* skip leading spaces */
207 while (*(++colon) == ' ');
208 rfc->hdr[rfc->hdr_count - 1].fv = colon;
209 rfc->hdr[rfc->hdr_count - 1].fv_end = header_end;
210 }
211 }
212 h->data = rfc;
213 return 0;
214 }
215
216 static int
217 rfc822_set_value (header_t h, const char *fn, const char *fv,
218 size_t n, int replace)
219 {
220 (void)h; (void)fn; (void)fv; (void)n; (void)replace;
221 return ENOSYS;
222 }
223
224 static int
225 rfc822_get_value (header_t h, const char *name, char *buffer,
226 size_t buflen, size_t *n)
227 {
228 size_t i = 0;
229 size_t name_len;
230 size_t total = 0, fn_len = 0, fv_len = 0;
231 int threshold;
232 rfc822_t rfc;
233
234 if (h == NULL || name == NULL ||
235 (rfc = (rfc822_t)h->data) == NULL)
236 return EINVAL;
237
238 /* we set the threshold to be 1 less for the null */
239 threshold = --buflen;
240
241 /*
242 * Caution: We may have more then one value for a field
243 * name, for example a "Received" field-name is added by
244 * each passing MTA. The way that the parsing (_parse())
245 * is done it's not take to account. So we just stuff in
246 * the buffer all the field-values to a corresponding field-name.
247 * FIXME: Should we kosher the output ? meaning replace
248 * occurences of " \t\r\n" for spaces ? for now we don't.
249 */
250 for (name_len = strlen (name), i = 0; i < rfc->hdr_count; i++)
251 {
252 fn_len = rfc->hdr[i].fn_end - rfc->hdr[i].fn;
253 if (fn_len == name_len && memcmp (rfc->hdr[i].fn, name, fn_len) == 0)
254 {
255 fv_len = (rfc->hdr[i].fv_end - rfc->hdr[i].fv);
256 total += fv_len;
257 /* can everything fit in the buffer */
258 if (buffer && threshold > 0)
259 {
260 threshold -= fv_len;
261 if (threshold > 0)
262 {
263 memcpy (buffer, rfc->hdr[i].fv, fv_len);
264 buffer += fv_len;
265 }
266 else if (threshold < 0)
267 {
268 threshold += fv_len;
269 memcpy (buffer, rfc->hdr[i].fv, threshold);
270 buffer += threshold;
271 threshold = 0;
272 }
273 }
274 }
275 }
276 if (buffer)
277 *buffer = '\0'; /* null terminated */
278 if (n)
279 *n = total;
280 return 0;
281 }
282
283 static int
284 rfc822_entry_count (header_t h, size_t *num)
285 {
286 rfc822_t rfc;
287 if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
288 return EINVAL;
289 if (num)
290 *num = rfc->hdr_count;
291 return 0;
292 }
293
294 static int
295 rfc822_entry_name (header_t h, size_t num, char *buf,
296 size_t buflen, size_t *nwritten)
297 {
298 rfc822_t rfc;
299 size_t len;
300 if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
301 return EINVAL;
302 if (rfc->hdr_count == 0 || num > rfc->hdr_count)
303 return ENOENT;
304 len = rfc->hdr[num].fn_end - rfc->hdr[num].fn;
305 /* save one for the null */
306 --buflen;
307 if (buf && buflen > 0)
308 {
309 buflen = (len > buflen) ? buflen : len;
310 memcpy (buf, rfc->hdr[num].fn, buflen);
311 buf[buflen] = '\0';
312 }
313 if (nwritten)
314 *nwritten = len;
315 return 0;
316 }
317
318 static int
319 rfc822_entry_value (header_t h, size_t num, char *buf,
320 size_t buflen, size_t *nwritten)
321 {
322 rfc822_t rfc;
323 size_t len;
324 if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
325 return EINVAL;
326 if (rfc->hdr_count == 0 || num > rfc->hdr_count)
327 return ENOENT;
328 len = rfc->hdr[num].fv_end - rfc->hdr[num].fv;
329 /* save one for the null */
330 --buflen;
331 if (buf && buflen > 0)
332 {
333 buflen = (len > buflen) ? buflen : len;
334 memcpy (buf, rfc->hdr[num].fv, buflen);
335 buf[buflen] = '\0';
336 }
337 if (nwritten)
338 *nwritten = len;
339 return 0;
340 }
341
342 static int
343 rfc822_read (istream_t is, char *buf, size_t buflen,
344 off_t off, ssize_t *pnread)
345 {
346 header_t h;
347 rfc822_t rfc = NULL;
348 ssize_t len;
349
350 if (is == NULL || (h = (header_t)is->owner) == NULL ||
351 (rfc = (rfc822_t)h->data) == NULL)
352 return EINVAL;
353
354 len = rfc->blurb_len - off;
355 if ((rfc->blurb_len - off) > 0)
356 {
357 if (buf)
358 {
359 len = (buflen < (size_t)len) ? buflen : len;
360 memcpy (buf, rfc->blurb + off, len);
361 }
362 }
363 else
364 len = 0;
365
366 if (pnread)
367 *pnread = len;
368 return 0;
369 }
370
371 int
372 rfc822_get_istream (header_t h, istream_t *pis)
373 {
374 int err;
375 if (h == NULL || pis == NULL)
376 return EINVAL;
377 /* already done */
378 if (h->is)
379 *pis = h->is;
380
381 err = istream_init (&(h->is), rfc822_read, h->owner);
382 if (err != 0)
383 return err;
384 /* tell the world this is ours */
385 h->is->owner = h;
386 h->is->_read = rfc822_read;
387 *pis = h->is;
388 return 0;
389 }
390
391 int
392 rfc822_get_ostream (header_t h, ostream_t *pos)
393 {
394 if (h == NULL || pos == NULL)
395 return EINVAL;
396 return ENOSYS;
397 }