NeoMutt  2024-04-25-89-g194907
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 "imap/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 "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.
 
void 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 (void)
 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 80 of file external.c.

81{
83}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:377
static struct Buffer LastSaveFolder
The folder the user last saved to. Used by ci_save_message()
Definition: external.c:75
+ 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 90 of file external.c.

91{
92 if (!m || !ea || ARRAY_EMPTY(ea))
93 return;
94
95 struct Buffer *buf = buf_pool_get();
96 struct Buffer *prompt = buf_pool_get();
97 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
98 char *err = NULL;
99 int rc;
100 int msg_count = 0;
101
102 struct Email **ep = NULL;
103 ARRAY_FOREACH(ep, ea)
104 {
105 struct Email *e = *ep;
106 /* RFC5322 mandates a From: header,
107 * so warn before bouncing messages without one */
108 if (TAILQ_EMPTY(&e->env->from))
109 mutt_error(_("Warning: message contains no From: header"));
110
111 msg_count++;
112 }
113
114 if (msg_count == 1)
115 buf_strcpy(prompt, _("Bounce message to: "));
116 else
117 buf_strcpy(prompt, _("Bounce tagged messages to: "));
118
120 &CompleteAliasOps, NULL);
121 if ((rc != 0) || buf_is_empty(buf))
122 goto done;
123
125 if (TAILQ_EMPTY(&al))
126 {
127 mutt_error(_("Error parsing address"));
128 goto done;
129 }
130
132
133 if (mutt_addrlist_to_intl(&al, &err) < 0)
134 {
135 mutt_error(_("Bad IDN: '%s'"), err);
136 FREE(&err);
137 goto done;
138 }
139
140 buf_reset(buf);
141 mutt_addrlist_write(&al, buf, true);
142
143 buf_printf(prompt, ngettext("Bounce message to %s?", "Bounce messages to %s?", msg_count),
144 buf_string(buf));
145
146 if (query_quadoption(buf_string(prompt), NeoMutt->sub, "bounce") != MUTT_YES)
147 {
148 msgwin_clear_text(NULL);
149 mutt_message(ngettext("Message not bounced", "Messages not bounced", msg_count));
150 goto done;
151 }
152
153 msgwin_clear_text(NULL);
154
155 struct Message *msg = NULL;
156 ARRAY_FOREACH(ep, ea)
157 {
158 struct Email *e = *ep;
159 msg = mx_msg_open(m, e);
160 if (!msg)
161 {
162 rc = -1;
163 break;
164 }
165
166 rc = mutt_bounce_message(msg->fp, m, e, &al, NeoMutt->sub);
167 mx_msg_close(m, &msg);
168
169 if (rc < 0)
170 break;
171 }
172
173 /* If no error, or background, display message. */
174 if ((rc == 0) || (rc == S_BKG))
175 mutt_message(ngettext("Message bounced", "Messages bounced", msg_count));
176
177done:
179 buf_pool_release(&buf);
180 buf_pool_release(&prompt);
181}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1206
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:644
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1293
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:295
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#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:161
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
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:274
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
@ HC_ALIAS
Aliases.
Definition: lib.h:52
#define FREE(x)
Definition: memory.h:45
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:519
#define _(a)
Definition: message.h:28
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1180
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1134
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
@ 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:365
#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:917
#define S_BKG
Definition: string2.h:41
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:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 190 of file external.c.

192{
193 if (decode)
194 {
195 *chflags |= CH_DECODE | CH_REORDER;
196 *cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
197
198 const bool c_print_decode_weed = cs_subset_bool(NeoMutt->sub, "print_decode_weed");
199 const bool c_pipe_decode_weed = cs_subset_bool(NeoMutt->sub, "pipe_decode_weed");
200 if (print ? c_print_decode_weed : c_pipe_decode_weed)
201 {
202 *chflags |= CH_WEED;
203 *cmflags |= MUTT_CM_WEED;
204 }
205
206 /* Just as with copy-decode, we need to update the mime fields to avoid
207 * confusing programs that may process the email. However, we don't want
208 * to force those fields to appear in printouts. */
209 if (!print)
210 *chflags |= CH_MIME | CH_TXTPLAIN;
211 }
212
213 if (print)
214 *cmflags |= MUTT_CM_PRINTING;
215}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:56
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:43
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:40
#define CH_WEED
Weed the headers?
Definition: copy.h:55
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition: copy.h:61
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:44
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:63
#define MUTT_CM_PRINTING
Printing the message - display light.
Definition: copy.h:45
#define CH_TXTPLAIN
Generate text/plain MIME headers.
Definition: copy.h:65
+ 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 226 of file external.c.

228{
230 CopyHeaderFlags chflags = CH_FROM;
231
232 pipe_set_flags(decode, print, &cmflags, &chflags);
233
234 if ((WithCrypto != 0) && decode && e->security & SEC_ENCRYPT)
235 {
237 return;
238 mutt_endwin();
239 }
240
241 const bool own_msg = !msg;
242 if (own_msg)
243 {
244 msg = mx_msg_open(m, e);
245 if (!msg)
246 {
247 return;
248 }
249 }
250
251 if (decode)
252 {
254 }
255
256 mutt_copy_message(fp, e, msg, cmflags, chflags, 0);
257
258 if (own_msg)
259 {
260 mx_msg_close(m, &msg);
261 }
262}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:597
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:907
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:58
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:52
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:37
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:36
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:132
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:151
static void pipe_set_flags(bool decode, bool print, CopyMessageFlags *cmflags, CopyHeaderFlags *chflags)
Generate flags for copy header/message.
Definition: external.c:190
#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:43
+ 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 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 278 of file external.c.

280{
281 if (!m || !ea || ARRAY_EMPTY(ea))
282 return 1;
283
284 int rc = 0;
285 pid_t pid;
286 FILE *fp_out = NULL;
287
288 if (ARRAY_SIZE(ea) == 1)
289 {
290 struct Email *e = *ARRAY_GET(ea, 0);
291 /* handle a single message */
293
294 struct Message *msg = mx_msg_open(m, e);
295 if (msg && (WithCrypto != 0) && decode)
296 {
299 {
300 mx_msg_close(m, &msg);
301 return 1;
302 }
303 }
304 mutt_endwin();
305
306 pid = filter_create(cmd, &fp_out, NULL, NULL, EnvList);
307 if (pid < 0)
308 {
309 mutt_perror(_("Can't create filter process"));
310 mx_msg_close(m, &msg);
311 return 1;
312 }
313
314 OptKeepQuiet = true;
315 pipe_msg(m, e, msg, fp_out, decode, print);
316 mx_msg_close(m, &msg);
317 mutt_file_fclose(&fp_out);
318 rc = filter_wait(pid);
319 OptKeepQuiet = false;
320 }
321 else
322 {
323 /* handle tagged messages */
324 if ((WithCrypto != 0) && decode)
325 {
326 struct Email **ep = NULL;
327 ARRAY_FOREACH(ep, ea)
328 {
329 struct Email *e = *ep;
330 struct Message *msg = mx_msg_open(m, e);
331 if (msg)
332 {
335 mx_msg_close(m, &msg);
336 }
338 {
339 return 1;
340 }
341 }
342 }
343
344 if (split)
345 {
346 struct Email **ep = NULL;
347 ARRAY_FOREACH(ep, ea)
348 {
349 struct Email *e = *ep;
351 mutt_endwin();
352 pid = filter_create(cmd, &fp_out, NULL, NULL, EnvList);
353 if (pid < 0)
354 {
355 mutt_perror(_("Can't create filter process"));
356 return 1;
357 }
358 OptKeepQuiet = true;
359 pipe_msg(m, e, NULL, fp_out, decode, print);
360 /* add the message separator */
361 if (sep)
362 fputs(sep, fp_out);
363 mutt_file_fclose(&fp_out);
364 if (filter_wait(pid) != 0)
365 rc = 1;
366 OptKeepQuiet = false;
367 }
368 }
369 else
370 {
371 mutt_endwin();
372 pid = filter_create(cmd, &fp_out, NULL, NULL, EnvList);
373 if (pid < 0)
374 {
375 mutt_perror(_("Can't create filter process"));
376 return 1;
377 }
378 OptKeepQuiet = true;
379 struct Email **ep = NULL;
380 ARRAY_FOREACH(ep, ea)
381 {
382 struct Email *e = *ep;
384 pipe_msg(m, e, NULL, fp_out, decode, print);
385 /* add the message separator */
386 if (sep)
387 fputs(sep, fp_out);
388 }
389 mutt_file_fclose(&fp_out);
390 if (filter_wait(pid) != 0)
391 rc = 1;
392 OptKeepQuiet = false;
393 }
394 }
395
396 const bool c_wait_key = cs_subset_bool(NeoMutt->sub, "wait_key");
397 if ((rc != 0) || c_wait_key)
399 return rc;
400}
#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
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:173
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:226
#define mutt_file_fclose(FP)
Definition: file.h:149
bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program
Definition: globals.c:66
char ** EnvList
Private copy of the environment variables.
Definition: globals.c:78
#define mutt_perror(...)
Definition: logging2.h:93
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:692
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:44
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
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:209
+ 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 407 of file external.c.

408{
409 if (!m || !ea)
410 return;
411
412 struct Buffer *buf = buf_pool_get();
413
414 if (mw_get_field(_("Pipe to command: "), buf, MUTT_COMP_NO_FLAGS,
415 HC_EXT_COMMAND, &CompleteFileOps, NULL) != 0)
416 {
417 goto cleanup;
418 }
419
420 if (buf_is_empty(buf))
421 goto cleanup;
422
423 buf_expand_path(buf);
424 const bool c_pipe_decode = cs_subset_bool(NeoMutt->sub, "pipe_decode");
425 const bool c_pipe_split = cs_subset_bool(NeoMutt->sub, "pipe_split");
426 const char *const c_pipe_sep = cs_subset_string(NeoMutt->sub, "pipe_sep");
427 pipe_message(m, ea, buf_string(buf), c_pipe_decode, false, c_pipe_split, c_pipe_sep);
428
429cleanup:
430 buf_pool_release(&buf);
431}
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
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:278
@ HC_EXT_COMMAND
External commands.
Definition: lib.h:51
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
+ 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 EmailArray *  ea 
)

Print a message.

Parameters
mMailbox
eaArray of Emails to print

Definition at line 438 of file external.c.

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

477{
478 enum SortType sort = SORT_DATE;
479
480 switch (mw_multi_choice(reverse ?
481 /* L10N: The highlighted letters must match the "Sort" options */
482 _("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?") :
483 /* L10N: The highlighted letters must match the "Rev-Sort" options */
484 _("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?"),
485 /* L10N: These must match the highlighted letters from "Sort" and "Rev-Sort" */
486 _("dfrsotuzcpl")))
487 {
488 case -1: /* abort - don't resort */
489 return false;
490
491 case 1: /* (d)ate */
492 sort = SORT_DATE;
493 break;
494
495 case 2: /* (f)rm */
496 sort = SORT_FROM;
497 break;
498
499 case 3: /* (r)ecv */
500 sort = SORT_RECEIVED;
501 break;
502
503 case 4: /* (s)ubj */
504 sort = SORT_SUBJECT;
505 break;
506
507 case 5: /* t(o) */
508 sort = SORT_TO;
509 break;
510
511 case 6: /* (t)hread */
512 sort = SORT_THREADS;
513 break;
514
515 case 7: /* (u)nsort */
516 sort = SORT_ORDER;
517 break;
518
519 case 8: /* si(z)e */
520 sort = SORT_SIZE;
521 break;
522
523 case 9: /* s(c)ore */
524 sort = SORT_SCORE;
525 break;
526
527 case 10: /* s(p)am */
528 sort = SORT_SPAM;
529 break;
530
531 case 11: /* (l)abel */
532 sort = SORT_LABEL;
533 break;
534 }
535
536 const unsigned char c_use_threads = cs_subset_enum(NeoMutt->sub, "use_threads");
537 const enum SortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
538 int rc = CSR_ERR_CODE;
539 if ((sort != SORT_THREADS) || (c_use_threads == UT_UNSET))
540 {
541 if ((sort != SORT_THREADS) && (c_sort & SORT_LAST))
542 sort |= SORT_LAST;
543 if (reverse)
544 sort |= SORT_REVERSE;
545
546 rc = cs_subset_str_native_set(NeoMutt->sub, "sort", sort, NULL);
547 }
548 else
549 {
550 ASSERT((c_sort & SORT_MASK) != SORT_THREADS); /* See index_config_observer() */
551 /* Preserve the value of $sort, and toggle whether we are threaded. */
552 switch (c_use_threads)
553 {
554 case UT_FLAT:
555 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
556 reverse ? UT_REVERSE : UT_THREADS, NULL);
557 break;
558 case UT_THREADS:
559 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
560 reverse ? UT_REVERSE : UT_FLAT, NULL);
561 break;
562 case UT_REVERSE:
563 rc = cs_subset_str_native_set(NeoMutt->sub, "use_threads",
564 reverse ? UT_FLAT : UT_THREADS, NULL);
565 break;
566 default:
567 ASSERT(false);
568 }
569 }
570
571 return ((CSR_RESULT(rc) == CSR_SUCCESS) && !(rc & CSR_SUC_NO_CHANGE));
572}
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: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
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:63
@ UT_FLAT
Unthreaded.
Definition: mutt_thread.h:99
@ UT_UNSET
Not yet set by user, stick to legacy semantics.
Definition: mutt_thread.h:98
@ UT_THREADS
Normal threading (root above subthreads)
Definition: mutt_thread.h:100
@ UT_REVERSE
Reverse threading (subthreads above root)
Definition: mutt_thread.h:101
#define ASSERT(COND)
Definition: signal2.h:58
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:70
#define SORT_LAST
Sort thread by last-X, e.g. received date.
Definition: sort2.h:72
SortType
Methods for sorting.
Definition: sort2.h:34
@ SORT_SUBJECT
Sort by the email's subject.
Definition: sort2.h:38
@ SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort2.h:40
@ SORT_THREADS
Sort by email threads.
Definition: sort2.h:41
@ SORT_SPAM
Sort by the email's spam score.
Definition: sort2.h:49
@ SORT_LABEL
Sort by the emails label.
Definition: sort2.h:54
@ SORT_FROM
Sort by the email's From field.
Definition: sort2.h:39
@ SORT_SIZE
Sort by the size of the email.
Definition: sort2.h:36
@ SORT_RECEIVED
Sort by when the message were delivered locally.
Definition: sort2.h:42
@ SORT_TO
Sort by the email's To field.
Definition: sort2.h:43
@ SORT_DATE
Sort by the date the email was sent.
Definition: sort2.h:35
@ SORT_SCORE
Sort by the email's score.
Definition: sort2.h:44
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:71
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:297
+ 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 579 of file external.c.

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

622{
623 struct Buffer *buf = buf_pool_get();
624 struct Buffer *err = buf_pool_get();
625
626 window_redraw(NULL);
627 /* if enter is pressed after : with no command, just return */
629 &CompleteCommandOps, NULL) != 0) ||
630 buf_is_empty(buf))
631 {
632 goto done;
633 }
634
635 enum CommandResult rc = parse_rc_line(buf_string(buf), err);
636 if (!buf_is_empty(err))
637 {
638 if (rc == MUTT_CMD_SUCCESS) /* command succeeded with message */
639 mutt_message("%s", buf_string(err));
640 else if (rc == MUTT_CMD_ERROR)
641 mutt_error("%s", buf_string(err));
642 else if (rc == MUTT_CMD_WARNING)
643 mutt_warning("%s", buf_string(err));
644 }
645
646 if (NeoMutt)
647 {
648 // Running commands could cause anything to change, so let others know
650 }
651
652done:
653 buf_pool_release(&buf);
654 buf_pool_release(&err);
655}
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
const struct CompleteOps CompleteCommandOps
Auto-Completion of Commands.
Definition: helpers.c:477
#define mutt_warning(...)
Definition: logging2.h:90
@ HC_NEO_COMMAND
NeoMutt commands.
Definition: lib.h:53
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.
Definition: mutt_window.c:634
@ NT_GLOBAL_COMMAND
A NeoMutt command.
Definition: neomutt.h:63
@ 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:104
struct Notify * notify
Notifications handler.
Definition: neomutt.h:43
+ 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 661 of file external.c.

662{
663 const char *pfx = NULL;
664
665 struct AddressList *al = mutt_get_address(env, &pfx);
666 if (!al)
667 return;
668
669 /* Note: We don't convert IDNA to local representation this time.
670 * That is intentional, so the user has an opportunity to copy &
671 * paste the on-the-wire form of the address to other, IDN-unable
672 * software. */
673 struct Buffer *buf = buf_pool_get();
674 mutt_addrlist_write(al, buf, false);
675 mutt_message("%s: %s", pfx, buf_string(buf));
676 buf_pool_release(&buf);
677}
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:327
+ 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 686 of file external.c.

688{
689 *cmflags = MUTT_CM_NO_FLAGS;
690 *chflags = CH_UPDATE_LEN;
691
692 const bool need_decrypt = (transform_opt == TRANSFORM_DECRYPT) &&
693 (e->security & SEC_ENCRYPT);
694 const bool want_pgp = (WithCrypto & APPLICATION_PGP);
695 const bool want_smime = (WithCrypto & APPLICATION_SMIME);
696 const bool is_pgp = mutt_is_application_pgp(e->body) & SEC_ENCRYPT;
697 const bool is_smime = mutt_is_application_smime(e->body) & SEC_ENCRYPT;
698
699 if (need_decrypt && want_pgp && mutt_is_multipart_encrypted(e->body))
700 {
701 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
702 *cmflags = MUTT_CM_DECODE_PGP;
703 }
704 else if (need_decrypt && want_pgp && is_pgp)
705 {
706 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN;
707 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
708 }
709 else if (need_decrypt && want_smime && is_smime)
710 {
711 *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
712 *cmflags = MUTT_CM_DECODE_SMIME;
713 }
714 else if (transform_opt == TRANSFORM_DECODE)
715 {
716 *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN | CH_DECODE; // then decode RFC2047
717 *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
718 const bool c_copy_decode_weed = cs_subset_bool(NeoMutt->sub, "copy_decode_weed");
719 if (c_copy_decode_weed)
720 {
721 *chflags |= CH_WEED; // and respect $weed
722 *cmflags |= MUTT_CM_WEED;
723 }
724 }
725}
#define CH_XMIT
Transmitting this message? (Ignore Lines: and Content-Length:)
Definition: copy.h:57
#define MUTT_CM_DECODE_PGP
Used for decoding PGP messages.
Definition: copy.h:47
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:62
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:48
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:64
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:609
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:443
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition: crypt.c:548
@ TRANSFORM_DECODE
Decode message.
Definition: external.h:44
@ TRANSFORM_DECRYPT
Decrypt message.
Definition: external.h:43
#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: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 737 of file external.c.

739{
742 int rc;
743
744 set_copy_flags(e, transform_opt, &cmflags, &chflags);
745
746 struct Message *msg = mx_msg_open(m_src, e);
747 if (msg && transform_opt != TRANSFORM_NONE)
748 {
750 }
751
752 rc = mutt_append_message(m_dst, m_src, e, msg, cmflags, chflags);
753 mx_msg_close(m_src, &msg);
754 if (rc != 0)
755 return rc;
756
757 if (save_opt == SAVE_MOVE)
758 {
759 mutt_set_flag(m_src, e, MUTT_DELETE, true, true);
760 mutt_set_flag(m_src, e, MUTT_PURGE, true, true);
761 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
762 if (c_delete_untag)
763 mutt_set_flag(m_src, e, MUTT_TAG, false, true);
764 }
765
766 return 0;
767}
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:982
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:53
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:686
@ TRANSFORM_NONE
No transformation.
Definition: external.h:42
@ SAVE_MOVE
Move message to another mailbox, removing the original.
Definition: external.h:53
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:57
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:77
@ MUTT_TAG
Tagged messages.
Definition: mutt.h:80
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:75
+ 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 778 of file external.c.

780{
781 if (!ea || ARRAY_EMPTY(ea))
782 return -1;
783
784 int rc = -1;
785 int tagged_progress_count = 0;
786 unsigned int msg_count = ARRAY_SIZE(ea);
787 struct Mailbox *m_save = NULL;
788
789 struct Buffer *buf = buf_pool_get();
790 struct stat st = { 0 };
791 struct Email *e_cur = *ARRAY_GET(ea, 0);
792
793 const SecurityFlags security_flags = WithCrypto ? e_cur->security : SEC_NO_FLAGS;
794 const bool is_passphrase_needed = security_flags & SEC_ENCRYPT;
795
796 const char *prompt = NULL;
797 const char *progress_msg = NULL;
798
799 // Set prompt and progress_msg
800 switch (save_opt)
801 {
802 case SAVE_COPY:
803 // L10N: Progress meter message when copying tagged messages
804 progress_msg = (msg_count > 1) ? _("Copying tagged messages...") : NULL;
805 switch (transform_opt)
806 {
807 case TRANSFORM_NONE:
808 prompt = (msg_count > 1) ? _("Copy tagged to mailbox") : _("Copy to mailbox");
809 break;
811 prompt = (msg_count > 1) ? _("Decrypt-copy tagged to mailbox") :
812 _("Decrypt-copy to mailbox");
813 break;
814 case TRANSFORM_DECODE:
815 prompt = (msg_count > 1) ? _("Decode-copy tagged to mailbox") :
816 _("Decode-copy to mailbox");
817 break;
818 }
819 break;
820
821 case SAVE_MOVE:
822 // L10N: Progress meter message when saving tagged messages
823 progress_msg = (msg_count > 1) ? _("Saving tagged messages...") : NULL;
824 switch (transform_opt)
825 {
826 case TRANSFORM_NONE:
827 prompt = (msg_count > 1) ? _("Save tagged to mailbox") : _("Save to mailbox");
828 break;
830 prompt = (msg_count > 1) ? _("Decrypt-save tagged to mailbox") :
831 _("Decrypt-save to mailbox");
832 break;
833 case TRANSFORM_DECODE:
834 prompt = (msg_count > 1) ? _("Decode-save tagged to mailbox") :
835 _("Decode-save to mailbox");
836 break;
837 }
838 break;
839 }
840
842 mutt_default_save(buf, e_cur);
844
845 if (mw_enter_fname(prompt, buf, false, NULL, false, NULL, NULL, MUTT_SEL_NO_FLAGS) == -1)
846 {
847 goto cleanup;
848 }
849
850 size_t pathlen = buf_len(buf);
851 if (pathlen == 0)
852 goto cleanup;
853
854 mutt_path_tidy(buf, true);
855
856 /* This is an undocumented feature of ELM pointed out to me by Felix von
857 * Leitner <leitner@prz.fu-berlin.de> */
860 if (mutt_str_equal(buf_string(buf), "."))
862 else
864
865 buf_expand_path(buf);
866
867 /* check to make sure that this file is really the one the user wants */
868 if (mutt_save_confirm(buf_string(buf), &st) != 0)
869 goto cleanup;
870
871 if (is_passphrase_needed && (transform_opt != TRANSFORM_NONE) &&
872 !crypt_valid_passphrase(security_flags))
873 {
874 rc = -1;
875 goto errcleanup;
876 }
877
878 mutt_message(_("Copying to %s..."), buf_string(buf));
879
880 enum MailboxType mailbox_type = imap_path_probe(buf_string(buf), NULL);
881 if ((m->type == MUTT_IMAP) && (transform_opt == TRANSFORM_NONE) && (mailbox_type == MUTT_IMAP))
882 {
883 rc = imap_copy_messages(m, ea, buf_string(buf), save_opt);
884 switch (rc)
885 {
886 /* success */
887 case 0:
889 rc = 0;
890 if (save_opt == SAVE_MOVE)
891 {
892 const bool c_delete_untag = cs_subset_bool(NeoMutt->sub, "delete_untag");
893 if (c_delete_untag)
894 {
895 struct Email **ep = NULL;
896 ARRAY_FOREACH(ep, ea)
897 {
898 mutt_set_flag(m, *ep, MUTT_TAG, false, true);
899 }
900 }
901 }
902 goto cleanup;
903 /* non-fatal error: continue to fetch/append */
904 case 1:
905 break;
906 /* fatal error, abort */
907 case -1:
908 goto errcleanup;
909 }
910 }
911
913 m_save = mx_path_resolve(buf_string(buf));
914 bool old_append = m_save->append;
915 OpenMailboxFlags mbox_flags = MUTT_NEWFOLDER;
916 /* Display a tagged message progress counter, rather than (for
917 * IMAP) a per-message progress counter */
918 if (msg_count > 1)
919 mbox_flags |= MUTT_QUIET;
920 if (!mx_mbox_open(m_save, mbox_flags))
921 {
922 rc = -1;
923 mailbox_free(&m_save);
924 goto errcleanup;
925 }
926 m_save->append = true;
927
928 /* If we're saving to a compressed mailbox, the stats won't be updated
929 * until the next open. Until then, improvise. */
930 struct Mailbox *m_comp = NULL;
931 if (m_save->compress_info)
932 {
933 m_comp = mailbox_find(m_save->realpath);
934 }
935 /* We probably haven't been opened yet */
936 if (m_comp && (m_comp->msg_count == 0))
937 m_comp = NULL;
938
939 if (msg_count == 1)
940 {
941 rc = mutt_save_message_mbox(m, e_cur, save_opt, transform_opt, m_save);
942 if (rc != 0)
943 {
944 mx_mbox_close(m_save);
945 m_save->append = old_append;
946 goto errcleanup;
947 }
948
949 if (m_comp)
950 {
951 m_comp->msg_count++;
952 if (!e_cur->read)
953 {
954 m_comp->msg_unread++;
955 if (!e_cur->old)
956 m_comp->msg_new++;
957 }
958 if (e_cur->flagged)
959 m_comp->msg_flagged++;
960 }
961 }
962 else
963 {
964 rc = 0;
965
966#ifdef USE_NOTMUCH
967 if (m->type == MUTT_NOTMUCH)
968 nm_db_longrun_init(m, true);
969#endif
970 struct Progress *progress = progress_new(MUTT_PROGRESS_WRITE, msg_count);
971 progress_set_message(progress, "%s", progress_msg);
972 struct Email **ep = NULL;
973 ARRAY_FOREACH(ep, ea)
974 {
975 struct Email *e = *ep;
976 progress_update(progress, ++tagged_progress_count, -1);
978 rc = mutt_save_message_mbox(m, e, save_opt, transform_opt, m_save);
979 if (rc != 0)
980 break;
981
982 if (m_comp)
983 {
984 struct Email *e2 = e;
985 m_comp->msg_count++;
986 if (!e2->read)
987 {
988 m_comp->msg_unread++;
989 if (!e2->old)
990 m_comp->msg_new++;
991 }
992 if (e2->flagged)
993 m_comp->msg_flagged++;
994 }
995 }
996 progress_free(&progress);
997
998#ifdef USE_NOTMUCH
999 if (m->type == MUTT_NOTMUCH)
1001#endif
1002 if (rc != 0)
1003 {
1004 mx_mbox_close(m_save);
1005 m_save->append = old_append;
1006 goto errcleanup;
1007 }
1008 }
1009
1010 const bool need_mailbox_cleanup = ((m_save->type == MUTT_MBOX) ||
1011 (m_save->type == MUTT_MMDF));
1012
1013 mx_mbox_close(m_save);
1014 m_save->append = old_append;
1015
1016 if (need_mailbox_cleanup)
1018
1020 rc = 0;
1021
1022errcleanup:
1023 if (rc != 0)
1024 {
1025 switch (save_opt)
1026 {
1027 case SAVE_MOVE:
1028 if (msg_count > 1)
1029 {
1030 // L10N: Message when an index tagged save operation fails for some reason
1031 mutt_error(_("Error saving tagged messages"));
1032 }
1033 else
1034 {
1035 // L10N: Message when an index/pager save operation fails for some reason
1036 mutt_error(_("Error saving message"));
1037 }
1038 break;
1039 case SAVE_COPY:
1040 if (msg_count > 1)
1041 {
1042 // L10N: Message when an index tagged copy operation fails for some reason
1043 mutt_error(_("Error copying tagged messages"));
1044 }
1045 else
1046 {
1047 // L10N: Message when an index/pager copy operation fails for some reason
1048 mutt_error(_("Error copying message"));
1049 }
1050 break;
1051 }
1052 }
1053
1054 mailbox_free(&m_save);
1055
1056cleanup:
1057 buf_pool_release(&buf);
1058 return rc;
1059}
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:57
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:337
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:89
struct Mailbox * mailbox_find(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:150
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
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:737
@ SAVE_COPY
Copy message, making a duplicate in another mailbox.
Definition: external.h:52
void mutt_file_resolve_symlink(struct Buffer *buf)
Resolve a symlink in place.
Definition: file.c:1659
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:236
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2345
void mutt_default_save(struct Buffer *path, struct Email *e)
Find the default save path for an email.
Definition: hook.c:770
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:1687
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:660
#define PATH_MAX
Definition: mutt.h:42
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
void mailbox_restore_timestamp(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mutt_mailbox.c:407
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:519
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:746
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:288
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1636
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:598
uint8_t OpenMailboxFlags
Flags for mutt_open_mailbox(), e.g. MUTT_NOSORT.
Definition: mxapi.h:39
#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:45
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:44
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:379
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:364
@ MUTT_PROGRESS_WRITE
Progress tracks elements, according to $write_inc
Definition: lib.h:83
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: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:121
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 1070 of file external.c.

1071{
1072 struct Buffer *buf = buf_pool_get();
1073 struct Buffer *charset = buf_pool_get();
1074 struct Buffer *obuf = buf_pool_get();
1075 struct Buffer *tmp = buf_pool_get();
1076
1077 bool rc = false;
1078 bool charset_changed = false;
1079 bool type_changed = false;
1080 bool structure_changed = false;
1081
1082 char *cp = mutt_param_get(&b->parameter, "charset");
1083 buf_strcpy(charset, cp);
1084
1085 buf_printf(buf, "%s/%s", TYPE(b), b->subtype);
1086 buf_copy(obuf, buf);
1087 if (!TAILQ_EMPTY(&b->parameter))
1088 {
1089 struct Parameter *np = NULL;
1090 TAILQ_FOREACH(np, &b->parameter, entries)
1091 {
1092 mutt_addr_cat(tmp->data, tmp->dsize, np->value, MimeSpecials);
1093 buf_add_printf(buf, "; %s=%s", np->attribute, buf_string(tmp));
1094 }
1095 }
1096
1097 if ((mw_get_field("Content-Type: ", buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
1098 buf_is_empty(buf))
1099 {
1100 goto done;
1101 }
1102
1103 /* clean up previous junk */
1105 FREE(&b->subtype);
1106
1108
1109 buf_printf(tmp, "%s/%s", TYPE(b), NONULL(b->subtype));
1110 type_changed = !mutt_istr_equal(buf_string(tmp), buf_string(obuf));
1111 charset_changed = !mutt_istr_equal(buf_string(charset),
1112 mutt_param_get(&b->parameter, "charset"));
1113
1114 /* if in send mode, check for conversion - current setting is default. */
1115
1116 if (!e && (b->type == TYPE_TEXT) && charset_changed)
1117 {
1118 buf_printf(tmp, _("Convert to %s upon sending?"),
1119 mutt_param_get(&b->parameter, "charset"));
1120 enum QuadOption ans = query_yesorno(buf_string(tmp), b->noconv ? MUTT_NO : MUTT_YES);
1121 if (ans != MUTT_ABORT)
1122 b->noconv = (ans == MUTT_NO);
1123 }
1124
1125 /* inform the user */
1126
1127 buf_printf(tmp, "%s/%s", TYPE(b), NONULL(b->subtype));
1128 if (type_changed)
1129 mutt_message(_("Content-Type changed to %s"), buf_string(tmp));
1130 if ((b->type == TYPE_TEXT) && charset_changed)
1131 {
1132 if (type_changed)
1133 mutt_sleep(1);
1134 mutt_message(b->noconv ? _("Character set changed to %s; not converting") :
1135 _("Character set changed to %s; converting"),
1136 mutt_param_get(&b->parameter, "charset"));
1137 }
1138
1139 b->force_charset |= charset_changed;
1140
1141 if (!is_multipart(b) && b->parts)
1142 {
1143 structure_changed = true;
1144 mutt_body_free(&b->parts);
1145 }
1146 if (!mutt_is_message_type(b->type, b->subtype) && b->email)
1147 {
1148 structure_changed = true;
1149 b->email->body = NULL;
1150 email_free(&b->email);
1151 }
1152
1153 if (fp && !b->parts && (is_multipart(b) || mutt_is_message_type(b->type, b->subtype)))
1154 {
1155 structure_changed = true;
1156 mutt_parse_part(fp, b);
1157 }
1158
1159 if ((WithCrypto != 0) && e)
1160 {
1161 if (e->body == b)
1163
1164 e->security |= crypt_query(b);
1165 }
1166
1167 rc = structure_changed | type_changed;
1168
1169done:
1170 buf_pool_release(&buf);
1171 buf_pool_release(&charset);
1172 buf_pool_release(&obuf);
1173 buf_pool_release(&tmp);
1174 return rc;
1175}
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:708
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:204
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition: crypt.c:687
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:1817
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition: parse.c:463
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1493
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
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:672
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:843
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:326
#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
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()

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

1184{
1185 bool rc = false;
1186
1188
1189 struct Message *msg = mx_msg_open(m, e);
1190 if (msg)
1191 {
1192 mutt_parse_mime_message(e, msg->fp);
1193 if (crypt_pgp_check_traditional(msg->fp, e->body, false))
1194 {
1195 e->security = crypt_query(e->body);
1196 rc = true;
1197 }
1198
1200 mx_msg_close(m, &msg);
1201 }
1202 return rc;
1203}
bool crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional()
Definition: cryptglue.c:282
#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 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 1211 of file external.c.

1212{
1213 bool rc = false;
1214
1215 struct Email **ep = NULL;
1216 ARRAY_FOREACH(ep, ea)
1217 {
1218 struct Email *e = *ep;
1220 rc = check_traditional_pgp(m, e) || rc;
1221 }
1222
1223 return rc;
1224}
static bool check_traditional_pgp(struct Mailbox *m, struct Email *e)
Check for an inline PGP content.
Definition: external.c:1183
+ 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.