Commit b703078d b703078dbb367e560ab2940d7991045473fb3a3e by Sergey Poznyakoff

New file. Derived from mh/mh_stream.c

1 parent ca5f00a6
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 }