NeoMutt  2018-07-16 +1783-b00bd9
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 "curs_lib.h"
#include "globals.h"
#include "index.h"
#include "mailbox.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)
 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 *msg, 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:129

+ 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 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:129

+ 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 
)
static

add an X-Label: field

Parameters
[in]mMailbox
[in]eEmail
[out]newSet 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) == 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);
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
Definition: email.h:48
unsigned char changed
Definition: envelope.h:69
struct Envelope * env
envelope information
Definition: email.h:92
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:32
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:456
char * x_label
Definition: envelope.h:56
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:618
static void label_ref_inc(struct Mailbox *m, char *label)
Increase the refcount of a label.
Definition: mutt_header.c:78

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

127 {
128  if (!m || !el)
129  return 0;
130 
131  char buf[1024] = { 0 };
132  char *new = NULL;
133 
134  struct EmailNode *en = STAILQ_FIRST(el);
135  if (!STAILQ_NEXT(en, entries))
136  {
137  // If there's only one email, use its label as a template
138  if (en->email->env->x_label)
139  mutt_str_strfcpy(buf, en->email->env->x_label, sizeof(buf));
140  }
141 
142  if (mutt_get_field("Label: ", buf, sizeof(buf), MUTT_LABEL /* | MUTT_CLEAR */) != 0)
143  return 0;
144 
145  new = buf;
146  SKIPWS(new);
147  if (*new == '\0')
148  new = NULL;
149 
150  int changed = 0;
151  STAILQ_FOREACH(en, el, entries)
152  {
153  if (label_message(m, en->email, new))
154  {
155  changed++;
157  }
158  }
159 
160  return changed;
161 }
#define MUTT_LABEL
Do label completion.
Definition: mutt.h:70
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:86
struct Envelope * env
envelope information
Definition: email.h:92
#define SKIPWS(ch)
Definition: string2.h:46
static bool label_message(struct Mailbox *m, struct Email *e, char *new)
add an X-Label: field
Definition: mutt_header.c:102
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:753
#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:3645
struct Email * email
Definition: email.h:123
List of Emails.
Definition: email.h:121
char * x_label
Definition: envelope.h:56
#define STAILQ_FIRST(head)
Definition: queue.h:348

+ 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 msg,
char *  fcc,
size_t  fcclen 
)

Let the user edit the message header and body.

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

Definition at line 171 of file mutt_header.c.

173 {
174  char path[PATH_MAX]; /* tempfile used to edit headers + body */
175  char buf[1024];
176  const char *p = NULL;
177  int i;
178  struct Envelope *n = NULL;
179  time_t mtime;
180  struct stat st;
181 
182  mutt_mktemp(path, sizeof(path));
183  FILE *fp_out = mutt_file_fopen(path, "w");
184  if (!fp_out)
185  {
186  mutt_perror(path);
187  return;
188  }
189 
190  mutt_env_to_local(msg->env);
191  mutt_rfc822_write_header(fp_out, msg->env, NULL, MUTT_WRITE_HEADER_EDITHDRS, false, false);
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  return;
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(path, &st) == -1)
209  {
210  mutt_perror(path);
211  return;
212  }
213 
214  mtime = mutt_file_decrease_mtime(path, &st);
215 
216  mutt_edit_file(editor, path);
217  stat(path, &st);
218  if (mtime == st.st_mtime)
219  {
220  mutt_debug(LL_DEBUG1, "temp file was not modified\n");
221  /* the file has not changed! */
222  mutt_file_unlink(path);
223  return;
224  }
225 
226  mutt_file_unlink(body);
227  mutt_list_free(&msg->env->userhdrs);
228 
229  /* Read the temp file back in */
230  fp_in = fopen(path, "r");
231  if (!fp_in)
232  {
233  mutt_perror(path);
234  return;
235  }
236 
237  fp_out = mutt_file_fopen(body, "w");
238  if (!fp_out)
239  {
240  /* intentionally leak a possible temporary file here */
241  mutt_file_fclose(&fp_in);
242  mutt_perror(body);
243  return;
244  }
245 
246  n = mutt_rfc822_read_header(fp_in, NULL, true, false);
247  while ((i = fread(buf, 1, sizeof(buf), fp_in)) > 0)
248  fwrite(buf, 1, i, fp_out);
249  mutt_file_fclose(&fp_out);
250  mutt_file_fclose(&fp_in);
251  mutt_file_unlink(path);
252 
253  /* in case the user modifies/removes the In-Reply-To header with
254  * $edit_headers set, we remove References: as they're likely invalid;
255  * we can simply compare strings as we don't generate References for
256  * multiple Message-Ids in IRT anyways */
257 #ifdef USE_NNTP
258  if (!OptNewsSend)
259 #endif
260  {
261  if (!STAILQ_EMPTY(&msg->env->in_reply_to) &&
262  (STAILQ_EMPTY(&n->in_reply_to) ||
264  STAILQ_FIRST(&msg->env->in_reply_to)->data) != 0)))
265  {
266  mutt_list_free(&msg->env->references);
267  }
268  }
269 
270  /* restore old info. */
273 
274  mutt_env_free(&msg->env);
275  msg->env = n;
276  n = NULL;
277 
279 
280  /* search through the user defined headers added to see if
281  * fcc: or attach: or pgp: was specified */
282 
283  struct ListNode *np, *tmp;
284  STAILQ_FOREACH_SAFE(np, &msg->env->userhdrs, entries, tmp)
285  {
286  bool keep = true;
287  size_t plen;
288 
289  if (fcc && (plen = mutt_str_startswith(np->data, "fcc:", CASE_IGNORE)))
290  {
291  p = mutt_str_skip_email_wsp(np->data + plen);
292  if (*p)
293  {
294  mutt_str_strfcpy(fcc, p, fcclen);
295  mutt_pretty_mailbox(fcc, fcclen);
296  }
297  keep = false;
298  }
299  else if ((plen = mutt_str_startswith(np->data, "attach:", CASE_IGNORE)))
300  {
301  struct Body *body2 = NULL;
302  struct Body *parts = NULL;
303 
304  p = mutt_str_skip_email_wsp(np->data + plen);
305  if (*p)
306  {
307  size_t l = 0;
308  for (; *p && *p != ' ' && *p != '\t'; p++)
309  {
310  if (*p == '\\')
311  {
312  if (!*(p + 1))
313  break;
314  p++;
315  }
316  if (l < sizeof(path) - 1)
317  path[l++] = *p;
318  }
320  path[l] = '\0';
321 
322  mutt_expand_path(path, sizeof(path));
323  body2 = mutt_make_file_attach(path);
324  if (body2)
325  {
326  body2->description = mutt_str_strdup(p);
327  for (parts = msg->content; parts->next; parts = parts->next)
328  ;
329  parts->next = body2;
330  }
331  else
332  {
333  mutt_pretty_mailbox(path, sizeof(path));
334  mutt_error(_("%s: unable to attach file"), path);
335  }
336  }
337  keep = false;
338  }
339  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
340  (plen = mutt_str_startswith(np->data, "pgp:", CASE_IGNORE)))
341  {
342  msg->security = mutt_parse_crypt_hdr(np->data + plen, false, APPLICATION_PGP);
343  if (msg->security)
344  msg->security |= APPLICATION_PGP;
345  keep = false;
346  }
347 
348  if (!keep)
349  {
350  STAILQ_REMOVE(&msg->env->userhdrs, np, ListNode, entries);
351  FREE(&np->data);
352  FREE(&np);
353  }
354  }
355 }
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:400
#define mutt_perror(...)
Definition: logging.h:84
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:313
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
struct Body * content
list of MIME parts
Definition: email.h:93
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
struct ListHead userhdrs
user defined headers
Definition: envelope.h:67
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:60
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:117
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:2233
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:127
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:66
struct Body * mutt_make_file_attach(const char *path)
Create a file attachment.
Definition: sendlib.c:1612
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:92
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:360
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:74
#define PATH_MAX
Definition: mutt.h:49
"light" mode (used for edit_hdrs)
Definition: sendlib.h:64
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:61
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:753
Ignore case when comparing strings.
Definition: string2.h:67
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:779
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:129
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:206
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:264
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:83
void mutt_env_free(struct Envelope **p)
Free an Envelope.
Definition: envelope.c:53
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:954
#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:80
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:578
struct ListHead references
message references (in reverse order)
Definition: envelope.h:65
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:1013
#define STAILQ_FIRST(head)
Definition: queue.h:348
#define WithCrypto
Definition: ncrypt.h:155
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:618
The header of an email.
Definition: envelope.h:38

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

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

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

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

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

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function: