NeoMutt  2018-07-16 +2225-8687db
Teaching an old dog new tricks
DOXYGEN
mutt_header.c File Reference

Manipulate an email's header. More...

#include "config.h"
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>
#include "mutt/mutt.h"
#include "email/lib.h"
#include "mutt.h"
#include "alias.h"
#include "context.h"
#include "core/lib.h"
#include "curs_lib.h"
#include "globals.h"
#include "index.h"
#include "muttlib.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "protos.h"
#include "sendlib.h"

Go to the source code of this file.

Functions

static void label_ref_dec (struct Mailbox *m, char *label)
 Decrease the refcount of a label. More...
 
static void label_ref_inc (struct Mailbox *m, char *label)
 Increase the refcount of a label. More...
 
static bool label_message (struct Mailbox *m, struct Email *e, char *new_label)
 add an X-Label: field More...
 
int mutt_label_message (struct Mailbox *m, struct EmailList *el)
 Let the user label a message. More...
 
void mutt_edit_headers (const char *editor, const char *body, struct Email *e, char *fcc, size_t fcclen)
 Let the user edit the message header and body. More...
 
void mutt_make_label_hash (struct Mailbox *m)
 Create a Hash Table to store the labels. More...
 
void mutt_label_hash_add (struct Mailbox *m, struct Email *e)
 Add a message's labels to the Hash Table. More...
 
void mutt_label_hash_remove (struct Mailbox *m, struct Email *e)
 Rmove a message's labels from the Hash Table. More...
 

Detailed Description

Manipulate an email's header.

Authors
  • Michael R. Elkins

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/.

Definition in file mutt_header.c.

Function Documentation

static void label_ref_dec ( struct Mailbox m,
char *  label 
)
static

Decrease the refcount of a label.

Parameters
mMailbox
labelLabel

Definition at line 56 of file mutt_header.c.

57 {
58  struct HashElem *elem = mutt_hash_find_elem(m->label_hash, label);
59  if (!elem)
60  return;
61 
62  uintptr_t count = (uintptr_t) elem->data;
63  if (count <= 1)
64  {
65  mutt_hash_delete(m->label_hash, label, NULL);
66  return;
67  }
68 
69  count--;
70  elem->data = (void *) count;
71 }
void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data)
Remove an element from a Hash table.
Definition: hash.c:444
struct HashElem * mutt_hash_find_elem(const struct Hash *table, const char *strkey)
Find the HashElem in a Hash table element using a key.
Definition: hash.c:394
void * data
Definition: hash.h:46
The item stored in a Hash Table.
Definition: hash.h:42
struct Hash * label_hash
Hash table for x-labels.
Definition: mailbox.h:141
static void label_ref_inc ( struct Mailbox m,
char *  label 
)
static

Increase the refcount of a label.

Parameters
mMailbox
labelLabel

Definition at line 78 of file mutt_header.c.

79 {
80  uintptr_t count;
81 
82  struct HashElem *elem = mutt_hash_find_elem(m->label_hash, label);
83  if (!elem)
84  {
85  count = 1;
86  mutt_hash_insert(m->label_hash, label, (void *) count);
87  return;
88  }
89 
90  count = (uintptr_t) elem->data;
91  count++;
92  elem->data = (void *) count;
93 }
struct HashElem * mutt_hash_find_elem(const struct Hash *table, const char *strkey)
Find the HashElem in a Hash table element using a key.
Definition: hash.c:394
void * data
Definition: hash.h:46
The item stored in a Hash Table.
Definition: hash.h:42
struct HashElem * mutt_hash_insert(struct Hash *table, const char *strkey, void *data)
Add a new element to the Hash table (with string keys)
Definition: hash.c:352
struct Hash * label_hash
Hash table for x-labels.
Definition: mailbox.h:141
static bool label_message ( struct Mailbox m,
struct Email e,
char *  new_label 
)
static

add an X-Label: field

Parameters
[in]mMailbox
[in]eEmail
[out]new_labelSet to true if this is a new label
Return values
trueIf the label was added

Definition at line 102 of file mutt_header.c.

103 {
104  if (!e)
105  return false;
106  if (mutt_str_strcmp(e->env->x_label, new_label) == 0)
107  return false;
108 
109  if (e->env->x_label)
110  label_ref_dec(m, e->env->x_label);
111  mutt_str_replace(&e->env->x_label, new_label);
112  if (e->env->x_label)
113  label_ref_inc(m, e->env->x_label);
114 
115  e->changed = true;
117  return true;
118 }
bool changed
Email has been edited.
Definition: email.h:48
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:71
struct Envelope * env
Envelope information.
Definition: email.h:89
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:34
static void label_ref_dec(struct Mailbox *m, char *label)
Decrease the refcount of a label.
Definition: mutt_header.c:56
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
char * x_label
X-Label.
Definition: envelope.h:58
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
static void label_ref_inc(struct Mailbox *m, char *label)
Increase the refcount of a label.
Definition: mutt_header.c:78
int mutt_label_message ( struct Mailbox m,
struct EmailList *  el 
)

Let the user label a message.

Parameters
mMailbox
elList of Emails to label
Return values
numNumber of messages changed

Definition at line 126 of file mutt_header.c.

127 {
128  if (!m || !el)
129  return 0;
130 
131  char buf[1024] = { 0 };
132 
133  struct EmailNode *en = STAILQ_FIRST(el);
134  if (!STAILQ_NEXT(en, entries))
135  {
136  // If there's only one email, use its label as a template
137  if (en->email->env->x_label)
138  mutt_str_strfcpy(buf, en->email->env->x_label, sizeof(buf));
139  }
140 
141  if (mutt_get_field("Label: ", buf, sizeof(buf), MUTT_LABEL /* | MUTT_CLEAR */) != 0)
142  return 0;
143 
144  char *new_label = buf;
145  SKIPWS(new_label);
146  if (*new_label == '\0')
147  new_label = NULL;
148 
149  int changed = 0;
150  STAILQ_FOREACH(en, el, entries)
151  {
152  if (label_message(m, en->email, new_label))
153  {
154  changed++;
156  }
157  }
158 
159  return changed;
160 }
#define MUTT_LABEL
Do label completion.
Definition: mutt.h:71
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:86
struct Envelope * env
Envelope information.
Definition: email.h:89
#define SKIPWS(ch)
Definition: string2.h:47
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:350
#define STAILQ_NEXT(elm, field)
Definition: queue.h:398
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: index.c:3641
struct Email * email
Email in the list.
Definition: email.h:119
List of Emails.
Definition: email.h:117
char * x_label
X-Label.
Definition: envelope.h:58
#define STAILQ_FIRST(head)
Definition: queue.h:348
static bool label_message(struct Mailbox *m, struct Email *e, char *new_label)
add an X-Label: field
Definition: mutt_header.c:102
void mutt_edit_headers ( const char *  editor,
const char *  body,
struct Email e,
char *  fcc,
size_t  fcclen 
)

Let the user edit the message header and body.

Parameters
editorEditor command
bodyFile containing message body
eEmail
fccBuffer for the fcc field
fcclenLength of buffer

Definition at line 170 of file mutt_header.c.

172 {
173  char path[PATH_MAX]; /* tempfile used to edit headers + body */
174  char buf[1024];
175  const char *p = NULL;
176  int i;
177  struct Envelope *n = NULL;
178  time_t mtime;
179  struct stat st;
180 
181  mutt_mktemp(path, sizeof(path));
182  FILE *fp_out = mutt_file_fopen(path, "w");
183  if (!fp_out)
184  {
185  mutt_perror(path);
186  return;
187  }
188 
190  mutt_rfc822_write_header(fp_out, e->env, NULL, MUTT_WRITE_HEADER_EDITHDRS, false, false);
191  fputc('\n', fp_out); /* tie off the header. */
192 
193  /* now copy the body of the message. */
194  FILE *fp_in = fopen(body, "r");
195  if (!fp_in)
196  {
197  mutt_perror(body);
198  mutt_file_fclose(&fp_out);
199  return;
200  }
201 
202  mutt_file_copy_stream(fp_in, fp_out);
203 
204  mutt_file_fclose(&fp_in);
205  mutt_file_fclose(&fp_out);
206 
207  if (stat(path, &st) == -1)
208  {
209  mutt_perror(path);
210  return;
211  }
212 
213  mtime = mutt_file_decrease_mtime(path, &st);
214 
215  mutt_edit_file(editor, path);
216  stat(path, &st);
217  if (mtime == st.st_mtime)
218  {
219  mutt_debug(LL_DEBUG1, "temp file was not modified\n");
220  /* the file has not changed! */
221  mutt_file_unlink(path);
222  return;
223  }
224 
225  mutt_file_unlink(body);
227 
228  /* Read the temp file back in */
229  fp_in = fopen(path, "r");
230  if (!fp_in)
231  {
232  mutt_perror(path);
233  return;
234  }
235 
236  fp_out = mutt_file_fopen(body, "w");
237  if (!fp_out)
238  {
239  /* intentionally leak a possible temporary file here */
240  mutt_file_fclose(&fp_in);
241  mutt_perror(body);
242  return;
243  }
244 
245  n = mutt_rfc822_read_header(fp_in, NULL, true, false);
246  while ((i = fread(buf, 1, sizeof(buf), fp_in)) > 0)
247  fwrite(buf, 1, i, fp_out);
248  mutt_file_fclose(&fp_out);
249  mutt_file_fclose(&fp_in);
250  mutt_file_unlink(path);
251 
252  /* in case the user modifies/removes the In-Reply-To header with
253  * $edit_headers set, we remove References: as they're likely invalid;
254  * we can simply compare strings as we don't generate References for
255  * multiple Message-Ids in IRT anyways */
256 #ifdef USE_NNTP
257  if (!OptNewsSend)
258 #endif
259  {
260  if (!STAILQ_EMPTY(&e->env->in_reply_to) &&
261  (STAILQ_EMPTY(&n->in_reply_to) ||
263  STAILQ_FIRST(&e->env->in_reply_to)->data) != 0)))
264  {
266  }
267  }
268 
269  /* restore old info. */
272 
273  mutt_env_free(&e->env);
274  e->env = n;
275  n = NULL;
276 
278 
279  /* search through the user defined headers added to see if
280  * fcc: or attach: or pgp: was specified */
281 
282  struct ListNode *np = NULL, *tmp = NULL;
283  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
284  {
285  bool keep = true;
286  size_t plen;
287 
288  if (fcc && (plen = mutt_str_startswith(np->data, "fcc:", CASE_IGNORE)))
289  {
290  p = mutt_str_skip_email_wsp(np->data + plen);
291  if (*p)
292  {
293  mutt_str_strfcpy(fcc, p, fcclen);
294  mutt_pretty_mailbox(fcc, fcclen);
295  }
296  keep = false;
297  }
298  else if ((plen = mutt_str_startswith(np->data, "attach:", CASE_IGNORE)))
299  {
300  struct Body *body2 = NULL;
301  struct Body *parts = NULL;
302 
303  p = mutt_str_skip_email_wsp(np->data + plen);
304  if (*p)
305  {
306  size_t l = 0;
307  for (; (p[0] != '\0') && (p[0] != ' ') && (p[0] != '\t'); p++)
308  {
309  if (p[0] == '\\')
310  {
311  if (p[1] == '\0')
312  break;
313  p++;
314  }
315  if (l < (sizeof(path) - 1))
316  path[l++] = *p;
317  }
319  path[l] = '\0';
320 
321  mutt_expand_path(path, sizeof(path));
322  body2 = mutt_make_file_attach(path);
323  if (body2)
324  {
325  body2->description = mutt_str_strdup(p);
326  for (parts = e->content; parts->next; parts = parts->next)
327  ;
328  parts->next = body2;
329  }
330  else
331  {
332  mutt_pretty_mailbox(path, sizeof(path));
333  mutt_error(_("%s: unable to attach file"), path);
334  }
335  }
336  keep = false;
337  }
338  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
339  (plen = mutt_str_startswith(np->data, "pgp:", CASE_IGNORE)))
340  {
341  e->security = mutt_parse_crypt_hdr(np->data + plen, false, APPLICATION_PGP);
342  if (e->security)
344  keep = false;
345  }
346 
347  if (!keep)
348  {
349  STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
350  FREE(&np->data);
351  FREE(&np);
352  }
353  }
354 }
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:400
#define mutt_perror(...)
Definition: logging.h:85
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:304
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
struct Body * content
List of MIME parts.
Definition: email.h:90
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
struct ListHead userhdrs
user defined headers
Definition: envelope.h:69
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
The body of an email.
Definition: body.h:34
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject)
Write out one RFC822 header line.
Definition: sendlib.c:2229
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:68
struct Body * mutt_make_file_attach(const char *path)
Create a file attachment.
Definition: sendlib.c:1611
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
struct Envelope * env
Envelope information.
Definition: email.h:89
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:360
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:76
#define PATH_MAX
Definition: mutt.h:50
"light" mode (used for edit_hdrs)
Definition: sendlib.h:66
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:750
Ignore case when comparing strings.
Definition: string2.h:68
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
void mutt_pretty_mailbox(char *buf, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:615
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:39
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:130
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope&#39;s Address fields to local format.
Definition: envelope.c:222
SecurityFlags mutt_parse_crypt_hdr(const char *p, bool set_empty_signas, SecurityFlags crypt_app)
Parse a crypto header string.
Definition: postpone.c:449
char * data
Definition: list.h:35
Log at debug level 1.
Definition: logging.h:56
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:267
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:84
void mutt_env_free(struct Envelope **p)
Free an Envelope.
Definition: envelope.c:63
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file&#39;s modification time by 1 second.
Definition: file.c:960
#define FREE(x)
Definition: memory.h:40
#define STAILQ_EMPTY(head)
Definition: queue.h:346
#define STAILQ_SWAP(head1, head2, type)
Definition: queue.h:426
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:43
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
struct ListHead references
message references (in reverse order)
Definition: envelope.h:67
A List node for strings.
Definition: list.h:33
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
parses an RFC822 header
Definition: parse.c:1023
#define STAILQ_FIRST(head)
Definition: queue.h:348
#define WithCrypto
Definition: ncrypt.h:156
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:308
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
The header of an Email.
Definition: envelope.h:40
void mutt_make_label_hash ( struct Mailbox m)

Create a Hash Table to store the labels.

Parameters
mMailbox

Definition at line 360 of file mutt_header.c.

361 {
362  /* 131 is just a rough prime estimate of how many distinct
363  * labels someone might have in a m. */
365 }
struct Hash * mutt_hash_new(size_t nelem, HashFlags flags)
Create a new Hash table (with string keys)
Definition: hash.c:276
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:76
struct Hash * label_hash
Hash table for x-labels.
Definition: mailbox.h:141
void mutt_label_hash_add ( struct Mailbox m,
struct Email e 
)

Add a message's labels to the Hash Table.

Parameters
mMailbox
eEmail

Definition at line 372 of file mutt_header.c.

373 {
374  if (!m || !m->label_hash)
375  return;
376  if (e->env->x_label)
377  label_ref_inc(m, e->env->x_label);
378 }
struct Envelope * env
Envelope information.
Definition: email.h:89
char * x_label
X-Label.
Definition: envelope.h:58
struct Hash * label_hash
Hash table for x-labels.
Definition: mailbox.h:141
static void label_ref_inc(struct Mailbox *m, char *label)
Increase the refcount of a label.
Definition: mutt_header.c:78
void mutt_label_hash_remove ( struct Mailbox m,
struct Email e 
)

Rmove a message's labels from the Hash Table.

Parameters
mMailbox
eEmail

Definition at line 385 of file mutt_header.c.

386 {
387  if (!m || !m->label_hash)
388  return;
389  if (e->env->x_label)
390  label_ref_dec(m, e->env->x_label);
391 }
struct Envelope * env
Envelope information.
Definition: email.h:89
static void label_ref_dec(struct Mailbox *m, char *label)
Decrease the refcount of a label.
Definition: mutt_header.c:56
char * x_label
X-Label.
Definition: envelope.h:58
struct Hash * label_hash
Hash table for x-labels.
Definition: mailbox.h:141