NeoMutt  2018-07-16 +2388-bcedc8
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 "core/lib.h"
#include "mutt.h"
#include "alias.h"
#include "curs_lib.h"
#include "index.h"
#include "muttlib.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "protos.h"
#include "sendlib.h"
+ Include dependency graph for mutt_header.c:

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 54 of file mutt_header.c.

55 {
56  struct HashElem *elem = mutt_hash_find_elem(m->label_hash, label);
57  if (!elem)
58  return;
59 
60  uintptr_t count = (uintptr_t) elem->data;
61  if (count <= 1)
62  {
63  mutt_hash_delete(m->label_hash, label, NULL);
64  return;
65  }
66 
67  count--;
68  elem->data = (void *) count;
69 }
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:140

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

Increase the refcount of a label.

Parameters
mMailbox
labelLabel

Definition at line 76 of file mutt_header.c.

77 {
78  uintptr_t count;
79 
80  struct HashElem *elem = mutt_hash_find_elem(m->label_hash, label);
81  if (!elem)
82  {
83  count = 1;
84  mutt_hash_insert(m->label_hash, label, (void *) count);
85  return;
86  }
87 
88  count = (uintptr_t) elem->data;
89  count++;
90  elem->data = (void *) count;
91 }
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:140

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 100 of file mutt_header.c.

101 {
102  if (!e)
103  return false;
104  if (mutt_str_strcmp(e->env->x_label, new_label) == 0)
105  return false;
106 
107  if (e->env->x_label)
108  label_ref_dec(m, e->env->x_label);
109  mutt_str_replace(&e->env->x_label, new_label);
110  if (e->env->x_label)
111  label_ref_inc(m, e->env->x_label);
112 
113  e->changed = true;
115  return true;
116 }
bool changed
Email has been edited.
Definition: email.h:50
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
struct Envelope * env
Envelope information.
Definition: email.h:91
#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:54
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:72
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:76

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 124 of file mutt_header.c.

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_strfcpy(buf, en->email->env->x_label, sizeof(buf));
137  }
138 
139  if (mutt_get_field("Label: ", buf, sizeof(buf), MUTT_LABEL /* | MUTT_CLEAR */) != 0)
140  return 0;
141 
142  char *new_label = buf;
143  SKIPWS(new_label);
144  if (*new_label == '\0')
145  new_label = NULL;
146 
147  int changed = 0;
148  STAILQ_FOREACH(en, el, entries)
149  {
150  if (label_message(m, en->email, new_label))
151  {
152  changed++;
154  }
155  }
156 
157  return changed;
158 }
#define MUTT_LABEL
Do label completion.
Definition: mutt.h:72
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:86
struct Envelope * env
Envelope information.
Definition: email.h:91
#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:3672
struct Email * email
Email in the list.
Definition: email.h:122
List of Emails.
Definition: email.h:120
char * x_label
X-Label.
Definition: envelope.h:72
#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:100

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 168 of file mutt_header.c.

170 {
171  char path[PATH_MAX]; /* tempfile used to edit headers + body */
172  char buf[1024];
173  const char *p = NULL;
174  int i;
175  struct Envelope *n = NULL;
176  time_t mtime;
177  struct stat st;
178 
179  mutt_mktemp(path, sizeof(path));
180  FILE *fp_out = mutt_file_fopen(path, "w");
181  if (!fp_out)
182  {
183  mutt_perror(path);
184  return;
185  }
186 
188  mutt_rfc822_write_header(fp_out, e->env, NULL, MUTT_WRITE_HEADER_EDITHDRS, false, false);
189  fputc('\n', fp_out); /* tie off the header. */
190 
191  /* now copy the body of the message. */
192  FILE *fp_in = fopen(body, "r");
193  if (!fp_in)
194  {
195  mutt_perror(body);
196  mutt_file_fclose(&fp_out);
197  return;
198  }
199 
200  mutt_file_copy_stream(fp_in, fp_out);
201 
202  mutt_file_fclose(&fp_in);
203  mutt_file_fclose(&fp_out);
204 
205  if (stat(path, &st) == -1)
206  {
207  mutt_perror(path);
208  return;
209  }
210 
211  mtime = mutt_file_decrease_mtime(path, &st);
212 
213  mutt_edit_file(editor, path);
214  stat(path, &st);
215  if (mtime == st.st_mtime)
216  {
217  mutt_debug(LL_DEBUG1, "temp file was not modified\n");
218  /* the file has not changed! */
219  mutt_file_unlink(path);
220  return;
221  }
222 
223  mutt_file_unlink(body);
225 
226  /* Read the temp file back in */
227  fp_in = fopen(path, "r");
228  if (!fp_in)
229  {
230  mutt_perror(path);
231  return;
232  }
233 
234  fp_out = mutt_file_fopen(body, "w");
235  if (!fp_out)
236  {
237  /* intentionally leak a possible temporary file here */
238  mutt_file_fclose(&fp_in);
239  mutt_perror(body);
240  return;
241  }
242 
243  n = mutt_rfc822_read_header(fp_in, NULL, true, false);
244  while ((i = fread(buf, 1, sizeof(buf), fp_in)) > 0)
245  fwrite(buf, 1, i, fp_out);
246  mutt_file_fclose(&fp_out);
247  mutt_file_fclose(&fp_in);
248  mutt_file_unlink(path);
249 
250  /* in case the user modifies/removes the In-Reply-To header with
251  * $edit_headers set, we remove References: as they're likely invalid;
252  * we can simply compare strings as we don't generate References for
253  * multiple Message-Ids in IRT anyways */
254 #ifdef USE_NNTP
255  if (!OptNewsSend)
256 #endif
257  {
258  if (!STAILQ_EMPTY(&e->env->in_reply_to) &&
259  (STAILQ_EMPTY(&n->in_reply_to) ||
261  STAILQ_FIRST(&e->env->in_reply_to)->data) != 0)))
262  {
264  }
265  }
266 
267  /* restore old info. */
270 
271  mutt_env_free(&e->env);
272  e->env = n;
273  n = NULL;
274 
276 
277  /* search through the user defined headers added to see if
278  * fcc: or attach: or pgp: was specified */
279 
280  struct ListNode *np = NULL, *tmp = NULL;
281  STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
282  {
283  bool keep = true;
284  size_t plen;
285 
286  if (fcc && (plen = mutt_str_startswith(np->data, "fcc:", CASE_IGNORE)))
287  {
288  p = mutt_str_skip_email_wsp(np->data + plen);
289  if (*p)
290  {
291  mutt_str_strfcpy(fcc, p, fcclen);
292  mutt_pretty_mailbox(fcc, fcclen);
293  }
294  keep = false;
295  }
296  else if ((plen = mutt_str_startswith(np->data, "attach:", CASE_IGNORE)))
297  {
298  struct Body *body2 = NULL;
299  struct Body *parts = NULL;
300 
301  p = mutt_str_skip_email_wsp(np->data + plen);
302  if (*p)
303  {
304  size_t l = 0;
305  for (; (p[0] != '\0') && (p[0] != ' ') && (p[0] != '\t'); p++)
306  {
307  if (p[0] == '\\')
308  {
309  if (p[1] == '\0')
310  break;
311  p++;
312  }
313  if (l < (sizeof(path) - 1))
314  path[l++] = *p;
315  }
317  path[l] = '\0';
318 
319  mutt_expand_path(path, sizeof(path));
320  body2 = mutt_make_file_attach(path);
321  if (body2)
322  {
323  body2->description = mutt_str_strdup(p);
324  for (parts = e->content; parts->next; parts = parts->next)
325  ;
326  parts->next = body2;
327  }
328  else
329  {
330  mutt_pretty_mailbox(path, sizeof(path));
331  mutt_error(_("%s: unable to attach file"), path);
332  }
333  }
334  keep = false;
335  }
336  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
337  (plen = mutt_str_startswith(np->data, "pgp:", CASE_IGNORE)))
338  {
339  e->security = mutt_parse_crypt_hdr(np->data + plen, false, APPLICATION_PGP);
340  if (e->security)
342  keep = false;
343  }
344 
345  if (!keep)
346  {
347  STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
348  FREE(&np->data);
349  FREE(&np);
350  }
351  }
352 }
#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:303
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
struct Body * content
List of MIME parts.
Definition: email.h:92
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
#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:2238
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:82
struct Body * mutt_make_file_attach(const char *path)
Create a file attachment.
Definition: sendlib.c:1620
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:91
#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:51
"light" mode (used for edit_hdrs)
Definition: sendlib.h:62
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:612
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/ncrypt.h pgplib.h, smime.h
Definition: email.h:41
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: ncrypt.h:134
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:251
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:86
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:44
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:81
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:1130
#define STAILQ_FIRST(head)
Definition: queue.h:348
#define WithCrypto
Definition: ncrypt.h:160
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:54

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_make_label_hash ( struct Mailbox m)

Create a Hash Table to store the labels.

Parameters
mMailbox

Definition at line 358 of file mutt_header.c.

359 {
360  /* 131 is just a rough prime estimate of how many distinct
361  * labels someone might have in a m. */
363 }
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:140

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 370 of file mutt_header.c.

371 {
372  if (!m || !m->label_hash)
373  return;
374  if (e->env->x_label)
375  label_ref_inc(m, e->env->x_label);
376 }
struct Envelope * env
Envelope information.
Definition: email.h:91
char * x_label
X-Label.
Definition: envelope.h:72
struct Hash * label_hash
Hash table for x-labels.
Definition: mailbox.h:140
static void label_ref_inc(struct Mailbox *m, char *label)
Increase the refcount of a label.
Definition: mutt_header.c:76

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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 383 of file mutt_header.c.

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function: