NeoMutt  2025-12-11-1039-g550ac6
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
external.c File Reference

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

#include "config.h"
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.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 "complete/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "hooks/lib.h"
#include "imap/lib.h"
#include "ncrypt/lib.h"
#include "parse/lib.h"
#include "progress/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "globals.h"
#include "mutt_logging.h"
#include "mutt_mailbox.h"
#include "muttlib.h"
#include "mx.h"
#include "notmuch/lib.h"
#include <libintl.h>
Include dependency graph for external.c:

Go to the source code of this file.

Functions

void external_cleanup (void)
 Clean up commands globals.
void index_bounce_message (struct Mailbox *m, struct EmailArray *ea)
 Bounce an email.
static void pipe_set_flags (bool decode, bool print, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
 Generate flags for copy header/message.
static void pipe_msg (struct Mailbox *m, struct Email *e, struct Message *msg, FILE *fp, bool decode, bool print)
 Pipe a message.
static int pipe_message (struct Mailbox *m, struct EmailArray *ea, const char *cmd, bool decode, bool print, bool split, const char *sep)
 Pipe message to a command.
void mutt_pipe_message (struct Mailbox *m, struct EmailArray *ea)
 Pipe a message.
bool mutt_print_message (struct Mailbox *m, struct EmailArray *ea)
 Print a message.
bool mutt_select_sort (bool reverse)
 Ask the user for a sort method.
bool mutt_shell_escape (void)
 Invoke a command in a subshell.
void mutt_enter_command (struct MuttWindow *win)
 Enter a neomutt command.
void mutt_display_address (struct Envelope *env)
 Display the address of a message.
static void set_copy_flags (struct Email *e, enum MessageTransformOpt transform_opt, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
 Set the flags for a message copy.
int mutt_save_message_mbox (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.
int mutt_save_message (struct Mailbox *m, struct EmailArray *ea, enum MessageSaveOpt save_opt, enum MessageTransformOpt transform_opt)
 Save an email.
bool mutt_edit_content_type (struct Email *e, struct Body *b, FILE *fp)
 Edit the content type of an attachment.
static bool check_traditional_pgp (struct Mailbox *m, struct Email *e)
 Check for an inline PGP content.
bool mutt_check_traditional_pgp (struct Mailbox *m, struct EmailArray *ea)
 Check if a message has inline PGP content.

Variables

static struct Buffer LastSaveFolder = { 0 }
 The folder the user last saved to. Used by ci_save_message().

Detailed Description

Manage where the email is piped to external commands.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Eric Blake
  • Ihor Antonov

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.

Function Documentation

◆ external_cleanup()

void external_cleanup ( void )

Clean up commands globals.

Definition at line 77 of file external.c.

78{
80}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition buffer.c:383
static struct Buffer LastSaveFolder
The folder the user last saved to. Used by ci_save_message().
Definition external.c:72
Here is the call graph for this function:
Here is the caller graph for this function:

◆ index_bounce_message()

void index_bounce_message ( struct Mailbox * m,
struct EmailArray * ea )

Bounce an email.

Parameters
mMailbox
eaArray of Emails to bounce

Definition at line 87 of file external.c.

88{
89 if (!m || !ea || ARRAY_EMPTY(ea))
90 return;
91
92 struct Buffer *buf = buf_pool_get();
93 struct Buffer *prompt = buf_pool_get();
94 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
95 char *err = NULL;
96 int rc;
97 int msg_count = 0;
98
99 struct Email **ep = NULL;
100 ARRAY_FOREACH(ep, ea)
101 {
102 struct Email *e = *ep;
103 /* RFC5322 mandates a From: header,
104 * so warn before bouncing messages without one */
105 if (TAILQ_EMPTY(&e->env->from))
106 mutt_error(_("Warning: message contains no From: header"));
107
108 msg_count++;
109 }
110
111 if (msg_count == 1)
112 buf_strcpy(prompt, _("Bounce message to: "));
113 else
114 buf_strcpy(prompt, _("Bounce tagged messages to: "));
115
117 &CompleteAliasOps, NULL);
118 if ((rc != 0) || buf_is_empty(buf))
119 goto done;
120
122 if (TAILQ_EMPTY(&al))
123 {
124 mutt_error(_("Error parsing address"));
125 goto done;
126 }
127
129
130 if (mutt_addrlist_to_intl(&al, &err) < 0)
131 {
132 mutt_error(_("Bad IDN: '%s'"), err);
133 FREE(&err);
134 goto done;
135 }
136
137 buf_reset(buf);
138 mutt_addrlist_write(&al, buf, true);
139
140 buf_printf(prompt, ngettext("Bounce message to %s?", "Bounce messages to %s?", msg_count),
141 buf_string(buf));
142
143 if (query_quadoption(buf_string(prompt), NeoMutt->sub, "bounce") != MUTT_YES)
144 {
145 msgwin_clear_text(NULL);
146 mutt_message(ngettext("Message not bounced", "Messages not bounced", msg_count));
147 goto done;
148 }
149
150 msgwin_clear_text(NULL);
151
152 struct Message *msg = NULL;
153 ARRAY_FOREACH(ep, ea)
154 {
155 struct Email *e = *ep;
156 msg = mx_msg_open(m, e);
157 if (!msg)
158 {
159 rc = -1;
160 break;
161 }
162
163 rc = mutt_bounce_message(msg->fp, m, e, &al, NeoMutt->sub);
164 mx_msg_close(m, &msg);
165
166 if (rc < 0)
167 break;
168 }
169
170 /* If no error, or background, display message. */
171 if ((rc == 0) || (rc == S_BKG))
172 mutt_message(ngettext("Message bounced", "Messages bounced", msg_count));
173
174done:
176 buf_pool_release(&buf);
177 buf_pool_release(&prompt);
178}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1473
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition address.c:1217
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:651
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1304
const struct CompleteOps CompleteAliasOps
Auto-Completion of Aliases.
Definition complete.c:108
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:297
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
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:502
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
@ HC_ALIAS
Aliases.
Definition lib.h:57
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition msgwin.c:556
#define _(a)
Definition message.h:28
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition mx.c:1185
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition mx.c:1139
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_quadoption(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
#define TAILQ_EMPTY(head)
Definition queue.h:778
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:888
#define S_BKG
Definition string2.h:48
String manipulation buffer.
Definition buffer.h:36
The envelope/body of an email.
Definition email.h:39
struct Envelope * env
Envelope information.
Definition email.h:68
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
A local copy of an email.
Definition message.h:34
FILE * fp
pointer to the message data
Definition message.h:35
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pipe_set_flags()

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 187 of file external.c.

189{
190 if (decode)
191 {
192 *chflags |= CH_DECODE | CH_REORDER;
193 *cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
194
195 const bool c_print_decode_weed = cs_subset_bool(NeoMutt->sub, "print_decode_weed");
196 const bool c_pipe_decode_weed = cs_subset_bool(NeoMutt->sub, "pipe_decode_weed");
197 if (print ? c_print_decode_weed : c_pipe_decode_weed)
198 {
199 *chflags |= CH_WEED;
200 *cmflags |= MUTT_CM_WEED;
201 }
202
203 /* Just as with copy-decode, we need to update the mime fields to avoid
204 * confusing programs that may process the email. However, we don't want
205 * to force those fields to appear in printouts. */
206 if (!print)
207 *chflags |= CH_MIME | CH_TXTPLAIN;
208 }
209
210 if (print)
211 *cmflags |= MUTT_CM_PRINTING;
212}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
@ MUTT_CM_DECODE
Decode the message body into text/plain.
Definition copy_email.h:44
@ MUTT_CM_PRINTING
Printing the message - display light.
Definition copy_email.h:49
@ MUTT_CM_CHARCONV
Perform character set conversions.
Definition copy_email.h:48
@ MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition copy_email.h:47
@ CH_WEED
Weed the headers?
Definition copy_email.h:67
@ CH_MIME
Ignore MIME fields.
Definition copy_email.h:75
@ CH_TXTPLAIN
Generate text/plain MIME headers.
Definition copy_email.h:77
@ CH_DECODE
Do RFC2047 header decoding.
Definition copy_email.h:68
@ CH_REORDER
Re-order output of headers (specified by 'header-order').
Definition copy_email.h:73
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pipe_msg()

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 223 of file external.c.

225{
227 CopyHeaderFlags chflags = CH_FROM;
228
229 pipe_set_flags(decode, print, &cmflags, &chflags);
230
231 if ((WithCrypto != 0) && decode && e->security & SEC_ENCRYPT)
232 {
234 return;
235 mutt_endwin();
236 }
237
238 const bool own_msg = !msg;
239 if (own_msg)
240 {
241 msg = mx_msg_open(m, e);
242 if (!msg)
243 {
244 return;
245 }
246 }
247
248 if (decode)
249 {
251 }
252
253 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
254
255 if (own_msg)
256 {
257 mx_msg_close(m, &msg);
258 }
259}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:629
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_email.c:920
@ MUTT_CM_NONE
No flags are set.
Definition copy_email.h:41
uint32_t CopyHeaderFlags
Definition copy_email.h:89
@ CH_FROM
Retain the "From " message separator?
Definition copy_email.h:70
uint16_t CopyMessageFlags
Definition copy_email.h:55
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition crypt.c:131
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
static void pipe_set_flags(bool decode, bool print, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
Generate flags for copy header/message.
Definition external.c:187
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
#define WithCrypto
Definition lib.h:132
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pipe_message()

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

Pipe message to a command.

Parameters
mMailbox
eaArray 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 275 of file external.c.

277{
278 if (!m || !ea || ARRAY_EMPTY(ea))
279 return 1;
280
281 int rc = 0;
282 pid_t pid;
283 FILE *fp_out = NULL;
284
285 if (ARRAY_SIZE(ea) == 1)
286 {
287 struct Email *e = *ARRAY_GET(ea, 0);
288 /* handle a single message */
290
291 struct Message *msg = mx_msg_open(m, e);
292 if (msg && (WithCrypto != 0) && decode)
293 {
296 {
297 mx_msg_close(m, &msg);
298 return 1;
299 }
300 }
301 mutt_endwin();
302
303 pid = filter_create(cmd, &fp_out, NULL, NULL, NeoMutt->env);
304 if (pid < 0)
305 {
306 mutt_perror(_("Can't create filter process"));
307 mx_msg_close(m, &msg);
308 return 1;
309 }
310
311 OptKeepQuiet = true;
312 pipe_msg(m, e, msg, fp_out, decode, print);
313 mx_msg_close(m, &msg);
314 mutt_file_fclose(&fp_out);
315 rc = filter_wait(pid);
316 OptKeepQuiet = false;
317 }
318 else
319 {
320 /* handle tagged messages */
321 if ((WithCrypto != 0) && decode)
322 {
323 struct Email **ep = NULL;
324 ARRAY_FOREACH(ep, ea)
325 {
326 struct Email *e = *ep;
327 struct Message *msg = mx_msg_open(m, e);
328 if (msg)
329 {
332 mx_msg_close(m, &msg);
333 }
335 {
336 return 1;
337 }
338 }
339 }
340
341 if (split)
342 {
343 struct Email **ep = NULL;
344 ARRAY_FOREACH(ep, ea)
345 {
346 struct Email *e = *ep;
348 mutt_endwin();
349 pid = filter_create(cmd, &fp_out, NULL, NULL, NeoMutt->env);
350 if (pid < 0)
351 {
352 mutt_perror(_("Can't create filter process"));
353 return 1;
354 }
355 OptKeepQuiet = true;
356 pipe_msg(m, e, NULL, fp_out, decode, print);
357 /* add the message separator */
358 if (sep)
359 fputs(sep, fp_out);
360 mutt_file_fclose(&fp_out);
361 if (filter_wait(pid) != 0)
362 rc = 1;
363 OptKeepQuiet = false;
364 }
365 }
366 else
367 {
368 mutt_endwin();
369 pid = filter_create(cmd, &fp_out, NULL, NULL, NeoMutt->env);
370 if (pid < 0)
371 {
372 mutt_perror(_("Can't create filter process"));
373 return 1;
374 }
375 OptKeepQuiet = true;
376 struct Email **ep = NULL;
377 ARRAY_FOREACH(ep, ea)
378 {
379 struct Email *e = *ep;
381 pipe_msg(m, e, NULL, fp_out, decode, print);
382 /* add the message separator */
383 if (sep)
384 fputs(sep, fp_out);
385 }
386 mutt_file_fclose(&fp_out);
387 if (filter_wait(pid) != 0)
388 rc = 1;
389 OptKeepQuiet = false;
390 }
391 }
392
393 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
394 if ((rc != 0) || c_wait_key)
396 return rc;
397}
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
@ CMD_MESSAGE_HOOK
:message-hook
Definition command.h:97
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
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:223
#define mutt_file_fclose(FP)
Definition file.h:144
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition globals.c:49
#define mutt_perror(...)
Definition logging2.h:95
void exec_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
Definition exec.c:137
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, char **envlist)
Set up filter program.
Definition filter.c:220
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
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 EmailArray * ea )

Pipe a message.

Parameters
mMailbox
eaArray of Emails to pipe

Definition at line 404 of file external.c.

405{
406 if (!m || !ea)
407 return;
408
409 struct Buffer *buf = buf_pool_get();
410
411 if (mw_get_field(_("Pipe to command: "), buf, MUTT_COMP_NONE, HC_EXT_COMMAND,
412 &CompleteFileOps, NULL) != 0)
413 {
414 goto cleanup;
415 }
416
417 if (buf_is_empty(buf))
418 goto cleanup;
419
420 expand_path(buf, false);
421 const bool c_pipe_decode = cs_subset_bool(NeoMutt->sub, "pipe_decode");
422 const bool c_pipe_split = cs_subset_bool(NeoMutt->sub, "pipe_split");
423 const char *const c_pipe_sep = cs_subset_string(NeoMutt->sub, "pipe_sep");
424 pipe_message(m, ea, buf_string(buf), c_pipe_decode, false, c_pipe_split, c_pipe_sep);
425
426cleanup:
427 buf_pool_release(&buf);
428}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
static int pipe_message(struct Mailbox *m, struct EmailArray *ea, const char *cmd, bool decode, bool print, bool split, const char *sep)
Pipe message to a command.
Definition external.c:275
@ HC_EXT_COMMAND
External commands.
Definition lib.h:56
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mutt_print_message()

bool mutt_print_message ( struct Mailbox * m,
struct EmailArray * ea )

Print a message.

Parameters
mMailbox
eaArray of Emails to print
Return values
trueThe messages were printed
falsePrinting was cancelled or failed

Definition at line 437 of file external.c.

438{
439 if (!m || !ea)
440 return false;
441
442 const enum QuadOption c_print = cs_subset_quad(NeoMutt->sub, "print");
443 const char *const c_print_command = cs_subset_string(NeoMutt->sub, "print_command");
444 if (c_print && !c_print_command)
445 {
446 mutt_message(_("No printing command has been defined"));
447 return false;
448 }
449
450 int msg_count = ARRAY_SIZE(ea);
451 const char *msg = ngettext("Print message?", "Print tagged messages?", msg_count);
452 if (query_quadoption(msg, NeoMutt->sub, "print") != MUTT_YES)
453 {
454 return false;
455 }
456
457 const bool c_print_decode = cs_subset_bool(NeoMutt->sub, "print_decode");
458 const bool c_print_split = cs_subset_bool(NeoMutt->sub, "print_split");
459 if (pipe_message(m, ea, c_print_command, c_print_decode, true, c_print_split, "\f") == 0)
460 {
461 mutt_message(ngettext("Message printed", "Messages printed", msg_count));
462 return true;
463 }
464
465 mutt_message(ngettext("Message could not be printed",
466 "Messages could not be printed", msg_count));
467 return false;
468}
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition helpers.c:192
QuadOption
Possible values for a quad-option.
Definition quad.h:36
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 475 of file external.c.

476{
477 enum EmailSortType sort = EMAIL_SORT_DATE;
478
479 switch (mw_multi_choice(reverse ?
480 /* L10N: The highlighted letters must match the "Sort" options */
481 _("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?") :
482 /* L10N: The highlighted letters must match the "Rev-Sort" options */
483 _("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?"),
484 /* L10N: These must match the highlighted letters from "Sort" and "Rev-Sort" */
485 _("dfrsotuzcpl")))
486 {
487 case -1: /* abort - don't resort */
488 return false;
489
490 case 1: /* (d)ate */
491 sort = EMAIL_SORT_DATE;
492 break;
493
494 case 2: /* (f)rm */
495 sort = EMAIL_SORT_FROM;
496 break;
497
498 case 3: /* (r)ecv */
500 break;
501
502 case 4: /* (s)ubj */
503 sort = EMAIL_SORT_SUBJECT;
504 break;
505
506 case 5: /* t(o) */
507 sort = EMAIL_SORT_TO;
508 break;
509
510 case 6: /* (t)hread */
511 sort = EMAIL_SORT_THREADS;
512 break;
513
514 case 7: /* (u)nsort */
515 sort = EMAIL_SORT_UNSORTED;
516 break;
517
518 case 8: /* si(z)e */
519 sort = EMAIL_SORT_SIZE;
520 break;
521
522 case 9: /* s(c)ore */
523 sort = EMAIL_SORT_SCORE;
524 break;
525
526 case 10: /* s(p)am */
527 sort = EMAIL_SORT_SPAM;
528 break;
529
530 case 11: /* (l)abel */
531 sort = EMAIL_SORT_LABEL;
532 break;
533
534 default:
535 return false;
536 }
537
538 const unsigned char c_use_threads = cs_subset_enum(NeoMutt->sub, "use_threads");
539 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
540 int rc = CSR_ERR_CODE;
541 if ((sort != EMAIL_SORT_THREADS) || (c_use_threads == UT_UNSET))
542 {
543 if ((sort != EMAIL_SORT_THREADS) && (c_sort & SORT_LAST))
544 sort |= SORT_LAST;
545 if (reverse)
546 sort |= SORT_REVERSE;
547
548 rc = cs_subset_str_native_set(NeoMutt->sub, "sort", sort, NULL);
549 }
550 else
551 {
552 ASSERT((c_sort & SORT_MASK) != EMAIL_SORT_THREADS); /* See index_config_observer() */
553 /* Preserve the value of $sort, and toggle whether we are threaded. */
554 switch (c_use_threads)
555 {
556 case UT_FLAT:
557 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
558 reverse ? UT_REVERSE : UT_THREADS, NULL);
559 break;
560 case UT_THREADS:
561 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
562 reverse ? UT_REVERSE : UT_FLAT, NULL);
563 break;
564 case UT_REVERSE:
565 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
566 reverse ? UT_FLAT : UT_THREADS, NULL);
567 break;
568 default:
569 ASSERT(false);
570 }
571 }
572
573 return ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE));
574}
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition helpers.c:71
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition helpers.c:266
#define CSR_SUC_NO_CHANGE
The value hasn't changed.
Definition set.h:42
#define CSR_ERR_CODE
Problem with the code.
Definition set.h:34
#define CSR_RESULT(x)
Extract the result code from CSR_* flags.
Definition set.h:53
#define CSR_SUCCESS
Action completed successfully.
Definition set.h:33
#define SORT_MASK
Mask for the sort id.
Definition sort.h:39
#define SORT_LAST
Sort thread by last-X, e.g. received date.
Definition sort.h:41
#define SORT_REVERSE
Reverse the order of the sort.
Definition sort.h:40
EmailSortType
Methods for sorting Emails.
Definition sort.h:53
@ EMAIL_SORT_LABEL
Sort by the emails label.
Definition sort.h:57
@ EMAIL_SORT_DATE_RECEIVED
Sort by when the message was delivered locally.
Definition sort.h:55
@ EMAIL_SORT_SPAM
Sort by the email's spam score.
Definition sort.h:60
@ EMAIL_SORT_SCORE
Sort by the email's score.
Definition sort.h:58
@ EMAIL_SORT_DATE
Sort by the date the email was sent.
Definition sort.h:54
@ EMAIL_SORT_THREADS
Sort by email threads.
Definition sort.h:62
@ EMAIL_SORT_SUBJECT
Sort by the email's subject.
Definition sort.h:61
@ EMAIL_SORT_FROM
Sort by the email's From field.
Definition sort.h:56
@ EMAIL_SORT_UNSORTED
Sort by the order the messages appear in the mailbox.
Definition sort.h:64
@ EMAIL_SORT_SIZE
Sort by the size of the email.
Definition sort.h:59
@ EMAIL_SORT_TO
Sort by the email's To field.
Definition sort.h:63
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
@ UT_FLAT
Unthreaded.
Definition thread.h:104
@ UT_UNSET
Not yet set by user, stick to legacy semantics.
Definition thread.h:103
@ UT_THREADS
Normal threading (root above subthreads).
Definition thread.h:105
@ UT_REVERSE
Reverse threading (subthreads above root).
Definition thread.h:106
#define ASSERT(COND)
Definition signal2.h:59
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:303
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 581 of file external.c.

582{
583 bool rc = false;
584 struct Buffer *buf = buf_pool_get();
585
586 if (mw_get_field(_("Shell command: "), buf, MUTT_COMP_NONE, HC_EXT_COMMAND,
587 &CompleteFileOps, NULL) != 0)
588 {
589 goto done;
590 }
591
592 if (buf_is_empty(buf))
593 {
594 const char *const c_shell = cs_subset_string(NeoMutt->sub, "shell");
595 buf_strcpy(buf, c_shell);
596 }
597
598 if (buf_is_empty(buf))
599 {
600 goto done;
601 }
602
603 msgwin_clear_text(NULL);
604 mutt_endwin();
605 fflush(stdout);
606 int rc2 = mutt_system(buf_string(buf));
607 if (rc2 == -1)
608 mutt_debug(LL_DEBUG1, "Error running \"%s\"\n", buf_string(buf));
609
610 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
611 if ((rc2 != 0) || c_wait_key)
613
614 rc = true;
615done:
616 buf_pool_release(&buf);
617 return rc;
618}
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
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 ( struct MuttWindow * win)

Enter a neomutt command.

Parameters
winFocused Window

Definition at line 624 of file external.c.

625{
626 struct Buffer *buf = buf_pool_get();
627 struct ParseContext *pc = parse_context_new();
628 struct ParseError *pe = parse_error_new();
629
630 window_redraw(NULL);
631
632 /* if enter is pressed after : with no command, just return */
633 struct FileCompletionData cdata = { false, NULL, NULL, NULL, win };
634 if ((mw_get_field(":", buf, MUTT_COMP_NONE, HC_NEO_COMMAND, &CompleteCommandOps, &cdata) != 0) ||
635 buf_is_empty(buf))
636 {
637 goto done;
638 }
639
640 enum CommandResult rc = parse_rc_line(buf, pc, pe);
641 if (!buf_is_empty(pe->message))
642 {
643 if (rc == MUTT_CMD_SUCCESS) /* command succeeded with message */
644 mutt_message("%s", buf_string(pe->message));
645 else if (rc == MUTT_CMD_ERROR)
646 mutt_error("%s", buf_string(pe->message));
647 else if (rc == MUTT_CMD_WARNING)
648 mutt_warning("%s", buf_string(pe->message));
649 }
650
651 if (NeoMutt)
652 {
653 // Running commands could cause anything to change, so let others know
655 }
656
657done:
658 buf_pool_release(&buf);
660 parse_error_free(&pe);
661}
CommandResult
Error codes for command_t parse functions.
Definition command.h:37
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition command.h:40
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:38
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition command.h:39
const struct CompleteOps CompleteCommandOps
Auto-Completion of Commands.
Definition helpers.c:534
#define mutt_warning(...)
Definition logging2.h:92
@ HC_NEO_COMMAND
NeoMutt commands.
Definition lib.h:58
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
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
@ NT_GLOBAL_COMMAND
A NeoMutt command.
Definition neomutt.h:71
@ NT_GLOBAL
Not object-related, NotifyGlobal.
Definition notify_type.h:46
void parse_context_free(struct ParseContext **pptr)
Free a ParseContext.
Definition pcontext.c:48
struct ParseContext * parse_context_new(void)
Create a new ParseContext.
Definition pcontext.c:37
void parse_error_free(struct ParseError **pptr)
Free a ParseError.
Definition perror.c:50
struct ParseError * parse_error_new(void)
Create a new ParseError.
Definition perror.c:37
enum CommandResult parse_rc_line(struct Buffer *line, struct ParseContext *pc, struct ParseError *pe)
Parse a line of user config.
Definition rc.c:45
Input for the file completion function.
Definition curs_lib.h:39
struct MuttWindow * win
Current Focused Window.
Definition curs_lib.h:44
struct Notify * notify
Notifications handler.
Definition neomutt.h:45
Context for config parsing (history/backtrace).
Definition pcontext.h:34
Detailed error information from config parsing.
Definition perror.h:34
struct Buffer * message
Error message.
Definition perror.h:35
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 667 of file external.c.

668{
669 const char *pfx = NULL;
670
671 struct AddressList *al = mutt_get_address(env, &pfx);
672 if (!al)
673 return;
674
675 /* Note: We don't convert IDNA to local representation this time.
676 * That is intentional, so the user has an opportunity to copy &
677 * paste the on-the-wire form of the address to other, IDN-unable
678 * software. */
679 struct Buffer *buf = buf_pool_get();
680 mutt_addrlist_write(al, buf, false);
681 mutt_message("%s: %s", pfx, buf_string(buf));
682 buf_pool_release(&buf);
683}
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition alias.c:329
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_copy_flags()

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 692 of file external.c.

694{
695 *cmflags = MUTT_CM_NONE;
696 *chflags = CH_UPDATE_LEN;
697
698 const bool need_decrypt = (transform_opt == TRANSFORM_DECRYPT) &&
699 (e->security & SEC_ENCRYPT);
700 const bool want_pgp = (WithCrypto & APPLICATION_PGP);
701 const bool want_smime = (WithCrypto & APPLICATION_SMIME);
702 const bool is_pgp = mutt_is_application_pgp(e->body) & SEC_ENCRYPT;
703 const bool is_smime = mutt_is_application_smime(e->body) & SEC_ENCRYPT;
704
705 if (need_decrypt && want_pgp && mutt_is_multipart_encrypted(e->body))
706 {
707 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
708 *cmflags = MUTT_CM_DECODE_PGP;
709 }
710 else if (need_decrypt && want_pgp && is_pgp)
711 {
712 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN;
713 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
714 }
715 else if (need_decrypt && want_smime && is_smime)
716 {
717 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
718 *cmflags = MUTT_CM_DECODE_SMIME;
719 }
720 else if (transform_opt == TRANSFORM_DECODE)
721 {
722 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN | CH_DECODE; // then decode RFC2047
723 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
724 const bool c_copy_decode_weed = cs_subset_bool(NeoMutt->sub, "copy_decode_weed");
725 if (c_copy_decode_weed)
726 {
727 *chflags |= CH_WEED; // and respect $weed
728 *cmflags |= MUTT_CM_WEED;
729 }
730 }
731}
@ MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition copy_email.h:52
@ MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition copy_email.h:51
@ CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:).
Definition copy_email.h:69
@ CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition copy_email.h:76
@ CH_NONEWLINE
Don't output terminating newline after the header.
Definition copy_email.h:74
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:610
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition crypt.c:444
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition crypt.c:549
@ TRANSFORM_DECODE
Decode message.
Definition external.h:45
@ TRANSFORM_DECRYPT
Decrypt message.
Definition external.h:44
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
struct Body * body
List of MIME parts.
Definition email.h:69
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mutt_save_message_mbox()

int mutt_save_message_mbox ( 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 743 of file external.c.

745{
747 CopyHeaderFlags chflags = CH_NONE;
748 int rc;
749
750 set_copy_flags(e, transform_opt, &cmflags, &chflags);
751
752 struct Message *msg = mx_msg_open(m_src, e);
753 if (msg && transform_opt != TRANSFORM_NONE)
754 {
756 }
757
758 rc = mutt_append_message(m_dst, m_src, e, msg, cmflags, chflags);
759 mx_msg_close(m_src, &msg);
760 if (rc != 0)
761 return rc;
762
763 if (save_opt == SAVE_MOVE)
764 {
765 mutt_set_flag(m_src, e, MUTT_DELETE, true, true);
766 mutt_set_flag(m_src, e, MUTT_PURGE, true, true);
767 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
768 if (c_delete_untag)
769 mutt_set_flag(m_src, e, MUTT_TAG, false, true);
770 }
771
772 return 0;
773}
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_email.c:995
@ CH_NONE
No flags are set.
Definition copy_email.h:65
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:692
@ TRANSFORM_NONE
No transformation.
Definition external.h:43
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition external.h:54
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
@ MUTT_PURGE
Messages to be purged (bypass trash).
Definition mutt.h:96
@ MUTT_TAG
Tagged messages.
Definition mutt.h:99
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
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 EmailArray * ea,
enum MessageSaveOpt save_opt,
enum MessageTransformOpt transform_opt )

Save an email.

Parameters
mMailbox
eaArray 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 784 of file external.c.

786{
787 if (!ea || ARRAY_EMPTY(ea))
788 return -1;
789
790 int rc = -1;
791 int tagged_progress_count = 0;
792 unsigned int msg_count = ARRAY_SIZE(ea);
793 struct Mailbox *m_save = NULL;
794
795 struct Buffer *buf = buf_pool_get();
796 struct stat st = { 0 };
797 struct Email *e_cur = *ARRAY_GET(ea, 0);
798
799 const SecurityFlags security_flags = WithCrypto ? e_cur->security : SEC_NONE;
800 const bool is_passphrase_needed = security_flags & SEC_ENCRYPT;
801
802 const char *prompt = NULL;
803 const char *progress_msg = NULL;
804
805 // Set prompt and progress_msg
806 switch (save_opt)
807 {
808 case SAVE_COPY:
809 // L10N: Progress meter message when copying tagged messages
810 progress_msg = (msg_count > 1) ? _("Copying tagged messages...") : NULL;
811 switch (transform_opt)
812 {
813 case TRANSFORM_NONE:
814 prompt = (msg_count > 1) ? _("Copy tagged to mailbox") : _("Copy to mailbox");
815 break;
817 prompt = (msg_count > 1) ? _("Decrypt-copy tagged to mailbox") :
818 _("Decrypt-copy to mailbox");
819 break;
820 case TRANSFORM_DECODE:
821 prompt = (msg_count > 1) ? _("Decode-copy tagged to mailbox") :
822 _("Decode-copy to mailbox");
823 break;
824 }
825 break;
826
827 case SAVE_MOVE:
828 // L10N: Progress meter message when saving tagged messages
829 progress_msg = (msg_count > 1) ? _("Saving tagged messages...") : NULL;
830 switch (transform_opt)
831 {
832 case TRANSFORM_NONE:
833 prompt = (msg_count > 1) ? _("Save tagged to mailbox") : _("Save to mailbox");
834 break;
836 prompt = (msg_count > 1) ? _("Decrypt-save tagged to mailbox") :
837 _("Decrypt-save to mailbox");
838 break;
839 case TRANSFORM_DECODE:
840 prompt = (msg_count > 1) ? _("Decode-save tagged to mailbox") :
841 _("Decode-save to mailbox");
842 break;
843 }
844 break;
845 }
846
848 mutt_default_save(buf, e_cur);
849 pretty_mailbox(buf);
850
851 if (mw_enter_fname(prompt, buf, false, NULL, false, NULL, NULL, MUTT_SEL_NONE) == -1)
852 {
853 goto cleanup;
854 }
855
856 size_t pathlen = buf_len(buf);
857 if (pathlen == 0)
858 goto cleanup;
859
860 mutt_path_tidy(buf, true);
861
862 /* This is an undocumented feature of ELM pointed out to me by Felix von
863 * Leitner <leitner@prz.fu-berlin.de> */
866 if (mutt_str_equal(buf_string(buf), "."))
868 else
870
871 expand_path(buf, false);
872
873 /* check to make sure that this file is really the one the user wants */
874 if (mutt_save_confirm(buf_string(buf), &st) != 0)
875 goto cleanup;
876
877 if (is_passphrase_needed && (transform_opt != TRANSFORM_NONE) &&
878 !crypt_valid_passphrase(security_flags))
879 {
880 rc = -1;
881 goto errcleanup;
882 }
883
884 mutt_message(_("Copying to %s..."), buf_string(buf));
885
886 enum MailboxType mailbox_type = imap_path_probe(buf_string(buf), NULL);
887 if ((m->type == MUTT_IMAP) && (transform_opt == TRANSFORM_NONE) && (mailbox_type == MUTT_IMAP))
888 {
889 rc = imap_copy_messages(m, ea, buf_string(buf), save_opt);
890 switch (rc)
891 {
892 /* success */
893 case 0:
895 rc = 0;
896 if (save_opt == SAVE_MOVE)
897 {
898 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
899 if (c_delete_untag)
900 {
901 struct Email **ep = NULL;
902 ARRAY_FOREACH(ep, ea)
903 {
904 mutt_set_flag(m, *ep, MUTT_TAG, false, true);
905 }
906 }
907 }
908 goto cleanup;
909 /* non-fatal error: continue to fetch/append */
910 case 1:
911 break;
912 /* fatal error, abort */
913 case -1:
914 default:
915 goto errcleanup;
916 }
917 }
918
920 m_save = mx_path_resolve(buf_string(buf));
921 bool old_append = m_save->append;
922 OpenMailboxFlags mbox_flags = MUTT_APPEND;
923 /* Display a tagged message progress counter, rather than (for
924 * IMAP) a per-message progress counter */
925 if (msg_count > 1)
926 mbox_flags |= MUTT_QUIET;
927 if (!mx_mbox_open(m_save, mbox_flags))
928 {
929 rc = -1;
930 mailbox_free(&m_save);
931 goto errcleanup;
932 }
933 m_save->append = true;
934
935 /* If we're saving to a compressed mailbox, the stats won't be updated
936 * until the next open. Until then, improvise. */
937 struct Mailbox *m_comp = NULL;
938 if (m_save->compress_info)
939 {
940 m_comp = mailbox_find(m_save->realpath);
941 }
942 /* We probably haven't been opened yet */
943 if (m_comp && (m_comp->msg_count == 0))
944 m_comp = NULL;
945
946 if (msg_count == 1)
947 {
948 rc = mutt_save_message_mbox(m, e_cur, save_opt, transform_opt, m_save);
949 if (rc != 0)
950 {
951 mx_mbox_close(m_save);
952 m_save->append = old_append;
953 goto errcleanup;
954 }
955
956 if (m_comp)
957 {
958 m_comp->msg_count++;
959 if (!e_cur->read)
960 {
961 m_comp->msg_unread++;
962 if (!e_cur->old)
963 m_comp->msg_new++;
964 }
965 if (e_cur->flagged)
966 m_comp->msg_flagged++;
967 }
968 }
969 else
970 {
971 rc = 0;
972
973#ifdef USE_NOTMUCH
974 if (m->type == MUTT_NOTMUCH)
975 nm_db_longrun_init(m, true);
976#endif
977 struct Progress *progress = progress_new(MUTT_PROGRESS_WRITE, msg_count);
978 progress_set_message(progress, "%s", progress_msg);
979 struct Email **ep = NULL;
980 ARRAY_FOREACH(ep, ea)
981 {
982 struct Email *e = *ep;
983 progress_update(progress, ++tagged_progress_count, -1);
985 rc = mutt_save_message_mbox(m, e, save_opt, transform_opt, m_save);
986 if (rc != 0)
987 break;
988
989 if (m_comp)
990 {
991 struct Email *e2 = e;
992 m_comp->msg_count++;
993 if (!e2->read)
994 {
995 m_comp->msg_unread++;
996 if (!e2->old)
997 m_comp->msg_new++;
998 }
999 if (e2->flagged)
1000 m_comp->msg_flagged++;
1001 }
1002 }
1003 progress_free(&progress);
1004
1005#ifdef USE_NOTMUCH
1006 if (m->type == MUTT_NOTMUCH)
1008#endif
1009 if (rc != 0)
1010 {
1011 mx_mbox_close(m_save);
1012 m_save->append = old_append;
1013 goto errcleanup;
1014 }
1015 }
1016
1017 const bool need_mailbox_cleanup = ((m_save->type == MUTT_MBOX) ||
1018 (m_save->type == MUTT_MMDF));
1019
1020 mx_mbox_close(m_save);
1021 m_save->append = old_append;
1022
1023 if (need_mailbox_cleanup)
1025
1027 rc = 0;
1028
1029errcleanup:
1030 if (rc != 0)
1031 {
1032 switch (save_opt)
1033 {
1034 case SAVE_MOVE:
1035 if (msg_count > 1)
1036 {
1037 // L10N: Message when an index tagged save operation fails for some reason
1038 mutt_error(_("Error saving tagged messages"));
1039 }
1040 else
1041 {
1042 // L10N: Message when an index/pager save operation fails for some reason
1043 mutt_error(_("Error saving message"));
1044 }
1045 break;
1046 case SAVE_COPY:
1047 if (msg_count > 1)
1048 {
1049 // L10N: Message when an index tagged copy operation fails for some reason
1050 mutt_error(_("Error copying tagged messages"));
1051 }
1052 else
1053 {
1054 // L10N: Message when an index/pager copy operation fails for some reason
1055 mutt_error(_("Error copying message"));
1056 }
1057 break;
1058 }
1059 }
1060
1061 mailbox_free(&m_save);
1062
1063cleanup:
1064 buf_pool_release(&buf);
1065 return rc;
1066}
@ MUTT_SEL_NONE
No flags are set.
Definition lib.h:59
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:607
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition mailbox.c:90
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition mailbox.c:151
MailboxType
Supported mailbox formats.
Definition mailbox.h:40
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_MMDF
'mmdf' Mailbox type
Definition mailbox.h:45
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
@ MUTT_MBOX
'mbox' Mailbox type
Definition mailbox.h:44
int mutt_save_message_mbox(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:743
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition external.h:53
void mutt_file_resolve_symlink(struct Buffer *buf)
Resolve a symlink in place.
Definition file.c:1555
int mw_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:237
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2683
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition exec.c:218
int imap_copy_messages(struct Mailbox *m, struct EmailArray *ea, const char *dest, enum MessageSaveOpt save_opt)
Server COPY messages to another folder.
Definition message.c:1722
bool mutt_path_tidy(struct Buffer *path, bool is_dir)
Remove unnecessary parts of a path.
Definition path.c:169
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
#define PATH_MAX
Definition mutt.h:49
void mutt_clear_error(void)
Clear the message line (bottom line of screen).
void mailbox_restore_timestamp(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:431
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition muttlib.c:698
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition mx.c:285
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition mx.c:1650
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition mx.c:595
uint8_t OpenMailboxFlags
Definition mxapi.h:51
@ MUTT_QUIET
Do not print any messages.
Definition mxapi.h:46
@ MUTT_APPEND
Open mailbox for appending messages.
Definition mxapi.h:44
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_NONE
No flags are set.
Definition lib.h:91
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition db.c:393
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition db.c:378
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc.
Definition lib.h:85
struct Progress * progress_new(enum ProgressType type, size_t size)
Create a new Progress Bar.
Definition progress.c:139
void progress_free(struct Progress **ptr)
Free a Progress Bar.
Definition progress.c:110
void progress_set_message(struct Progress *progress, const char *fmt,...) __attribute__((__format__(__printf__
bool progress_update(struct Progress *progress, size_t pos, int percent)
Update the state of the progress bar.
Definition progress.c:80
bool read
Email is read.
Definition email.h:50
bool old
Email is seen, but unread.
Definition email.h:49
bool flagged
Marked important?
Definition email.h:47
A mailbox.
Definition mailbox.h:81
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition mailbox.h:83
bool append
Mailbox is opened in append mode.
Definition mailbox.h:111
int msg_new
Number of new messages.
Definition mailbox.h:94
int msg_count
Total number of messages.
Definition mailbox.h:90
enum MailboxType type
Mailbox type.
Definition mailbox.h:104
int msg_flagged
Number of flagged messages.
Definition mailbox.h:92
void * compress_info
Compressed mbox module private data.
Definition mailbox.h:123
int msg_unread
Number of unread messages.
Definition mailbox.h:91
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 1077 of file external.c.

1078{
1079 struct Buffer *buf = buf_pool_get();
1080 struct Buffer *charset = buf_pool_get();
1081 struct Buffer *obuf = buf_pool_get();
1082 struct Buffer *tmp = buf_pool_get();
1083
1084 bool rc = false;
1085 bool charset_changed = false;
1086 bool type_changed = false;
1087 bool structure_changed = false;
1088
1089 char *cp = mutt_param_get(&b->parameter, "charset");
1090 buf_strcpy(charset, cp);
1091
1092 buf_printf(buf, "%s/%s", BODY_TYPE(b), b->subtype);
1093 buf_copy(obuf, buf);
1094 if (!TAILQ_EMPTY(&b->parameter))
1095 {
1096 struct Parameter *np = NULL;
1097 TAILQ_FOREACH(np, &b->parameter, entries)
1098 {
1099 mutt_addr_cat(tmp->data, tmp->dsize, np->value, MimeSpecials);
1100 buf_add_printf(buf, "; %s=%s", np->attribute, buf_string(tmp));
1101 }
1102 }
1103
1104 if ((mw_get_field("Content-Type: ", buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
1105 buf_is_empty(buf))
1106 {
1107 goto done;
1108 }
1109
1110 /* clean up previous junk */
1112 FREE(&b->subtype);
1113
1115
1116 buf_printf(tmp, "%s/%s", BODY_TYPE(b), NONULL(b->subtype));
1117 type_changed = !mutt_istr_equal(buf_string(tmp), buf_string(obuf));
1118 charset_changed = !mutt_istr_equal(buf_string(charset),
1119 mutt_param_get(&b->parameter, "charset"));
1120
1121 /* if in send mode, check for conversion - current setting is default. */
1122
1123 if (!e && (b->type == TYPE_TEXT) && charset_changed)
1124 {
1125 buf_printf(tmp, _("Convert to %s upon sending?"),
1126 mutt_param_get(&b->parameter, "charset"));
1127 enum QuadOption ans = query_yesorno(buf_string(tmp), b->noconv ? MUTT_NO : MUTT_YES);
1128 if (ans != MUTT_ABORT)
1129 b->noconv = (ans == MUTT_NO);
1130 }
1131
1132 /* inform the user */
1133
1134 buf_printf(tmp, "%s/%s", BODY_TYPE(b), NONULL(b->subtype));
1135 if (type_changed)
1136 mutt_message(_("Content-Type changed to %s"), buf_string(tmp));
1137 if ((b->type == TYPE_TEXT) && charset_changed)
1138 {
1139 if (type_changed)
1140 mutt_sleep(1);
1141 mutt_message(b->noconv ? _("Character set changed to %s; not converting") :
1142 _("Character set changed to %s; converting"),
1143 mutt_param_get(&b->parameter, "charset"));
1144 }
1145
1146 b->force_charset |= charset_changed;
1147
1148 if (!is_multipart(b) && b->parts)
1149 {
1150 structure_changed = true;
1151 mutt_body_free(&b->parts);
1152 }
1153 if (!mutt_is_message_type(b->type, b->subtype) && b->email)
1154 {
1155 structure_changed = true;
1156 b->email->body = NULL;
1157 email_free(&b->email);
1158 }
1159
1160 if (fp && !b->parts && (is_multipart(b) || mutt_is_message_type(b->type, b->subtype)))
1161 {
1162 structure_changed = true;
1163 mutt_parse_part(fp, b);
1164 }
1165
1166 if ((WithCrypto != 0) && e)
1167 {
1168 if (e->body == b)
1169 e->security = SEC_NONE;
1170
1171 e->security |= crypt_query(b);
1172 }
1173
1174 rc = structure_changed | type_changed;
1175
1176done:
1177 buf_pool_release(&buf);
1178 buf_pool_release(&charset);
1179 buf_pool_release(&obuf);
1180 buf_pool_release(&tmp);
1181 return rc;
1182}
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:715
int buf_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:693
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1982
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition parse.c:464
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition parse.c:1653
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition mime.c:69
@ TYPE_TEXT
Type: 'text/*'.
Definition mime.h:38
#define BODY_TYPE(body)
Get the type name of a body part.
Definition mime.h:92
#define is_multipart(body)
Check if a body part is multipart or a message container.
Definition mime.h:84
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:795
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition parameter.c:85
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition parameter.c:62
@ 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 query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:329
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define NONULL(x)
Definition string2.h:44
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
bool noconv
Don't do character set conversion.
Definition body.h:46
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
struct Email * email
header information for message/rfc822
Definition body.h:74
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:61
unsigned int type
content-type primary type, ContentType
Definition body.h:40
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
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()

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 1190 of file external.c.

1191{
1192 bool rc = false;
1193
1195
1196 struct Message *msg = mx_msg_open(m, e);
1197 if (msg)
1198 {
1199 mutt_parse_mime_message(e, msg->fp);
1200 if (crypt_pgp_check_traditional(msg->fp, e->body, false))
1201 {
1202 e->security = crypt_query(e->body);
1203 rc = true;
1204 }
1205
1207 mx_msg_close(m, &msg);
1208 }
1209 return rc;
1210}
bool crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional().
Definition cryptglue.c:321
#define PGP_TRADITIONAL_CHECKED
Email has a traditional (inline) signature.
Definition lib.h:108
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 EmailArray * ea )

Check if a message has inline PGP content.

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

Definition at line 1218 of file external.c.

1219{
1220 bool rc = false;
1221
1222 struct Email **ep = NULL;
1223 ARRAY_FOREACH(ep, ea)
1224 {
1225 struct Email *e = *ep;
1227 rc = check_traditional_pgp(m, e) || rc;
1228 }
1229
1230 return rc;
1231}
static bool check_traditional_pgp(struct Mailbox *m, struct Email *e)
Check for an inline PGP content.
Definition external.c:1190
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 72 of file external.c.

72{ 0 };