NeoMutt  2021-02-05-89-gabe350
Teaching an old dog new tricks
DOXYGEN
mutt_header.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <stddef.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <sys/stat.h>
35 #include <time.h>
36 #include "mutt/lib.h"
37 #include "email/lib.h"
38 #include "core/lib.h"
39 #include "alias/lib.h"
40 #include "gui/lib.h"
41 #include "mutt.h"
42 #include "mutt_header.h"
43 #include "index/lib.h"
44 #include "ncrypt/lib.h"
45 #include "send/lib.h"
46 #include "muttlib.h"
47 #include "options.h"
48 #include "protos.h"
49 
55 static void label_ref_dec(struct Mailbox *m, char *label)
56 {
57  struct HashElem *elem = mutt_hash_find_elem(m->label_hash, label);
58  if (!elem)
59  return;
60 
61  uintptr_t count = (uintptr_t) elem->data;
62  if (count <= 1)
63  {
64  mutt_hash_delete(m->label_hash, label, NULL);
65  return;
66  }
67 
68  count--;
69  elem->data = (void *) count;
70 }
71 
77 static void label_ref_inc(struct Mailbox *m, char *label)
78 {
79  uintptr_t count;
80 
81  struct HashElem *elem = mutt_hash_find_elem(m->label_hash, label);
82  if (!elem)
83  {
84  count = 1;
85  mutt_hash_insert(m->label_hash, label, (void *) count);
86  return;
87  }
88 
89  count = (uintptr_t) elem->data;
90  count++;
91  elem->data = (void *) count;
92 }
93 
101 static bool label_message(struct Mailbox *m, struct Email *e, char *new_label)
102 {
103  if (!e)
104  return false;
105  if (mutt_str_equal(e->env->x_label, new_label))
106  return false;
107 
108  if (e->env->x_label)
109  label_ref_dec(m, e->env->x_label);
110  if (mutt_str_replace(&e->env->x_label, new_label))
111  label_ref_inc(m, e->env->x_label);
112 
113  e->changed = true;
115  return true;
116 }
117 
124 int mutt_label_message(struct Mailbox *m, struct EmailList *el)
125 {
126  if (!m || !el)
127  return 0;
128 
129  char buf[1024] = { 0 };
130 
131  struct EmailNode *en = STAILQ_FIRST(el);
132  if (!STAILQ_NEXT(en, entries))
133  {
134  // If there's only one email, use its label as a template
135  if (en->email->env->x_label)
136  mutt_str_copy(buf, en->email->env->x_label, sizeof(buf));
137  }
138 
139  if (mutt_get_field("Label: ", buf, sizeof(buf), MUTT_LABEL /* | MUTT_CLEAR */,
140  false, NULL, NULL) != 0)
141  {
142  return 0;
143  }
144 
145  char *new_label = buf;
146  SKIPWS(new_label);
147  if (*new_label == '\0')
148  new_label = NULL;
149 
150  int changed = 0;
151  STAILQ_FOREACH(en, el, entries)
152  {
153  if (label_message(m, en->email, new_label))
154  {
155  changed++;
157  }
158  }
159 
160  return changed;
161 }
162 
170 void mutt_edit_headers(const char *editor, const char *body, struct Email *e,
171  struct Buffer *fcc)
172 {
173  char buf[1024];
174  const char *p = NULL;
175  int i;
176  struct Envelope *n = NULL;
177  time_t mtime;
178  struct stat st;
179 
180  struct Buffer *path = mutt_buffer_pool_get();
181  mutt_buffer_mktemp(path);
182  FILE *fp_out = mutt_file_fopen(mutt_buffer_string(path), "w");
183  if (!fp_out)
184  {
186  goto cleanup;
187  }
188 
191  false, false, NeoMutt->sub);
192  fputc('\n', fp_out); /* tie off the header. */
193 
194  /* now copy the body of the message. */
195  FILE *fp_in = fopen(body, "r");
196  if (!fp_in)
197  {
198  mutt_perror(body);
199  mutt_file_fclose(&fp_out);
200  goto cleanup;
201  }
202 
203  mutt_file_copy_stream(fp_in, fp_out);
204 
205  mutt_file_fclose(&fp_in);
206  mutt_file_fclose(&fp_out);
207 
208  if (stat(mutt_buffer_string(path), &st) == -1)
209  {
211  goto cleanup;
212  }
213 
214  mtime = mutt_file_decrease_mtime(mutt_buffer_string(path), &st);
215  if (mtime == (time_t) -1)
216  {
218  goto cleanup;
219  }
220 
221  mutt_edit_file(editor, mutt_buffer_string(path));
222  stat(mutt_buffer_string(path), &st);
223  if (mtime == st.st_mtime)
224  {
225  mutt_debug(LL_DEBUG1, "temp file was not modified\n");
226  /* the file has not changed! */
228  goto cleanup;
229  }
230 
231  mutt_file_unlink(body);
233 
234  /* Read the temp file back in */
235  fp_in = fopen(mutt_buffer_string(path), "r");
236  if (!fp_in)
237  {
239  goto cleanup;
240  }
241 
242  fp_out = mutt_file_fopen(body, "w");
243  if (!fp_out)
244  {
245  /* intentionally leak a possible temporary file here */
246  mutt_file_fclose(&fp_in);
247  mutt_perror(body);
248  goto cleanup;
249  }
250 
251  n = mutt_rfc822_read_header(fp_in, NULL, true, false);
252  while ((i = fread(buf, 1, sizeof(buf), fp_in)) > 0)
253  fwrite(buf, 1, i, fp_out);
254  mutt_file_fclose(&fp_out);
255  mutt_file_fclose(&fp_in);
257 
258  /* in case the user modifies/removes the In-Reply-To header with
259  * $edit_headers set, we remove References: as they're likely invalid;
260  * we can simply compare strings as we don't generate References for
261  * multiple Message-Ids in IRT anyways */
262 #ifdef USE_NNTP
263  if (!OptNewsSend)
264 #endif
265  {
266  if (!STAILQ_EMPTY(&e->env->in_reply_to) &&
267  (STAILQ_EMPTY(&n->in_reply_to) ||
269  STAILQ_FIRST(&e->env->in_reply_to)->data)))
270  {
272  }
273  }
274 
275  /* restore old info. */
278 
279  mutt_env_free(&e->env);
280  e->env = n;
281  n = NULL;
282 
284 
285  /* search through the user defined headers added to see if
286  * fcc: or attach: or pgp: was specified */
287 
288  struct ListNode *np = NULL, *tmp = NULL;
289  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
290  {
291  bool keep = true;
292  size_t plen;
293 
294  if (fcc && (plen = mutt_istr_startswith(np->data, "fcc:")))
295  {
296  p = mutt_str_skip_email_wsp(np->data + plen);
297  if (*p)
298  {
299  mutt_buffer_strcpy(fcc, p);
301  }
302  keep = false;
303  }
304  else if ((plen = mutt_istr_startswith(np->data, "attach:")))
305  {
306  struct Body *body2 = NULL;
307  struct Body *parts = NULL;
308 
309  p = mutt_str_skip_email_wsp(np->data + plen);
310  if (*p)
311  {
312  mutt_buffer_reset(path);
313  for (; (p[0] != '\0') && (p[0] != ' ') && (p[0] != '\t'); p++)
314  {
315  if (p[0] == '\\')
316  {
317  if (p[1] == '\0')
318  break;
319  p++;
320  }
321  mutt_buffer_addch(path, *p);
322  }
324 
327  if (body2)
328  {
329  body2->description = mutt_str_dup(p);
330  for (parts = e->body; parts->next; parts = parts->next)
331  ; // do nothing
332 
333  parts->next = body2;
334  }
335  else
336  {
338  mutt_error(_("%s: unable to attach file"), mutt_buffer_string(path));
339  }
340  }
341  keep = false;
342  }
343  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
344  (plen = mutt_istr_startswith(np->data, "pgp:")))
345  {
347  if (e->security)
349  keep = false;
350  }
351 
352  if (!keep)
353  {
354  STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
355  FREE(&np->data);
356  FREE(&np);
357  }
358  }
359 
360 cleanup:
362 }
363 
369 {
370  /* 131 is just a rough prime estimate of how many distinct
371  * labels someone might have in a m. */
373 }
374 
380 void mutt_label_hash_add(struct Mailbox *m, struct Email *e)
381 {
382  if (!m || !m->label_hash)
383  return;
384  if (e->env->x_label)
385  label_ref_inc(m, e->env->x_label);
386 }
387 
393 void mutt_label_hash_remove(struct Mailbox *m, struct Email *e)
394 {
395  if (!m || !m->label_hash)
396  return;
397  if (e->env->x_label)
398  label_ref_dec(m, e->env->x_label);
399 }
lib.h
Envelope
The header of an Email.
Definition: envelope.h:54
mutt_expand_aliases_env
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:308
lib.h
mutt_hash_new
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:251
mutt_hash_delete
void mutt_hash_delete(struct HashTable *table, const char *strkey, const void *data)
Remove an element from a Hash Table.
Definition: hash.c:419
_
#define _(a)
Definition: message.h:28
Mailbox
A mailbox.
Definition: mailbox.h:81
mutt_file_decrease_mtime
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file's modification time by 1 second.
Definition: file.c:963
Envelope::in_reply_to
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
ListNode
A List node for strings.
Definition: list.h:34
Buffer
String manipulation buffer.
Definition: buffer.h:33
STAILQ_REMOVE
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:399
mutt_file_fclose
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
mutt_buffer_pretty_mailbox
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:599
Body::next
struct Body * next
next attachment in the list
Definition: body.h:53
Body
The body of an email.
Definition: body.h:34
STAILQ_SWAP
#define STAILQ_SWAP(head1, head2, type)
Definition: queue.h:425
HashElem::data
void * data
User-supplied data.
Definition: hash.h:47
Envelope::x_label
char * x_label
X-Label.
Definition: envelope.h:72
mutt_buffer_mktemp
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
mutt_parse_crypt_hdr
SecurityFlags mutt_parse_crypt_hdr(const char *p, bool set_empty_signas, SecurityFlags crypt_app)
Parse a crypto header string.
Definition: postpone.c:508
EmailNode::email
struct Email * email
Email in the list.
Definition: email.h:127
mutt_str_dup
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
mutt_file_fopen
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
mutt_file_unlink
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
LL_DEBUG1
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
FREE
#define FREE(x)
Definition: memory.h:40
options.h
EmailNode
List of Emails.
Definition: email.h:125
STAILQ_FIRST
#define STAILQ_FIRST(head)
Definition: queue.h:347
mutt_perror
#define mutt_perror(...)
Definition: logging.h:85
mutt_label_message
int mutt_label_message(struct Mailbox *m, struct EmailList *el)
Let the user label a message.
Definition: mutt_header.c:124
MUTT_LABEL
#define MUTT_LABEL
Do label completion.
Definition: mutt.h:65
mutt_buffer_reset
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
mutt_buffer_pool_release
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
STAILQ_EMPTY
#define STAILQ_EMPTY(head)
Definition: queue.h:345
mutt_header.h
STAILQ_FOREACH
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
Mailbox::label_hash
struct HashTable * label_hash
Hash Table for x-labels.
Definition: mailbox.h:129
mutt_edit_headers
void mutt_edit_headers(const char *editor, const char *body, struct Email *e, struct Buffer *fcc)
Let the user edit the message header and body.
Definition: mutt_header.c:170
SKIPWS
#define SKIPWS(ch)
Definition: string2.h:46
mutt_str_equal
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
protos.h
mutt_rfc822_write_header
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:574
mutt_buffer_addch
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
mutt_env_free
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
mutt_buffer_pool_get
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
label_ref_dec
static void label_ref_dec(struct Mailbox *m, char *label)
Decrease the refcount of a label.
Definition: mutt_header.c:55
mutt_edit_file
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:356
Envelope::changed
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
mutt_make_file_attach
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:1083
lib.h
mutt_file_copy_stream
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
muttlib.h
APPLICATION_PGP
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
lib.h
mutt_label_hash_add
void mutt_label_hash_add(struct Mailbox *m, struct Email *e)
Add a message's labels to the Hash Table.
Definition: mutt_header.c:380
mutt_str_skip_email_wsp
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:743
mutt_env_to_local
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
Definition: envelope.c:271
mutt_hash_insert
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition: hash.c:327
Body::description
char * description
content-description
Definition: body.h:40
Body::parts
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
Email::env
struct Envelope * env
Envelope information.
Definition: email.h:90
mutt_debug
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
mutt_set_header_color
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:4091
mutt_buffer_expand_path
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
mutt_buffer_string
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
STAILQ_FOREACH_SAFE
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:359
label_message
static bool label_message(struct Mailbox *m, struct Email *e, char *new_label)
add an X-Label: field
Definition: mutt_header.c:101
Email::security
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:39
mutt_str_replace
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
WithCrypto
#define WithCrypto
Definition: lib.h:123
lib.h
lib.h
HashElem
The item stored in a Hash Table.
Definition: hash.h:43
lib.h
Envelope::userhdrs
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
mutt_label_hash_remove
void mutt_label_hash_remove(struct Mailbox *m, struct Email *e)
Remove a message's labels from the Hash Table.
Definition: mutt_header.c:393
MUTT_HASH_STRDUP_KEYS
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:99
NeoMutt
Container for Accounts, Notifications.
Definition: neomutt.h:36
mutt.h
mutt_istr_startswith
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
ListNode::data
char * data
String.
Definition: list.h:36
mutt_rfc822_read_header
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1112
NeoMutt::sub
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
plen
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
STAILQ_NEXT
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
OptNewsSend
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:46
mutt_get_field
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:311
Email
The envelope/body of an email.
Definition: email.h:37
lib.h
Envelope::references
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
MUTT_WRITE_HEADER_EDITHDRS
@ MUTT_WRITE_HEADER_EDITHDRS
"light" mode (used for edit_hdrs)
Definition: header.h:43
mutt_list_free
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
mutt_make_label_hash
void mutt_make_label_hash(struct Mailbox *m)
Create a Hash Table to store the labels.
Definition: mutt_header.c:368
label_ref_inc
static void label_ref_inc(struct Mailbox *m, char *label)
Increase the refcount of a label.
Definition: mutt_header.c:77
mutt_buffer_strcpy
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
Email::changed
bool changed
Email has been edited.
Definition: email.h:48
mutt_hash_find_elem
struct HashElem * mutt_hash_find_elem(const struct HashTable *table, const char *strkey)
Find the HashElem in a Hash Table element using a key.
Definition: hash.c:369
Email::body
struct Body * body
List of MIME parts.
Definition: email.h:91
MUTT_ENV_CHANGED_XLABEL
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:34
mutt_error
#define mutt_error(...)
Definition: logging.h:84
mutt_str_copy
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716