2 * Copyright notice from original mutt:
3 * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org>
4 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
6 * This file is part of mutt-ng, see http://www.muttng.org/.
7 * It's licensed under the GNU General Public License,
8 * please see the file GPL in the top level source directory.
11 #include <lib-lib/lib-lib.h>
15 #include <lib-lua/lib-lua.h>
16 #include <lib-sys/unix.h>
17 #include <lib-mime/mime.h>
18 #include <lib-ui/sidebar.h>
33 #include <imap/imap.h>
39 static mx_t const *mxfmts[] = {
51 #define MX_IDX(idx) (idx >= 0 && idx < countof(mxfmts))
52 #define mutt_is_spool(s) (m_strcmp(Spoolfile, s) == 0)
54 static int dotlock_file(const char *path, int retry)
56 char lockfile[_POSIX_PATH_MAX];
57 snprintf(lockfile, sizeof(lockfile), "%s.lock", path);
59 if (lockfile_create(lockfile, retry ? 1 : 0, 0)) {
61 mutt_error (_("Can't dotlock %s.\n"), lockfile);
66 static int undotlock_file (const char *path)
68 char lockfile[_POSIX_PATH_MAX];
69 snprintf(lockfile, sizeof(lockfile), "%s.lock", path);
70 return lockfile_remove(lockfile);
73 /* looks up index of type for path in mxfmts */
74 static int mx_get_idx (const char* path) {
78 /* first, test all non-local folders to avoid stat() call */
79 for (i = 0; i < countof(mxfmts); i++) {
80 if (!mxfmts[i]->local)
81 t = mxfmts[i]->mx_is_magic(path, NULL);
85 if (stat (path, &st) == 0) {
86 /* if stat() succeeded, keep testing until success and
87 * pass stat() info so that we only need to do it once */
88 for (i = 0; i < countof(mxfmts); i++) {
90 t = mxfmts[i]->mx_is_magic(path, &st);
99 * excl if excl != 0, request an exclusive lock
100 * dot if dot != 0, try to dotlock the file
101 * time_out should retry locking?
103 int mx_lock_file (const char *path, int fd, int excl, int dot, int time_out)
105 #if defined (USE_FCNTL) || defined (USE_FLOCK)
116 lck.l_type = excl ? F_WRLCK : F_RDLCK;
117 lck.l_whence = SEEK_SET;
122 while (fcntl (fd, F_SETLK, &lck) == -1) {
125 if (errno != EAGAIN && errno != EACCES) {
126 mutt_perror ("fcntl");
130 if (fstat (fd, &sb) != 0)
136 /* only unlock file if it is unchanged */
137 if (prev_sb.st_size == sb.st_size
138 && ++count >= (time_out ? MAXLOCKATTEMPT : 0)) {
140 mutt_error _("Timeout exceeded while attempting fcntl lock!");
147 mutt_message (_("Waiting for fcntl lock... %d"), ++attempt);
150 #endif /* USE_FCNTL */
155 while (flock (fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1) {
158 if (errno != EWOULDBLOCK) {
159 mutt_perror ("flock");
164 if (fstat (fd, &sb) != 0)
170 /* only unlock file if it is unchanged */
171 if (prev_sb.st_size == sb.st_size
172 && ++count >= (time_out ? MAXLOCKATTEMPT : 0)) {
174 mutt_error _("Timeout exceeded while attempting flock lock!");
182 mutt_message (_("Waiting for flock attempt... %d"), ++attempt);
185 #endif /* USE_FLOCK */
188 r = dotlock_file(path, time_out);
191 /* release any other locks obtained in this routine */
194 lck.l_type = F_UNLCK;
195 fcntl (fd, F_SETLK, &lck);
196 #endif /* USE_FCNTL */
200 #endif /* USE_FLOCK */
208 int mx_unlock_file (const char *path, int fd, int dot)
211 struct flock unlockit;
213 p_clear(&unlockit, 1);
214 unlockit.l_type = F_UNLCK;
215 unlockit.l_whence = SEEK_SET;
216 fcntl (fd, F_SETLK, &unlockit);
224 undotlock_file (path);
229 /* try to figure out what type of mailbox ``path'' is */
230 int mx_get_magic (const char *path) {
233 if (m_strlen(path) == 0)
235 if ((i = mx_get_idx (path)) >= 0)
236 return (mxfmts[i]->type);
240 int mx_is_local (int m) {
243 return (mxfmts[m]->local);
247 * set DefaultMagic to the given value
249 int mx_set_magic (const char *s)
251 if (ascii_strcasecmp (s, "mbox") == 0)
252 DefaultMagic = M_MBOX;
253 else if (ascii_strcasecmp (s, "mh") == 0)
255 else if (ascii_strcasecmp (s, "maildir") == 0)
256 DefaultMagic = M_MAILDIR;
263 /* mx_access: Wrapper for access, checks permissions on a given mailbox.
264 * We may be interested in using ACL-style flags at some point, currently
265 * we use the normal access() flags. */
266 int mx_access (const char *path, int flags)
270 if ((i = mx_get_idx (path)) >= 0 && mxfmts[i]->mx_access)
271 return (mxfmts[i]->mx_access(path,flags));
275 static int mx_open_mailbox_append (CONTEXT * ctx, int flags)
279 /* special case for appending to compressed folders -
280 * even if we can not open them for reading */
281 if (mutt_can_append_compressed (ctx->path))
282 mutt_open_append_compressed (ctx);
286 if (mx_get_magic (ctx->path) == M_IMAP)
287 return imap_open_mailbox_append (ctx);
289 if (stat (ctx->path, &sb) == 0) {
290 ctx->magic = mx_get_magic (ctx->path);
292 switch (ctx->magic) {
294 mutt_error (_("%s is not a mailbox."), ctx->path);
300 else if (errno == ENOENT) {
301 ctx->magic = DefaultMagic;
303 if (ctx->magic == M_MH || ctx->magic == M_MAILDIR) {
304 char tmp[_POSIX_PATH_MAX];
306 if (mkdir (ctx->path, S_IRWXU)) {
307 mutt_perror (ctx->path);
311 if (ctx->magic == M_MAILDIR) {
312 snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
313 if (mkdir (tmp, S_IRWXU)) {
319 snprintf (tmp, sizeof (tmp), "%s/new", ctx->path);
320 if (mkdir (tmp, S_IRWXU)) {
322 snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
327 snprintf (tmp, sizeof (tmp), "%s/tmp", ctx->path);
328 if (mkdir (tmp, S_IRWXU)) {
330 snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path);
332 snprintf (tmp, sizeof (tmp), "%s/new", ctx->path);
341 snprintf (tmp, sizeof (tmp), "%s/.mh_sequences", ctx->path);
342 if ((i = creat (tmp, S_IRWXU)) == -1) {
352 mutt_perror (ctx->path);
356 switch (ctx->magic) {
359 safe_fopen (ctx->path, flags & M_NEWFOLDER ? "w" : "a")) == NULL
360 || mbox_lock_mailbox (ctx, 1, 1) != 0) {
362 mutt_perror (ctx->path);
364 mutt_error (_("Couldn't lock %s\n"), ctx->path);
369 fseeko (ctx->fp, 0, 2);
385 * open a mailbox and parse it
388 * flags M_NOSORT do not sort mailbox
389 * M_APPEND open mailbox for appending
390 * M_READONLY open mailbox in read-only mode
391 * M_QUIET only print error messages
392 * ctx if non-null, context struct to use
394 CONTEXT *mx_open_mailbox (const char *path, int flags, CONTEXT * pctx)
400 ctx = p_new(CONTEXT, 1);
402 ctx->path = m_strdup(path);
404 ctx->msgnotreadyet = -1;
409 if (flags & M_READONLY)
414 if (flags & (M_APPEND | M_NEWFOLDER)) {
415 if (mx_open_mailbox_append (ctx, flags) != 0) {
416 mx_fastclose_mailbox (ctx);
424 if (!MX_IDX(ctx->magic-1))
425 ctx->magic = mx_get_magic (path);
427 if (ctx->magic == M_COMPRESSED)
428 mutt_open_read_compressed (ctx);
431 mutt_error (_("%s is not a mailbox."), path);
433 if (ctx->magic == -1)
436 if (ctx->magic <= 0) {
437 mx_fastclose_mailbox (ctx);
443 /* if the user has a `push' command in their .muttrc, or in a folder-hook,
444 * it will cause the progress messages not to be displayed because
445 * mutt_refresh() will think we are in the middle of a macro. so set a
446 * flag to indicate that we should really refresh the screen.
448 set_option (OPTFORCEREFRESH);
451 mutt_message (_("Reading %s..."), ctx->path);
453 rc = mxfmts[ctx->magic-1]->mx_open_mailbox(ctx);
456 if ((flags & M_NOSORT) == 0) {
457 /* avoid unnecessary work since the mailbox is completely unthreaded
459 unset_option (OPTSORTSUBTHREADS);
460 unset_option (OPTNEEDRESCORE);
461 mutt_sort_headers (ctx, 1);
467 mx_fastclose_mailbox (ctx);
472 unset_option (OPTFORCEREFRESH);
476 /* free up memory associated with the mailbox context */
477 void mx_fastclose_mailbox (CONTEXT * ctx)
484 if (MX_IDX(ctx->magic-1) && mxfmts[ctx->magic-1]->mx_fastclose_mailbox)
485 mxfmts[ctx->magic-1]->mx_fastclose_mailbox(ctx);
487 hash_delete (&ctx->subj_hash, NULL);
489 hash_delete (&ctx->id_hash, NULL);
490 mutt_clear_threads (ctx);
491 for (i = 0; i < ctx->msgcount; i++)
492 header_delete(&ctx->hdrs[i]);
493 p_delete(&ctx->hdrs);
497 mutt_fast_close_compressed (ctx);
499 p_delete(&ctx->path);
500 p_delete(&ctx->pattern);
501 pattern_list_wipe(&ctx->limit_pattern);
506 /* save changes to disk */
507 static int sync_mailbox (CONTEXT * ctx, int *index_hint)
512 mutt_message (_("Writing %s..."), ctx->path);
514 if (MX_IDX(ctx->magic-1))
515 /* the 1 is only of interest for IMAP and means EXPUNGE */
516 rc = mxfmts[ctx->magic-1]->mx_sync_mailbox(ctx,1,index_hint);
518 if (rc == 0 && ctx->cinfo)
519 return mutt_sync_compressed (ctx);
524 /* move deleted mails to the trash folder */
525 static int trash_append (CONTEXT * ctx)
531 if (!TrashPath || !ctx->deleted ||
532 (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH)))
535 for (; i < ctx->msgcount && (!ctx->hdrs[i]->deleted ||
536 ctx->hdrs[i]->appended); i++);
537 if (i == ctx->msgcount)
538 return 0; /* nothing to be done */
540 if (mutt_save_confirm (TrashPath, &st) != 0) {
541 mutt_error _("message(s) not deleted");
546 if (lstat (ctx->path, &stc) == 0 && stc.st_ino == st.st_ino
547 && stc.st_dev == st.st_dev && stc.st_rdev == st.st_rdev)
548 return 0; /* we are in the trash folder: simple sync */
550 if ((ctx_trash = mx_open_mailbox (TrashPath, M_APPEND, NULL)) != NULL) {
551 for (i = 0; i < ctx->msgcount; i++)
552 if (ctx->hdrs[i]->deleted && !ctx->hdrs[i]->appended
553 && !ctx->hdrs[i]->purged
554 && mutt_append_message (ctx_trash, ctx, ctx->hdrs[i], 0, 0) == -1) {
555 mx_close_mailbox (ctx_trash, NULL);
559 mx_close_mailbox (ctx_trash, NULL);
562 mutt_error _("Can't open trash folder");
570 /* save changes and close mailbox */
571 static int _mx_close_mailbox (CONTEXT * ctx, int *index_hint)
573 int i, move_messages = 0, purge = 1, read_msgs = 0;
577 char mbox[_POSIX_PATH_MAX];
586 if (ctx->magic == M_NNTP) {
589 ret = nntp_close_mailbox (ctx);
590 mx_fastclose_mailbox (ctx);
594 if (ctx->readonly || ctx->dontwrite) {
595 /* mailbox is readonly or we don't want to write */
596 mx_fastclose_mailbox (ctx);
601 /* mailbox was opened in write-mode */
602 if (ctx->magic == M_MBOX)
603 mbox_close_mailbox (ctx);
605 mx_fastclose_mailbox (ctx);
609 for (i = 0; i < ctx->msgcount; i++) {
610 if (!ctx->hdrs[i]->deleted && ctx->hdrs[i]->read
611 && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED)))
615 if (read_msgs && quadoption (OPT_MOVE) != M_NO) {
618 if ((p = mutt_find_hook (M_MBOXHOOK, ctx->path))) {
620 m_strcpy(mbox, sizeof(mbox), p);
623 m_strcpy(mbox, sizeof(mbox), NONULL(Inbox));
624 isSpool = mutt_is_spool (ctx->path) && !mutt_is_spool (mbox);
626 mutt_expand_path (mbox, sizeof (mbox));
629 snprintf (buf, sizeof (buf), _("Move read messages to %s?"), mbox);
630 if ((move_messages = query_quadoption (OPT_MOVE, buf)) == -1) {
638 * There is no point in asking whether or not to purge if we are
639 * just marking messages as "trash".
641 if (ctx->deleted && !(ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH))) {
642 snprintf (buf, sizeof (buf), ctx->deleted == 1
643 ? _("Purge %d deleted message?") :
644 _("Purge %d deleted messages?"), ctx->deleted);
645 if ((purge = query_quadoption (OPT_DELETE, buf)) < 0) {
651 /* IMAP servers manage the OLD flag themselves */
652 if (ctx->magic != M_IMAP)
653 if (option (OPTMARKOLD)) {
654 for (i = 0; i < ctx->msgcount; i++) {
655 if (!ctx->hdrs[i]->deleted && !ctx->hdrs[i]->old)
656 mutt_set_flag (ctx, ctx->hdrs[i], M_OLD, 1);
661 mutt_message (_("Moving read messages to %s..."), mbox);
663 /* try to use server-side copy first */
666 if (ctx->magic == M_IMAP && imap_is_magic (mbox, NULL) == M_IMAP) {
667 /* tag messages for moving, and clear old tags, if any */
668 for (i = 0; i < ctx->msgcount; i++)
669 if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted
670 && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED)))
671 ctx->hdrs[i]->tagged = 1;
673 ctx->hdrs[i]->tagged = 0;
675 i = imap_copy_messages (ctx, NULL, mbox, 1);
678 if (i == 0) /* success */
680 else if (i == -1) { /* horrible error, bail */
684 else /* use regular append-copy mode */
686 if (mx_open_mailbox (mbox, M_APPEND, &f) == NULL) {
691 for (i = 0; i < ctx->msgcount; i++) {
692 if (ctx->hdrs[i]->read && !ctx->hdrs[i]->deleted
693 && !(ctx->hdrs[i]->flagged && option (OPTKEEPFLAGGED))) {
694 if (mutt_append_message (&f, ctx, ctx->hdrs[i], 0, CH_UPDATE_LEN) ==
696 mutt_set_flag (ctx, ctx->hdrs[i], M_DELETE, 1);
697 mutt_set_flag (ctx, ctx->hdrs[i], M_APPENDED, 1);
700 mx_close_mailbox (&f, NULL);
707 mx_close_mailbox (&f, NULL);
711 else if (!ctx->changed && ctx->deleted == 0) {
712 mutt_message _("Mailbox is unchanged.");
714 mx_fastclose_mailbox (ctx);
718 /* copy mails to the trash before expunging */
719 if (purge && ctx->deleted)
720 if (trash_append (ctx) != 0) {
725 /* allow IMAP to preserve the deleted flag across sessions */
726 if (ctx->magic == M_IMAP) {
727 if ((check = imap_sync_mailbox (ctx, purge, index_hint)) != 0) {
735 for (i = 0; i < ctx->msgcount; i++)
736 ctx->hdrs[i]->deleted = 0;
740 if (ctx->changed || ctx->deleted) {
741 if ((check = sync_mailbox (ctx, index_hint)) != 0) {
749 mutt_message (_("%d kept, %d moved, %d deleted."),
750 ctx->msgcount - ctx->deleted, read_msgs, ctx->deleted);
752 mutt_message (_("%d kept, %d deleted."),
753 ctx->msgcount - ctx->deleted, ctx->deleted);
755 if (ctx->cinfo && mutt_slow_close_compressed (ctx))
758 mx_fastclose_mailbox (ctx);
763 int mx_close_mailbox (CONTEXT * ctx, int *index_hint) {
767 ret = _mx_close_mailbox (ctx, index_hint);
768 sidebar_set_buffystats (ctx);
772 /* update a Context structure's internal tables. */
774 void mx_update_tables (CONTEXT * ctx, int committing)
778 /* update memory to reflect the new state of the mailbox */
787 #define this_body ctx->hdrs[j]->content
788 for (i = 0, j = 0; i < ctx->msgcount; i++) {
789 if ((committing && (!ctx->hdrs[i]->deleted ||
790 (ctx->magic == M_MAILDIR
791 && option (OPTMAILDIRTRASH)))) || (!committing
795 ctx->hdrs[j] = ctx->hdrs[i];
798 ctx->hdrs[j]->msgno = j;
799 if (ctx->hdrs[j]->virtual != -1) {
800 ctx->v2r[ctx->vcount] = j;
801 ctx->hdrs[j]->virtual = ctx->vcount++;
802 ctx->vsize += this_body->length + this_body->offset -
803 this_body->hdr_offset;
807 ctx->hdrs[j]->changed = 0;
808 else if (ctx->hdrs[j]->changed)
812 || (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH))) {
813 if (ctx->hdrs[j]->deleted)
817 if (ctx->hdrs[j]->tagged)
819 if (ctx->hdrs[j]->flagged)
821 if (!ctx->hdrs[j]->read) {
823 if (!ctx->hdrs[j]->old)
830 if (ctx->magic == M_MH || ctx->magic == M_MAILDIR)
831 ctx->size -= (ctx->hdrs[i]->content->length +
832 ctx->hdrs[i]->content->offset -
833 ctx->hdrs[i]->content->hdr_offset);
834 /* remove message from the hash tables */
835 if (ctx->subj_hash && ctx->hdrs[i]->env->real_subj)
836 hash_remove (ctx->subj_hash, ctx->hdrs[i]->env->real_subj,
838 if (ctx->id_hash && ctx->hdrs[i]->env->message_id)
839 hash_remove (ctx->id_hash, ctx->hdrs[i]->env->message_id,
841 header_delete(&ctx->hdrs[i]);
847 /* update sidebar count */
848 sidebar_set_buffystats (ctx);
852 /* save changes to mailbox
858 static int _mx_sync_mailbox (CONTEXT * ctx, int *index_hint)
862 int msgcount, deleted;
864 if (ctx->dontwrite) {
865 char buf[STRING], tmp[STRING];
867 if (km_expand_key (buf, sizeof (buf),
868 km_find_func (MENU_MAIN, OP_TOGGLE_WRITE)))
869 snprintf (tmp, sizeof (tmp), _(" Press '%s' to toggle write"), buf);
871 m_strcpy(tmp, sizeof(tmp), _("Use 'toggle-write' to re-enable write!"));
873 mutt_error (_("Mailbox is marked unwritable. %s"), tmp);
876 else if (ctx->readonly) {
877 mutt_error _("Mailbox is read-only.");
882 if (!ctx->changed && !ctx->deleted) {
883 mutt_message _("Mailbox is unchanged.");
891 snprintf (buf, sizeof (buf), ctx->deleted == 1
892 ? _("Purge %d deleted message?") :
893 _("Purge %d deleted messages?"), ctx->deleted);
894 if ((purge = query_quadoption (OPT_DELETE, buf)) < 0)
896 else if (purge == M_NO) {
898 return 0; /* nothing to do! */
899 /* let IMAP servers hold on to D flags */
900 if (ctx->magic != M_IMAP)
902 for (i = 0; i < ctx->msgcount; i++)
903 ctx->hdrs[i]->deleted = 0;
907 else if (ctx->last_tag && ctx->last_tag->deleted)
908 ctx->last_tag = NULL; /* reset last tagged msg now useless */
911 /* really only for IMAP - imap_sync_mailbox results in a call to
912 * mx_update_tables, so ctx->deleted is 0 when it comes back */
913 msgcount = ctx->msgcount;
914 deleted = ctx->deleted;
916 if (purge && ctx->deleted) {
917 if (trash_append (ctx) == -1)
921 if (ctx->magic == M_IMAP)
922 rc = imap_sync_mailbox (ctx, purge, index_hint);
924 rc = sync_mailbox (ctx, index_hint);
926 if (ctx->magic == M_IMAP && !purge)
927 mutt_message (_("Mailbox checkpointed."));
929 mutt_message (_("%d kept, %d deleted."), msgcount - deleted, deleted);
933 /* if we haven't deleted any messages, we don't need to resort */
934 /* ... except for certain folder formats which need "unsorted"
935 * sort order in order to synchronize folders.
937 * MH and maildir are safe. mbox-style seems to need re-sorting,
938 * at least with the new threading code.
940 if (purge || (ctx->magic != M_MAILDIR && ctx->magic != M_MH)) {
941 /* IMAP does this automatically after handling EXPUNGE */
942 if (ctx->magic != M_IMAP)
944 mx_update_tables (ctx, 1);
945 mutt_sort_headers (ctx, 1); /* rethread from scratch */
953 int mx_sync_mailbox (CONTEXT* ctx, int* index_hint) {
954 int ret = _mx_sync_mailbox (ctx, index_hint);
955 sidebar_set_buffystats (ctx);
960 * dest destintation mailbox
961 * hdr message being copied (required for maildir support, because
962 * the filename depends on the message flags)
964 MESSAGE *mx_open_new_message (CONTEXT * dest, HEADER * hdr, int flags)
969 if (!MX_IDX(dest->magic-1)) {
973 msg = p_new(MESSAGE, 1);
974 msg->magic = dest->magic;
978 msg->flags.flagged = hdr->flagged;
979 msg->flags.replied = hdr->replied;
980 msg->flags.read = hdr->read;
981 msg->received = hdr->received;
984 if (msg->received == 0)
985 time (&msg->received);
987 if (mxfmts[dest->magic-1]->mx_open_new_message(msg, dest, hdr) == 0) {
988 if (msg->magic == M_MBOX && flags & M_ADD_FROM) {
990 if (hdr->env->return_path)
991 p = hdr->env->return_path;
992 else if (hdr->env->sender)
993 p = hdr->env->sender;
998 fprintf (msg->fp, "From %s %s", p ? p->mailbox : NONULL(mod_core.username),
999 ctime (&msg->received));
1008 /* check for new mail */
1009 int mx_check_mailbox (CONTEXT * ctx, int *index_hint, int lock) {
1011 return mutt_check_mailbox_compressed (ctx);
1016 if (MX_IDX(ctx->magic-1) && mxfmts[ctx->magic-1]->mx_check_mailbox)
1017 return (mxfmts[ctx->magic-1]->mx_check_mailbox(ctx, index_hint, lock));
1023 /* return a stream pointer for a message */
1024 MESSAGE *mx_open_message (CONTEXT * ctx, int msgno)
1028 msg = p_new(MESSAGE, 1);
1029 switch (msg->magic = ctx->magic) {
1037 HEADER *cur = ctx->hdrs[msgno];
1038 char path[_POSIX_PATH_MAX];
1040 snprintf (path, sizeof (path), "%s/%s", ctx->path, cur->path);
1042 if ((msg->fp = fopen (path, "r")) == NULL && errno == ENOENT &&
1043 ctx->magic == M_MAILDIR)
1044 msg->fp = maildir_open_find_message (ctx->path, cur->path);
1046 if (msg->fp == NULL) {
1055 if (imap_fetch_message (msg, ctx, msgno) != 0)
1062 if (pop_fetch_message (msg, ctx, msgno) != 0)
1070 if (nntp_fetch_message (msg, ctx, msgno) != 0)
1074 #endif /* USE_NNTP */
1083 /* commit a message to a folder */
1085 int mx_commit_message (MESSAGE * msg, CONTEXT * ctx) {
1086 if (!(msg->write && ctx->append)) {
1089 if (!ctx || !MX_IDX(ctx->magic-1) || !mxfmts[ctx->magic-1]->mx_commit_message)
1091 return (mxfmts[ctx->magic-1]->mx_commit_message (msg, ctx));
1094 /* close a pointer to a message */
1095 int mx_close_message (MESSAGE ** msg)
1099 if ((*msg)->magic == M_MH || (*msg)->magic == M_MAILDIR
1100 || (*msg)->magic == M_IMAP
1101 || (*msg)->magic == M_POP
1103 || (*msg)->magic == M_NNTP
1106 r = m_fclose(&(*msg)->fp);
1112 unlink ((*msg)->path);
1113 p_delete(&(*msg)->path);
1120 void mx_alloc_memory (CONTEXT * ctx)
1124 p_realloc(&ctx->hdrs, ctx->hdrmax);
1125 p_realloc(&ctx->v2r, ctx->hdrmax);
1126 p_clear(ctx->hdrs + ctx->msgcount, ctx->hdrmax - ctx->msgcount);
1127 p_clear(ctx->v2r + ctx->msgcount, ctx->hdrmax - ctx->msgcount);
1130 /* this routine is called to update the counts in the context structure for
1131 * the last message header parsed.
1133 void mx_update_context (CONTEXT * ctx, int new_messages)
1138 for (msgno = ctx->msgcount - new_messages; msgno < ctx->msgcount; msgno++) {
1139 h = ctx->hdrs[msgno];
1141 /* NOTE: this _must_ be done before the check for mailcap! */
1142 h->security = crypt_query (h->content);
1144 if (!ctx->pattern) {
1145 ctx->v2r[ctx->vcount] = msgno;
1146 h->virtual = ctx->vcount++;
1152 if (h->env->supersedes) {
1156 ctx->id_hash = mutt_make_id_hash (ctx);
1158 h2 = hash_find (ctx->id_hash, h->env->supersedes);
1160 /* p_delete(&h->env->supersedes); should I ? */
1163 if (!ctx->counting && mod_score.enable)
1164 mutt_score_message (ctx, h2, 1);
1168 /* add this message to the hash tables */
1169 if (ctx->id_hash && h->env->message_id)
1170 hash_insert (ctx->id_hash, h->env->message_id, h);
1171 if (!ctx->counting) {
1172 if (ctx->subj_hash && h->env->real_subj)
1173 hash_insert (ctx->subj_hash, h->env->real_subj, h);
1175 if (mod_score.enable)
1176 mutt_score_message (ctx, h, 0);
1191 /* update sidebar count */
1192 sidebar_set_buffystats (ctx);
1197 * 1 if the specified mailbox contains 0 messages.
1198 * 0 if the mailbox contains messages
1201 int mx_check_empty (const char *path)
1204 if ((i = mx_get_idx (path)) >= 0 && mxfmts[i]->mx_check_empty)
1205 return (mxfmts[i]->mx_check_empty(path));
1210 int mx_acl_check(CONTEXT *ctx, int flag)
1212 if (!mxfmts[ctx->magic-1]->mx_acl_check)
1214 return mxfmts[ctx->magic-1]->mx_acl_check(ctx,flag);
1217 void mutt_parse_mime_message (CONTEXT * ctx, HEADER * cur)
1223 if (cur->content->type != TYPEMESSAGE
1224 && cur->content->type != TYPEMULTIPART)
1225 break; /* nothing to do */
1227 if (cur->content->parts)
1228 break; /* The message was parsed earlier. */
1230 if ((msg = mx_open_message (ctx, cur->msgno))) {
1231 mutt_parse_part (msg->fp, cur->content);
1233 cur->security = crypt_query (cur->content);
1235 mx_close_message (&msg);
1238 mutt_count_body_parts (cur, flags | M_PARTS_RECOUNT);