New file. Derived from mh/mh_stream.c
Showing
1 changed file
with
448 additions
and
0 deletions
mailbox/message_stream.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000, 2001, 2002, 2005, | ||
3 | 2006 Free Software Foundation, Inc. | ||
4 | |||
5 | GNU Mailutils 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, or (at your option) | ||
8 | any later version. | ||
9 | |||
10 | GNU Mailutils 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 GNU Mailutils; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
18 | MA 02110-1301 USA */ | ||
19 | |||
20 | /* This file implements an MH draftfile stream: a read-only stream used | ||
21 | to transparently pass MH draftfiles to mailers. The only difference | ||
22 | between the usual RFC822 and MH draft is that the latter allows to use | ||
23 | a string of dashes to separate the headers from the body. */ | ||
24 | |||
25 | #ifdef HAVE_CONFIG_H | ||
26 | # include <config.h> | ||
27 | #endif | ||
28 | #include <stdlib.h> | ||
29 | #include <ctype.h> | ||
30 | #include <string.h> | ||
31 | |||
32 | #include <mailutils/types.h> | ||
33 | #include <mailutils/address.h> | ||
34 | #include <mailutils/envelope.h> | ||
35 | #include <mailutils/message.h> | ||
36 | #include <mailutils/header.h> | ||
37 | #include <mailutils/body.h> | ||
38 | #include <mailutils/stream.h> | ||
39 | #include <mailutils/mutil.h> | ||
40 | #include <mailutils/errno.h> | ||
41 | #include <mailutils/error.h> | ||
42 | |||
43 | struct _mu_rfc822_stream | ||
44 | { | ||
45 | mu_stream_t stream; /* Actual stream */ | ||
46 | size_t mark_offset; /* Offset of the header separator */ | ||
47 | size_t mark_length; /* Length of the header separator (not counting the | ||
48 | newline) */ | ||
49 | }; | ||
50 | |||
51 | static int | ||
52 | _mu_rfc822_read (mu_stream_t stream, char *optr, size_t osize, | ||
53 | mu_off_t offset, size_t *nbytes) | ||
54 | { | ||
55 | struct _mu_rfc822_stream *s = mu_stream_get_owner (stream); | ||
56 | |||
57 | if (offset < s->mark_offset) | ||
58 | { | ||
59 | if (offset + osize >= s->mark_offset) | ||
60 | osize = s->mark_offset - offset; | ||
61 | } | ||
62 | else | ||
63 | offset += s->mark_length; | ||
64 | return mu_stream_read (s->stream, optr, osize, offset, nbytes); | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | _mu_rfc822_readline (mu_stream_t stream, char *optr, size_t osize, | ||
69 | mu_off_t offset, size_t *nbytes) | ||
70 | { | ||
71 | struct _mu_rfc822_stream *s = mu_stream_get_owner (stream); | ||
72 | |||
73 | if (offset < s->mark_offset) | ||
74 | { | ||
75 | if (offset + osize >= s->mark_offset) | ||
76 | { | ||
77 | int rc; | ||
78 | size_t n; | ||
79 | size_t rdsize = s->mark_offset - offset + 1; | ||
80 | |||
81 | rc = mu_stream_readline (s->stream, optr, rdsize, offset, &n); | ||
82 | if (rc == 0) | ||
83 | { | ||
84 | if (nbytes) | ||
85 | *nbytes = n; | ||
86 | } | ||
87 | return rc; | ||
88 | } | ||
89 | } | ||
90 | else | ||
91 | offset += s->mark_length; | ||
92 | |||
93 | return mu_stream_readline (s->stream, optr, osize, offset, nbytes); | ||
94 | } | ||
95 | |||
96 | static int | ||
97 | _mu_rfc822_size (mu_stream_t stream, mu_off_t *psize) | ||
98 | { | ||
99 | struct _mu_rfc822_stream *s = mu_stream_get_owner (stream); | ||
100 | int rc = mu_stream_size (s->stream, psize); | ||
101 | |||
102 | if (rc == 0) | ||
103 | *psize -= s->mark_length; | ||
104 | return rc; | ||
105 | } | ||
106 | |||
107 | static int | ||
108 | _mu_rfc822_open (mu_stream_t stream) | ||
109 | { | ||
110 | struct _mu_rfc822_stream *s = mu_stream_get_owner (stream); | ||
111 | size_t offset, len; | ||
112 | char buffer[256]; | ||
113 | int rc; | ||
114 | |||
115 | offset = 0; | ||
116 | while ((rc = mu_stream_readline (s->stream, buffer, sizeof buffer, | ||
117 | offset, &len)) == 0 | ||
118 | && len > 0) | ||
119 | { | ||
120 | if (mu_mh_delim (buffer)) | ||
121 | { | ||
122 | s->mark_offset = offset; | ||
123 | s->mark_length = len - 1; /* do not count the terminating newline */ | ||
124 | break; | ||
125 | } | ||
126 | |||
127 | offset += len; | ||
128 | } | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static int | ||
133 | _mu_rfc822_close (mu_stream_t stream) | ||
134 | { | ||
135 | struct _mu_rfc822_stream *s = mu_stream_get_owner (stream); | ||
136 | return mu_stream_close (s->stream); | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | _mu_rfc822_destroy (mu_stream_t stream) | ||
141 | { | ||
142 | struct _mu_rfc822_stream *s = mu_stream_get_owner (stream); | ||
143 | if (s->stream) | ||
144 | mu_stream_destroy (&s->stream, mu_stream_get_owner (s->stream)); | ||
145 | free (s); | ||
146 | } | ||
147 | |||
148 | int | ||
149 | mu_rfc822_stream_create (mu_stream_t *stream, mu_stream_t src, int flags) | ||
150 | { | ||
151 | struct _mu_rfc822_stream *s; | ||
152 | int rc; | ||
153 | |||
154 | if (!flags) | ||
155 | flags = MU_STREAM_READ; | ||
156 | if (flags != MU_STREAM_READ) | ||
157 | return EINVAL; | ||
158 | |||
159 | s = calloc (1, sizeof (*s)); | ||
160 | if (s == NULL) | ||
161 | return ENOMEM; | ||
162 | |||
163 | s->stream = src; | ||
164 | |||
165 | rc = mu_stream_create (stream, flags|MU_STREAM_NO_CHECK, s); | ||
166 | if (rc) | ||
167 | { | ||
168 | free (s); | ||
169 | return rc; | ||
170 | } | ||
171 | |||
172 | mu_stream_set_open (*stream, _mu_rfc822_open, s); | ||
173 | mu_stream_set_close (*stream, _mu_rfc822_close, s); | ||
174 | mu_stream_set_destroy (*stream, _mu_rfc822_destroy, s); | ||
175 | mu_stream_set_readline (*stream, _mu_rfc822_readline, s); | ||
176 | mu_stream_set_read (*stream, _mu_rfc822_read, s); | ||
177 | mu_stream_set_size (*stream, _mu_rfc822_size, s); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | |||
183 | |||
184 | /* *************************** MH draft message **************************** */ | ||
185 | |||
186 | static char * | ||
187 | skipws (char *p, size_t off) | ||
188 | { | ||
189 | int len; | ||
190 | for (p += off; *p && isspace (*p); p++) | ||
191 | ; | ||
192 | len = strlen (p); | ||
193 | if (len > 0 && p[len-1] == '\n') | ||
194 | p[len-1] = 0; | ||
195 | return p; | ||
196 | } | ||
197 | |||
198 | struct _mu_rfc822_message | ||
199 | { | ||
200 | char *from; | ||
201 | char *date; | ||
202 | mu_off_t body_start; | ||
203 | mu_off_t body_end; | ||
204 | }; | ||
205 | |||
206 | static int | ||
207 | restore_envelope (mu_stream_t str, struct _mu_rfc822_message **pmenv) | ||
208 | { | ||
209 | size_t offset = 0; | ||
210 | char *from = NULL; | ||
211 | char *env_from = NULL; | ||
212 | char *env_date = NULL; | ||
213 | int rc; | ||
214 | char buffer[128]; | ||
215 | size_t len; | ||
216 | mu_off_t body_start, body_end; | ||
217 | |||
218 | while ((rc = mu_stream_readline (str, buffer, sizeof buffer, offset, &len)) | ||
219 | == 0 | ||
220 | && len > 0) | ||
221 | { | ||
222 | if (buffer[0] == '\n') | ||
223 | break; | ||
224 | buffer[len] = 0; | ||
225 | offset += len; | ||
226 | if (strncasecmp (buffer, MU_HEADER_FROM, | ||
227 | sizeof (MU_HEADER_FROM) - 1) == 0) | ||
228 | from = strdup (skipws (buffer, sizeof (MU_HEADER_FROM))); | ||
229 | else if (strncasecmp (buffer, MU_HEADER_ENV_SENDER, | ||
230 | sizeof (MU_HEADER_ENV_SENDER) - 1) == 0) | ||
231 | env_from = strdup (skipws (buffer, sizeof (MU_HEADER_ENV_SENDER))); | ||
232 | else if (strncasecmp (buffer, MU_HEADER_ENV_DATE, | ||
233 | sizeof (MU_HEADER_ENV_DATE) - 1) == 0) | ||
234 | env_date = strdup (skipws (buffer, sizeof (MU_HEADER_ENV_DATE))); | ||
235 | } | ||
236 | |||
237 | body_start = offset + 1; | ||
238 | mu_stream_size (str, &body_end); | ||
239 | |||
240 | if (!env_from) | ||
241 | { | ||
242 | if (from) | ||
243 | { | ||
244 | mu_address_t addr; | ||
245 | |||
246 | mu_address_create (&addr, from); | ||
247 | if (!addr | ||
248 | || mu_address_aget_email (addr, 1, &env_from)) | ||
249 | env_from = strdup ("GNU Mailutils"); | ||
250 | mu_address_destroy (&addr); | ||
251 | } | ||
252 | else | ||
253 | env_from = strdup ("GNU-MH"); | ||
254 | } | ||
255 | |||
256 | if (!env_date) | ||
257 | { | ||
258 | struct tm *tm; | ||
259 | time_t t; | ||
260 | char date[80]; | ||
261 | |||
262 | time(&t); | ||
263 | tm = gmtime(&t); | ||
264 | strftime (date, sizeof (date), "%a %b %e %H:%M:%S %Y", tm); | ||
265 | env_date = strdup (date); | ||
266 | } | ||
267 | |||
268 | *pmenv = malloc (sizeof (**pmenv) | ||
269 | + strlen (env_from) | ||
270 | + strlen (env_date) | ||
271 | + 2); | ||
272 | if (!*pmenv) | ||
273 | { | ||
274 | free (env_from); | ||
275 | free (env_date); | ||
276 | return ENOMEM; | ||
277 | } | ||
278 | |||
279 | (*pmenv)->from = (char*) (*pmenv + 1); | ||
280 | (*pmenv)->date = (char*) ((*pmenv)->from + strlen (env_from) + 1); | ||
281 | |||
282 | strcpy ((*pmenv)->from, env_from); | ||
283 | strcpy ((*pmenv)->date, env_date); | ||
284 | |||
285 | (*pmenv)->body_start = body_start; | ||
286 | (*pmenv)->body_end = body_end; | ||
287 | |||
288 | free (env_from); | ||
289 | free (env_date); | ||
290 | free (from); | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int | ||
295 | _env_msg_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite) | ||
296 | { | ||
297 | mu_message_t msg = mu_envelope_get_owner (envelope); | ||
298 | struct _mu_rfc822_message *env = mu_message_get_owner (msg); | ||
299 | |||
300 | if (!env || !env->date) | ||
301 | return EINVAL; | ||
302 | if (buf) | ||
303 | { | ||
304 | strncpy (buf, env->date, len); | ||
305 | buf[len-1] = 0; | ||
306 | if (pnwrite) | ||
307 | *pnwrite = len; | ||
308 | } | ||
309 | else if (!pnwrite) | ||
310 | return EINVAL; | ||
311 | else | ||
312 | *pnwrite = strlen (env->date); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int | ||
317 | _env_msg_sender (mu_envelope_t envelope, char *buf, size_t len, | ||
318 | size_t *pnwrite) | ||
319 | { | ||
320 | mu_message_t msg = mu_envelope_get_owner (envelope); | ||
321 | struct _mu_rfc822_message *env = mu_message_get_owner (msg); | ||
322 | |||
323 | if (!env || !env->from) | ||
324 | return EINVAL; | ||
325 | if (buf) | ||
326 | { | ||
327 | strncpy (buf, env->from, len); | ||
328 | buf[len-1] = 0; | ||
329 | if (pnwrite) | ||
330 | *pnwrite = len; | ||
331 | } | ||
332 | else if (!pnwrite) | ||
333 | return EINVAL; | ||
334 | else | ||
335 | *pnwrite = strlen (env->from); | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static int | ||
341 | _body_size (mu_body_t body, size_t *size) | ||
342 | { | ||
343 | mu_message_t msg = mu_body_get_owner (body); | ||
344 | struct _mu_rfc822_message *mp = mu_message_get_owner (msg); | ||
345 | |||
346 | if (size) | ||
347 | *size = mp->body_end - mp->body_start; | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int | ||
352 | _body_read (mu_stream_t stream, char *optr, size_t osize, | ||
353 | mu_off_t offset, size_t *nbytes) | ||
354 | { | ||
355 | mu_body_t body = mu_stream_get_owner (stream); | ||
356 | mu_message_t msg = mu_body_get_owner (body); | ||
357 | struct _mu_rfc822_message *mp = mu_message_get_owner (msg); | ||
358 | mu_stream_t str; | ||
359 | |||
360 | mu_message_get_stream (msg, &str); | ||
361 | return mu_stream_read (str, optr, osize, mp->body_start + offset, nbytes); | ||
362 | } | ||
363 | |||
364 | static int | ||
365 | _body_readline (mu_stream_t stream, char *optr, size_t osize, | ||
366 | mu_off_t offset, size_t *nbytes) | ||
367 | { | ||
368 | mu_body_t body = mu_stream_get_owner (stream); | ||
369 | mu_message_t msg = mu_body_get_owner (body); | ||
370 | struct _mu_rfc822_message *mp = mu_message_get_owner (msg); | ||
371 | mu_stream_t str; | ||
372 | |||
373 | mu_message_get_stream (msg, &str); | ||
374 | return mu_stream_readline (str, optr, osize, | ||
375 | mp->body_start + offset, nbytes); | ||
376 | } | ||
377 | |||
378 | static int | ||
379 | _body_stream_size (mu_stream_t stream, mu_off_t *psize) | ||
380 | { | ||
381 | mu_body_t body = mu_stream_get_owner (stream); | ||
382 | mu_message_t msg = mu_body_get_owner (body); | ||
383 | struct _mu_rfc822_message *mp = mu_message_get_owner (msg); | ||
384 | |||
385 | if (psize) | ||
386 | *psize = mp->body_end - mp->body_start; | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int | ||
391 | _body_stream_flush (mu_stream_t str ARG_UNUSED) | ||
392 | { | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | int | ||
397 | mu_stream_to_message (mu_stream_t instream, mu_message_t *pmsg) | ||
398 | { | ||
399 | struct _mu_rfc822_message *mp; | ||
400 | mu_envelope_t env; | ||
401 | mu_message_t msg; | ||
402 | mu_body_t body; | ||
403 | mu_stream_t bstream; | ||
404 | mu_stream_t draftstream; | ||
405 | int rc; | ||
406 | |||
407 | if ((rc = mu_rfc822_stream_create (&draftstream, instream, 0))) | ||
408 | return rc; | ||
409 | |||
410 | if ((rc = mu_stream_open (draftstream))) | ||
411 | { | ||
412 | mu_stream_destroy (&draftstream, mu_stream_get_owner (draftstream)); | ||
413 | return rc; | ||
414 | } | ||
415 | |||
416 | if ((rc = restore_envelope (draftstream, &mp) | ||
417 | || (rc = mu_message_create (&msg, mp)))) | ||
418 | { | ||
419 | mu_stream_destroy (&draftstream, mu_stream_get_owner (draftstream)); | ||
420 | return rc; | ||
421 | } | ||
422 | |||
423 | mu_message_set_stream (msg, draftstream, mp); | ||
424 | |||
425 | if ((rc = mu_envelope_create (&env, msg))) | ||
426 | { | ||
427 | mu_stream_destroy (&draftstream, mu_stream_get_owner (draftstream)); | ||
428 | return rc; | ||
429 | } | ||
430 | |||
431 | mu_envelope_set_date (env, _env_msg_date, msg); | ||
432 | mu_envelope_set_sender (env, _env_msg_sender, msg); | ||
433 | mu_message_set_envelope (msg, env, mp); | ||
434 | |||
435 | mu_body_create (&body, msg); | ||
436 | mu_stream_create (&bstream, MU_STREAM_RDWR | MU_STREAM_SEEKABLE, body); | ||
437 | |||
438 | mu_stream_set_read (bstream, _body_read, body); | ||
439 | mu_stream_set_readline (bstream, _body_readline, body); | ||
440 | mu_stream_set_size (bstream, _body_stream_size, body); | ||
441 | mu_stream_set_flush (bstream, _body_stream_flush, body); | ||
442 | mu_body_set_stream (body, bstream, msg); | ||
443 | mu_body_set_size (body, _body_size, msg); | ||
444 | mu_message_set_body (msg, body, mp); | ||
445 | |||
446 | *pmsg = msg; | ||
447 | return 0; | ||
448 | } |
-
Please register or sign in to post a comment