📄 mh.c
字号:
} }#if USE_HCACHE if (ctx->magic == M_MAILDIR || ctx->magic == M_MH) mutt_hcache_close (hc);#endif /* USE_HCACHE */ if (ctx->magic == M_MH) mh_update_sequences (ctx); /* XXX race condition? */ maildir_update_mtime (ctx); /* adjust indices */ if (ctx->deleted) { for (i = 0, j = 0; i < ctx->msgcount; i++) { if (!ctx->hdrs[i]->deleted || (ctx->magic == M_MAILDIR && option (OPTMAILDIRTRASH))) ctx->hdrs[i]->index = j++; } } return 0;err:#if USE_HCACHE if (ctx->magic == M_MAILDIR || ctx->magic == M_MH) mutt_hcache_close (hc);#endif /* USE_HCACHE */ return -1;}static char *maildir_canon_filename (char *dest, const char *src, size_t l){ char *t, *u; if ((t = strrchr (src, '/'))) src = t + 1; strfcpy (dest, src, l); if ((u = strrchr (dest, ':'))) *u = '\0'; return dest;}static void maildir_update_tables (CONTEXT *ctx, int *index_hint){ short old_sort; int old_count; int i, j; if (Sort != SORT_ORDER) { old_sort = Sort; Sort = SORT_ORDER; mutt_sort_headers (ctx, 1); Sort = old_sort; } old_count = ctx->msgcount; for (i = 0, j = 0; i < old_count; i++) { if (ctx->hdrs[i]->active && index_hint && *index_hint == i) *index_hint = j; if (ctx->hdrs[i]->active) ctx->hdrs[i]->index = j++; } mx_update_tables (ctx, 0); mutt_clear_threads (ctx);}static void maildir_update_flags (CONTEXT *ctx, HEADER *o, HEADER *n){ /* save the global state here so we can reset it at the * end of list block if required. */ int context_changed = ctx->changed; /* user didn't modify this message. alter the flags to * match the current state on disk. This may not actually * do anything, but we can't tell right now. mutt_set_flag() * will just ignore the call if the status bits are * already properly set. */ mutt_set_flag (ctx, o, M_FLAG, n->flagged); mutt_set_flag (ctx, o, M_REPLIED, n->replied); mutt_set_flag (ctx, o, M_READ, n->read); mutt_set_flag (ctx, o, M_OLD, n->old); /* mutt_set_flag() will set this, but we don't need to * sync the changes we made because we just updated the * context to match the current on-disk state of the * message. */ o->changed = 0; /* if the mailbox was not modified before we made these * changes, unset the changed flag since nothing needs to * be synchronized. */ if (!context_changed) ctx->changed = 0;}/* This function handles arrival of new mail and reopening of * maildir folders. The basic idea here is we check to see if either * the new or cur subdirectories have changed, and if so, we scan them * for the list of files. We check for newly added messages, and * then merge the flags messages we already knew about. We don't treat * either subdirectory differently, as mail could be copied directly into * the cur directory from another agent. */int maildir_check_mailbox (CONTEXT * ctx, int *index_hint){ struct stat st_new; /* status of the "new" subdirectory */ struct stat st_cur; /* status of the "cur" subdirectory */ char buf[_POSIX_PATH_MAX]; int changed = 0; /* bitmask representing which subdirectories have changed. 0x1 = new, 0x2 = cur */ int occult = 0; /* messages were removed from the mailbox */ int have_new = 0; /* messages were added to the mailbox */ struct maildir *md; /* list of messages in the mailbox */ struct maildir **last, *p; int i; HASH *fnames; /* hash table for quickly looking up the base filename for a maildir message */ /* XXX seems like this check belongs in mx_check_mailbox() * rather than here. */ if (!option (OPTCHECKNEW)) return 0; snprintf (buf, sizeof (buf), "%s/new", ctx->path); if (stat (buf, &st_new) == -1) return -1; snprintf (buf, sizeof (buf), "%s/cur", ctx->path); if (stat (buf, &st_cur) == -1) return -1; /* determine which subdirectories need to be scanned */ if (st_new.st_mtime > ctx->mtime) changed = 1; if (st_cur.st_mtime > ctx->mtime_cur) changed |= 2; if (!changed) return 0; /* nothing to do */ /* update the modification times on the mailbox */ ctx->mtime_cur = st_cur.st_mtime; ctx->mtime = st_new.st_mtime; /* do a fast scan of just the filenames in * the subdirectories that have changed. */ md = NULL; last = &md; if (changed & 1) maildir_parse_dir (ctx, &last, "new", NULL); if (changed & 2) maildir_parse_dir (ctx, &last, "cur", NULL); /* we create a hash table keyed off the canonical (sans flags) filename * of each message we scanned. This is used in the loop over the * existing messages below to do some correlation. */ fnames = hash_create (1031); for (p = md; p; p = p->next) { maildir_canon_filename (buf, p->h->path, sizeof (buf)); p->canon_fname = safe_strdup (buf); hash_insert (fnames, p->canon_fname, p, 0); } /* check for modifications and adjust flags */ for (i = 0; i < ctx->msgcount; i++) { ctx->hdrs[i]->active = 0; maildir_canon_filename (buf, ctx->hdrs[i]->path, sizeof (buf)); p = hash_find (fnames, buf); if (p && p->h) { /* message already exists, merge flags */ ctx->hdrs[i]->active = 1; /* check to see if the message has moved to a different * subdirectory. If so, update the associated filename. */ if (mutt_strcmp (ctx->hdrs[i]->path, p->h->path)) mutt_str_replace (&ctx->hdrs[i]->path, p->h->path); /* if the user hasn't modified the flags on this message, update * the flags we just detected. */ if (!ctx->hdrs[i]->changed) maildir_update_flags (ctx, ctx->hdrs[i], p->h); if (ctx->hdrs[i]->deleted == ctx->hdrs[i]->trash) ctx->hdrs[i]->deleted = p->h->deleted; ctx->hdrs[i]->trash = p->h->trash; /* this is a duplicate of an existing header, so remove it */ mutt_free_header (&p->h); } /* This message was not in the list of messages we just scanned. * Check to see if we have enough information to know if the * message has disappeared out from underneath us. */ else if (((changed & 1) && (!strncmp (ctx->hdrs[i]->path, "new/", 4))) || ((changed & 2) && (!strncmp (ctx->hdrs[i]->path, "cur/", 4)))) { /* This message disappeared, so we need to simulate a "reopen" * event. We know it disappeared because we just scanned the * subdirectory it used to reside in. */ occult = 1; } else { /* This message resides in a subdirectory which was not * modified, so we assume that it is still present and * unchanged. */ ctx->hdrs[i]->active = 1; } } /* destroy the file name hash */ hash_destroy (&fnames, NULL); /* If we didn't just get new mail, update the tables. */ if (occult) maildir_update_tables (ctx, index_hint); /* do any delayed parsing we need to do. */ maildir_delayed_parsing (ctx, md); /* Incorporate new messages */ have_new = maildir_move_to_context (ctx, &md); return occult ? M_REOPENED : (have_new ? M_NEW_MAIL : 0);}/* * This function handles arrival of new mail and reopening of * mh/maildir folders. Things are getting rather complex because we * don't have a well-defined "mailbox order", so the tricks from * mbox.c and mx.c won't work here. * * Don't change this code unless you _really_ understand what * happens. * */int mh_check_mailbox (CONTEXT * ctx, int *index_hint){ char buf[_POSIX_PATH_MAX]; struct stat st, st_cur; short modified = 0, have_new = 0, occult = 0; struct maildir *md, *p; struct maildir **last = NULL; struct mh_sequences mhs; HASH *fnames; int i; if (!option (OPTCHECKNEW)) return 0; strfcpy (buf, ctx->path, sizeof (buf)); if (stat (buf, &st) == -1) return -1; /* create .mh_sequences when there isn't one. */ snprintf (buf, sizeof (buf), "%s/.mh_sequences", ctx->path); if ((i = stat (buf, &st_cur) == -1) && errno == ENOENT) { char *tmp; FILE *fp = NULL; if (mh_mkstemp (ctx, &fp, &tmp) == 0) { safe_fclose (&fp); if (safe_rename (tmp, buf) == -1) unlink (tmp); FREE (&tmp); } } if (i == -1 && stat (buf, &st_cur) == -1) modified = 1; if (st.st_mtime > ctx->mtime || st_cur.st_mtime > ctx->mtime_cur) modified = 1; if (!modified) return 0; ctx->mtime_cur = st_cur.st_mtime; ctx->mtime = st.st_mtime; memset (&mhs, 0, sizeof (mhs)); md = NULL; last = &md; maildir_parse_dir (ctx, &last, NULL, NULL); mh_read_sequences (&mhs, ctx->path); mh_update_maildir (md, &mhs); mhs_free_sequences (&mhs); /* check for modifications and adjust flags */ fnames = hash_create (1031); for (p = md; p; p = p->next) hash_insert (fnames, p->h->path, p, 0); for (i = 0; i < ctx->msgcount; i++) { ctx->hdrs[i]->active = 0; if ((p = hash_find (fnames, ctx->hdrs[i]->path)) && p->h && (mbox_strict_cmp_headers (ctx->hdrs[i], p->h))) { ctx->hdrs[i]->active = 1; /* found the right message */ if (!ctx->hdrs[i]->changed) maildir_update_flags (ctx, ctx->hdrs[i], p->h); mutt_free_header (&p->h); } else /* message has disappeared */ occult = 1; } /* destroy the file name hash */ hash_destroy (&fnames, NULL); /* If we didn't just get new mail, update the tables. */ if (occult) maildir_update_tables (ctx, index_hint); /* Incorporate new messages */ have_new = maildir_move_to_context (ctx, &md); return occult ? M_REOPENED : (have_new ? M_NEW_MAIL : 0);}/* * These functions try to find a message in a maildir folder when it * has moved under our feet. Note that this code is rather expensive, but * then again, it's called rarely. */FILE *_maildir_open_find_message (const char *folder, const char *unique, const char *subfolder){ char dir[_POSIX_PATH_MAX]; char tunique[_POSIX_PATH_MAX]; char fname[_POSIX_PATH_MAX]; DIR *dp; struct dirent *de; FILE *fp = NULL; int oe = ENOENT; snprintf (dir, sizeof (dir), "%s/%s", folder, subfolder); if ((dp = opendir (dir)) == NULL) { errno = ENOENT; return NULL; } while ((de = readdir (dp))) { maildir_canon_filename (tunique, de->d_name, sizeof (tunique)); if (!mutt_strcmp (tunique, unique)) { snprintf (fname, sizeof (fname), "%s/%s/%s", folder, subfolder, de->d_name); fp = fopen (fname, "r"); /* __FOPEN_CHECKED__ */ oe = errno; break; } } closedir (dp); errno = oe; return fp;}FILE *maildir_open_find_message (const char *folder, const char *msg){ char unique[_POSIX_PATH_MAX]; FILE *fp; static unsigned int new_hits = 0, cur_hits = 0; /* simple dynamic optimization */ maildir_canon_filename (unique, msg, sizeof (unique)); if ( (fp = _maildir_open_find_message (folder, unique, new_hits > cur_hits ? "new" : "cur")) || errno != ENOENT) { if (new_hits < UINT_MAX && cur_hits < UINT_MAX) { new_hits += (new_hits > cur_hits ? 1 : 0); cur_hits += (new_hits > cur_hits ? 0 : 1); } return fp; } if ( (fp = _maildir_open_find_message (folder, unique, new_hits > cur_hits ? "cur" : "new")) || errno != ENOENT) { if (new_hits < UINT_MAX && cur_hits < UINT_MAX) { new_hits += (new_hits > cur_hits ? 0 : 1); cur_hits += (new_hits > cur_hits ? 1 : 0); } return fp; } return NULL;}/* * Returns: * 1 if there are no messages in the mailbox * 0 if there are messages in the mailbox * -1 on error */int maildir_check_empty (const char *path){ DIR *dp; struct dirent *de; int r = 1; /* assume empty until we find a message */ char realpath[_POSIX_PATH_MAX]; int iter = 0; /* Strategy here is to look for any file not beginning with a period */ do { /* we do "cur" on the first iteration since its more likely that we'll * find old messages without having to scan both subdirs */ snprintf (realpath, sizeof (realpath), "%s/%s", path, iter == 0 ? "cur" : "new"); if ((dp = opendir (realpath)) == NULL) return -1; while ((de = readdir (dp))) { if (*de->d_name != '.') { r = 0; break; } } closedir (dp); iter++; } while (r && iter < 2); return r;}/* * Returns: * 1 if there are no messages in the mailbox * 0 if there are messages in the mailbox * -1 on error */int mh_check_empty (const char *path){ DIR *dp; struct dirent *de; int r = 1; /* assume empty until we find a message */ if ((dp = opendir (path)) == NULL) return -1; while ((de = readdir (dp))) { if (mh_valid_message (de->d_name)) { r = 0; break; } } closedir (dp); return r;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -