NeoMutt  2021-02-05-666-ge300cd
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_thread_key)
80  {
81  for (tmp = cur->parent;
82  tmp && (tmp->sort_thread_key == cur->sort_thread_key); tmp = tmp->parent)
83  {
84  tmp->sort_thread_key = NULL;
85  }
86  }
87  if (cur->sort_aux_key)
88  {
89  for (tmp = cur->parent; tmp && (tmp->sort_aux_key == cur->sort_aux_key); tmp = tmp->parent)
90  tmp->sort_aux_key = NULL;
91  }
92 }
93 
102 void insert_message(struct MuttThread **add, struct MuttThread *parent, struct MuttThread *cur)
103 {
104  if (!cur || !add)
105  return;
106 
107  if (*add)
108  (*add)->prev = cur;
109 
110  cur->parent = parent;
111  cur->next = *add;
112  cur->prev = NULL;
113  *add = cur;
114 }
115 
119 void thread_hash_destructor(int type, void *obj, intptr_t data)
120 {
121  FREE(&obj);
122 }
123 
130 struct Email *find_virtual(struct MuttThread *cur, bool reverse)
131 {
132  if (!cur)
133  return NULL;
134 
135  struct MuttThread *top = NULL;
136 
137  if (cur->message && (cur->message->vnum >= 0))
138  return cur->message;
139 
140  top = cur;
141  cur = cur->child;
142  if (!cur)
143  return NULL;
144 
145  while (reverse && cur->next)
146  cur = cur->next;
147 
148  while (true)
149  {
150  if (cur->message && (cur->message->vnum >= 0))
151  return cur->message;
152 
153  if (cur->child)
154  {
155  cur = cur->child;
156 
157  while (reverse && cur->next)
158  cur = cur->next;
159  }
160  else if (reverse ? cur->prev : cur->next)
161  cur = reverse ? cur->prev : cur->next;
162  else
163  {
164  while (!(reverse ? cur->prev : cur->next))
165  {
166  cur = cur->parent;
167  if (cur == top)
168  return NULL;
169  }
170  cur = reverse ? cur->prev : cur->next;
171  }
172  /* not reached */
173  }
174 }
175 
181 void clean_references(struct MuttThread *brk, struct MuttThread *cur)
182 {
183  struct ListNode *ref = NULL;
184  bool done = false;
185 
186  for (; cur; cur = cur->next, done = false)
187  {
188  /* parse subthread recursively */
189  clean_references(brk, cur->child);
190 
191  if (!cur->message)
192  break; /* skip pseudo-message */
193 
194  /* Looking for the first bad reference according to the new threading.
195  * Optimal since NeoMutt stores the references in reverse order, and the
196  * first loop should match immediately for mails respecting RFC2822. */
197  for (struct MuttThread *p = brk; !done && p; p = p->parent)
198  {
199  for (ref = STAILQ_FIRST(&cur->message->env->references);
200  p->message && ref; ref = STAILQ_NEXT(ref, entries))
201  {
202  if (mutt_istr_equal(ref->data, p->message->env->message_id))
203  {
204  done = true;
205  break;
206  }
207  }
208  }
209 
210  if (done)
211  {
212  struct Email *e = cur->message;
213 
214  /* clearing the References: header from obsolete Message-ID(s) */
215  struct ListNode *np = NULL;
216  while ((np = STAILQ_NEXT(ref, entries)))
217  {
218  STAILQ_REMOVE_AFTER(&cur->message->env->references, ref, entries);
219  FREE(&np->data);
220  FREE(&np);
221  }
222 
223  e->changed = true;
225  }
226  }
227 }
228 
233 void mutt_break_thread(struct Email *e)
234 {
235  if (!e)
236  return;
237 
240  e->changed = true;
242 
244 }
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 hash_hdata_free_t.
Definition: thread.c:119
The envelope/body of an email.
Definition: email.h:37
struct Email * sort_thread_key
Email that controls how top thread sorts.
Definition: thread.h:50
struct MuttThread * thread
Thread of Emails.
Definition: email.h:95
struct Email * find_virtual(struct MuttThread *cur, bool reverse)
Find an email with a Virtual message number.
Definition: thread.c:130
bool changed
Email has been edited.
Definition: email.h:48
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
struct Email * sort_aux_key
Email that controls how subthread siblings sort.
Definition: thread.h:51
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
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:90
void mutt_break_thread(struct Email *e)
Break the email Thread.
Definition: thread.c:233
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
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:181
int vnum
Virtual message number.
Definition: email.h:88
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
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:36
#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:102
#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:34
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_REMOVE_AFTER(head, elm, field)
Definition: queue.h:416