NeoMutt  2023-03-22
Teaching an old dog new tricks
DOXYGEN
external.c File Reference

Manage where the email is piped to external commands. More...

#include "config.h"
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "external.h"
#include "attach/lib.h"
#include "browser/lib.h"
#include "enter/lib.h"
#include "ncrypt/lib.h"
#include "parse/lib.h"
#include "progress/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "copy.h"
#include "globals.h"
#include "hook.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "mutt_thread.h"
#include "muttlib.h"
#include "mx.h"
#include "protos.h"
#include "imap/lib.h"
#include "notmuch/lib.h"
#include <libintl.h>
+ Include dependency graph for external.c:

Go to the source code of this file.

Macros

#define EXTRA_SPACE   (15 + 7 + 2)
 

Functions

void commands_cleanup (void)
 Clean up commands globals. More...
 
void ci_bounce_message (struct Mailbox *m, struct EmailList *el)
 Bounce an email. More...
 
static void pipe_set_flags (bool decode, bool print, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
 Generate flags for copy header/message. More...
 
static void pipe_msg (struct Mailbox *m, struct Email *e, struct Message *msg, FILE *fp, bool decode, bool print)
 Pipe a message. More...
 
static int pipe_message (struct Mailbox *m, struct EmailList *el, const char *cmd, bool decode, bool print, bool split, const char *sep)
 Pipe message to a command. More...
 
void mutt_pipe_message (struct Mailbox *m, struct EmailList *el)
 Pipe a message. More...
 
void mutt_print_message (struct Mailbox *m, struct EmailList *el)
 Print a message. More...
 
bool mutt_select_sort (bool reverse)
 Ask the user for a sort method. More...
 
bool mutt_shell_escape (void)
 Invoke a command in a subshell. More...
 
void mutt_enter_command (void)
 Enter a neomutt command. More...
 
void mutt_display_address (struct Envelope *env)
 Display the address of a message. More...
 
static void set_copy_flags (struct Email *e, enum MessageTransformOpt transform_opt, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
 Set the flags for a message copy. More...
 
int mutt_save_message_ctx (struct Mailbox *m_src, struct Email *e, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt, struct Mailbox *m_dst)
 Save a message to a given mailbox. More...
 
int mutt_save_message (struct Mailbox *m, struct EmailList *el, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
 Save an email. More...
 
bool mutt_edit_content_type (struct Email *e, struct Body *b, FILE *fp)
 Edit the content type of an attachment. More...
 
static bool check_traditional_pgp (struct Mailbox *m, struct Email *e)
 Check for an inline PGP content. More...
 
bool mutt_check_traditional_pgp (struct Mailbox *m, struct EmailList *el)
 Check if a message has inline PGP content. More...
 

Variables

static struct Buffer LastSaveFolder = { 0 }
 The folder the user last saved to. More...
 

Detailed Description

Manage where the email is piped to external commands.

Authors
  • Michael R. Elkins
  • Thomas Roessler
  • Pietro Cerutti

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 external.c.

Macro Definition Documentation

◆ EXTRA_SPACE

#define EXTRA_SPACE   (15 + 7 + 2)

Function Documentation

◆ commands_cleanup()

void commands_cleanup ( void  )

Clean up commands globals.

Definition at line 80 of file external.c.

81{
83}
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:347
static struct Buffer LastSaveFolder
The folder the user last saved to.
Definition: external.c:75
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ ci_bounce_message()

void ci_bounce_message ( struct Mailbox m,
struct EmailList *  el 
)

Bounce an email.

Parameters
mMailbox
elList of Emails to bounce

Definition at line 90 of file external.c.

91{
92 if (!m || !el || STAILQ_EMPTY(el))
93 return;
94
95 struct Buffer *buf = mutt_buffer_pool_get();
96 struct Buffer *prompt = mutt_buffer_pool_get();
97 struct Buffer *scratch = NULL;
98
99 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
100 char *err = NULL;
101 int rc;
102 int msg_count = 0;
103
104 struct EmailNode *en = NULL;
105 STAILQ_FOREACH(en, el, entries)
106 {
107 /* RFC5322 mandates a From: header,
108 * so warn before bouncing messages without one */
109 if (TAILQ_EMPTY(&en->email->env->from))
110 mutt_error(_("Warning: message contains no From: header"));
111
112 msg_count++;
113 }
114
115 if (msg_count == 1)
116 mutt_buffer_strcpy(prompt, _("Bounce message to: "));
117 else
118 mutt_buffer_strcpy(prompt, _("Bounce tagged messages to: "));
119
121 false, NULL, NULL, NULL);
122 if ((rc != 0) || mutt_buffer_is_empty(buf))
123 goto done;
124
126 if (TAILQ_EMPTY(&al))
127 {
128 mutt_error(_("Error parsing address"));
129 goto done;
130 }
131
133
134 if (mutt_addrlist_to_intl(&al, &err) < 0)
135 {
136 mutt_error(_("Bad IDN: '%s'"), err);
137 FREE(&err);
138 goto done;
139 }
140
142 mutt_addrlist_write(&al, buf, true);
143
144#define EXTRA_SPACE (15 + 7 + 2)
145 scratch = mutt_buffer_pool_get();
146 mutt_buffer_printf(scratch,
147 ngettext("Bounce message to %s?", "Bounce messages to %s?", msg_count),
148 mutt_buffer_string(buf));
149
150 const size_t width = msgwin_get_width();
151 if (mutt_strwidth(mutt_buffer_string(scratch)) > (width - EXTRA_SPACE))
152 {
153 mutt_simple_format(prompt->data, prompt->dsize, 0, width - EXTRA_SPACE,
154 JUSTIFY_LEFT, 0, scratch->data, scratch->dsize, false);
155 mutt_buffer_addstr(prompt, "...?");
156 }
157 else
158 mutt_buffer_copy(prompt, scratch);
159
160 const enum QuadOption c_bounce = cs_subset_quad(NeoMutt->sub, "bounce");
161 if (query_quadoption(c_bounce, mutt_buffer_string(prompt)) != MUTT_YES)
162 {
164 mutt_message(ngettext("Message not bounced", "Messages not bounced", msg_count));
165 goto done;
166 }
167
169
170 struct Message *msg = NULL;
171 STAILQ_FOREACH(en, el, entries)
172 {
173 msg = mx_msg_open(m, en->email->msgno);
174 if (!msg)
175 {
176 rc = -1;
177 break;
178 }
179
180 rc = mutt_bounce_message(msg->fp, m, en->email, &al, NeoMutt->sub);
181 mx_msg_close(m, &msg);
182
183 if (rc < 0)
184 break;
185 }
186
187 /* If no error, or background, display message. */
188 if ((rc == 0) || (rc == S_BKG))
189 mutt_message(ngettext("Message bounced", "Messages bounced", msg_count));
190
191done:
195 mutt_buffer_pool_release(&scratch);
196}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1435
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1184
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:616
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1270
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:298
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:365
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:500
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, enum FormatJustify justify, char pad_char, const char *s, size_t n, bool arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:638
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:906
@ JUSTIFY_LEFT
Left justify the text.
Definition: curs_lib.h:42
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:178
#define EXTRA_SPACE
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define FREE(x)
Definition: memory.h:43
size_t msgwin_get_width(void)
Get the width of the Message Window.
Definition: msgwin.c:269
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:249
#define _(a)
Definition: message.h:28
#define MUTT_COMP_ALIAS
Alias completion (in alias dialog)
Definition: mutt.h:56
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1192
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1146
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
int mutt_bounce_message(FILE *fp, struct Mailbox *m, struct Email *e, struct AddressList *to, struct ConfigSubset *sub)
Bounce an email message.
Definition: sendlib.c:908
#define S_BKG
Definition: string2.h:42
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
List of Emails.
Definition: email.h:131
struct Email * email
Email in the list.
Definition: email.h:132
struct Envelope * env
Envelope information.
Definition: email.h:66
int msgno
Number displayed to the user.
Definition: email.h:110
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pipe_set_flags()

static void pipe_set_flags ( bool  decode,
bool  print,
CopyMessageFlags cmflags,
CopyHeaderFlags chflags 
)
static

Generate flags for copy header/message.

Parameters
[in]decodeIf true decode the message
[in]printIf true, mark the message for printing
[out]cmflagsFlags, see CopyMessageFlags
[out]chflagsFlags, see CopyHeaderFlags

Definition at line 205 of file external.c.

207{
208 if (decode)
209 {
210 *chflags |= CH_DECODE | CH_REORDER;
211 *cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
212
213 const bool c_print_decode_weed = cs_subset_bool(NeoMutt->sub, "print_decode_weed");
214 const bool c_pipe_decode_weed = cs_subset_bool(NeoMutt->sub, "pipe_decode_weed");
215 if (print ? c_print_decode_weed : c_pipe_decode_weed)
216 {
217 *chflags |= CH_WEED;
218 *cmflags |= MUTT_CM_WEED;
219 }
220
221 /* Just as with copy-decode, we need to update the mime fields to avoid
222 * confusing programs that may process the email. However, we don't want
223 * to force those fields to appear in printouts. */
224 if (!print)
225 *chflags |= CH_MIME | CH_TXTPLAIN;
226 }
227
228 if (print)
229 *cmflags |= MUTT_CM_PRINTING;
230}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:41
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition: copy.h:59
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:43
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:63
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pipe_msg()

static void pipe_msg ( struct Mailbox m,
struct Email e,
struct Message msg,
FILE *  fp,
bool  decode,
bool  print 
)
static

Pipe a message.

Parameters
mMailbox
eEmail to pipe
msgMessage
fpFile to write to
decodeIf true, decode the message
printIf true, message is for printing

Definition at line 241 of file external.c.

243{
245 CopyHeaderFlags chflags = CH_FROM;
246
247 pipe_set_flags(decode, print, &cmflags, &chflags);
248
249 if ((WithCrypto != 0) && decode && e->security & SEC_ENCRYPT)
250 {
252 return;
253 endwin();
254 }
255
256 const bool own_msg = !msg;
257 if (own_msg)
258 {
259 msg = mx_msg_open(m, e->msgno);
260 if (!msg)
261 {
262 return;
263 }
264 }
265
266 if (decode)
267 {
269 }
270
271 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
272
273 if (own_msg)
274 {
275 mx_msg_close(m, &msg);
276 }
277}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:590
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:868
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:56
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:34
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
static void pipe_set_flags(bool decode, bool print, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
Generate flags for copy header/message.
Definition: external.c:205
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ pipe_message()

static int pipe_message ( struct Mailbox m,
struct EmailList *  el,
const char *  cmd,
bool  decode,
bool  print,
bool  split,
const char *  sep 
)
static

Pipe message to a command.

Parameters
mMailbox
elList of Emails to pipe
cmdCommand to pipe to
decodeShould the message be decrypted
printTrue if this is a print job
splitShould a separator be sent between messages?
sepSeparator string
Return values
0Success
1Error

The following code is shared between printing and piping.

Definition at line 293 of file external.c.

295{
296 if (!m || !el)
297 return 1;
298
299 struct EmailNode *en = STAILQ_FIRST(el);
300 if (!en)
301 return 1;
302
303 int rc = 0;
304 pid_t pid;
305 FILE *fp_out = NULL;
306
307 if (!STAILQ_NEXT(en, entries))
308 {
309 /* handle a single message */
311
312 struct Message *msg = mx_msg_open(m, en->email->msgno);
313 if (msg && (WithCrypto != 0) && decode)
314 {
316 if ((en->email->security & SEC_ENCRYPT) &&
318 {
319 mx_msg_close(m, &msg);
320 return 1;
321 }
322 }
323 mutt_endwin();
324
325 pid = filter_create(cmd, &fp_out, NULL, NULL);
326 if (pid < 0)
327 {
328 mutt_perror(_("Can't create filter process"));
329 mx_msg_close(m, &msg);
330 return 1;
331 }
332
333 OptKeepQuiet = true;
334 pipe_msg(m, en->email, msg, fp_out, decode, print);
335 mx_msg_close(m, &msg);
336 mutt_file_fclose(&fp_out);
337 rc = filter_wait(pid);
338 OptKeepQuiet = false;
339 }
340 else
341 {
342 /* handle tagged messages */
343 if ((WithCrypto != 0) && decode)
344 {
345 STAILQ_FOREACH(en, el, entries)
346 {
347 struct Message *msg = mx_msg_open(m, en->email->msgno);
348 if (msg)
349 {
352 mx_msg_close(m, &msg);
353 }
354 if ((en->email->security & SEC_ENCRYPT) &&
356 {
357 return 1;
358 }
359 }
360 }
361
362 if (split)
363 {
364 STAILQ_FOREACH(en, el, entries)
365 {
367 mutt_endwin();
368 pid = filter_create(cmd, &fp_out, NULL, NULL);
369 if (pid < 0)
370 {
371 mutt_perror(_("Can't create filter process"));
372 return 1;
373 }
374 OptKeepQuiet = true;
375 pipe_msg(m, en->email, NULL, fp_out, decode, print);
376 /* add the message separator */
377 if (sep)
378 fputs(sep, fp_out);
379 mutt_file_fclose(&fp_out);
380 if (filter_wait(pid) != 0)
381 rc = 1;
382 OptKeepQuiet = false;
383 }
384 }
385 else
386 {
387 mutt_endwin();
388 pid = filter_create(cmd, &fp_out, NULL, NULL);
389 if (pid < 0)
390 {
391 mutt_perror(_("Can't create filter process"));
392 return 1;
393 }
394 OptKeepQuiet = true;
395 STAILQ_FOREACH(en, el, entries)
396 {
398 pipe_msg(m, en->email, NULL, fp_out, decode, print);
399 /* add the message separator */
400 if (sep)
401 fputs(sep, fp_out);
402 }
403 mutt_file_fclose(&fp_out);
404 if (filter_wait(pid) != 0)
405 rc = 1;
406 OptKeepQuiet = false;
407 }
408 }
409
410 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
411 if ((rc != 0) || c_wait_key)
413 return rc;
414}
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:386
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:353
static void pipe_msg(struct Mailbox *m, struct Email *e, struct Message *msg, FILE *fp, bool decode, bool print)
Pipe a message.
Definition: external.c:241
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:151
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: globals.c:72
#define mutt_perror(...)
Definition: logging.h:88
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:656
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:45
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pipe_message()

void mutt_pipe_message ( struct Mailbox m,
struct EmailList *  el 
)

Pipe a message.

Parameters
mMailbox
elList of Emails to pipe

Definition at line 421 of file external.c.

422{
423 if (!m || !el)
424 return;
425
426 struct Buffer *buf = mutt_buffer_pool_get();
427
428 if (mutt_buffer_get_field(_("Pipe to command: "), buf, MUTT_COMP_FILE_SIMPLE,
429 false, NULL, NULL, NULL) != 0)
430 {
431 goto cleanup;
432 }
433
434 if (mutt_buffer_len(buf) == 0)
435 goto cleanup;
436
438 const bool c_pipe_decode = cs_subset_bool(NeoMutt->sub, "pipe_decode");
439 const bool c_pipe_split = cs_subset_bool(NeoMutt->sub, "pipe_split");
440 const char *const c_pipe_sep = cs_subset_string(NeoMutt->sub, "pipe_sep");
441 pipe_message(m, el, mutt_buffer_string(buf), c_pipe_decode, false, c_pipe_split, c_pipe_sep);
442
443cleanup:
445}
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:409
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
static int pipe_message(struct Mailbox *m, struct EmailList *el, const char *cmd, bool decode, bool print, bool split, const char *sep)
Pipe message to a command.
Definition: external.c:293
#define MUTT_COMP_FILE_SIMPLE
File completion (no browser)
Definition: mutt.h:60
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_print_message()

void mutt_print_message ( struct Mailbox m,
struct EmailList *  el 
)

Print a message.

Parameters
mMailbox
elList of Emails to print

Definition at line 452 of file external.c.

453{
454 if (!m || !el)
455 return;
456
457 const enum QuadOption c_print = cs_subset_quad(NeoMutt->sub, "print");
458 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
459 if (c_print && !c_print_command)
460 {
461 mutt_message(_("No printing command has been defined"));
462 return;
463 }
464
465 int msg_count = 0;
466 struct EmailNode *en = NULL;
467 STAILQ_FOREACH(en, el, entries)
468 {
469 msg_count++;
470 }
471
472 if (query_quadoption(c_print, (msg_count == 1) ? _("Print message?") :
473 _("Print tagged messages?")) != MUTT_YES)
474 {
475 return;
476 }
477
478 const bool c_print_decode = cs_subset_bool(NeoMutt->sub, "print_decode");
479 const bool c_print_split = cs_subset_bool(NeoMutt->sub, "print_split");
480 if (pipe_message(m, el, c_print_command, c_print_decode, true, c_print_split, "\f") == 0)
481 mutt_message(ngettext("Message printed", "Messages printed", msg_count));
482 else
483 {
484 mutt_message(ngettext("Message could not be printed",
485 "Messages could not be printed", msg_count));
486 }
487}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_select_sort()

bool mutt_select_sort ( bool  reverse)

Ask the user for a sort method.

Parameters
reverseIf true make it a reverse sort
Return values
trueThe sort type changed

Definition at line 494 of file external.c.

495{
496 enum SortType sort = SORT_DATE;
497
498 switch (mutt_multi_choice(
499 reverse ?
500 /* L10N: The highlighted letters must match the "Sort" options */
501 _("Rev-Sort (d)ate,(f)rm,(r)ecv,(s)ubj,t(o),(t)hread,(u)nsort,si(z)e,s(c)ore,s(p)am,(l)abel?") :
502 /* L10N: The highlighted letters must match the "Rev-Sort" options */
503 _("Sort (d)ate,(f)rm,(r)ecv,(s)ubj,t(o),(t)hread,(u)nsort,si(z)e,s(c)ore,s(p)am,(l)abel?"),
504 /* L10N: These must match the highlighted letters from "Sort" and "Rev-Sort" */
505 _("dfrsotuzcpl")))
506 {
507 case -1: /* abort - don't resort */
508 return false;
509
510 case 1: /* (d)ate */
511 sort = SORT_DATE;
512 break;
513
514 case 2: /* (f)rm */
515 sort = SORT_FROM;
516 break;
517
518 case 3: /* (r)ecv */
519 sort = SORT_RECEIVED;
520 break;
521
522 case 4: /* (s)ubj */
523 sort = SORT_SUBJECT;
524 break;
525
526 case 5: /* t(o) */
527 sort = SORT_TO;
528 break;
529
530 case 6: /* (t)hread */
531 sort = SORT_THREADS;
532 break;
533
534 case 7: /* (u)nsort */
535 sort = SORT_ORDER;
536 break;
537
538 case 8: /* si(z)e */
539 sort = SORT_SIZE;
540 break;
541
542 case 9: /* s(c)ore */
543 sort = SORT_SCORE;
544 break;
545
546 case 10: /* s(p)am */
547 sort = SORT_SPAM;
548 break;
549
550 case 11: /* (l)abel */
551 sort = SORT_LABEL;
552 break;
553 }
554
555 const unsigned char c_use_threads = cs_subset_enum(NeoMutt->sub, "use_threads");
556 const short c_sort = cs_subset_sort(NeoMutt->sub, "sort");
557 int rc = CSR_ERR_CODE;
558 if ((sort != SORT_THREADS) || (c_use_threads == UT_UNSET))
559 {
560 if ((sort != SORT_THREADS) && (c_sort & SORT_LAST))
561 sort |= SORT_LAST;
562 if (reverse)
563 sort |= SORT_REVERSE;
564
565 rc = cs_subset_str_native_set(NeoMutt->sub, "sort", sort, NULL);
566 }
567 else
568 {
569 assert((c_sort & SORT_MASK) != SORT_THREADS); /* See index_config_observer() */
570 /* Preserve the value of $sort, and toggle whether we are threaded. */
571 switch (c_use_threads)
572 {
573 case UT_FLAT:
574 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
575 reverse ? UT_REVERSE : UT_THREADS, NULL);
576 break;
577 case UT_THREADS:
578 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
579 reverse ? UT_REVERSE : UT_FLAT, NULL);
580 break;
581 case UT_REVERSE:
582 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
583 reverse ? UT_FLAT : UT_THREADS, NULL);
584 break;
585 default:
586 assert(false);
587 }
588 }
589
590 return ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE));
591}
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:97
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
#define CSR_SUC_NO_CHANGE
The value hasn't changed.
Definition: set.h:44
#define CSR_ERR_CODE
Problem with the code.
Definition: set.h:36
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
@ UT_FLAT
Unthreaded.
Definition: mutt_thread.h:85
@ UT_UNSET
Not yet set by user, stick to legacy semantics.
Definition: mutt_thread.h:84
@ UT_THREADS
Normal threading (root above subthreads)
Definition: mutt_thread.h:86
@ UT_REVERSE
Reverse threading (subthreads above root)
Definition: mutt_thread.h:87
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:74
#define SORT_LAST
Sort thread by last-X, e.g. received date.
Definition: sort2.h:76
SortType
Methods for sorting.
Definition: sort2.h:38
@ SORT_SUBJECT
Sort by the email's subject.
Definition: sort2.h:42
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:44
@ SORT_THREADS
Sort by email threads.
Definition: sort2.h:45
@ SORT_SPAM
Sort by the email's spam score.
Definition: sort2.h:53
@ SORT_LABEL
Sort by the emails label.
Definition: sort2.h:58
@ SORT_FROM
Sort by the email's From field.
Definition: sort2.h:43
@ SORT_SIZE
Sort by the size of the email.
Definition: sort2.h:40
@ SORT_RECEIVED
Sort by when the message were delivered locally.
Definition: sort2.h:46
@ SORT_TO
Sort by the email's To field.
Definition: sort2.h:47
@ SORT_DATE
Sort by the date the email was sent.
Definition: sort2.h:39
@ SORT_SCORE
Sort by the email's score.
Definition: sort2.h:48
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:75
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_shell_escape()

bool mutt_shell_escape ( void  )

Invoke a command in a subshell.

Return values
trueA command was invoked (no matter what its result)
falseNo command was invoked

Definition at line 598 of file external.c.

599{
600 bool rc = false;
601 struct Buffer *buf = mutt_buffer_pool_get();
602
603 if (mutt_buffer_get_field(_("Shell command: "), buf, MUTT_COMP_FILE_SIMPLE,
604 false, NULL, NULL, NULL) != 0)
605 {
606 goto done;
607 }
608
609 if (mutt_buffer_is_empty(buf))
610 {
611 const char *const c_shell = cs_subset_string(NeoMutt->sub, "shell");
612 mutt_buffer_strcpy(buf, c_shell);
613 }
614
615 if (mutt_buffer_is_empty(buf))
616 {
617 goto done;
618 }
619
621 mutt_endwin();
622 fflush(stdout);
623 int rc2 = mutt_system(mutt_buffer_string(buf));
624 if (rc2 == -1)
625 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", mutt_buffer_string(buf));
626
627 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
628 if ((rc2 != 0) || c_wait_key)
630
631 rc = true;
632done:
634 return rc;
635}
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_enter_command()

void mutt_enter_command ( void  )

Enter a neomutt command.

Definition at line 640 of file external.c.

641{
642 struct Buffer *buf = mutt_buffer_pool_get();
643 struct Buffer *err = mutt_buffer_pool_get();
644
645 window_redraw(NULL);
646 /* if enter is pressed after : with no command, just return */
647 if ((mutt_buffer_get_field(":", buf, MUTT_COMP_COMMAND, false, NULL, NULL, NULL) != 0) ||
649 {
650 goto done;
651 }
652
654 if (!mutt_buffer_is_empty(err))
655 {
656 if (rc == MUTT_CMD_SUCCESS) /* command succeeded with message */
658 else if (rc == MUTT_CMD_ERROR)
659 mutt_error("%s", mutt_buffer_string(err));
660 else if (rc == MUTT_CMD_WARNING)
662 }
663
664 if (NeoMutt)
665 {
666 // Running commands could cause anything to change, so let others know
668 }
669
670done:
673}
CommandResult
Error codes for command_t parse functions.
Definition: command.h:36
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:39
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:37
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition: command.h:38
#define mutt_warning(...)
Definition: logging.h:85
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
#define MUTT_COMP_COMMAND
Complete a NeoMutt command.
Definition: mutt.h:57
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:603
@ NT_GLOBAL_COMMAND
A NeoMutt command.
Definition: neomutt.h:55
@ NT_GLOBAL
Not object-related, NotifyGlobal.
Definition: notify_type.h:46
enum CommandResult parse_rc_line(const char *line, struct Buffer *err)
Parse a line of user config.
Definition: rc.c:109
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_display_address()

void mutt_display_address ( struct Envelope env)

Display the address of a message.

Parameters
envEnvelope containing address

Definition at line 679 of file external.c.

680{
681 const char *pfx = NULL;
682
683 struct AddressList *al = mutt_get_address(env, &pfx);
684 if (!al)
685 return;
686
687 /* Note: We don't convert IDNA to local representation this time.
688 * That is intentional, so the user has an opportunity to copy &
689 * paste the on-the-wire form of the address to other, IDN-unable
690 * software. */
691 struct Buffer *buf = mutt_buffer_pool_get();
692 mutt_addrlist_write(al, buf, false);
693 mutt_message("%s: %s", pfx, mutt_buffer_string(buf));
695}
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:330
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_copy_flags()

static void set_copy_flags ( struct Email e,
enum MessageTransformOpt  transform_opt,
CopyMessageFlags cmflags,
CopyHeaderFlags chflags 
)
static

Set the flags for a message copy.

Parameters
[in]eEmail
[in]transform_optTransformation, e.g. TRANSFORM_DECRYPT
[out]cmflagsFlags, see CopyMessageFlags
[out]chflagsFlags, see CopyHeaderFlags

Definition at line 704 of file external.c.

706{
707 *cmflags = MUTT_CM_NO_FLAGS;
708 *chflags = CH_UPDATE_LEN;
709
710 const bool need_decrypt = (transform_opt == TRANSFORM_DECRYPT) &&
711 (e->security & SEC_ENCRYPT);
712 const bool want_pgp = (WithCrypto & APPLICATION_PGP);
713 const bool want_smime = (WithCrypto & APPLICATION_SMIME);
714 const bool is_pgp = mutt_is_application_pgp(e->body) & SEC_ENCRYPT;
715 const bool is_smime = mutt_is_application_smime(e->body) & SEC_ENCRYPT;
716
717 if (need_decrypt && want_pgp && mutt_is_multipart_encrypted(e->body))
718 {
719 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
720 *cmflags = MUTT_CM_DECODE_PGP;
721 }
722 else if (need_decrypt && want_pgp && is_pgp)
723 {
724 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN;
725 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
726 }
727 else if (need_decrypt && want_smime && is_smime)
728 {
729 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
730 *cmflags = MUTT_CM_DECODE_SMIME;
731 }
732 else if (transform_opt == TRANSFORM_DECODE)
733 {
734 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN | CH_DECODE; // then decode RFC2047
735 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
736 const bool c_copy_decode_weed = cs_subset_bool(NeoMutt->sub, "copy_decode_weed");
737 if (c_copy_decode_weed)
738 {
739 *chflags |= CH_WEED; // and respect $weed
740 *cmflags |= MUTT_CM_WEED;
741 }
742 }
743}
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:55
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:45
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:60
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:46
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:62
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:542
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:599
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:437
@ TRANSFORM_DECODE
Decode message.
Definition: external.h:42
@ TRANSFORM_DECRYPT
Decrypt message.
Definition: external.h:41
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
struct Body * body
List of MIME parts.
Definition: email.h:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_message_ctx()

int mutt_save_message_ctx ( struct Mailbox m_src,
struct Email e,
enum MessageSaveOpt  save_opt,
enum MessageTransformOpt  transform_opt,
struct Mailbox m_dst 
)

Save a message to a given mailbox.

Parameters
m_srcMailbox to copy from
eEmail
save_optCopy or move, e.g. SAVE_MOVE
transform_optTransformation, e.g. TRANSFORM_DECRYPT
m_dstMailbox to save to
Return values
0Success
-1Error

Definition at line 755 of file external.c.

757{
760 int rc;
761
762 set_copy_flags(e, transform_opt, &cmflags, &chflags);
763
764 struct Message *msg = mx_msg_open(m_src, e->msgno);
765 if (msg && transform_opt != TRANSFORM_NONE)
766 {
768 }
769
770 rc = mutt_append_message(m_dst, m_src, e, msg, cmflags, chflags);
771 mx_msg_close(m_src, &msg);
772 if (rc != 0)
773 return rc;
774
775 if (save_opt == SAVE_MOVE)
776 {
777 mutt_set_flag(m_src, e, MUTT_DELETE, true);
778 mutt_set_flag(m_src, e, MUTT_PURGE, true);
779 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
780 if (c_delete_untag)
781 mutt_set_flag(m_src, e, MUTT_TAG, false);
782 }
783
784 return 0;
785}
int mutt_append_message(struct Mailbox *m_dst, struct Mailbox *m_src, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
Append a message.
Definition: copy.c:943
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
static void set_copy_flags(struct Email *e, enum MessageTransformOpt transform_opt, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
Set the flags for a message copy.
Definition: external.c:704
@ TRANSFORM_NONE
No transformation.
Definition: external.h:40
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:51
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:85
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:88
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:83
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:63
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_message()

int mutt_save_message ( struct Mailbox m,
struct EmailList *  el,
enum MessageSaveOpt  save_opt,
enum MessageTransformOpt  transform_opt 
)

Save an email.

Parameters
mMailbox
elList of Emails to save
save_optCopy or move, e.g. SAVE_MOVE
transform_optTransformation, e.g. TRANSFORM_DECRYPT
Return values
0Copy/save was successful
-1Error/abort

Definition at line 796 of file external.c.

798{
799 if (!el || STAILQ_EMPTY(el))
800 return -1;
801
802 int rc = -1;
803 int tagged_progress_count = 0;
804 unsigned int msg_count = 0;
805 struct Mailbox *m_save = NULL;
806
807 struct Buffer *buf = mutt_buffer_pool_get();
808 struct stat st = { 0 };
809 struct EmailNode *en = NULL;
810
811 STAILQ_FOREACH(en, el, entries)
812 {
813 msg_count++;
814 }
815 en = STAILQ_FIRST(el);
816
817 const SecurityFlags security_flags = WithCrypto ? en->email->security : SEC_NO_FLAGS;
818 const bool is_passphrase_needed = security_flags & SEC_ENCRYPT;
819
820 const char *prompt = NULL;
821 const char *progress_msg = NULL;
822
823 // Set prompt and progress_msg
824 switch (save_opt)
825 {
826 case SAVE_COPY:
827 // L10N: Progress meter message when copying tagged messages
828 progress_msg = (msg_count > 1) ? _("Copying tagged messages...") : NULL;
829 switch (transform_opt)
830 {
831 case TRANSFORM_NONE:
832 prompt = (msg_count > 1) ? _("Copy tagged to mailbox") : _("Copy to mailbox");
833 break;
835 prompt = (msg_count > 1) ? _("Decrypt-copy tagged to mailbox") :
836 _("Decrypt-copy to mailbox");
837 break;
838 case TRANSFORM_DECODE:
839 prompt = (msg_count > 1) ? _("Decode-copy tagged to mailbox") :
840 _("Decode-copy to mailbox");
841 break;
842 }
843 break;
844
845 case SAVE_MOVE:
846 // L10N: Progress meter message when saving tagged messages
847 progress_msg = (msg_count > 1) ? _("Saving tagged messages...") : NULL;
848 switch (transform_opt)
849 {
850 case TRANSFORM_NONE:
851 prompt = (msg_count > 1) ? _("Save tagged to mailbox") : _("Save to mailbox");
852 break;
854 prompt = (msg_count > 1) ? _("Decrypt-save tagged to mailbox") :
855 _("Decrypt-save to mailbox");
856 break;
857 case TRANSFORM_DECODE:
858 prompt = (msg_count > 1) ? _("Decode-save tagged to mailbox") :
859 _("Decode-save to mailbox");
860 break;
861 }
862 break;
863 }
864
866 mutt_default_save(buf->data, buf->dsize, en->email);
869
870 if (mutt_buffer_enter_fname(prompt, buf, false, NULL, false, NULL, NULL,
871 MUTT_SEL_NO_FLAGS) == -1)
872 {
873 goto cleanup;
874 }
875
876 size_t pathlen = mutt_buffer_len(buf);
877 if (pathlen == 0)
878 goto cleanup;
879
880 /* Trim any trailing '/' */
881 if (buf->data[pathlen - 1] == '/')
882 buf->data[pathlen - 1] = '\0';
883
884 /* This is an undocumented feature of ELM pointed out to me by Felix von
885 * Leitner <leitner@prz.fu-berlin.de> */
888 if (mutt_str_equal(mutt_buffer_string(buf), "."))
890 else
892
894
895 /* check to make sure that this file is really the one the user wants */
896 if (mutt_save_confirm(mutt_buffer_string(buf), &st) != 0)
897 goto cleanup;
898
899 if (is_passphrase_needed && (transform_opt != TRANSFORM_NONE) &&
900 !crypt_valid_passphrase(security_flags))
901 {
902 rc = -1;
903 goto errcleanup;
904 }
905
906 mutt_message(_("Copying to %s..."), mutt_buffer_string(buf));
907
908#ifdef USE_IMAP
909 enum MailboxType mailbox_type = imap_path_probe(mutt_buffer_string(buf), NULL);
910 if ((m->type == MUTT_IMAP) && (transform_opt == TRANSFORM_NONE) && (mailbox_type == MUTT_IMAP))
911 {
912 rc = imap_copy_messages(m, el, mutt_buffer_string(buf), save_opt);
913 switch (rc)
914 {
915 /* success */
916 case 0:
918 rc = 0;
919 goto cleanup;
920 /* non-fatal error: continue to fetch/append */
921 case 1:
922 break;
923 /* fatal error, abort */
924 case -1:
925 goto errcleanup;
926 }
927 }
928#endif
929
931 m_save = mx_path_resolve(mutt_buffer_string(buf));
932 bool old_append = m_save->append;
933 OpenMailboxFlags mbox_flags = MUTT_NEWFOLDER;
934 /* Display a tagged message progress counter, rather than (for
935 * IMAP) a per-message progress counter */
936 if (msg_count > 1)
937 mbox_flags |= MUTT_QUIET;
938 if (!mx_mbox_open(m_save, mbox_flags))
939 {
940 rc = -1;
941 mailbox_free(&m_save);
942 goto errcleanup;
943 }
944 m_save->append = true;
945
946#ifdef USE_COMP_MBOX
947 /* If we're saving to a compressed mailbox, the stats won't be updated
948 * until the next open. Until then, improvise. */
949 struct Mailbox *m_comp = NULL;
950 if (m_save->compress_info)
951 {
952 m_comp = mailbox_find(m_save->realpath);
953 }
954 /* We probably haven't been opened yet */
955 if (m_comp && (m_comp->msg_count == 0))
956 m_comp = NULL;
957#endif
958 if (msg_count == 1)
959 {
960 rc = mutt_save_message_ctx(m, en->email, save_opt, transform_opt, m_save);
961 if (rc != 0)
962 {
963 mx_mbox_close(m_save);
964 m_save->append = old_append;
965 goto errcleanup;
966 }
967#ifdef USE_COMP_MBOX
968 if (m_comp)
969 {
970 m_comp->msg_count++;
971 if (!en->email->read)
972 {
973 m_comp->msg_unread++;
974 if (!en->email->old)
975 m_comp->msg_new++;
976 }
977 if (en->email->flagged)
978 m_comp->msg_flagged++;
979 }
980#endif
981 }
982 else
983 {
984 rc = 0;
985
986#ifdef USE_NOTMUCH
987 if (m->type == MUTT_NOTMUCH)
988 nm_db_longrun_init(m, true);
989#endif
990 struct Progress *progress = progress_new(progress_msg, MUTT_PROGRESS_WRITE, msg_count);
991 STAILQ_FOREACH(en, el, entries)
992 {
993 progress_update(progress, ++tagged_progress_count, -1);
995 rc = mutt_save_message_ctx(m, en->email, save_opt, transform_opt, m_save);
996 if (rc != 0)
997 break;
998#ifdef USE_COMP_MBOX
999 if (m_comp)
1000 {
1001 struct Email *e2 = en->email;
1002 m_comp->msg_count++;
1003 if (!e2->read)
1004 {
1005 m_comp->msg_unread++;
1006 if (!e2->old)
1007 m_comp->msg_new++;
1008 }
1009 if (e2->flagged)
1010 m_comp->msg_flagged++;
1011 }
1012#endif
1013 }
1014 progress_free(&progress);
1015
1016#ifdef USE_NOTMUCH
1017 if (m->type == MUTT_NOTMUCH)
1019#endif
1020 if (rc != 0)
1021 {
1022 mx_mbox_close(m_save);
1023 m_save->append = old_append;
1024 goto errcleanup;
1025 }
1026 }
1027
1028 const bool need_mailbox_cleanup = ((m_save->type == MUTT_MBOX) ||
1029 (m_save->type == MUTT_MMDF));
1030
1031 mx_mbox_close(m_save);
1032 m_save->append = old_append;
1033
1034 if (need_mailbox_cleanup)
1036
1038 rc = 0;
1039
1040errcleanup:
1041 if (rc != 0)
1042 {
1043 switch (save_opt)
1044 {
1045 case SAVE_MOVE:
1046 if (msg_count > 1)
1047 {
1048 // L10N: Message when an index tagged save operation fails for some reason
1049 mutt_error(_("Error saving tagged messages"));
1050 }
1051 else
1052 {
1053 // L10N: Message when an index/pager save operation fails for some reason
1054 mutt_error(_("Error saving message"));
1055 }
1056 break;
1057 case SAVE_COPY:
1058 if (msg_count > 1)
1059 {
1060 // L10N: Message when an index tagged copy operation fails for some reason
1061 mutt_error(_("Error copying tagged messages"));
1062 }
1063 else
1064 {
1065 // L10N: Message when an index/pager copy operation fails for some reason
1066 mutt_error(_("Error copying message"));
1067 }
1068 break;
1069 }
1070 }
1071
1072 mailbox_free(&m_save);
1073
1074cleanup:
1076 return rc;
1077}
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:55
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:313
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:189
int mutt_buffer_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file.
Definition: curs_lib.c:444
int mutt_save_message_ctx(struct Mailbox *m_src, struct Email *e, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt, struct Mailbox *m_dst)
Save a message to a given mailbox.
Definition: external.c:755
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition: external.h:50
void mutt_file_resolve_symlink(struct Buffer *buf)
Resolve a symlink in place.
Definition: file.c:1707
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2401
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:735
int imap_copy_messages(struct Mailbox *m, struct EmailList *el, const char *dest, enum MessageSaveOpt save_opt)
Server COPY messages to another folder.
Definition: message.c:1655
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:87
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:139
MailboxType
Supported mailbox formats.
Definition: mailbox.h:41
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
@ MUTT_MMDF
'mmdf' Mailbox type
Definition: mailbox.h:46
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
@ MUTT_MBOX
'mbox' Mailbox type
Definition: mailbox.h:45
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
#define PATH_MAX
Definition: mutt.h:41
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:424
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:600
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1357
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:303
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1676
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:614
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:60
#define MUTT_NEWFOLDER
Create a new folder - same as MUTT_APPEND, but uses mutt_file_fopen() with mode "w" for mbox-style fo...
Definition: mxapi.h:66
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:65
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:77
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:368
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:353
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:50
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition: progress.c:86
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition: progress.c:73
struct Progress * progress_new(const char *msg, enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition: progress.c:118
The envelope/body of an email.
Definition: email.h:37
bool read
Email is read.
Definition: email.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
bool flagged
Marked important?
Definition: email.h:45
A mailbox.
Definition: mailbox.h:79
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
bool append
Mailbox is opened in append mode.
Definition: mailbox.h:109
int msg_new
Number of new messages.
Definition: mailbox.h:92
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:90
void * compress_info
Compressed mbox module private data.
Definition: mailbox.h:120
int msg_unread
Number of unread messages.
Definition: mailbox.h:89
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_edit_content_type()

bool mutt_edit_content_type ( struct Email e,
struct Body b,
FILE *  fp 
)

Edit the content type of an attachment.

Parameters
eEmail
bAttachment
fpFile handle to the attachment
Return values
trueA Any change is made

recvattach requires the return code to know when to regenerate the actx.

Definition at line 1088 of file external.c.

1089{
1090 struct Buffer *buf = mutt_buffer_pool_get();
1091 struct Buffer *charset = mutt_buffer_pool_get();
1092 struct Buffer *obuf = mutt_buffer_pool_get();
1093 struct Buffer *tmp = mutt_buffer_pool_get();
1094
1095 bool rc = false;
1096 bool charset_changed = false;
1097 bool type_changed = false;
1098 bool structure_changed = false;
1099
1100 char *cp = mutt_param_get(&b->parameter, "charset");
1101 mutt_buffer_strcpy(charset, cp);
1102
1103 mutt_buffer_printf(buf, "%s/%s", TYPE(b), b->subtype);
1104 mutt_buffer_copy(obuf, buf);
1105 if (!TAILQ_EMPTY(&b->parameter))
1106 {
1107 struct Parameter *np = NULL;
1108 TAILQ_FOREACH(np, &b->parameter, entries)
1109 {
1110 mutt_addr_cat(tmp->data, tmp->dsize, np->value, MimeSpecials);
1111 mutt_buffer_add_printf(buf, "; %s=%s", np->attribute, mutt_buffer_string(tmp));
1112 }
1113 }
1114
1115 if ((mutt_buffer_get_field("Content-Type: ", buf, MUTT_COMP_NO_FLAGS, false,
1116 NULL, NULL, NULL) != 0) ||
1118 {
1119 goto done;
1120 }
1121
1122 /* clean up previous junk */
1124 FREE(&b->subtype);
1125
1127
1128 mutt_buffer_printf(tmp, "%s/%s", TYPE(b), NONULL(b->subtype));
1129 type_changed = !mutt_istr_equal(mutt_buffer_string(tmp), mutt_buffer_string(obuf));
1130 charset_changed = !mutt_istr_equal(mutt_buffer_string(charset),
1131 mutt_param_get(&b->parameter, "charset"));
1132
1133 /* if in send mode, check for conversion - current setting is default. */
1134
1135 if (!e && (b->type == TYPE_TEXT) && charset_changed)
1136 {
1137 mutt_buffer_printf(tmp, _("Convert to %s upon sending?"),
1138 mutt_param_get(&b->parameter, "charset"));
1140 if (ans != MUTT_ABORT)
1141 b->noconv = (ans == MUTT_NO);
1142 }
1143
1144 /* inform the user */
1145
1146 mutt_buffer_printf(tmp, "%s/%s", TYPE(b), NONULL(b->subtype));
1147 if (type_changed)
1148 mutt_message(_("Content-Type changed to %s"), mutt_buffer_string(tmp));
1149 if ((b->type == TYPE_TEXT) && charset_changed)
1150 {
1151 if (type_changed)
1152 mutt_sleep(1);
1153 mutt_message(b->noconv ? _("Character set changed to %s; not converting") :
1154 _("Character set changed to %s; converting"),
1155 mutt_param_get(&b->parameter, "charset"));
1156 }
1157
1158 b->force_charset |= charset_changed;
1159
1160 if (!is_multipart(b) && b->parts)
1161 {
1162 structure_changed = true;
1163 mutt_body_free(&b->parts);
1164 }
1165 if (!mutt_is_message_type(b->type, b->subtype) && b->email)
1166 {
1167 structure_changed = true;
1168 b->email->body = NULL;
1169 email_free(&b->email);
1170 }
1171
1172 if (fp && !b->parts && (is_multipart(b) || mutt_is_message_type(b->type, b->subtype)))
1173 {
1174 structure_changed = true;
1175 mutt_parse_part(fp, b);
1176 }
1177
1178 if ((WithCrypto != 0) && e)
1179 {
1180 if (e->body == b)
1182
1183 e->security |= crypt_query(b);
1184 }
1185
1186 rc = structure_changed | type_changed;
1187
1188done:
1190 mutt_buffer_pool_release(&charset);
1193 return rc;
1194}
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and wrap it in quotes if it contains special characters.
Definition: address.c:681
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:211
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition: crypt.c:673
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
#define TYPE(body)
Definition: mime.h:89
#define is_multipart(body)
Definition: mime.h:82
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1456
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1736
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:424
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1441
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define NONULL(x)
Definition: string2.h:37
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool noconv
Don't do character set conversion.
Definition: body.h:46
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
struct Email * email
header information for message/rfc822
Definition: body.h:73
bool force_charset
Send mode: don't adjust the character set when in send-mode.
Definition: body.h:44
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
Attribute associated with a MIME part.
Definition: parameter.h:33
char * attribute
Parameter name.
Definition: parameter.h:34
char * value
Parameter value.
Definition: parameter.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_traditional_pgp()

static bool check_traditional_pgp ( struct Mailbox m,
struct Email e 
)
static

Check for an inline PGP content.

Parameters
mMailbox
eEmail to check
Return values
trueMessage contains inline PGP content

Definition at line 1202 of file external.c.

1203{
1204 bool rc = false;
1205
1207
1208 struct Message *msg = mx_msg_open(m, e->msgno);
1209 if (msg)
1210 {
1211 mutt_parse_mime_message(e, msg->fp);
1212 if (crypt_pgp_check_traditional(msg->fp, e->body, false))
1213 {
1214 e->security = crypt_query(e->body);
1215 rc = true;
1216 }
1217
1219 mx_msg_close(m, &msg);
1220 }
1221 return rc;
1222}
bool crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional()
Definition: cryptglue.c:283
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition: lib.h:92
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_check_traditional_pgp()

bool mutt_check_traditional_pgp ( struct Mailbox m,
struct EmailList *  el 
)

Check if a message has inline PGP content.

Parameters
mMailbox
elList of Emails to check
Return values
trueMessage contains inline PGP content

Definition at line 1230 of file external.c.

1231{
1232 bool rc = false;
1233 struct EmailNode *en = NULL;
1234 STAILQ_FOREACH(en, el, entries)
1235 {
1237 rc = check_traditional_pgp(m, en->email) || rc;
1238 }
1239
1240 return rc;
1241}
static bool check_traditional_pgp(struct Mailbox *m, struct Email *e)
Check for an inline PGP content.
Definition: external.c:1202
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ LastSaveFolder

struct Buffer LastSaveFolder = { 0 }
static

The folder the user last saved to.

Used by ci_save_message()

Definition at line 75 of file external.c.