From 894a91578e52c750bdb17abd0ecfed676561b656 Mon Sep 17 00:00:00 2001 From: Richard Russon Date: Tue, 3 Jul 2018 17:55:23 +0100 Subject: [PATCH] move MuttThread to library --- Makefile.autosetup | 6 +- curs_main.c | 2 +- flags.c | 1 - hdrline.c | 2 +- mbox.c | 2 +- mh.c | 2 +- mutt/mutt.h | 2 + mutt/thread.c | 225 ++++++++++++++++++++++++++++++++++++++ mutt/thread.h | 61 +++++++++++ mutt_notmuch.c | 2 +- thread.c => mutt_thread.c | 163 +-------------------------- thread.h => mutt_thread.h | 31 +----- mx.c | 2 +- nntp.c | 2 +- pattern.c | 1 - po/POTFILES.in | 2 + postpone.c | 2 +- sort.c | 2 +- 18 files changed, 306 insertions(+), 204 deletions(-) create mode 100644 mutt/thread.c create mode 100644 mutt/thread.h rename thread.c => mutt_thread.c (90%) rename thread.h => mutt_thread.h (79%) diff --git a/Makefile.autosetup b/Makefile.autosetup index e7e38e0ef..e62029ffa 100644 --- a/Makefile.autosetup +++ b/Makefile.autosetup @@ -67,12 +67,12 @@ NEOMUTTOBJS= addrbook.o alias.o bcache.o browser.o buffy.o \ 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 @@ -97,7 +97,7 @@ LIBMUTTOBJS= mutt/address.o mutt/attach.o mutt/base64.o mutt/body.o mutt/buffer. 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) diff --git a/curs_main.c b/curs_main.c index 94b695150..4718086d9 100644 --- a/curs_main.c +++ b/curs_main.c @@ -41,6 +41,7 @@ #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" @@ -52,7 +53,6 @@ #include "protos.h" #include "sort.h" #include "terminal.h" -#include "thread.h" #ifdef USE_SIDEBAR #include "sidebar.h" #endif diff --git a/flags.c b/flags.c index fd13bbfe5..b54a3dcc5 100644 --- a/flags.c +++ b/flags.c @@ -41,7 +41,6 @@ #include "options.h" #include "protos.h" #include "sort.h" -#include "thread.h" /** * mutt_set_flag_update - Set a flag on an email diff --git a/hdrline.c b/hdrline.c index 947312d33..8dc0a2099 100644 --- a/hdrline.c +++ b/hdrline.c @@ -37,12 +37,12 @@ #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) diff --git a/mbox.c b/mbox.c index bfa9f1b28..cb032c80f 100644 --- a/mbox.c +++ b/mbox.c @@ -41,12 +41,12 @@ #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() diff --git a/mh.c b/mh.c index 7bd48e05b..9a89ea663 100644 --- a/mh.c +++ b/mh.c @@ -47,12 +47,12 @@ #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 diff --git a/mutt/mutt.h b/mutt/mutt.h index 929a2f134..fb4e8c794 100644 --- a/mutt/mutt.h +++ b/mutt/mutt.h @@ -54,6 +54,7 @@ * | 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. @@ -92,5 +93,6 @@ #include "signal2.h" #include "string2.h" #include "tags.h" +#include "thread.h" #endif /* _MUTT_MUTT_H */ diff --git a/mutt/thread.c b/mutt/thread.c new file mode 100644 index 000000000..260f7ae76 --- /dev/null +++ b/mutt/thread.c @@ -0,0 +1,225 @@ +/** + * @file + * Create/manipulate threading in emails + * + * @authors + * Copyright (C) 1996-2002 Michael R. Elkins + * + * @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 . + */ + +/** + * @page thread Create/manipulate threading in emails + * + * Create/manipulate threading in emails + */ + +#include "config.h" +#include +#include +#include +#include +#include +#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); +} diff --git a/mutt/thread.h b/mutt/thread.h new file mode 100644 index 000000000..80122493a --- /dev/null +++ b/mutt/thread.h @@ -0,0 +1,61 @@ +/** + * @file + * Create/manipulate threading in emails + * + * @authors + * Copyright (C) 2017 Richard Russon + * + * @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 . + */ + +#ifndef _MUTT_THREAD_H +#define _MUTT_THREAD_H + +#include +#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 */ diff --git a/mutt_notmuch.c b/mutt_notmuch.c index 6d45e40af..86e5945d2 100644 --- a/mutt_notmuch.c +++ b/mutt_notmuch.c @@ -56,10 +56,10 @@ #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 diff --git a/thread.c b/mutt_thread.c similarity index 90% rename from thread.c rename to mutt_thread.c index fa05913f0..247321217 100644 --- a/thread.c +++ b/mutt_thread.c @@ -28,7 +28,7 @@ #include #include "mutt/mutt.h" #include "mutt.h" -#include "thread.h" +#include "mutt_thread.h" #include "context.h" #include "globals.h" #include "header.h" @@ -41,20 +41,6 @@ static bool is_visible(struct Header *hdr, struct Context *ctx) 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 */ @@ -467,49 +453,6 @@ static struct MuttThread *find_subject(struct Context *ctx, struct MuttThread *c 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); @@ -790,11 +733,6 @@ static void check_subjects(struct Context *ctx, int init) } } -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; @@ -1026,49 +964,6 @@ void mutt_sort_threads(struct Context *ctx, int init) } } -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 @@ -1414,62 +1309,6 @@ struct Hash *mutt_make_id_hash(struct Context *ctx) 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) diff --git a/thread.h b/mutt_thread.h similarity index 79% rename from thread.h rename to mutt_thread.h index b5f0d676e..8e982fb88 100644 --- a/thread.h +++ b/mutt_thread.h @@ -20,36 +20,12 @@ * this program. If not, see . */ -#ifndef _MUTT_THREAD_H -#define _MUTT_THREAD_H +#ifndef _MUTT_THREAD2_H +#define _MUTT_THREAD2_H #include #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) @@ -64,7 +40,6 @@ int mutt_traverse_thread(struct Context *ctx, struct Header *cur, int flag); #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); @@ -76,4 +51,4 @@ int mutt_parent_message(struct Context *ctx, struct Header *hdr, int find_root); void mutt_set_virtual(struct Context *ctx); struct Hash *mutt_make_id_hash(struct Context *ctx); -#endif /* _MUTT_THREAD_H */ +#endif /* _MUTT_THREAD2_H */ diff --git a/mx.c b/mx.c index 80fd481cf..185109897 100644 --- a/mx.c +++ b/mx.c @@ -46,13 +46,13 @@ #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" diff --git a/nntp.c b/nntp.c index 2f4bd1d5a..fdc2e05ef 100644 --- a/nntp.c +++ b/nntp.c @@ -47,12 +47,12 @@ #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" diff --git a/pattern.c b/pattern.c index 14c292024..a19d6b66f 100644 --- a/pattern.c +++ b/pattern.c @@ -53,7 +53,6 @@ #include "progress.h" #include "protos.h" #include "state.h" -#include "thread.h" #ifdef USE_IMAP #include "imap/imap.h" #endif diff --git a/po/POTFILES.in b/po/POTFILES.in index e0af21eb6..97a9f3a1a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -87,6 +87,7 @@ mutt/sha1.c mutt/signal.c mutt/string.c mutt/tags.c +mutt/thread.c mutt_account.c mutt_attach.c mutt_body.c @@ -95,6 +96,7 @@ mutt_lua.c mutt_notmuch.c mutt_signal.c mutt_socket.c +mutt_thread.c mutt_window.c muttlib.c mx.c diff --git a/postpone.c b/postpone.c index 1f65d7458..d3ea06aae 100644 --- a/postpone.c +++ b/postpone.c @@ -46,13 +46,13 @@ #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 diff --git a/sort.c b/sort.c index 8584914f1..54629b2f8 100644 --- a/sort.c +++ b/sort.c @@ -29,9 +29,9 @@ #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" -- 2.40.0