Commit 28d63fd9 28d63fd9026b85abd7f244d043d41ee6b7434140 by Sergey Poznyakoff

Re-implemented via AMD.

1 parent 5ba7cf41
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2000, 2001, 2002, 2003,
3 2004 Free Software Foundation, Inc.
3 4
4 This library is free software; you can redistribute it and/or 5 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public 6 modify it under the terms of the GNU Lesser General Public
...@@ -61,951 +62,65 @@ ...@@ -61,951 +62,65 @@
61 #include <mailutils/observer.h> 62 #include <mailutils/observer.h>
62 #include <mailbox0.h> 63 #include <mailbox0.h>
63 #include <registrar0.h> 64 #include <registrar0.h>
65 #include <amd.h>
64 66
65 #define MAX_OPEN_STREAMS 16 67 struct _mh_message
66 68 {
67 /* Notifications ADD_MESG. */ 69 struct _amd_message amd_message;
68 #define DISPATCH_ADD_MSG(mbox,mhd) \ 70 size_t seq_number; /* message sequence number */
69 do \ 71 };
70 { \
71 int bailing = 0; \
72 monitor_unlock (mbox->monitor); \
73 if (mbox->observable) \
74 bailing = observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD); \
75 if (bailing != 0) \
76 { \
77 if (pcount) \
78 *pcount = (mhd)->msg_count; \
79 locker_unlock (mbox->locker); \
80 return EINTR; \
81 } \
82 monitor_wrlock (mbox->monitor); \
83 } while (0);
84
85 /* Note: In this particular implementation the message sequence number
86 serves also as its UID. This allows to avoid many problems related
87 to keeping the uids in the headers of the messages. */
88
89 struct _mh_data;
90 struct _mh_message
91 {
92 struct _mh_message *next;
93 struct _mh_message *prev;
94
95 stream_t stream; /* Associated file stream */
96 off_t body_start; /* Offset of body start in the message file */
97 off_t body_end; /* Offset of body end (size of file, effectively)*/
98
99 size_t seq_number; /* message sequence number */
100
101 int attr_flags; /* Attribute flags */
102 int deleted; /* Was the message originally deleted */
103
104 time_t mtime; /* Time of last modification */
105 size_t header_lines; /* Number of lines in the header part */
106 size_t body_lines; /* Number of lines in the body */
107
108 message_t message; /* Corresponding message_t */
109 struct _mh_data *mhd; /* Back pointer. */
110 };
111
112 struct _mh_data
113 {
114 /* List of messages: */
115 size_t msg_count; /* number of messages in the list */
116 struct _mh_message *msg_head; /* First */
117 struct _mh_message *msg_tail; /* Last */
118
119 unsigned long uidvalidity;
120
121 char *name; /* Directory name */
122
123 /* Pool of open message streams */
124 struct _mh_message *msg_pool[MAX_OPEN_STREAMS];
125 int pool_first; /* Index to the first used entry in msg_pool */
126 int pool_last; /* Index to the first free entry in msg_pool */
127
128 time_t mtime; /* Time of last modification */
129
130 mailbox_t mailbox; /* Back pointer. */
131 };
132
133 static void mh_destroy __P((mailbox_t mailbox));
134 static int mh_open __P ((mailbox_t, int));
135 static int mh_close __P ((mailbox_t));
136 static int mh_get_message __P ((mailbox_t, size_t, message_t *));
137 static int mh_append_message __P ((mailbox_t, message_t));
138 static int mh_messages_count __P ((mailbox_t, size_t *));
139 static int mh_messages_recent __P ((mailbox_t, size_t *));
140 static int mh_message_unseen __P ((mailbox_t, size_t *));
141 static int mh_expunge __P ((mailbox_t));
142 static int mh_save_attributes __P ((mailbox_t));
143 static int mh_uidvalidity __P ((mailbox_t, unsigned long *));
144 static int mh_uidnext __P ((mailbox_t, size_t *));
145 static int mh_scan __P ((mailbox_t, size_t, size_t *));
146 static int mh_scan0 __P ((mailbox_t mailbox, size_t msgno, size_t *pcount,
147 int do_notify));
148 static int mh_is_updated __P ((mailbox_t));
149 static int mh_get_size __P ((mailbox_t, off_t *));
150
151 static int mh_body_read __P ((stream_t, char *, size_t, off_t, size_t *));
152 static int mh_body_readline __P ((stream_t, char *, size_t, off_t, size_t *));
153 static int mh_stream_size __P ((stream_t stream, off_t *psize));
154
155 static int mh_body_size __P ((body_t body, size_t *psize));
156 static int mh_body_lines __P ((body_t body, size_t *plines));
157
158 static int mh_message_uid __P ((message_t msg, size_t *puid));
159
160 static int mh_message_stream_open __P((struct _mh_message *mhm));
161 static void mh_message_stream_close __P((struct _mh_message *mhm));
162
163 static int mh_header_fill __P((header_t header, char *buffer, size_t len,
164 off_t off, size_t *pnread));
165 static int mh_header_size __P((header_t header, size_t *psize));
166 static int mh_header_lines __P((header_t header, size_t *plines));
167
168 static int mh_get_attr_flags __P((attribute_t attr, int *pflags));
169 static int mh_set_attr_flags __P((attribute_t attr, int flags));
170 static int mh_unset_attr_flags __P((attribute_t attr, int flags));
171
172 static void _mh_message_insert __P((struct _mh_data *mhd,
173 struct _mh_message *msg));
174 static void _mh_message_delete __P((struct _mh_data *mhd,
175 struct _mh_message *msg));
176 static int mh_pool_open __P((struct _mh_message *mhm));
177 static int mh_pool_open_count __P((struct _mh_data *mhd));
178 static struct _mh_message **mh_pool_lookup __P((struct _mh_message *mhm));
179
180 static int mh_envelope_date __P((envelope_t envelope, char *buf, size_t len,
181 size_t *psize));
182 static int mh_envelope_sender __P((envelope_t envelope, char *buf, size_t len,
183 size_t *psize));
184
185 /* Should be in other header file. */
186 extern int mh_message_number __P ((message_t msg, size_t *pnum));
187
188 /* Return filename for the message.
189 NOTE: Allocates memory. */
190 static char *
191 _mh_message_name (struct _mh_message *mhm, int deleted)
192 {
193 char *filename;
194 size_t len = strlen (mhm->mhd->name) + 32;
195 filename = malloc (len);
196 if (deleted)
197 snprintf (filename, len, "%s/,%lu", mhm->mhd->name,
198 (unsigned long) mhm->seq_number);
199 else
200 snprintf (filename, len, "%s/%lu", mhm->mhd->name,
201 (unsigned long) mhm->seq_number);
202 return filename;
203 }
204
205 int
206 _mailbox_mh_init (mailbox_t mailbox)
207 {
208 struct _mh_data *mhd;
209 size_t name_len;
210
211 if (mailbox == NULL)
212 return EINVAL;
213
214 mhd = mailbox->data = calloc (1, sizeof (*mhd));
215 if (mailbox->data == NULL)
216 return ENOMEM;
217
218 /* Back pointer. */
219 mhd->mailbox = mailbox;
220
221 url_get_path (mailbox->url, NULL, 0, &name_len);
222 mhd->name = calloc (name_len + 1, sizeof (char));
223 if (mhd->name == NULL)
224 {
225 free (mhd);
226 mailbox->data = NULL;
227 return ENOMEM;
228 }
229 url_get_path (mailbox->url, mhd->name, name_len + 1, NULL);
230
231 /* Overloading the defaults. */
232 mailbox->_destroy = mh_destroy;
233
234 mailbox->_open = mh_open;
235 mailbox->_close = mh_close;
236
237 /* Overloading of the entire mailbox object methods. */
238 mailbox->_get_message = mh_get_message;
239 mailbox->_append_message = mh_append_message;
240 mailbox->_messages_count = mh_messages_count;
241 mailbox->_messages_recent = mh_messages_recent;
242 mailbox->_message_unseen = mh_message_unseen;
243 mailbox->_expunge = mh_expunge;
244 mailbox->_save_attributes = mh_save_attributes;
245 mailbox->_uidvalidity = mh_uidvalidity;
246 mailbox->_uidnext = mh_uidnext;
247
248 mailbox->_scan = mh_scan;
249 mailbox->_is_updated = mh_is_updated;
250
251 mailbox->_get_size = mh_get_size;
252
253 /* Set our properties. */
254 {
255 property_t property = NULL;
256 mailbox_get_property (mailbox, &property);
257 property_set_value (property, "TYPE", "MH", 1);
258 }
259
260 MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mh_init(%s)\n", mhd->name);
261 return 0;
262 }
263
264 static void
265 mh_destroy (mailbox_t mailbox)
266 {
267 struct _mh_data *mhd = mailbox->data;
268 struct _mh_message *msg, *next;
269
270 if (!mhd)
271 return;
272
273 monitor_wrlock (mailbox->monitor);
274 msg = mhd->msg_head;
275 while (msg)
276 {
277 next = msg->next;
278 message_destroy (&msg->message, msg);
279 free (msg);
280 msg = next;
281 }
282
283 if (mhd->name)
284 free (mhd->name);
285
286 free (mhd);
287 mailbox->data = NULL;
288 monitor_unlock (mailbox->monitor);
289 }
290
291 static int
292 mh_open (mailbox_t mailbox, int flags)
293 {
294 struct _mh_data *mhd = mailbox->data;
295 int status = 0;
296 struct stat st;
297
298 mailbox->flags = flags;
299 if (stat (mhd->name, &st) < 0)
300 return errno;
301
302 if (!S_ISDIR (st.st_mode))
303 return EINVAL;
304
305 mhd->mtime = st.st_mtime;
306
307 /* FIXME: is this the right kind of locking for mh folders? */
308 if (mailbox->locker == NULL)
309 status = locker_create (&mailbox->locker, mhd->name, 0);
310 return 0;
311 }
312
313 static int
314 mh_close (mailbox_t mailbox)
315 {
316 if (!mailbox)
317 return EINVAL;
318 return locker_unlock (mailbox->locker);
319 }
320
321 static struct _mh_message *
322 _mh_get_message (struct _mh_data *mhd, size_t msgno)
323 {
324 size_t n;
325 struct _mh_message *msg;
326
327 for (n = 1, msg = mhd->msg_head; msg && n < msgno; n++, msg = msg->next)
328 ;
329
330 return msg;
331 }
332
333 /* Find the message with the given sequence number */
334 static struct _mh_message *
335 _mh_get_message_seq (struct _mh_data *mhd, size_t seq)
336 {
337 struct _mh_message *msg;
338
339 for (msg = mhd->msg_head; msg && msg->seq_number < seq; msg = msg->next)
340 ;
341
342 if (msg)
343 return msg->seq_number == seq ? msg : NULL;
344 return NULL;
345 }
346
347 static int
348 _mh_attach_message (mailbox_t mailbox, struct _mh_message *mhm,
349 message_t *pmsg)
350 {
351 int status;
352 message_t msg;
353
354 /* Check if we already have it. */
355 if (mhm->message)
356 {
357 if (pmsg)
358 *pmsg = mhm->message;
359 return 0;
360 }
361
362 /* Get an empty message struct. */
363 status = message_create (&msg, mhm);
364 if (status != 0)
365 return status;
366
367 /* Set the header. */
368 {
369 header_t header = NULL;
370 status = header_create (&header, NULL, 0, msg);
371 if (status != 0)
372 {
373 message_destroy (&msg, mhm);
374 return status;
375 }
376 header_set_fill (header, mh_header_fill, msg);
377 header_set_size (header, mh_header_size, msg);
378 header_set_lines (header, mh_header_lines, msg);
379 /*FIXME:
380 header_set_get_fvalue (header, mh_header_get_fvalue, msg);
381 */
382 message_set_header (msg, header, mhm);
383 }
384
385 /* Set the attribute. */
386 {
387 attribute_t attribute;
388 status = attribute_create (&attribute, msg);
389 if (status != 0)
390 {
391 message_destroy (&msg, mhm);
392 return status;
393 }
394 attribute_set_get_flags (attribute, mh_get_attr_flags, msg);
395 attribute_set_set_flags (attribute, mh_set_attr_flags, msg);
396 attribute_set_unset_flags (attribute, mh_unset_attr_flags, msg);
397 message_set_attribute (msg, attribute, mhm);
398 }
399
400 /* Prepare the body. */
401 {
402 body_t body = NULL;
403 stream_t stream = NULL;
404 if ((status = body_create (&body, msg)) != 0
405 || (status = stream_create (&stream,
406 mailbox->flags | MU_STREAM_SEEKABLE,
407 body)) != 0)
408 {
409 body_destroy (&body, msg);
410 stream_destroy (&stream, body);
411 message_destroy (&msg, mhm);
412 return status;
413 }
414 stream_set_read (stream, mh_body_read, body);
415 stream_set_readline (stream, mh_body_readline, body);
416 stream_set_size (stream, mh_stream_size, body);
417 body_set_stream (body, stream, msg);
418 body_set_size (body, mh_body_size, msg);
419 body_set_lines (body, mh_body_lines, msg);
420 message_set_body (msg, body, mhm);
421 }
422
423 /* Set the envelope. */
424 {
425 envelope_t envelope = NULL;
426 status = envelope_create (&envelope, msg);
427 if (status != 0)
428 {
429 message_destroy (&msg, mhm);
430 return status;
431 }
432 envelope_set_sender (envelope, mh_envelope_sender, msg);
433 envelope_set_date (envelope, mh_envelope_date, msg);
434 message_set_envelope (msg, envelope, mhm);
435 }
436
437 /* Set the UID. */
438 message_set_uid (msg, mh_message_uid, mhm);
439
440 /* Attach the message to the mailbox mbox data. */
441 mhm->message = msg;
442 message_set_mailbox (msg, mailbox, mhm);
443
444 if (pmsg)
445 *pmsg = msg;
446
447 return 0;
448 }
449
450 static int
451 mh_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
452 {
453 int status;
454 struct _mh_data *mhd = mailbox->data;
455 struct _mh_message *mhm;
456
457 /* Sanity checks. */
458 if (pmsg == NULL || mhd == NULL)
459 return EINVAL;
460
461 /* If we did not start a scanning yet do it now. */
462 if (mhd->msg_count == 0)
463 {
464 status = mh_scan0 (mailbox, 1, NULL, 0);
465 if (status != 0)
466 return status;
467 }
468
469 if ((mhm = _mh_get_message (mhd, msgno)) == NULL)
470 return EINVAL;
471 return _mh_attach_message (mailbox, mhm, pmsg);
472 }
473
474 static size_t
475 _mh_next_seq (struct _mh_data *mhd)
476 {
477 return (mhd->msg_tail ? mhd->msg_tail->seq_number : 0) + 1;
478 }
479
480 static FILE *
481 _mh_tempfile(struct _mh_data *mhd, char **namep)
482 {
483 int fd = mu_tempfile (mhd->name, namep);
484 if (fd == -1)
485 return NULL;
486 return fdopen (fd, "w");
487 }
488
489 static int
490 _mh_delim (char *str)
491 {
492 if (str[0] == '-')
493 {
494 for (; *str == '-'; str++)
495 ;
496 for (; *str == ' ' || *str == '\t'; str++)
497 ;
498 }
499 return str[0] == '\n';
500 }
501
502 static int
503 _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
504 {
505 stream_t stream = NULL;
506 char *name = NULL, *buf = NULL, *msg_name;
507 size_t n, off = 0;
508 size_t bsize;
509 size_t nlines, nbytes;
510 size_t new_body_start, new_header_lines;
511 FILE *fp;
512 message_t msg = mhm->message;
513 header_t hdr;
514 int status;
515 attribute_t attr;
516 body_t body;
517 char buffer[512];
518 envelope_t env = NULL;
519
520 fp = _mh_tempfile (mhm->mhd, &name);
521 if (!fp)
522 return errno;
523
524 message_size (msg, &bsize);
525
526 /* Try to allocate large buffer */
527 for (; bsize > 1; bsize /= 2)
528 if ((buf = malloc (bsize)))
529 break;
530
531 if (!bsize)
532 return ENOMEM;
533
534 /* Copy flags */
535 message_get_header (msg, &hdr);
536 header_get_stream (hdr, &stream);
537 off = 0;
538 nlines = nbytes = 0;
539 while ((status = stream_readline (stream, buf, bsize, off, &n)) == 0
540 && n != 0)
541 {
542 if (_mh_delim(buf))
543 break;
544
545 if (!(strncasecmp (buf, "status:", 7) == 0
546 || strncasecmp (buf, "x-imapbase:", 11) == 0
547 || strncasecmp (buf, "x-uid:", 6) == 0
548 || strncasecmp (buf, MU_HEADER_ENV_DATE ":", sizeof (MU_HEADER_ENV_DATE)) == 0
549 || strncasecmp (buf, MU_HEADER_ENV_SENDER ":", sizeof (MU_HEADER_ENV_SENDER)) == 0))
550 {
551 nlines++;
552 nbytes += fprintf (fp, "%s", buf);
553 }
554
555 off += n;
556 }
557
558 /* Add imapbase */
559 if (!mhd->msg_head || (mhd->msg_head == mhm)) /*FIXME*/
560 {
561 nbytes += fprintf (fp, "X-IMAPbase: %lu %u\n",
562 (unsigned long) mhd->uidvalidity,
563 (unsigned) _mh_next_seq(mhd));
564 nlines++;
565 }
566
567 message_get_envelope (msg, &env);
568 if (envelope_date (env, buffer, sizeof buffer, &n) == 0 && n > 0)
569 {
570 /* NOTE: buffer is terminated with \n */
571 char *p = buffer;
572 while (isspace (*p))
573 p++;
574 nbytes += fprintf (fp, "%s: %s", MU_HEADER_ENV_DATE, p);
575
576 if (*p && p[strlen (p) - 1] != '\n')
577 nbytes += fprintf (fp, "\n");
578
579 nlines++;
580 }
581
582 if (envelope_sender (env, buffer, sizeof buffer, &n) == 0 && n > 0)
583 {
584 fprintf (fp, "%s: %s\n", MU_HEADER_ENV_SENDER, buffer);
585 nlines++;
586 }
587
588 /* Add status */
589 message_get_attribute (msg, &attr);
590 attribute_to_string (attr, buf, bsize, &n);
591 if (n)
592 {
593 nbytes += fprintf (fp, "%s", buf);
594 nlines++;
595 }
596 nbytes += fprintf (fp, "\n");
597 nlines++;
598
599 new_header_lines = nlines;
600 new_body_start = nbytes;
601
602 /* Copy message body */
603
604 message_get_body (msg, &body);
605 body_get_stream (body, &stream);
606 off = 0;
607 nlines = 0;
608 while (stream_read (stream, buf, bsize, off, &n) == 0 && n != 0)
609 {
610 char *p;
611 for (p = buf; p < buf + n; p++)
612 if (*p == '\n')
613 nlines++;
614 fwrite (buf, 1, n, fp);
615 off += n;
616 nbytes += n;
617 }
618
619 mhm->header_lines = new_header_lines;
620 mhm->body_start = new_body_start;
621 mhm->body_lines = nlines;
622 mhm->body_end = nbytes;
623
624 free (buf);
625 fclose (fp);
626
627 msg_name = _mh_message_name (mhm, mhm->deleted);
628 rename (name, msg_name);
629 free (name);
630 free (msg_name);
631
632 return 0;
633 }
634
635 static int
636 mh_append_message (mailbox_t mailbox, message_t msg)
637 {
638 int status;
639 struct _mh_data *mhd = mailbox->data;
640 struct _mh_message *mhm;
641
642 if (!mailbox || !msg)
643 return EINVAL;
644
645 mhm = calloc (1, sizeof(*mhm));
646 if (!mhm)
647 return ENOMEM;
648
649 /* If we did not start a scanning yet do it now. */
650 if (mhd->msg_count == 0)
651 {
652 status = mh_scan0 (mailbox, 1, NULL, 0);
653 if (status != 0)
654 return status;
655 }
656
657 mhm->mhd = mhd;
658 mhm->seq_number = _mh_next_seq (mhd);
659 mhm->message = msg;
660 status = _mh_message_save (mhd, mhm, 0);
661 mhm->message = NULL;
662 /* Insert and re-scan the message */
663 _mh_message_insert (mhd, mhm);
664 return status;
665 }
666
667 static int
668 mh_messages_count (mailbox_t mailbox, size_t *pcount)
669 {
670 struct _mh_data *mhd = mailbox->data;
671
672 if (mhd == NULL)
673 return EINVAL;
674
675 if (!mh_is_updated (mailbox))
676 return mh_scan0 (mailbox, mhd->msg_count, pcount, 0);
677
678 if (pcount)
679 *pcount = mhd->msg_count;
680
681 return 0;
682 }
683
684 /* A "recent" message is the one not marked with MU_ATTRIBUTE_SEEN
685 ('O' in the Status header), i.e. a message that is first seen
686 by the current session (see attributes.h) */
687 static int
688 mh_messages_recent (mailbox_t mailbox, size_t *pcount)
689 {
690 struct _mh_data *mhd = mailbox->data;
691 struct _mh_message *mhm;
692 size_t count;
693
694 /* If we did not start a scanning yet do it now. */
695 if (mhd->msg_count == 0)
696 {
697 int status = mh_scan0 (mailbox, 1, NULL, 0);
698 if (status != 0)
699 return status;
700 }
701 count = 0;
702 for (mhm = mhd->msg_head; mhm; mhm = mhm->next)
703 {
704 if (MU_ATTRIBUTE_IS_UNSEEN(mhm->attr_flags))
705 count++;
706 }
707 *pcount = count;
708 return 0;
709 }
710
711 /* An "unseen" message is the one that has not been read yet */
712 static int
713 mh_message_unseen (mailbox_t mailbox, size_t *pmsgno)
714 {
715 struct _mh_data *mhd = mailbox->data;
716 struct _mh_message *mhm;
717 size_t i, unseen;
718
719 /* If we did not start a scanning yet do it now. */
720 if (mhd->msg_count == 0)
721 {
722 int status = mh_scan0 (mailbox, 1, NULL, 0);
723 if (status != 0)
724 return status;
725 }
726 for (unseen = i = 1, mhm = mhd->msg_head; mhm; i++, mhm = mhm->next)
727 {
728 if (MU_ATTRIBUTE_IS_UNREAD(mhm->attr_flags))
729 {
730 unseen = i;
731 break;
732 }
733 }
734 *pmsgno = unseen;
735 return 0;
736 }
737
738 static int
739 mh_expunge (mailbox_t mailbox)
740 {
741 struct _mh_data *mhd = mailbox->data;
742 struct _mh_message *mhm;
743
744 if (mhd == NULL)
745 return EINVAL;
746
747 if (mhd->msg_count == 0)
748 return 0;
749
750 /* Find the first dirty(modified) message. */
751 for (mhm = mhd->msg_head; mhm; mhm = mhm->next)
752 {
753 if ((mhm->attr_flags & MU_ATTRIBUTE_MODIFIED) ||
754 (mhm->attr_flags & MU_ATTRIBUTE_DELETED) ||
755 (mhm->message && message_is_modified (mhm->message)))
756 break;
757 }
758
759 if (!mhm)
760 return 0; /* Nothing changed, just return. */
761
762 while (mhm)
763 {
764 struct _mh_message *next = mhm->next;
765
766 if (mhm->attr_flags & MU_ATTRIBUTE_DELETED)
767 {
768 if (!mhm->deleted)
769 {
770 char *old_name, *new_name;
771 /* Rename original message */
772 old_name = _mh_message_name (mhm, 0);
773 new_name = _mh_message_name (mhm, 1);
774 rename (old_name, new_name);
775 free (old_name);
776 free (new_name);
777 }
778 _mh_message_delete (mhd, mhm);
779 }
780 else if ((mhm->attr_flags & MU_ATTRIBUTE_MODIFIED)
781 || (mhm->message && message_is_modified (mhm->message)))
782 {
783 _mh_attach_message (mailbox, mhm, NULL);
784 mhm->deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED;
785 _mh_message_save (mhd, mhm, 1);
786 }
787 mhm = next;
788 }
789
790 return 0;
791 }
792
793 static int
794 mh_save_attributes (mailbox_t mailbox)
795 {
796 struct _mh_data *mhd = mailbox->data;
797 struct _mh_message *mhm;
798
799 if (mhd == NULL)
800 return EINVAL;
801
802 if (mhd->msg_count == 0)
803 return 0;
804
805 /* Find the first dirty(modified) message. */
806 for (mhm = mhd->msg_head; mhm; mhm = mhm->next)
807 {
808 if ((mhm->attr_flags & MU_ATTRIBUTE_MODIFIED)
809 || (mhm->message && message_is_modified (mhm->message)))
810 break;
811 }
812
813 if (!mhm)
814 return 0; /* Nothing changed, just return. */
815
816 while (mhm)
817 {
818 struct _mh_message *next = mhm->next;
819
820 if ((mhm->attr_flags & MU_ATTRIBUTE_MODIFIED)
821 || (mhm->message && message_is_modified (mhm->message)))
822 {
823 _mh_attach_message (mailbox, mhm, NULL);
824 mhm->deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED;
825 _mh_message_save (mhd, mhm, 0);
826 }
827 mhm = next;
828 }
829
830 return 0;
831 }
832
833 static int
834 mh_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity)
835 {
836 struct _mh_data *mhd = mailbox->data;
837 int status = mh_messages_count (mailbox, NULL);
838 if (status != 0)
839 return status;
840 /* If we did not start a scanning yet do it now. */
841 if (mhd->msg_count == 0)
842 {
843 status = mh_scan0 (mailbox, 1, NULL, 0);
844 if (status != 0)
845 return status;
846 }
847 if (puidvalidity)
848 *puidvalidity = mhd->uidvalidity;
849 return 0;
850 }
851 72
852 static int 73 static int
853 mh_uidnext (mailbox_t mailbox, size_t *puidnext) 74 mh_message_cmp (struct _amd_message *a, struct _amd_message *b)
854 { 75 {
855 struct _mh_data *mhd = mailbox->data; 76 struct _mh_message *ma = (struct _mh_message *) a;
856 int status = mh_messages_count (mailbox, NULL); 77 struct _mh_message *mb = (struct _mh_message *) b;
857 if (status != 0) 78 if (ma->seq_number < mb->seq_number)
858 return status; 79 return -1;
859 /* If we did not start a scanning yet do it now. */ 80 else if (ma->seq_number > mb->seq_number)
860 if (mhd->msg_count == 0) 81 return 1;
861 {
862 status = mh_scan0 (mailbox, 1, NULL, 0);
863 if (status != 0)
864 return status;
865 }
866 if (puidnext)
867 *puidnext = _mh_next_seq(mhd);
868 return 0; 82 return 0;
869 } 83 }
870 84
871 /* FIXME: effectively the same as mbox_cleanup */ 85 static size_t
872 static void 86 _mh_next_seq (struct _amd_data *amd)
873 mh_cleanup (void *arg)
874 {
875 mailbox_t mailbox = arg;
876 monitor_unlock (mailbox->monitor);
877 locker_unlock (mailbox->locker);
878 }
879
880 /* Insert message msg into the message list on the appropriate position */
881 static void
882 _mh_message_insert (struct _mh_data *mhd, struct _mh_message *msg)
883 { 87 {
884 struct _mh_message *p; 88 struct _mh_message *msg = (struct _mh_message *) amd->msg_tail;
885 struct _mh_message *prev; 89 return (msg ? msg->seq_number : 0) + 1;
886 size_t n = msg->seq_number;
887
888 for (p = mhd->msg_head; p && p->seq_number < n; p = p->next)
889 ;
890
891 if (!p)
892 {
893 msg->next = NULL;
894 msg->prev = mhd->msg_tail;
895 mhd->msg_tail = msg;
896 if (!mhd->msg_head)
897 mhd->msg_head = msg;
898 }
899 else
900 {
901 msg->next = p;
902 msg->prev = p->prev;
903 p->prev = msg;
904 }
905 if ((prev = msg->prev) != NULL)
906 prev->next = msg;
907 else
908 mhd->msg_head = msg;
909 msg->mhd = mhd;
910 mhd->msg_count++;
911 } 90 }
912 91
913 static void 92 /* Return filename for the message.
914 _mh_message_delete (struct _mh_data *mhd, struct _mh_message *msg) 93 NOTE: Allocates memory. */
94 static char *
95 _mh_message_name (struct _amd_message *amsg, int deleted)
915 { 96 {
916 struct _mh_message *p; 97 struct _mh_message *mhm = (struct _mh_message *) amsg;
917 struct _mh_message **pp = mh_pool_lookup (msg); 98 char *filename;
918 99 size_t len = strlen (amsg->amd->name) + 32;
919 if (pp) 100 filename = malloc (len);
920 *pp = NULL; 101 if (deleted)
921 102 snprintf (filename, len, "%s/,%lu", amsg->amd->name,
922 if ((p = msg->next) != NULL) 103 (unsigned long) mhm->seq_number);
923 p->prev = msg->prev;
924 else
925 mhd->msg_tail = msg->prev;
926
927 if ((p = msg->prev) != NULL)
928 p->next = msg->next;
929 else 104 else
930 mhd->msg_head = msg->next; 105 snprintf (filename, len, "%s/%lu", amsg->amd->name,
931 106 (unsigned long) mhm->seq_number);
932 message_destroy (&msg->message, msg); 107 return filename;
933 free (msg);
934 mhd->msg_count--;
935 } 108 }
936 109
937 /* Scan given message and fill mh_message_t fields. 110 /* Find the message with the given sequence number */
938 NOTE: the function assumes mhm->stream != NULL. */ 111 static struct _mh_message *
939 static int 112 _mh_get_message_seq (struct _amd_data *amd, size_t seq)
940 mh_scan_message (struct _mh_message *mhm)
941 { 113 {
942 stream_t stream = mhm->stream; 114 struct _mh_message *msg;
943 char buf[1024];
944 off_t off = 0;
945 size_t n;
946 int status;
947 int in_header = 1;
948 size_t hlines = 0;
949 size_t blines = 0;
950 size_t body_start = 0;
951
952 /* Check if the message was modified after the last scan */
953 if (mhm->mtime)
954 {
955 struct stat st;
956 char *msg_name = _mh_message_name (mhm, mhm->deleted);
957
958 if (stat (msg_name, &st) == 0 && st.st_mtime == mhm->mtime)
959 {
960 /* Nothing to do */
961 free (msg_name);
962 return 0;
963 }
964 free (msg_name);
965 }
966
967 while ((status = stream_readline (stream, buf, sizeof (buf), off, &n) == 0)
968 && n != 0)
969 {
970 if (in_header)
971 {
972 if (buf[0] == '\n')
973 {
974 in_header = 0;
975 body_start = off+1;
976 }
977 if (buf[n - 1] == '\n')
978 hlines++;
979 115
980 /* Process particular attributes */ 116 for (msg = (struct _mh_message *) amd->msg_head;
981 if (strncasecmp (buf, "status:", 7) == 0) 117 msg && msg->seq_number < seq;
982 { 118 msg = (struct _mh_message *) msg->amd_message.next)
983 int deleted = mhm->attr_flags & MU_ATTRIBUTE_DELETED; 119 ;
984 string_to_flags (buf, &mhm->attr_flags);
985 mhm->attr_flags |= deleted;
986 }
987 else if (strncasecmp (buf, "x-imapbase:", 11) == 0)
988 {
989 char *p;
990 mhm->mhd->uidvalidity = strtoul (buf + 11, &p, 10);
991 /* second number is next uid. Ignored */
992 }
993 }
994 else
995 {
996 if (buf[n - 1] == '\n')
997 blines++;
998 }
999 off += n;
1000 }
1001 120
1002 if (!body_start) 121 if (msg)
1003 body_start = off; 122 return msg->seq_number == seq ? msg : NULL;
1004 mhm->header_lines = hlines; 123 return NULL;
1005 mhm->body_lines = blines;
1006 mhm->body_start = body_start;
1007 mhm->body_end = off;
1008 return 0;
1009 } 124 }
1010 125
1011 /* Scan the mailbox */ 126 /* Scan the mailbox */
...@@ -1013,24 +128,24 @@ static int ...@@ -1013,24 +128,24 @@ static int
1013 mh_scan0 (mailbox_t mailbox, size_t msgno ARG_UNUSED, size_t *pcount, 128 mh_scan0 (mailbox_t mailbox, size_t msgno ARG_UNUSED, size_t *pcount,
1014 int do_notify) 129 int do_notify)
1015 { 130 {
1016 struct _mh_data *mhd = mailbox->data; 131 struct _amd_data *amd = mailbox->data;
1017 struct _mh_message *msg; 132 struct _mh_message *msg;
1018 DIR *dir; 133 DIR *dir;
1019 struct dirent *entry; 134 struct dirent *entry;
1020 int status = 0; 135 int status = 0;
1021 struct stat st; 136 struct stat st;
1022 137
1023 if (mhd == NULL) 138 if (amd == NULL)
1024 return EINVAL; 139 return EINVAL;
1025 140
1026 dir = opendir (mhd->name); 141 dir = opendir (amd->name);
1027 if (!dir) 142 if (!dir)
1028 return errno; 143 return errno;
1029 144
1030 monitor_wrlock (mailbox->monitor); 145 monitor_wrlock (mailbox->monitor);
1031 146
1032 #ifdef WITH_PTHREAD 147 #ifdef WITH_PTHREAD
1033 pthread_cleanup_push (mh_cleanup, (void *)mailbox); 148 pthread_cleanup_push (amd_cleanup, (void *)mailbox);
1034 #endif 149 #endif
1035 150
1036 locker_lock (mailbox->locker); 151 locker_lock (mailbox->locker);
...@@ -1069,316 +184,69 @@ mh_scan0 (mailbox_t mailbox, size_t msgno ARG_UNUSED, size_t *pcount, ...@@ -1069,316 +184,69 @@ mh_scan0 (mailbox_t mailbox, size_t msgno ARG_UNUSED, size_t *pcount,
1069 if (namep[0]) 184 if (namep[0])
1070 continue; 185 continue;
1071 186
1072 msg = _mh_get_message_seq (mhd, num); 187 msg = _mh_get_message_seq (amd, num);
1073 if (!msg) 188 if (!msg)
1074 { 189 {
1075 msg = calloc (1, sizeof(*msg)); 190 msg = calloc (1, sizeof(*msg));
1076 191
1077 msg->seq_number = num; 192 msg->seq_number = num;
1078 msg->attr_flags = attr_flags; 193 msg->amd_message.attr_flags = attr_flags;
1079 msg->deleted = attr_flags & MU_ATTRIBUTE_DELETED; 194 msg->amd_message.deleted = attr_flags & MU_ATTRIBUTE_DELETED;
1080
1081 _mh_message_insert (mhd, msg);
1082 195
196 _amd_message_insert (amd, (struct _amd_message*) msg);
1083 } 197 }
1084 else 198 else
1085 { 199 {
1086 msg->attr_flags = attr_flags; 200 msg->amd_message.attr_flags = attr_flags;
1087 } 201 }
1088 } 202 }
1089 203
1090 closedir (dir); 204 closedir (dir);
1091 205
1092 if (do_notify) 206 if (do_notify)
1093 for (msg = mhd->msg_head; msg; msg = msg->next) 207 {
1094 { 208 struct _amd_message *mp;
1095 DISPATCH_ADD_MSG(mailbox, mhd); 209 for (mp = amd->msg_head; mp; mp = mp->next)
1096 } 210 {
1097 211 DISPATCH_ADD_MSG(mailbox, amd);
1098 if (stat (mhd->name, &st) == 0) 212 }
1099 mhd->mtime = st.st_mtime; 213 }
214
215 if (stat (amd->name, &st) == 0)
216 amd->mtime = st.st_mtime;
1100 217
1101 if (pcount) 218 if (pcount)
1102 *pcount = mhd->msg_count; 219 *pcount = amd->msg_count;
1103 220
1104 /* Reset the uidvalidity. */ 221 /* Reset the uidvalidity. */
1105 if (mhd->msg_count > 0) 222 if (amd->msg_count > 0)
1106 { 223 {
1107 if (mhd->uidvalidity == 0) 224 if (amd->uidvalidity == 0)
1108 { 225 {
1109 mhd->uidvalidity = (unsigned long)time (NULL); 226 amd->uidvalidity = (unsigned long)time (NULL);
1110 /* FIXME mhd->uidnext = mhd->msg_count + 1;*/ 227 /* FIXME amd->uidnext = amd->msg_count + 1;*/
1111 /* Tell that we have been modified for expunging. */ 228 /* Tell that we have been modified for expunging. */
1112 if (mhd->msg_head) 229 if (amd->msg_head)
1113 { 230 {
1114 mh_message_stream_open (mhd->msg_head); 231 amd_message_stream_open (amd->msg_head);
1115 mh_message_stream_close (mhd->msg_head); 232 amd_message_stream_close (amd->msg_head);
1116 mhd->msg_head->attr_flags |= MU_ATTRIBUTE_MODIFIED; 233 amd->msg_head->attr_flags |= MU_ATTRIBUTE_MODIFIED;
1117 } 234 }
1118 } 235 }
1119 } 236 }
1120 237
1121 /* Clean up the things */ 238 /* Clean up the things */
1122 239
1123 mh_cleanup (mailbox); 240 amd_cleanup (mailbox);
1124 #ifdef WITH_PTHREAD
1125 pthread_cleanup_pop (0);
1126 #endif
1127 return status;
1128 }
1129
1130
1131 static int
1132 mh_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
1133 {
1134 struct _mh_data *mhd = mailbox->data;
1135
1136 if (! mh_is_updated (mailbox))
1137 return mh_scan0 (mailbox, msgno, pcount, 1);
1138
1139 if (pcount)
1140 *pcount = mhd->msg_count;
1141
1142 return 0;
1143 }
1144
1145 /* Is the internal representation of the mailbox up to date.
1146 Return 1 if so, 0 otherwise. */
1147 static int
1148 mh_is_updated (mailbox_t mailbox)
1149 {
1150 struct stat st;
1151 struct _mh_data *mhd = mailbox->data;
1152
1153 if (!mhd->msg_head)
1154 return 0;
1155
1156 if (stat (mhd->name, &st) < 0)
1157 return 1;
1158
1159 return mhd->mtime == st.st_mtime;
1160 }
1161
1162 static int
1163 mh_get_size (mailbox_t mailbox ARG_UNUSED, off_t *psize ARG_UNUSED)
1164 {
1165 /*FIXME*/
1166 return ENOSYS;
1167 }
1168
1169 /* Return number of open streams residing in a message pool */
1170 static int
1171 mh_pool_open_count (struct _mh_data *mhd)
1172 {
1173 int cnt = mhd->pool_last - mhd->pool_first;
1174 if (cnt < 0)
1175 cnt += MAX_OPEN_STREAMS;
1176 return cnt;
1177 }
1178
1179 /* Look up a _mh_message in the pool of open messages.
1180 If the message is found in the pool, returns the address of
1181 the pool slot occupied by it. Otherwise returns NULL. */
1182 static struct _mh_message **
1183 mh_pool_lookup (struct _mh_message *mhm)
1184 {
1185 struct _mh_data *mhd = mhm->mhd;
1186 int i;
1187
1188 for (i = mhd->pool_first; i != mhd->pool_last; )
1189 {
1190 if (mhd->msg_pool[i] == mhm)
1191 return &mhd->msg_pool[i];
1192 if (++i == MAX_OPEN_STREAMS)
1193 i = 0;
1194 }
1195 return NULL;
1196 }
1197
1198 /* Open a stream associated with the message mhm. If the stream is
1199 already open, do nothing.
1200 NOTE: We could have reused the NULL holes in the msg_pool, but
1201 that hardly is worth the effort, since the holes appear only when
1202 expunging. On the other hand this may be useful when MAX_OPEN_STREAMS
1203 size is very big. "Premature optimization is the root of all evil" */
1204 static int
1205 mh_pool_open (struct _mh_message *mhm)
1206 {
1207 struct _mh_data *mhd = mhm->mhd;
1208 if (mh_pool_lookup (mhm))
1209 return 0;
1210 if (mh_pool_open_count(mhd) == MAX_OPEN_STREAMS-1)
1211 {
1212 mh_message_stream_close (mhd->msg_pool[mhd->pool_first++]);
1213 mhd->pool_first %= MAX_OPEN_STREAMS;
1214 }
1215 mh_message_stream_open (mhm);
1216 mhd->msg_pool[mhd->pool_last++] = mhm;
1217 mhd->pool_last %= MAX_OPEN_STREAMS;
1218 return 0;
1219 }
1220
1221 /* Attach a stream to a given message structure. The latter is supposed
1222 to be already added to the open message pool. */
1223 int
1224 mh_message_stream_open (struct _mh_message *mhm)
1225 {
1226 struct _mh_data *mhd = mhm->mhd;
1227 char *filename = NULL;
1228 int status;
1229 int flags = MU_STREAM_ALLOW_LINKS;
1230 filename = _mh_message_name (mhm, mhm->deleted);
1231
1232 if (!filename)
1233 return ENOMEM;
1234
1235 /* The message should be at least readable */
1236 if (mhd->mailbox->flags & (MU_STREAM_RDWR|MU_STREAM_WRITE|MU_STREAM_APPEND))
1237 flags |= MU_STREAM_RDWR;
1238 else
1239 flags |= MU_STREAM_READ;
1240 status = file_stream_create (&mhm->stream, filename, flags);
1241
1242 free (filename);
1243
1244 if (status != 0)
1245 return status;
1246
1247 status = stream_open (mhm->stream);
1248
1249 if (status != 0)
1250 stream_destroy (&mhm->stream, NULL);
1251
1252 if (status == 0)
1253 status = mh_scan_message (mhm);
1254
1255 return status;
1256 }
1257
1258 /* Close the stream associated with the given message. */
1259 void
1260 mh_message_stream_close (struct _mh_message *mhm)
1261 {
1262 if (mhm)
1263 {
1264 stream_close (mhm->stream);
1265 mhm->stream = NULL;
1266 }
1267 }
1268
1269 void
1270 mh_check_message (struct _mh_message *mhm)
1271 {
1272 if (mhm->body_end == 0)
1273 mh_pool_open (mhm);
1274 }
1275
1276 /* Reading functions */
1277
1278 static int
1279 mh_readstream (struct _mh_message *mhm, char *buffer, size_t buflen,
1280 off_t off, size_t *pnread, int isreadline,
1281 off_t start, off_t end)
1282 {
1283 size_t nread = 0;
1284 int status = 0;
1285 off_t ln;
1286
1287 if (buffer == NULL || buflen == 0)
1288 {
1289 if (pnread)
1290 *pnread = nread;
1291 return 0;
1292 }
1293
1294 monitor_rdlock (mhm->mhd->mailbox->monitor);
1295 #ifdef WITH_PTHREAD
1296 /* read() is cancellation point since we're doing a potentially
1297 long operation. Lets make sure we clean the state. */
1298 pthread_cleanup_push (mh_cleanup, (void *)mhm->mhd->mailbox);
1299 #endif
1300
1301 ln = end - (start + off);
1302 if (ln > 0)
1303 {
1304 /* Position the file pointer and the buffer. */
1305 nread = ((size_t)ln < buflen) ? (size_t)ln : buflen;
1306 if (isreadline)
1307 status = stream_readline (mhm->stream, buffer, buflen,
1308 start + off, &nread);
1309 else
1310 status = stream_read (mhm->stream, buffer, nread,
1311 start + off, &nread);
1312 }
1313
1314 monitor_unlock (mhm->mhd->mailbox->monitor);
1315 #ifdef WITH_PTHREAD 241 #ifdef WITH_PTHREAD
1316 pthread_cleanup_pop (0); 242 pthread_cleanup_pop (0);
1317 #endif 243 #endif
1318
1319 if (pnread)
1320 *pnread = nread;
1321 return status; 244 return status;
1322 } 245 }
1323 246
1324 static int 247 /* Note: In this particular implementation the message sequence number
1325 mh_body_read (stream_t is, char *buffer, size_t buflen, off_t off, 248 serves also as its UID. This allows to avoid many problems related
1326 size_t *pnread) 249 to keeping the uids in the headers of the messages. */
1327 {
1328 body_t body = stream_get_owner (is);
1329 message_t msg = body_get_owner (body);
1330 struct _mh_message *mhm = message_get_owner (msg);
1331 mh_pool_open (mhm);
1332 return mh_readstream (mhm, buffer, buflen, off, pnread, 0,
1333 mhm->body_start, mhm->body_end);
1334 }
1335
1336 static int
1337 mh_body_readline (stream_t is, char *buffer, size_t buflen,
1338 off_t off, size_t *pnread)
1339 {
1340 body_t body = stream_get_owner (is);
1341 message_t msg = body_get_owner (body);
1342 struct _mh_message *mhm = message_get_owner (msg);
1343 mh_pool_open (mhm);
1344 return mh_readstream (mhm, buffer, buflen, off, pnread, 1,
1345 mhm->body_start, mhm->body_end);
1346 }
1347
1348 /* Return corresponding sizes */
1349
1350 static int
1351 mh_stream_size (stream_t stream, off_t *psize)
1352 {
1353 body_t body = stream_get_owner (stream);
1354 return mh_body_size (body, (size_t*) psize);
1355 }
1356
1357 static int
1358 mh_body_size (body_t body, size_t *psize)
1359 {
1360 message_t msg = body_get_owner (body);
1361 struct _mh_message *mhm = message_get_owner (msg);
1362 if (mhm == NULL)
1363 return EINVAL;
1364 mh_check_message (mhm);
1365 if (psize)
1366 *psize = mhm->body_end - mhm->body_start;
1367 return 0;
1368 }
1369
1370 static int
1371 mh_body_lines (body_t body, size_t *plines)
1372 {
1373 message_t msg = body_get_owner (body);
1374 struct _mh_message *mhm = message_get_owner (msg);
1375 if (mhm == NULL)
1376 return EINVAL;
1377 mh_check_message (mhm);
1378 if (plines)
1379 *plines = mhm->body_lines;
1380 return 0;
1381 }
1382 250
1383 static int 251 static int
1384 mh_message_uid (message_t msg, size_t *puid) 252 mh_message_uid (message_t msg, size_t *puid)
...@@ -1389,153 +257,43 @@ mh_message_uid (message_t msg, size_t *puid) ...@@ -1389,153 +257,43 @@ mh_message_uid (message_t msg, size_t *puid)
1389 return 0; 257 return 0;
1390 } 258 }
1391 259
1392 /* Headers */
1393 static int
1394 mh_header_fill (header_t header, char *buffer, size_t len,
1395 off_t off, size_t *pnread)
1396 {
1397 message_t msg = header_get_owner (header);
1398 struct _mh_message *mhm = message_get_owner (msg);
1399
1400 mh_pool_open (mhm);
1401 return mh_readstream (mhm, buffer, len, off, pnread, 0,
1402 0, mhm->body_start);
1403 }
1404
1405 static int
1406 mh_header_size (header_t header, size_t *psize)
1407 {
1408 message_t msg = header_get_owner (header);
1409 struct _mh_message *mhm = message_get_owner (msg);
1410 if (mhm == NULL)
1411 return EINVAL;
1412 mh_check_message (mhm);
1413 if (psize)
1414 *psize = mhm->body_start;
1415 return 0;
1416 }
1417
1418 static int
1419 mh_header_lines (header_t header, size_t *plines)
1420 {
1421 message_t msg = header_get_owner (header);
1422 struct _mh_message *mhm = message_get_owner (msg);
1423 if (mhm == NULL)
1424 return EINVAL;
1425 mh_check_message (mhm);
1426 if (plines)
1427 *plines = mhm->header_lines;
1428 return 0;
1429 }
1430
1431 /* Attributes */
1432 static int
1433 mh_get_attr_flags (attribute_t attr, int *pflags)
1434 {
1435 message_t msg = attribute_get_owner (attr);
1436 struct _mh_message *mhm = message_get_owner (msg);
1437
1438 if (mhm == NULL)
1439 return EINVAL;
1440 if (pflags)
1441 *pflags = mhm->attr_flags;
1442 return 0;
1443 }
1444
1445 static int 260 static int
1446 mh_set_attr_flags (attribute_t attr, int flags) 261 _mh_msg_init (struct _amd_data *amd, struct _amd_message *amm)
1447 { 262 {
1448 message_t msg = attribute_get_owner (attr); 263 struct _mh_message *mhm = (struct _mh_message *) amm;
1449 struct _mh_message *mhm = message_get_owner (msg); 264 mhm->seq_number = _mh_next_seq (amd);
1450
1451 if (mhm == NULL)
1452 return EINVAL;
1453 mhm->attr_flags |= flags;
1454 return 0; 265 return 0;
1455 } 266 }
1456 267
1457 static int 268
1458 mh_unset_attr_flags (attribute_t attr, int flags)
1459 {
1460 message_t msg = attribute_get_owner (attr);
1461 struct _mh_message *mhm = message_get_owner (msg);
1462
1463 if (mhm == NULL)
1464 return EINVAL;
1465 mhm->attr_flags &= ~flags;
1466 return 0;
1467 }
1468 269
1469 /* Envelope */ 270 int
1470 static int 271 _mailbox_mh_init (mailbox_t mailbox)
1471 mh_envelope_date (envelope_t envelope, char *buf, size_t len,
1472 size_t *psize)
1473 { 272 {
1474 message_t msg = envelope_get_owner (envelope); 273 int rc;
1475 struct _mh_message *mhm = message_get_owner (msg); 274 struct _amd_data *amd;
1476 header_t hdr = NULL; 275
1477 char *from; 276 rc = amd_init_mailbox (mailbox, sizeof (struct _amd_data), &amd);
1478 int status; 277 if (rc)
278 return rc;
279
280 amd->msg_size = sizeof (struct _mh_message);
281 amd->msg_free = NULL;
282 amd->msg_init_delivery = _mh_msg_init;
283 amd->msg_finish_delivery = NULL;
284 amd->msg_file_name = _mh_message_name;
285 amd->scan0 = mh_scan0;
286 amd->msg_cmp = mh_message_cmp;
287 amd->message_uid = mh_message_uid;
288 amd->next_uid = _mh_next_seq;
1479 289
1480 if (mhm == NULL) 290 /* Set our properties. */
1481 return EINVAL; 291 {
1482 292 property_t property = NULL;
1483 if ((status = message_get_header (msg, &hdr)) != 0) 293 mailbox_get_property (mailbox, &property);
1484 return status; 294 property_set_value (property, "TYPE", "MH", 1);
1485 if (header_aget_value (hdr, MU_HEADER_ENV_DATE, &from)) 295 }
1486 return ENOSYS;
1487
1488 /* Format: "sender date" */
1489 if (buf && len > 0)
1490 {
1491 len--; /* Leave space for the null. */
1492 strncpy (buf, from, len);
1493 if (strlen (from) < len)
1494 {
1495 len = strlen (buf);
1496 buf[len++] = '\n';
1497 }
1498 buf[len] = '\0';
1499 }
1500 else
1501 len = 0;
1502
1503 if (psize)
1504 *psize = len;
1505 return 0;
1506 }
1507
1508 static int
1509 mh_envelope_sender (envelope_t envelope, char *buf, size_t len, size_t *psize)
1510 {
1511 message_t msg = envelope_get_owner (envelope);
1512 struct _mh_message *mhm = message_get_owner (msg);
1513 header_t hdr = NULL;
1514 char *from;
1515 int status;
1516
1517 if (mhm == NULL)
1518 return EINVAL;
1519
1520 if ((status = message_get_header (msg, &hdr)) != 0)
1521 return status;
1522 if (header_aget_value (hdr, MU_HEADER_ENV_SENDER, &from))
1523 return ENOSYS;
1524
1525 if (buf && len > 0)
1526 {
1527 int slen = strlen (from);
1528
1529 if (len < slen + 1)
1530 slen = len - 1;
1531 memcpy (buf, from, slen);
1532 buf[slen] = 0;
1533 }
1534 else
1535 len = 0;
1536 296
1537 if (psize)
1538 *psize = len;
1539 return 0; 297 return 0;
1540 } 298 }
1541 299
......