enriched.o enter.o filter.o flags.o from.o group.o handler.o \
hdrline.o header.o help.o history.o hook.o init.o keymap.o \
main.o mbox.o menu.o mh.o muttlib.o mutt_account.o mutt_attach.o mutt_body.o \
- mutt_logging.o mutt_signal.o mutt_socket.o mutt_window.o mx.o newsrc.o \
+ mutt_logging.o mutt_signal.o mutt_socket.o mutt_thread.o mutt_window.o mx.o newsrc.o \
nntp.o pager.o parse.o pattern.o pop.o pop_auth.o pop_lib.o \
postpone.o progress.o query.o recvattach.o recvcmd.o resize.o rfc1524.o \
rfc2047.o rfc2231.o rfc3676.o safe_asprintf.o score.o send.o \
sendlib.o sidebar.o smtp.o sort.o state.o status.o system.o \
- terminal.o thread.o url.o version.o
+ terminal.o url.o version.o
@if !HAVE_WCSCASECMP
NEOMUTTOBJS+= wcscasecmp.o
mutt/idna.o mutt/list.o mutt/logging.o mutt/mapping.o \
mutt/mbyte.o mutt/md5.o mutt/memory.o mutt/mime.o \
mutt/parameter.o mutt/regex.o mutt/rfc2047.o mutt/sha1.o \
- mutt/signal.o mutt/string.o mutt/tags.o
+ mutt/signal.o mutt/string.o mutt/tags.o mutt/thread.o
CLEANFILES+= $(LIBMUTT) $(LIBMUTTOBJS)
MUTTLIBS+= $(LIBMUTT)
ALLOBJS+= $(LIBMUTTOBJS)
#include "mailbox.h"
#include "mutt_curses.h"
#include "mutt_menu.h"
+#include "mutt_thread.h"
#include "mutt_window.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "protos.h"
#include "sort.h"
#include "terminal.h"
-#include "thread.h"
#ifdef USE_SIDEBAR
#include "sidebar.h"
#endif
#include "options.h"
#include "protos.h"
#include "sort.h"
-#include "thread.h"
/**
* mutt_set_flag_update - Set a flag on an email
#include "header.h"
#include "mbtable.h"
#include "mutt_curses.h"
+#include "mutt_thread.h"
#include "mutt_window.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "protos.h"
#include "sort.h"
-#include "thread.h"
/**
* enum FlagChars - Index into the FlagChars variable ($flag_chars)
#include "header.h"
#include "mailbox.h"
#include "mutt_curses.h"
+#include "mutt_thread.h"
#include "mx.h"
#include "options.h"
#include "progress.h"
#include "protos.h"
#include "sort.h"
-#include "thread.h"
/**
* struct MUpdate - Store of new offsets, used by mutt_sync_mailbox()
#include "header.h"
#include "mailbox.h"
#include "mutt_curses.h"
+#include "mutt_thread.h"
#include "mx.h"
#include "options.h"
#include "progress.h"
#include "protos.h"
#include "sort.h"
-#include "thread.h"
#ifdef USE_NOTMUCH
#include "mutt_notmuch.h"
#endif
* | mutt/signal.c | @subpage signal |
* | mutt/string.c | @subpage string |
* | mutt/tags.c | @subpage tags |
+ * | mutt/thread.c | @subpage thread |
*
* @note The library is self-contained -- some files may depend on others in
* the library, but none depends on source from outside.
#include "signal2.h"
#include "string2.h"
#include "tags.h"
+#include "thread.h"
#endif /* _MUTT_MUTT_H */
--- /dev/null
+/**
+ * @file
+ * Create/manipulate threading in emails
+ *
+ * @authors
+ * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org>
+ *
+ * @copyright
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @page thread Create/manipulate threading in emails
+ *
+ * Create/manipulate threading in emails
+ */
+
+#include "config.h"
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "header.h"
+
+/**
+ * is_descendant - Is one thread a descendant of another
+ * @param a Parent thread
+ * @param b Child thread
+ * @retval 1 If b is a descendent of a (child, grandchild, etc)
+ */
+int is_descendant(struct MuttThread *a, struct MuttThread *b)
+{
+ while (a)
+ {
+ if (a == b)
+ return 1;
+ a = a->parent;
+ }
+ return 0;
+}
+
+/**
+ * unlink_message - Break the message out of the thread
+ * @param[in,out] old Root of thread
+ * @param[in] cur Child thread to separate
+ *
+ * Remove cur and its descendants from their current location. Also make sure
+ * ancestors of cur no longer are sorted by the fact that cur is their
+ * descendant.
+ */
+void unlink_message(struct MuttThread **old, struct MuttThread *cur)
+{
+ struct MuttThread *tmp = NULL;
+
+ if (cur->prev)
+ cur->prev->next = cur->next;
+ else
+ *old = cur->next;
+
+ if (cur->next)
+ cur->next->prev = cur->prev;
+
+ if (cur->sort_key)
+ {
+ for (tmp = cur->parent; tmp && tmp->sort_key == cur->sort_key; tmp = tmp->parent)
+ tmp->sort_key = NULL;
+ }
+}
+
+/**
+ * insert_message - Insert a message into a thread
+ * @param[in,out] new New thread to add
+ * @param[in] newparent Parent of new thread
+ * @param[in] cur Current thread to add after
+ *
+ * add cur as a prior sibling of *new, with parent newparent
+ */
+void insert_message(struct MuttThread **new, struct MuttThread *newparent,
+ struct MuttThread *cur)
+{
+ if (*new)
+ (*new)->prev = cur;
+
+ cur->parent = newparent;
+ cur->next = *new;
+ cur->prev = NULL;
+ *new = cur;
+}
+
+/**
+ * thread_hash_destructor - Hash Destructor callback
+ * @param type Hash Type
+ * @param obj Object to free
+ * @param data Data associated with the Hash
+ */
+void thread_hash_destructor(int type, void *obj, intptr_t data)
+{
+ FREE(&obj);
+}
+
+/**
+ * find_virtual - Find an email with a Virtual message number
+ * @param cur Thread to search
+ * @param reverse If true, reverse the direction of the search
+ * @retval ptr Matching Header
+ */
+struct Header *find_virtual(struct MuttThread *cur, int reverse)
+{
+ struct MuttThread *top = NULL;
+
+ if (cur->message && cur->message->virtual >= 0)
+ return cur->message;
+
+ top = cur;
+ cur = cur->child;
+ if (!cur)
+ return NULL;
+
+ while (reverse && cur->next)
+ cur = cur->next;
+
+ while (true)
+ {
+ 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 */
+ }
+}
+
+/**
+ * clean_references - Update email references for a broken Thread
+ * @param brk Broken thread
+ * @param cur Current thread
+ */
+void clean_references(struct MuttThread *brk, struct MuttThread *cur)
+{
+ struct ListNode *ref = NULL;
+ bool done = false;
+
+ for (; cur; cur = cur->next, done = false)
+ {
+ /* 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 NeoMutt stores the references in reverse order, and the
+ * first loop should match immediately for mails respecting RFC2822. */
+ for (struct MuttThread *p = brk; !done && p; p = p->parent)
+ {
+ for (ref = STAILQ_FIRST(&cur->message->env->references);
+ p->message && ref; ref = STAILQ_NEXT(ref, entries))
+ {
+ if (mutt_str_strcasecmp(ref->data, p->message->env->message_id) == 0)
+ {
+ done = true;
+ break;
+ }
+ }
+ }
+
+ if (done)
+ {
+ struct Header *h = cur->message;
+
+ /* clearing the References: header from obsolete Message-ID(s) */
+ struct ListNode *np;
+ while ((np = STAILQ_NEXT(ref, entries)) != NULL)
+ {
+ STAILQ_REMOVE_AFTER(&cur->message->env->references, ref, entries);
+ FREE(&np->data);
+ FREE(&np);
+ }
+
+ h->env->refs_changed = h->changed = true;
+ }
+ }
+}
+
+/**
+ * mutt_break_thread - Break the email Thread
+ * @param hdr Email Header to break at
+ */
+void mutt_break_thread(struct Header *hdr)
+{
+ mutt_list_free(&hdr->env->in_reply_to);
+ mutt_list_free(&hdr->env->references);
+ hdr->env->irt_changed = hdr->env->refs_changed = hdr->changed = true;
+
+ clean_references(hdr->thread, hdr->thread->child);
+}
--- /dev/null
+/**
+ * @file
+ * Create/manipulate threading in emails
+ *
+ * @authors
+ * Copyright (C) 2017 Richard Russon <rich@flatcap.org>
+ *
+ * @copyright
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _MUTT_THREAD_H
+#define _MUTT_THREAD_H
+
+#include <stdbool.h>
+#include "mutt.h"
+
+struct Context;
+struct Header;
+
+/**
+ * struct MuttThread - An email conversation
+ */
+struct MuttThread
+{
+ bool fake_thread : 1;
+ bool duplicate_thread : 1;
+ bool sort_children : 1;
+ bool check_subject : 1;
+ bool visible : 1;
+ bool deep : 1;
+ unsigned int subtree_visible : 2;
+ bool next_subtree_visible : 1;
+ struct MuttThread *parent;
+ struct MuttThread *child;
+ struct MuttThread *next;
+ struct MuttThread *prev;
+ struct Header *message;
+ struct Header *sort_key;
+};
+
+void clean_references(struct MuttThread *brk, struct MuttThread *cur);
+struct Header *find_virtual(struct MuttThread *cur, int reverse);
+void insert_message(struct MuttThread **new, struct MuttThread *newparent, struct MuttThread *cur);
+int is_descendant(struct MuttThread *a, struct MuttThread *b);
+void mutt_break_thread(struct Header *hdr);
+void thread_hash_destructor(int type, void *obj, intptr_t data);
+void unlink_message(struct MuttThread **old, struct MuttThread *cur);
+
+#endif /* _MUTT_THREAD_H */
#include "header.h"
#include "mailbox.h"
#include "mutt_curses.h"
+#include "mutt_thread.h"
#include "mx.h"
#include "progress.h"
#include "protos.h"
-#include "thread.h"
#include "url.h"
#ifdef LIBNOTMUCH_CHECK_VERSION
#include <time.h>
#include "mutt/mutt.h"
#include "mutt.h"
-#include "thread.h"
+#include "mutt_thread.h"
#include "context.h"
#include "globals.h"
#include "header.h"
return (hdr->virtual >= 0 || (hdr->collapsed && (!ctx->pattern || hdr->limited)));
}
-/**
- * is_descendant - Is one thread a descendant of another
- */
-static int is_descendant(struct MuttThread *a, struct MuttThread *b)
-{
- while (a)
- {
- if (a == b)
- return 1;
- a = a->parent;
- }
- return 0;
-}
-
/**
* need_display_subject - Determines whether to display a message's subject
*/
return last;
}
-/**
- * unlink_message - Break the message out of the thread
- *
- * Remove cur and its descendants from their current location. Also make sure
- * ancestors of cur no longer are sorted by the fact that cur is their
- * descendant.
- */
-static void unlink_message(struct MuttThread **old, struct MuttThread *cur)
-{
- struct MuttThread *tmp = NULL;
-
- if (cur->prev)
- cur->prev->next = cur->next;
- else
- *old = cur->next;
-
- if (cur->next)
- cur->next->prev = cur->prev;
-
- if (cur->sort_key)
- {
- for (tmp = cur->parent; tmp && tmp->sort_key == cur->sort_key; tmp = tmp->parent)
- tmp->sort_key = NULL;
- }
-}
-
-/**
- * insert_message - Insert a message into a thread
- *
- * add cur as a prior sibling of *new, with parent newparent
- */
-static void insert_message(struct MuttThread **new,
- struct MuttThread *newparent, struct MuttThread *cur)
-{
- if (*new)
- (*new)->prev = cur;
-
- cur->parent = newparent;
- cur->next = *new;
- cur->prev = NULL;
- *new = cur;
-}
-
static struct Hash *make_subj_hash(struct Context *ctx)
{
struct Hash *hash = mutt_hash_create(ctx->msgcount * 2, MUTT_HASH_ALLOW_DUPS);
}
}
-void thread_hash_destructor(int type, void *obj, intptr_t data)
-{
- FREE(&obj);
-}
-
void mutt_sort_threads(struct Context *ctx, int init)
{
struct Header *cur = NULL;
}
}
-static struct Header *find_virtual(struct MuttThread *cur, int reverse)
-{
- struct MuttThread *top = NULL;
-
- if (cur->message && cur->message->virtual >= 0)
- return cur->message;
-
- top = cur;
- cur = cur->child;
- if (!cur)
- return NULL;
-
- while (reverse && cur->next)
- cur = cur->next;
-
- while (true)
- {
- 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 */
- }
-}
-
/**
* mutt_aside_thread - Find the next/previous (sub)thread
* @param hdr Search from this message
return hash;
}
-static void clean_references(struct MuttThread *brk, struct MuttThread *cur)
-{
- struct ListNode *ref = NULL;
- bool done = false;
-
- for (; cur; cur = cur->next, done = false)
- {
- /* 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 NeoMutt stores the references in reverse order, and the
- * first loop should match immediately for mails respecting RFC2822. */
- for (struct MuttThread *p = brk; !done && p; p = p->parent)
- {
- for (ref = STAILQ_FIRST(&cur->message->env->references);
- p->message && ref; ref = STAILQ_NEXT(ref, entries))
- {
- if (mutt_str_strcasecmp(ref->data, p->message->env->message_id) == 0)
- {
- done = true;
- break;
- }
- }
- }
-
- if (done)
- {
- struct Header *h = cur->message;
-
- /* clearing the References: header from obsolete Message-ID(s) */
- struct ListNode *np;
- while ((np = STAILQ_NEXT(ref, entries)) != NULL)
- {
- STAILQ_REMOVE_AFTER(&cur->message->env->references, ref, entries);
- FREE(&np->data);
- FREE(&np);
- }
-
- h->env->refs_changed = h->changed = true;
- }
- }
-}
-
-void mutt_break_thread(struct Header *hdr)
-{
- mutt_list_free(&hdr->env->in_reply_to);
- mutt_list_free(&hdr->env->references);
- hdr->env->irt_changed = hdr->env->refs_changed = hdr->changed = true;
-
- clean_references(hdr->thread, hdr->thread->child);
-}
-
static bool link_threads(struct Header *parent, struct Header *child, struct Context *ctx)
{
if (child == parent)
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _MUTT_THREAD_H
-#define _MUTT_THREAD_H
+#ifndef _MUTT_THREAD2_H
+#define _MUTT_THREAD2_H
#include <stdbool.h>
#include "mutt.h"
-struct Context;
-struct Header;
-
-/**
- * struct MuttThread - An email conversation
- */
-struct MuttThread
-{
- bool fake_thread : 1;
- bool duplicate_thread : 1;
- bool sort_children : 1;
- bool check_subject : 1;
- bool visible : 1;
- bool deep : 1;
- unsigned int subtree_visible : 2;
- bool next_subtree_visible : 1;
- struct MuttThread *parent;
- struct MuttThread *child;
- struct MuttThread *next;
- struct MuttThread *prev;
- struct Header *message;
- struct Header *sort_key;
-};
-
int mutt_aside_thread(struct Header *hdr, short dir, short subthreads);
#define mutt_next_thread(x) mutt_aside_thread(x, 1, 0)
#define mutt_previous_thread(x) mutt_aside_thread(x, 0, 0)
#define mutt_thread_contains_flagged(x, y) mutt_traverse_thread(x, y, MUTT_THREAD_FLAGGED)
#define mutt_thread_next_unread(x, y) mutt_traverse_thread(x, y, MUTT_THREAD_NEXT_UNREAD)
-void mutt_break_thread(struct Header *hdr);
int mutt_link_threads(struct Header *cur, struct Header *last, struct Context *ctx);
int mutt_messages_in_thread(struct Context *ctx, struct Header *hdr, int flag);
void mutt_draw_tree(struct Context *ctx);
void mutt_set_virtual(struct Context *ctx);
struct Hash *mutt_make_id_hash(struct Context *ctx);
-#endif /* _MUTT_THREAD_H */
+#endif /* _MUTT_THREAD2_H */
#include "header.h"
#include "keymap.h"
#include "mailbox.h"
+#include "mutt_thread.h"
#include "ncrypt/ncrypt.h"
#include "opcodes.h"
#include "options.h"
#include "pattern.h"
#include "protos.h"
#include "sort.h"
-#include "thread.h"
#include "url.h"
#ifdef USE_SIDEBAR
#include "sidebar.h"
#include "mutt_curses.h"
#include "mutt_logging.h"
#include "mutt_socket.h"
+#include "mutt_thread.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "progress.h"
#include "protos.h"
-#include "thread.h"
#include "url.h"
#ifdef USE_HCACHE
#include "hcache/hcache.h"
#include "progress.h"
#include "protos.h"
#include "state.h"
-#include "thread.h"
#ifdef USE_IMAP
#include "imap/imap.h"
#endif
mutt/signal.c
mutt/string.c
mutt/tags.c
+mutt/thread.c
mutt_account.c
mutt_attach.c
mutt_body.c
mutt_notmuch.c
mutt_signal.c
mutt_socket.c
+mutt_thread.c
mutt_window.c
muttlib.c
mx.c
#include "keymap.h"
#include "mailbox.h"
#include "mutt_menu.h"
+#include "mutt_thread.h"
#include "ncrypt/ncrypt.h"
#include "opcodes.h"
#include "options.h"
#include "protos.h"
#include "sort.h"
#include "state.h"
-#include "thread.h"
#ifdef USE_IMAP
#include "imap/imap.h"
#endif
#include "context.h"
#include "globals.h"
#include "header.h"
+#include "mutt_thread.h"
#include "options.h"
#include "protos.h"
-#include "thread.h"
#ifdef USE_NNTP
#include "mx.h"
#include "nntp.h"