NeoMutt  2023-11-03-85-g512e01
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mutt_header.c File Reference

Manipulate an email's header. More...

#include "config.h"
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "mutt/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "mutt_header.h"
#include "complete/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "index/lib.h"
#include "ncrypt/lib.h"
#include "postpone/lib.h"
#include "send/lib.h"
#include "globals.h"
#include "muttlib.h"
#include "mview.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.
 
static void label_ref_inc (struct Mailbox *m, char *label)
 Increase the refcount of a label.
 
static bool label_message (struct Mailbox *m, struct Email *e, char *new_label)
 Add an X-Label: field.
 
int mutt_label_message (struct MailboxView *mv, struct EmailArray *ea)
 Let the user label a message.
 
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.
 
void mutt_make_label_hash (struct Mailbox *m)
 Create a Hash Table to store the labels.
 
void mutt_label_hash_add (struct Mailbox *m, struct Email *e)
 Add a message's labels to the Hash Table.
 
void mutt_label_hash_remove (struct Mailbox *m, struct Email *e)
 Remove a message's labels from the Hash Table.
 

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

◆ label_ref_dec()

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

Decrease the refcount of a label.

Parameters
mMailbox
labelLabel

Definition at line 59 of file mutt_header.c.

60{
61 struct HashElem *he = mutt_hash_find_elem(m->label_hash, label);
62 if (!he)
63 return;
64
65 uintptr_t count = (uintptr_t) he->data;
66 if (count <= 1)
67 {
68 mutt_hash_delete(m->label_hash, label, NULL);
69 return;
70 }
71
72 count--;
73 he->data = (void *) count;
74}
void mutt_hash_delete(struct HashTable *table, const char *strkey, const void *data)
Remove an element from a Hash Table.
Definition: hash.c:427
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:377
The item stored in a Hash Table.
Definition: hash.h:44
void * data
User-supplied data.
Definition: hash.h:47
struct HashTable * label_hash
Hash Table: "x-labels" -> Email.
Definition: mailbox.h:124
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ label_ref_inc()

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

Increase the refcount of a label.

Parameters
mMailbox
labelLabel

Definition at line 81 of file mutt_header.c.

82{
83 uintptr_t count;
84
85 struct HashElem *he = mutt_hash_find_elem(m->label_hash, label);
86 if (!he)
87 {
88 count = 1;
89 mutt_hash_insert(m->label_hash, label, (void *) count);
90 return;
91 }
92
93 count = (uintptr_t) he->data;
94 count++;
95 he->data = (void *) count;
96}
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:335
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ label_message()

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
trueThe label was added

Definition at line 105 of file mutt_header.c.

106{
107 if (!e)
108 return false;
109 if (mutt_str_equal(e->env->x_label, new_label))
110 return false;
111
112 if (e->env->x_label)
113 label_ref_dec(m, e->env->x_label);
114 if (mutt_str_replace(&e->env->x_label, new_label))
115 label_ref_inc(m, e->env->x_label);
116
117 e->changed = true;
119 return true;
120}
#define MUTT_ENV_CHANGED_XLABEL
X-Label edited.
Definition: envelope.h:36
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
static void label_ref_inc(struct Mailbox *m, char *label)
Increase the refcount of a label.
Definition: mutt_header.c:81
static void label_ref_dec(struct Mailbox *m, char *label)
Decrease the refcount of a label.
Definition: mutt_header.c:59
struct Envelope * env
Envelope information.
Definition: email.h:66
bool changed
Email has been edited.
Definition: email.h:75
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:90
char * x_label
X-Label.
Definition: envelope.h:76
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_label_message()

int mutt_label_message ( struct MailboxView mv,
struct EmailArray *  ea 
)

Let the user label a message.

Parameters
mvMailbox
eaArray of Emails to label
Return values
numNumber of messages changed

Definition at line 128 of file mutt_header.c.

129{
130 if (!mv || !mv->mailbox || !ea)
131 return 0;
132
133 struct Mailbox *m = mv->mailbox;
134
135 int changed = 0;
136 struct Buffer *buf = buf_pool_get();
137
138 struct Email **ep = ARRAY_GET(ea, 0);
139 if (ARRAY_SIZE(ea) == 1)
140 {
141 // If there's only one email, use its label as a template
142 struct Email *e = *ep;
143 if (e->env->x_label)
144 buf_strcpy(buf, e->env->x_label);
145 }
146
147 if (mw_get_field("Label: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, &CompleteLabelOps, NULL) != 0)
148 {
149 goto done;
150 }
151
152 char *new_label = buf->data;
153 SKIPWS(new_label);
154 if (*new_label == '\0')
155 new_label = NULL;
156
157 ARRAY_FOREACH(ep, ea)
158 {
159 struct Email *e = *ep;
160 if (label_message(m, e, new_label))
161 {
162 changed++;
164 }
165 }
166
167done:
168 buf_pool_release(&buf);
169 return changed;
170}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:108
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
const struct CompleteOps CompleteLabelOps
Auto-Completion of Labels.
Definition: helpers.c:482
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: dlg_index.c:1360
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:275
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
static bool label_message(struct Mailbox *m, struct Email *e, char *new_label)
Add an X-Label: field.
Definition: mutt_header.c:105
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define SKIPWS(ch)
Definition: string2.h:45
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
The envelope/body of an email.
Definition: email.h:37
struct Mailbox * mailbox
Current Mailbox.
Definition: mview.h:50
A mailbox.
Definition: mailbox.h:79
bool changed
Mailbox has been modified.
Definition: mailbox.h:109
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

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

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

Definition at line 179 of file mutt_header.c.

181{
182 struct Buffer *path = buf_pool_get();
183 buf_mktemp(path);
184 FILE *fp_out = mutt_file_fopen(buf_string(path), "w");
185 if (!fp_out)
186 {
187 mutt_perror("%s", buf_string(path));
188 goto cleanup;
189 }
190
193 false, false, NeoMutt->sub);
194 fputc('\n', fp_out); /* tie off the header. */
195
196 /* now copy the body of the message. */
197 FILE *fp_in = fopen(body, "r");
198 if (!fp_in)
199 {
200 mutt_perror("%s", body);
201 mutt_file_fclose(&fp_out);
202 goto cleanup;
203 }
204
205 mutt_file_copy_stream(fp_in, fp_out);
206
207 mutt_file_fclose(&fp_in);
208 mutt_file_fclose(&fp_out);
209
210 struct stat st = { 0 };
211 if (stat(buf_string(path), &st) == -1)
212 {
213 mutt_perror("%s", buf_string(path));
214 goto cleanup;
215 }
216
217 time_t mtime = mutt_file_decrease_mtime(buf_string(path), &st);
218 if (mtime == (time_t) -1)
219 {
220 mutt_perror("%s", buf_string(path));
221 goto cleanup;
222 }
223
224 mutt_edit_file(editor, buf_string(path));
225 if ((stat(buf_string(path), &st) != 0) || (mtime == st.st_mtime))
226 {
227 mutt_debug(LL_DEBUG1, "temp file was not modified\n");
228 /* the file has not changed! */
230 goto cleanup;
231 }
232
233 mutt_file_unlink(body);
235
236 /* Read the temp file back in */
237 fp_in = fopen(buf_string(path), "r");
238 if (!fp_in)
239 {
240 mutt_perror("%s", buf_string(path));
241 goto cleanup;
242 }
243
244 fp_out = mutt_file_fopen(body, "w");
245 if (!fp_out)
246 {
247 /* intentionally leak a possible temporary file here */
248 mutt_file_fclose(&fp_in);
249 mutt_perror("%s", body);
250 goto cleanup;
251 }
252
253 struct Envelope *env_new = NULL;
254 char buf[1024] = { 0 };
255 env_new = mutt_rfc822_read_header(fp_in, NULL, true, false);
256 int bytes_read;
257 while ((bytes_read = fread(buf, 1, sizeof(buf), fp_in)) > 0)
258 fwrite(buf, 1, bytes_read, fp_out);
259 mutt_file_fclose(&fp_out);
260 mutt_file_fclose(&fp_in);
262
263 /* in case the user modifies/removes the In-Reply-To header with
264 * $edit_headers set, we remove References: as they're likely invalid;
265 * we can simply compare strings as we don't generate References for
266 * multiple Message-Ids in IRT anyways */
267 if (!OptNewsSend)
268 {
269 if (!STAILQ_EMPTY(&e->env->in_reply_to) &&
270 (STAILQ_EMPTY(&env_new->in_reply_to) ||
271 !mutt_str_equal(STAILQ_FIRST(&env_new->in_reply_to)->data,
272 STAILQ_FIRST(&e->env->in_reply_to)->data)))
273 {
275 }
276 }
277
278 /* restore old info. */
279 mutt_list_free(&env_new->references);
280 STAILQ_SWAP(&env_new->references, &e->env->references, ListNode);
281
282 mutt_env_free(&e->env);
283 e->env = env_new;
284 env_new = NULL;
285
287
288 /* search through the user defined headers added to see if
289 * fcc: or attach: or pgp: or smime: was specified */
290
291 struct ListNode *np = NULL, *tmp = NULL;
292 STAILQ_FOREACH_SAFE(np, &e->env->userhdrs, entries, tmp)
293 {
294 bool keep = true;
295 size_t plen = 0;
296
297 // Check for header names: most specific first
298 if (fcc && ((plen = mutt_istr_startswith(np->data, "X-Mutt-Fcc:")) ||
299 (plen = mutt_istr_startswith(np->data, "Mutt-Fcc:")) ||
300 (plen = mutt_istr_startswith(np->data, "fcc:"))))
301 {
302 const char *p = mutt_str_skip_email_wsp(np->data + plen);
303 if (*p)
304 {
305 buf_strcpy(fcc, p);
307 }
308 keep = false;
309 }
310 // Check for header names: most specific first
311 else if ((plen = mutt_istr_startswith(np->data, "X-Mutt-Attach:")) ||
312 (plen = mutt_istr_startswith(np->data, "Mutt-Attach:")) ||
313 (plen = mutt_istr_startswith(np->data, "attach:")))
314 {
315 struct Body *body2 = NULL;
316 struct Body *parts = NULL;
317
318 const char *p = mutt_str_skip_email_wsp(np->data + plen);
319 if (*p)
320 {
321 buf_reset(path);
322 for (; (p[0] != '\0') && (p[0] != ' ') && (p[0] != '\t'); p++)
323 {
324 if (p[0] == '\\')
325 {
326 if (p[1] == '\0')
327 break;
328 p++;
329 }
330 buf_addch(path, *p);
331 }
333
334 buf_expand_path(path);
336 if (body2)
337 {
338 body2->description = mutt_str_dup(p);
339 for (parts = e->body; parts->next; parts = parts->next)
340 ; // do nothing
341
342 parts->next = body2;
343 }
344 else
345 {
346 buf_pretty_mailbox(path);
347 mutt_error(_("%s: unable to attach file"), buf_string(path));
348 }
349 }
350 keep = false;
351 }
352 // Check for header names: most specific first
353 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
354 ((plen = mutt_istr_startswith(np->data, "X-Mutt-PGP:")) ||
355 (plen = mutt_istr_startswith(np->data, "Mutt-PGP:")) ||
356 (plen = mutt_istr_startswith(np->data, "pgp:"))))
357 {
358 SecurityFlags sec = mutt_parse_crypt_hdr(np->data + plen, false, APPLICATION_PGP);
359 if (sec != SEC_NO_FLAGS)
360 sec |= APPLICATION_PGP;
361 if (sec != e->security)
362 {
363 e->security = sec;
365 }
366 keep = false;
367 }
368 // Check for header names: most specific first
369 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
370 ((plen = mutt_istr_startswith(np->data, "X-Mutt-SMIME:")) ||
371 (plen = mutt_istr_startswith(np->data, "Mutt-SMIME:")) ||
372 (plen = mutt_istr_startswith(np->data, "smime:"))))
373 {
375 if (sec != SEC_NO_FLAGS)
376 sec |= APPLICATION_SMIME;
377 if (sec != e->security)
378 {
379 e->security = sec;
381 }
382 keep = false;
383 }
384#ifdef MIXMASTER
385 // Check for header names: most specific first
386 else if ((plen = mutt_istr_startswith(np->data, "X-Mutt-Mix:")) ||
387 (plen = mutt_istr_startswith(np->data, "Mutt-Mix:")))
388 {
390
391 char *t = strtok(np->data + plen, ", \t\n");
392 while (t)
393 {
395 t = strtok(NULL, ", \t\n");
396 }
397 keep = false;
398 }
399#endif
400
401 if (!keep)
402 {
403 STAILQ_REMOVE(&e->env->userhdrs, np, ListNode, entries);
404 FREE(&np->data);
405 FREE(&np);
406 }
407 }
408
409cleanup:
410 buf_pool_release(&path);
411}
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:312
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:113
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1156
@ NT_EMAIL_CHANGE
Email has changed.
Definition: email.h:152
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
Definition: envelope.c:288
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:262
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:636
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file's modification time by 1 second.
Definition: file.c:1031
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:196
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:76
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
#define mutt_perror(...)
Definition: logging2.h:93
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *b, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:575
@ MUTT_WRITE_HEADER_EDITHDRS
"light" mode (used for edit_hdrs)
Definition: header.h:43
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define FREE(x)
Definition: memory.h:45
#define _(a)
Definition: message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:173
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:680
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:556
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:329
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:77
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:91
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:92
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:117
@ NT_EMAIL
Email has changed, NotifyEmail, EventEmail.
Definition: notify_type.h:44
SecurityFlags mutt_parse_crypt_hdr(const char *p, bool set_empty_signas, SecurityFlags crypt_app)
Parse a crypto header string.
Definition: postpone.c:202
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
#define STAILQ_SWAP(head1, head2, type)
Definition: queue.h:428
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:605
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
char * description
content-description
Definition: body.h:55
struct Body * next
next attachment in the list
Definition: body.h:71
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
struct ListHead chain
Mixmaster chain.
Definition: email.h:91
struct Notify * notify
Notifications: NotifyEmail, EventEmail.
Definition: email.h:71
The header of an Email.
Definition: envelope.h:57
struct ListHead userhdrs
user defined headers
Definition: envelope.h:85
struct ListHead references
message references (in reverse order)
Definition: envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:84
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
#define buf_mktemp(buf)
Definition: tmp.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_label_hash()

void mutt_make_label_hash ( struct Mailbox m)

Create a Hash Table to store the labels.

Parameters
mMailbox

Definition at line 417 of file mutt_header.c.

418{
419 /* 131 is just a rough prime estimate of how many distinct
420 * labels someone might have in a mailbox. */
422}
struct HashTable * mutt_hash_new(size_t num_elems, HashFlags flags)
Create a new Hash Table (with string keys)
Definition: hash.c:259
#define MUTT_HASH_STRDUP_KEYS
make a copy of the keys
Definition: hash.h:112
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_label_hash_add()

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

430{
431 if (!m || !m->label_hash)
432 return;
433 if (e->env->x_label)
434 label_ref_inc(m, e->env->x_label);
435}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_label_hash_remove()

void mutt_label_hash_remove ( struct Mailbox m,
struct Email e 
)

Remove a message's labels from the Hash Table.

Parameters
mMailbox
eEmail

Definition at line 442 of file mutt_header.c.

443{
444 if (!m || !m->label_hash)
445 return;
446 if (e->env->x_label)
447 label_ref_dec(m, e->env->x_label);
448}
+ Here is the call graph for this function:
+ Here is the caller graph for this function: