NeoMutt  2020-04-24
Teaching an old dog new tricks
DOXYGEN
thread.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <stdbool.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include "mutt/lib.h"
34 #include "thread.h"
35 #include "email.h"
36 #include "envelope.h"
37 
44 bool is_descendant(struct MuttThread *a, struct MuttThread *b)
45 {
46  while (a)
47  {
48  if (a == b)
49  return true;
50  a = a->parent;
51  }
52  return false;
53 }
54 
64 void unlink_message(struct MuttThread **old, struct MuttThread *cur)
65 {
66  if (!old || !cur)
67  return;
68 
69  struct MuttThread *tmp = NULL;
70 
71  if (cur->prev)
72  cur->prev->next = cur->next;
73  else
74  *old = cur->next;
75 
76  if (cur->next)
77  cur->next->prev = cur->prev;
78 
79  if (cur->sort_key)
80  {
81  for (tmp = cur->parent; tmp && (tmp->sort_key == cur->sort_key); tmp = tmp->parent)
82  tmp->sort_key = NULL;
83  }
84 }
85 
94 void insert_message(struct MuttThread **add, struct MuttThread *parent, struct MuttThread *cur)
95 {
96  if (!cur || !add)
97  return;
98 
99  if (*add)
100  (*add)->prev = cur;
101 
102  cur->parent = parent;
103  cur->next = *add;
104  cur->prev = NULL;
105  *add = cur;
106 }
107 
111 void thread_hash_destructor(int type, void *obj, intptr_t data)
112 {
113  FREE(&obj);
114 }
115 
122 struct Email *find_virtual(struct MuttThread *cur, int reverse)
123 {
124  if (!cur)
125  return NULL;
126 
127  struct MuttThread *top = NULL;
128 
129  if (cur->message && (cur->message->vnum >= 0))
130  return cur->message;
131 
132  top = cur;
133  cur = cur->child;
134  if (!cur)
135  return NULL;
136 
137  while (reverse && cur->next)
138  cur = cur->next;
139 
140  while (true)
141  {
142  if (cur->message && (cur->message->vnum >= 0))
143  return cur->message;
144 
145  if (cur->child)
146  {
147  cur = cur->child;
148 
149  while (reverse && cur->next)
150  cur = cur->next;
151  }
152  else if (reverse ? cur->prev : cur->next)
153  cur = reverse ? cur->prev : cur->next;
154  else
155  {
156  while (!(reverse ? cur->prev : cur->next))
157  {
158  cur = cur->parent;
159  if (cur == top)
160  return NULL;
161  }
162  cur = reverse ? cur->prev : cur->next;
163  }
164  /* not reached */
165  }
166 }
167 
173 void clean_references(struct MuttThread *brk, struct MuttThread *cur)
174 {
175  struct ListNode *ref = NULL;
176  bool done = false;
177 
178  for (; cur; cur = cur->next, done = false)
179  {
180  /* parse subthread recursively */
181  clean_references(brk, cur->child);
182 
183  if (!cur->message)
184  break; /* skip pseudo-message */
185 
186  /* Looking for the first bad reference according to the new threading.
187  * Optimal since NeoMutt stores the references in reverse order, and the
188  * first loop should match immediately for mails respecting RFC2822. */
189  for (struct MuttThread *p = brk; !done && p; p = p->parent)
190  {
191  for (ref = STAILQ_FIRST(&cur->message->env->references);
192  p->message && ref; ref = STAILQ_NEXT(ref, entries))
193  {
194  if (mutt_str_strcasecmp(ref->data, p->message->env->message_id) == 0)
195  {
196  done = true;
197  break;
198  }
199  }
200  }
201 
202  if (done)
203  {
204  struct Email *e = cur->message;
205 
206  /* clearing the References: header from obsolete Message-ID(s) */
207  struct ListNode *np = NULL;
208  while ((np = STAILQ_NEXT(ref, entries)))
209  {
210  STAILQ_REMOVE_AFTER(&cur->message->env->references, ref, entries);
211  FREE(&np->data);
212  FREE(&np);
213  }
214 
215  e->changed = true;
217  }
218  }
219 }
220 
225 void mutt_break_thread(struct Email *e)
226 {
227  if (!e)
228  return;
229 
232  e->changed = true;
234 
236 }
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
void thread_hash_destructor(int type, void *obj, intptr_t data)
Hash Destructor callback - Implements hashelem_free_t.
Definition: thread.c:111
The envelope/body of an email.
Definition: email.h:37
struct Email * find_virtual(struct MuttThread *cur, int reverse)
Find an email with a Virtual message number.
Definition: thread.c:122
struct MuttThread * thread
Thread of Emails.
Definition: email.h:94
bool changed
Email has been edited.
Definition: email.h:48
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
Representation of an email.
Create/manipulate threading in emails.
struct Envelope * env
Envelope information.
Definition: email.h:89
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition: thread.c:225
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
struct Email * sort_key
Email that this Thread is sorted against.
Definition: thread.h:50
Representation of an email header (envelope)
void clean_references(struct MuttThread *brk, struct MuttThread *cur)
Update email references for a broken Thread.
Definition: thread.c:173
int vnum
Virtual message number.
Definition: email.h:87
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
void unlink_message(struct MuttThread **old, struct MuttThread *cur)
Break the message out of the thread.
Definition: thread.c:64
An Email conversation.
Definition: thread.h:34
char * data
String.
Definition: list.h:35
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:654
#define FREE(x)
Definition: memory.h:40
void insert_message(struct MuttThread **add, struct MuttThread *parent, struct MuttThread *cur)
Insert a message into a thread.
Definition: thread.c:94
#define MUTT_ENV_CHANGED_REFS
References changed to break thread.
Definition: envelope.h:33
bool is_descendant(struct MuttThread *a, struct MuttThread *b)
Is one thread a descendant of another.
Definition: thread.c:44
#define MUTT_ENV_CHANGED_IRT
In-Reply-To changed to link/break threads.
Definition: envelope.h:32
Convenience wrapper for the library headers.
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:33
#define STAILQ_FIRST(head)
Definition: queue.h:347
#define STAILQ_REMOVE_AFTER(head, elm, field)
Definition: queue.h:413