📄 thread.c
字号:
ctx->tree = top.child; check_subjects (ctx, init); if (!option (OPTSTRICTTHREADS)) pseudo_threads (ctx); if (ctx->tree) { ctx->tree = mutt_sort_subthreads (ctx->tree, init); /* restore the oldsort order. */ Sort = oldsort; /* Put the list into an array. */ linearize_tree (ctx); /* Draw the thread tree. */ mutt_draw_tree (ctx); }}static HEADER *find_virtual (THREAD *cur, int reverse){ THREAD *top; if (cur->message && cur->message->virtual >= 0) return (cur->message); top = cur; if ((cur = cur->child) == NULL) return (NULL); while (reverse && cur->next) cur = cur->next; FOREVER { if (cur->message && cur->message->virtual >= 0) return (cur->message); if (cur->child) { cur = cur->child; while (reverse && cur->next) cur = cur->next; } else if (reverse ? cur->prev : cur->next) cur = reverse ? cur->prev : cur->next; else { while (!(reverse ? cur->prev : cur->next)) { cur = cur->parent; if (cur == top) return (NULL); } cur = reverse ? cur->prev : cur->next; } /* not reached */ }}int _mutt_aside_thread (HEADER *hdr, short dir, short subthreads){ THREAD *cur; HEADER *tmp; if ((Sort & SORT_MASK) != SORT_THREADS) { mutt_error _("Threading is not enabled."); return (hdr->virtual); } cur = hdr->thread; if (!subthreads) { while (cur->parent) cur = cur->parent; } else { if ((dir != 0) ^ ((Sort & SORT_REVERSE) != 0)) { while (!cur->next && cur->parent) cur = cur->parent; } else { while (!cur->prev && cur->parent) cur = cur->parent; } } if ((dir != 0) ^ ((Sort & SORT_REVERSE) != 0)) { do { cur = cur->next; if (!cur) return (-1); tmp = find_virtual (cur, 0); } while (!tmp); } else { do { cur = cur->prev; if (!cur) return (-1); tmp = find_virtual (cur, 1); } while (!tmp); } return (tmp->virtual);}int mutt_parent_message (CONTEXT *ctx, HEADER *hdr){ THREAD *thread; if ((Sort & SORT_MASK) != SORT_THREADS) { mutt_error _("Threading is not enabled."); return (hdr->virtual); } for (thread = hdr->thread->parent; thread; thread = thread->parent) { if ((hdr = thread->message) != NULL) { if (VISIBLE (hdr, ctx)) return (hdr->virtual); else { mutt_error _("Parent message is not visible in this limited view."); return (-1); } } } mutt_error _("Parent message is not available."); return (-1);}void mutt_set_virtual (CONTEXT *ctx){ int i; HEADER *cur; ctx->vcount = 0; ctx->vsize = 0; for (i = 0; i < ctx->msgcount; i++) { cur = ctx->hdrs[i]; if (cur->virtual >= 0) { cur->virtual = ctx->vcount; ctx->v2r[ctx->vcount] = i; ctx->vcount++; ctx->vsize += cur->content->length + cur->content->offset - cur->content->hdr_offset; cur->num_hidden = mutt_get_hidden (ctx, cur); } }}int _mutt_traverse_thread (CONTEXT *ctx, HEADER *cur, int flag){ THREAD *thread, *top; HEADER *roothdr = NULL; int final, reverse = (Sort & SORT_REVERSE), minmsgno; int num_hidden = 0, new = 0, old = 0; int min_unread_msgno = INT_MAX, min_unread = cur->virtual;#define CHECK_LIMIT (!ctx->pattern || cur->limited) if ((Sort & SORT_MASK) != SORT_THREADS && !(flag & M_THREAD_GET_HIDDEN)) { mutt_error (_("Threading is not enabled.")); return (cur->virtual); } final = cur->virtual; thread = cur->thread; while (thread->parent) thread = thread->parent; top = thread; while (!thread->message) thread = thread->child; cur = thread->message; minmsgno = cur->msgno; if (!cur->read && CHECK_LIMIT) { if (cur->old) old = 2; else new = 1; if (cur->msgno < min_unread_msgno) { min_unread = cur->virtual; min_unread_msgno = cur->msgno; } } if (cur->virtual == -1 && CHECK_LIMIT) num_hidden++; if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) { cur->pair = 0; /* force index entry's color to be re-evaluated */ cur->collapsed = flag & M_THREAD_COLLAPSE; if (cur->virtual != -1) { roothdr = cur; if (flag & M_THREAD_COLLAPSE) final = roothdr->virtual; } } if (thread == top && (thread = thread->child) == NULL) { /* return value depends on action requested */ if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) return (final); else if (flag & M_THREAD_UNREAD) return ((old && new) ? new : (old ? old : new)); else if (flag & M_THREAD_GET_HIDDEN) return (num_hidden); else if (flag & M_THREAD_NEXT_UNREAD) return (min_unread); } FOREVER { cur = thread->message; if (cur) { if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) { cur->pair = 0; /* force index entry's color to be re-evaluated */ cur->collapsed = flag & M_THREAD_COLLAPSE; if (!roothdr && CHECK_LIMIT) { roothdr = cur; if (flag & M_THREAD_COLLAPSE) final = roothdr->virtual; } if (reverse && (flag & M_THREAD_COLLAPSE) && (cur->msgno < minmsgno) && CHECK_LIMIT) { minmsgno = cur->msgno; final = cur->virtual; } if (flag & M_THREAD_COLLAPSE) { if (cur != roothdr) cur->virtual = -1; } else { if (CHECK_LIMIT) cur->virtual = cur->msgno; } } if (!cur->read && CHECK_LIMIT) { if (cur->old) old = 2; else new = 1; if (cur->msgno < min_unread_msgno) { min_unread = cur->virtual; min_unread_msgno = cur->msgno; } } if (cur->virtual == -1 && CHECK_LIMIT) num_hidden++; } if (thread->child) thread = thread->child; else if (thread->next) thread = thread->next; else { int done = 0; while (!thread->next) { thread = thread->parent; if (thread == top) { done = 1; break; } } if (done) break; thread = thread->next; } } /* return value depends on action requested */ if (flag & (M_THREAD_COLLAPSE | M_THREAD_UNCOLLAPSE)) return (final); else if (flag & M_THREAD_UNREAD) return ((old && new) ? new : (old ? old : new)); else if (flag & M_THREAD_GET_HIDDEN) return (num_hidden+1); else if (flag & M_THREAD_NEXT_UNREAD) return (min_unread); return (0);#undef CHECK_LIMIT}/* if flag is 0, we want to know how many messages * are in the thread. if flag is 1, we want to know * our position in the thread. */int mutt_messages_in_thread (CONTEXT *ctx, HEADER *hdr, int flag){ THREAD *threads[2]; int i, rc; if ((Sort & SORT_MASK) != SORT_THREADS || !hdr->thread) return (1); threads[0] = hdr->thread; while (threads[0]->parent) threads[0] = threads[0]->parent; threads[1] = flag ? hdr->thread : threads[0]->next; for (i = 0; i < ((flag || !threads[1]) ? 1 : 2); i++) { while (!threads[i]->message) threads[i] = threads[i]->child; } if (Sort & SORT_REVERSE) rc = threads[0]->message->msgno - (threads[1] ? threads[1]->message->msgno : -1); else rc = (threads[1] ? threads[1]->message->msgno : ctx->msgcount) - threads[0]->message->msgno; if (flag) rc += 1; return (rc);}HASH *mutt_make_id_hash (CONTEXT *ctx){ int i; HEADER *hdr; HASH *hash; hash = hash_create (ctx->msgcount * 2); for (i = 0; i < ctx->msgcount; i++) { hdr = ctx->hdrs[i]; if (hdr->env->message_id) hash_insert (hash, hdr->env->message_id, hdr, 0); } return hash;}HASH *mutt_make_subj_hash (CONTEXT *ctx){ int i; HEADER *hdr; HASH *hash; hash = hash_create (ctx->msgcount * 2); for (i = 0; i < ctx->msgcount; i++) { hdr = ctx->hdrs[i]; if (hdr->env->real_subj) hash_insert (hash, hdr->env->real_subj, hdr, 1); } return hash;}static void clean_references (THREAD *brk, THREAD *cur){ THREAD *p; LIST *ref = NULL; int done = 0; for (; cur; cur = cur->next, done = 0) { /* parse subthread recursively */ clean_references (brk, cur->child); if (!cur->message) break; /* skip pseudo-message */ /* Looking for the first bad reference according to the new threading. * Optimal since Mutt stores the references in reverse order, and the * first loop should match immediatly for mails respecting RFC2822. */ for (p = brk; !done && p; p = p->parent) for (ref = cur->message->env->references; p->message && ref; ref = ref->next) if (!mutt_strcasecmp (ref->data, p->message->env->message_id)) { done = 1; break; } if (done) { HEADER *h = cur->message; /* clearing the References: header from obsolete Message-ID(s) */ mutt_free_list (&ref->next); h->env->refs_changed = h->changed = 1; } }}void mutt_break_thread (HEADER *hdr){ mutt_free_list (&hdr->env->in_reply_to); mutt_free_list (&hdr->env->references); hdr->env->irt_changed = hdr->env->refs_changed = hdr->changed = 1; clean_references (hdr->thread, hdr->thread->child);}static int link_threads (HEADER *parent, HEADER *child, CONTEXT *ctx){ if (child == parent) return 0; mutt_break_thread (child); child->env->in_reply_to = mutt_new_list (); child->env->in_reply_to->data = safe_strdup (parent->env->message_id); mutt_set_flag (ctx, child, M_TAG, 0); child->env->irt_changed = child->changed = 1; return 1;}int mutt_link_threads (HEADER *cur, HEADER *last, CONTEXT *ctx){ int i, changed = 0; if (!last) { for (i = 0; i < ctx->vcount; i++) if (ctx->hdrs[Context->v2r[i]]->tagged) changed |= link_threads (cur, ctx->hdrs[Context->v2r[i]], ctx); } else changed = link_threads (cur, last, ctx); return changed;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -