NeoMutt  2018-07-16 +952-a2da0a
Teaching an old dog new tricks
DOXYGEN
commands.c File Reference

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

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "conn/conn.h"
#include "mutt.h"
#include "alias.h"
#include "context.h"
#include "copy.h"
#include "curs_lib.h"
#include "filter.h"
#include "format_flags.h"
#include "globals.h"
#include "hdrline.h"
#include "hook.h"
#include "keymap.h"
#include "mailbox.h"
#include "menu.h"
#include "mutt_curses.h"
#include "mutt_logging.h"
#include "mutt_parse.h"
#include "mutt_window.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "pager.h"
#include "protos.h"
#include "sendlib.h"
#include "sort.h"
#include "imap/imap.h"
#include "notmuch/mutt_notmuch.h"
#include <libintl.h>
+ Include dependency graph for commands.c:

Go to the source code of this file.

Macros

#define EXTRA_SPACE   (15 + 7 + 2)
 

Functions

int mutt_display_message (struct Email *cur)
 Display a message in the pager. More...
 
void ci_bounce_message (struct Email *e)
 Bounce an email. More...
 
static void pipe_set_flags (bool decode, bool print, int *cmflags, int *chflags)
 Generate flags for copy header/message. More...
 
static void pipe_msg (struct Email *e, FILE *fp, bool decode, bool print)
 Pipe a message. More...
 
static int pipe_message (struct Email *e, char *cmd, bool decode, bool print, bool split, const char *sep)
 Pipe message to a command. More...
 
void mutt_pipe_message (struct Email *e)
 Pipe a message. More...
 
void mutt_print_message (struct Email *e)
 Print a message. More...
 
int mutt_select_sort (int reverse)
 Ask the user for a sort method. More...
 
void mutt_shell_escape (void)
 invoke a command in a subshell More...
 
void mutt_enter_command (void)
 enter a neomutt command More...
 
void mutt_display_address (struct Envelope *env)
 Display the address of a message. More...
 
static void set_copy_flags (struct Email *e, bool decode, bool decrypt, int *cmflags, int *chflags)
 Set the flags for a message copy. More...
 
int mutt_save_message_ctx (struct Email *e, bool delete, bool decode, bool decrypt, struct Mailbox *m)
 Save a message to a given mailbox. More...
 
int mutt_save_message (struct Email *e, bool delete, bool decode, bool decrypt)
 Save an email. More...
 
int mutt_edit_content_type (struct Email *e, struct Body *b, FILE *fp)
 Edit the content type of an attachment. More...
 
static bool check_traditional_pgp (struct Email *e, int *redraw)
 Check for an inline PGP content. More...
 
bool mutt_check_traditional_pgp (struct Email *e, int *redraw)
 Check if a message has inline PGP content. More...
 
void mutt_check_stats (void)
 Forcibly update mailbox stats. More...
 

Variables

unsigned char CryptVerifySig
 Config: Verify PGP or SMIME signatures. More...
 
char * DisplayFilter
 Config: External command to pre-process an email before display. More...
 
bool PipeDecode
 Config: Decode the message when piping it. More...
 
char * PipeSep
 Config: Separator to add between multiple piped messages. More...
 
bool PipeSplit
 Config: Run the pipe command on each message separately. More...
 
bool PrintDecode
 Config: Decode message before printing it. More...
 
bool PrintSplit
 Config: Print multiple messages separately. More...
 
bool PromptAfter
 Config: Pause after running an external pager. More...
 
static const char * ExtPagerProgress = "all"
 
static char LastSaveFolder [PATH_MAX] = ""
 The folder the user last saved to. More...
 

Detailed Description

Manage where the email is piped to external commands.

Authors
  • Michael R. Elkins
  • Thomas Roessler

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

Macro Definition Documentation

#define EXTRA_SPACE   (15 + 7 + 2)

Function Documentation

int mutt_display_message ( struct Email cur)

Display a message in the pager.

Parameters
curHeader of current message
Return values
0Success
-1Error

Definition at line 98 of file commands.c.

99 {
100  char tempfile[PATH_MAX], buf[LONG_STRING];
101  int rc = 0;
102  bool builtin = false;
104  int chflags;
105  FILE *fpout = NULL;
106  FILE *fpfilterout = NULL;
107  pid_t filterpid = -1;
108  int res;
109 
110  snprintf(buf, sizeof(buf), "%s/%s", TYPE(cur->content), cur->content->subtype);
111 
114 
115  /* see if crypto is needed for this message. if so, we should exit curses */
116  if ((WithCrypto != 0) && cur->security)
117  {
118  if (cur->security & ENCRYPT)
119  {
120  if (cur->security & APPLICATION_SMIME)
121  crypt_smime_getkeys(cur->env);
122  if (!crypt_valid_passphrase(cur->security))
123  return 0;
124 
125  cmflags |= MUTT_CM_VERIFY;
126  }
127  else if (cur->security & SIGN)
128  {
129  /* find out whether or not the verify signature */
130  /* L10N: Used for the $crypt_verify_sig prompt */
131  if (query_quadoption(CryptVerifySig, _("Verify signature?")) == MUTT_YES)
132  {
133  cmflags |= MUTT_CM_VERIFY;
134  }
135  }
136  }
137 
138  if (cmflags & MUTT_CM_VERIFY || cur->security & ENCRYPT)
139  {
140  if (cur->security & APPLICATION_PGP)
141  {
142  if (cur->env->from)
144 
146  }
147 
148  if (cur->security & APPLICATION_SMIME)
150  }
151 
152  mutt_mktemp(tempfile, sizeof(tempfile));
153  fpout = mutt_file_fopen(tempfile, "w");
154  if (!fpout)
155  {
156  mutt_error(_("Could not create temporary file"));
157  return 0;
158  }
159 
161  {
162  fpfilterout = fpout;
163  fpout = NULL;
164  filterpid = mutt_create_filter_fd(DisplayFilter, &fpout, NULL, NULL, -1,
165  fileno(fpfilterout), -1);
166  if (filterpid < 0)
167  {
168  mutt_error(_("Cannot create display filter"));
169  mutt_file_fclose(&fpfilterout);
170  unlink(tempfile);
171  return 0;
172  }
173  }
174 
175  if (!Pager || (mutt_str_strcmp(Pager, "builtin") == 0))
176  builtin = true;
177  else
178  {
179  struct HdrFormatInfo hfi;
180  hfi.ctx = Context;
181  hfi.pager_progress = ExtPagerProgress;
182  hfi.email = cur;
183  mutt_make_string_info(buf, sizeof(buf), MuttIndexWindow->cols,
185  fputs(buf, fpout);
186  fputs("\n\n", fpout);
187  }
188 
189  chflags = (Weed ? (CH_WEED | CH_REORDER) : 0) | CH_DECODE | CH_FROM | CH_DISPLAY;
190 #ifdef USE_NOTMUCH
192  chflags |= CH_VIRTUAL;
193 #endif
194  res = mutt_copy_message_ctx(fpout, Context->mailbox, cur, cmflags, chflags);
195 
196  if ((mutt_file_fclose(&fpout) != 0 && errno != EPIPE) || res < 0)
197  {
198  mutt_error(_("Could not copy message"));
199  if (fpfilterout)
200  {
201  mutt_wait_filter(filterpid);
202  mutt_file_fclose(&fpfilterout);
203  }
204  mutt_file_unlink(tempfile);
205  return 0;
206  }
207 
208  if (fpfilterout && mutt_wait_filter(filterpid) != 0)
210 
211  mutt_file_fclose(&fpfilterout); /* XXX - check result? */
212 
213  if (WithCrypto)
214  {
215  /* update crypto information for this message */
216  cur->security &= ~(GOODSIGN | BADSIGN);
217  cur->security |= crypt_query(cur->content);
218 
219  /* Remove color cache for this message, in case there
220  are color patterns for both ~g and ~V */
221  cur->pair = 0;
222  }
223 
224  if (builtin)
225  {
226  if ((WithCrypto != 0) && (cur->security & APPLICATION_SMIME) && (cmflags & MUTT_CM_VERIFY))
227  {
228  if (cur->security & GOODSIGN)
229  {
230  if (crypt_smime_verify_sender(cur) == 0)
231  mutt_message(_("S/MIME signature successfully verified"));
232  else
233  mutt_error(_("S/MIME certificate owner does not match sender"));
234  }
235  else if (cur->security & PARTSIGN)
236  mutt_message(_("Warning: Part of this message has not been signed"));
237  else if (cur->security & SIGN || cur->security & BADSIGN)
238  mutt_error(_("S/MIME signature could NOT be verified"));
239  }
240 
241  if ((WithCrypto != 0) && (cur->security & APPLICATION_PGP) && (cmflags & MUTT_CM_VERIFY))
242  {
243  if (cur->security & GOODSIGN)
244  mutt_message(_("PGP signature successfully verified"));
245  else if (cur->security & PARTSIGN)
246  mutt_message(_("Warning: Part of this message has not been signed"));
247  else if (cur->security & SIGN)
248  mutt_message(_("PGP signature could NOT be verified"));
249  }
250 
251  struct Pager info = { 0 };
252  /* Invoke the builtin pager */
253  info.email = cur;
254  info.ctx = Context;
255  rc = mutt_pager(NULL, tempfile, MUTT_PAGER_MESSAGE, &info);
256  }
257  else
258  {
259  int r;
260 
261  char cmd[HUGE_STRING];
262  mutt_endwin();
263  snprintf(cmd, sizeof(cmd), "%s %s", NONULL(Pager), tempfile);
264  r = mutt_system(cmd);
265  if (r == -1)
266  mutt_error(_("Error running \"%s\""), cmd);
267  unlink(tempfile);
268  if (!OptNoCurses)
269  keypad(stdscr, true);
270  if (r != -1)
272  if (r != -1 && PromptAfter)
273  {
274  mutt_unget_event(mutt_any_key_to_continue(_("Command: ")), 0);
275  rc = km_dokey(MENU_PAGER);
276  }
277  else
278  rc = 0;
279  }
280 
281  return rc;
282 }
struct Context * ctx
Definition: hdrline.h:45
The "current" mailbox.
Definition: context.h:36
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: magic.h:43
#define SIGN
Definition: ncrypt.h:120
#define NONULL(x)
Definition: string2.h:39
int km_dokey(int menu)
Determine what a keypress should do.
Definition: keymap.c:572
#define mutt_message(...)
Definition: logging.h:87
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
#define MUTT_PAGER_MESSAGE
Definition: pager.h:53
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
int mutt_copy_message_ctx(FILE *fpout, struct Mailbox *src, struct Email *e, int flags, int chflags)
Copy a message from a Context.
Definition: copy.c:792
struct Body * content
list of MIME parts
Definition: email.h:92
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:192
void mutt_unget_event(int ch, int op)
Return a keystroke to the input buffer.
Definition: curs_lib.c:668
#define CH_FROM
retain the "From " message separator?
Definition: copy.h:51
#define _(a)
Definition: message.h:28
static const char * ExtPagerProgress
Definition: commands.c:87
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:45
#define MUTT_MESSAGE_HOOK
Definition: hook.h:48
make sure that all chars are printable
Definition: format_flags.h:35
#define LONG_STRING
Definition: string2.h:36
An email being displayed.
Definition: pager.h:63
void crypt_invoke_message(int type)
Display an informative message.
Definition: cryptglue.c:138
int mutt_pager(const char *banner, const char *fname, int flags, struct Pager *extra)
Display a file, or help, in a window.
Definition: pager.c:2203
struct Mailbox * mailbox
Definition: context.h:50
#define MUTT_CM_DISPLAY
output is displayed to the user
Definition: copy.h:35
Data passed to index_format_str()
Definition: hdrline.h:43
enum MailboxType magic
mailbox type
Definition: mailbox.h:99
#define CH_WEED
weed the headers?
Definition: copy.h:48
struct Envelope * env
envelope information
Definition: email.h:91
void mutt_parse_mime_message(struct Mailbox *m, struct Email *cur)
Parse a MIME email.
Definition: mutt_parse.c:50
#define CH_VIRTUAL
write virtual header lines too
Definition: copy.h:67
bool Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:38
struct Address * from
Definition: envelope.h:35
#define HUGE_STRING
Definition: string2.h:37
char * subtype
content-type subtype
Definition: body.h:36
#define ENCRYPT
Definition: ncrypt.h:119
struct Context * ctx
current mailbox
Definition: pager.h:65
WHERE struct Context * Context
Definition: globals.h:41
#define PARTSIGN
Definition: ncrypt.h:123
#define mutt_mktemp(a, b)
Definition: muttlib.h:71
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:498
bool PromptAfter
Config: Pause after running an external pager.
Definition: commands.c:85
#define PATH_MAX
Definition: mutt.h:46
struct MuttWindow * MuttIndexWindow
Index Window.
Definition: mutt_window.c:39
int query_quadoption(int opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3227
#define MUTT_CM_DECODE
decode the message body into text/plain
Definition: copy.h:34
#define CH_REORDER
Re-order output of headers.
Definition: copy.h:54
#define MUTT_CM_CHARCONV
perform character set conversions
Definition: copy.h:38
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition: cryptglue.c:406
#define CH_DECODE
do RFC1522 decoding?
Definition: copy.h:49
void crypt_pgp_invoke_getkeys(struct Address *addr)
Wrapper for CryptModuleSpecs::pgp_invoke_getkeys()
Definition: cryptglue.c:229
#define CH_DISPLAY
display result to user
Definition: copy.h:65
#define mutt_set_flag(a, b, c, d)
Definition: protos.h:54
#define TYPE(X)
Definition: mime.h:82
int crypt_smime_verify_sender(struct Email *e)
Wrapper for CryptModuleSpecs::smime_verify_sender()
Definition: cryptglue.c:415
WHERE char * PagerFormat
Config: printf-like format string for the pager&#39;s status bar.
Definition: globals.h:136
#define MUTT_CM_VERIFY
do signature verification
Definition: copy.h:44
void mutt_make_string_info(char *buf, size_t buflen, int cols, const char *s, struct HdrFormatInfo *hfi, enum FormatFlag flags)
Create pager status bar string.
Definition: hdrline.c:1476
#define APPLICATION_PGP
Definition: ncrypt.h:129
Messages that have been read.
Definition: mutt.h:116
unsigned char CryptVerifySig
Config: Verify PGP or SMIME signatures.
Definition: commands.c:78
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:548
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:531
struct Email * email
current message
Definition: pager.h:66
int crypt_query(struct Body *m)
Check out the type of encryption used.
Definition: crypt.c:647
int mutt_file_fclose(FILE **f)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_error(...)
Definition: logging.h:88
#define BADSIGN
Definition: ncrypt.h:122
int crypt_valid_passphrase(int flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:144
pid_t mutt_create_filter_fd(const char *cmd, FILE **in, FILE **out, FILE **err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:64
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
void mutt_message_hook(struct Mailbox *m, struct Email *e, int type)
Perform a message hook.
Definition: hook.c:438
#define WithCrypto
Definition: ncrypt.h:154
Pager pager (email viewer)
Definition: keymap.h:74
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:612
int pair
color-pair to use when displaying in the index
Definition: email.h:81
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
char * DisplayFilter
Config: External command to pre-process an email before display.
Definition: commands.c:79
#define APPLICATION_SMIME
Definition: ncrypt.h:130
#define GOODSIGN
Definition: ncrypt.h:121

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void ci_bounce_message ( struct Email e)

Bounce an email.

Parameters
eEmail to bounce

Definition at line 288 of file commands.c.

289 {
290  char prompt[SHORT_STRING];
291  char scratch[SHORT_STRING];
292  char buf[HUGE_STRING] = { 0 };
293  struct Address *addr = NULL;
294  char *err = NULL;
295  int rc;
296  int msgcount; // for L10N with ngettext
297 
298  /* RFC5322 mandates a From: header, so warn before bouncing
299  * messages without one */
300  if (e)
301  {
302  msgcount = 1;
303  if (!e->env->from)
304  {
305  mutt_error(_("Warning: message contains no From: header"));
306  }
307  }
308  else if (Context)
309  {
310  msgcount = 0; // count the precise number of messages.
311  for (rc = 0; rc < Context->mailbox->msg_count; rc++)
312  {
313  if (message_is_tagged(Context, rc) && !Context->mailbox->hdrs[rc]->env->from)
314  {
315  msgcount++;
316  if (!Context->mailbox->hdrs[rc]->env->from)
317  {
318  mutt_error(_("Warning: message contains no From: header"));
319  break;
320  }
321  }
322  }
323  }
324  else
325  msgcount = 0;
326 
327  if (e)
328  mutt_str_strfcpy(prompt, _("Bounce message to: "), sizeof(prompt));
329  else
330  mutt_str_strfcpy(prompt, _("Bounce tagged messages to: "), sizeof(prompt));
331 
332  rc = mutt_get_field(prompt, buf, sizeof(buf), MUTT_ALIAS);
333  if (rc || !buf[0])
334  return;
335 
336  addr = mutt_addr_parse_list2(addr, buf);
337  if (!addr)
338  {
339  mutt_error(_("Error parsing address"));
340  return;
341  }
342 
343  addr = mutt_expand_aliases(addr);
344 
345  if (mutt_addrlist_to_intl(addr, &err) < 0)
346  {
347  mutt_error(_("Bad IDN: '%s'"), err);
348  FREE(&err);
349  mutt_addr_free(&addr);
350  return;
351  }
352 
353  buf[0] = '\0';
354  mutt_addr_write(buf, sizeof(buf), addr, true);
355 
356 #define EXTRA_SPACE (15 + 7 + 2)
357  snprintf(scratch, sizeof(scratch),
358  ngettext("Bounce message to %s", "Bounce messages to %s", msgcount), buf);
359 
361  {
362  mutt_simple_format(prompt, sizeof(prompt), 0, MuttMessageWindow->cols - EXTRA_SPACE,
363  FMT_LEFT, 0, scratch, sizeof(scratch), 0);
364  mutt_str_strcat(prompt, sizeof(prompt), "...?");
365  }
366  else
367  snprintf(prompt, sizeof(prompt), "%s?", scratch);
368 
369  if (query_quadoption(Bounce, prompt) != MUTT_YES)
370  {
371  mutt_addr_free(&addr);
373  mutt_message(ngettext("Message not bounced", "Messages not bounced", msgcount));
374  return;
375  }
376 
378 
379  rc = mutt_bounce_message(NULL, e, addr);
380  mutt_addr_free(&addr);
381  /* If no error, or background, display message. */
382  if ((rc == 0) || (rc == S_BKG))
383  mutt_message(ngettext("Message bounced", "Messages bounced", msgcount));
384 }
The "current" mailbox.
Definition: context.h:36
struct Address * mutt_addr_parse_list2(struct Address *p, const char *s)
Parse a list of email addresses.
Definition: address.c:630
int msg_count
total number of messages
Definition: mailbox.h:86
#define SHORT_STRING
Definition: string2.h:34
int mutt_bounce_message(FILE *fp, struct Email *e, struct Address *to)
Bounce an email message.
Definition: sendlib.c:3039
void mutt_simple_format(char *buf, size_t buflen, int min_width, int max_width, int justify, char pad_char, const char *s, size_t n, int arboreal)
Format a string, like snprintf()
Definition: curs_lib.c:911
#define MUTT_ALIAS
do alias "completion" by calling up the alias-menu
Definition: mutt.h:58
#define mutt_message(...)
Definition: logging.h:87
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
#define FMT_LEFT
Definition: curs_lib.h:41
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:32
#define S_BKG
Definition: string2.h:45
struct Email ** hdrs
Definition: mailbox.h:93
int mutt_addrlist_to_intl(struct Address *a, char **err)
Convert an Address list to Punycode.
Definition: address.c:1208
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write an Address to a buffer.
Definition: address.c:1146
struct Mailbox * mailbox
Definition: context.h:50
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:69
struct Envelope * env
envelope information
Definition: email.h:91
struct Address * from
Definition: envelope.h:35
#define HUGE_STRING
Definition: string2.h:37
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1176
int query_quadoption(int opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3227
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: curs_lib.c:1236
#define mutt_get_field(A, B, C, D)
Definition: curs_lib.h:78
char * mutt_str_strcat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:402
struct Address * mutt_expand_aliases(struct Address *a)
Expand aliases in a List of Addresses.
Definition: alias.c:296
#define mutt_error(...)
Definition: logging.h:88
WHERE unsigned char Bounce
Config: Confirm before bouncing a message.
Definition: globals.h:185
#define FREE(x)
Definition: memory.h:46
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:41
#define EXTRA_SPACE
void mutt_addr_free(struct Address **p)
Free a list of Addresses.
Definition: address.c:446

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void pipe_set_flags ( bool  decode,
bool  print,
int *  cmflags,
int *  chflags 
)
static

Generate flags for copy header/message.

Parameters
[in]decodeIf true decode the message
[in]printIf true, mark the message for printing
[out]cmflagsCopy message flags, e.g. MUTT_CM_DECODE
[out]chflagsCopy header flags, e.g. CH_DECODE

Definition at line 393 of file commands.c.

394 {
395  if (decode)
396  {
397  *cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
398  *chflags |= CH_DECODE | CH_REORDER;
399 
400  if (Weed)
401  {
402  *chflags |= CH_WEED;
403  *cmflags |= MUTT_CM_WEED;
404  }
405  }
406 
407  if (print)
408  *cmflags |= MUTT_CM_PRINTING;
409 }
#define MUTT_CM_WEED
weed message/rfc822 attachment headers
Definition: copy.h:37
#define MUTT_CM_PRINTING
printing the message - display light
Definition: copy.h:39
#define CH_WEED
weed the headers?
Definition: copy.h:48
bool Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:38
#define MUTT_CM_DECODE
decode the message body into text/plain
Definition: copy.h:34
#define CH_REORDER
Re-order output of headers.
Definition: copy.h:54
#define MUTT_CM_CHARCONV
perform character set conversions
Definition: copy.h:38
#define CH_DECODE
do RFC1522 decoding?
Definition: copy.h:49

+ Here is the caller graph for this function:

static void pipe_msg ( struct Email e,
FILE *  fp,
bool  decode,
bool  print 
)
static

Pipe a message.

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

Definition at line 418 of file commands.c.

419 {
420  int cmflags = 0;
421  int chflags = CH_FROM;
422 
423  pipe_set_flags(decode, print, &cmflags, &chflags);
424 
425  if ((WithCrypto != 0) && decode && e->security & ENCRYPT)
426  {
428  return;
429  endwin();
430  }
431 
432  if (decode)
434 
435  mutt_copy_message_ctx(fp, Context->mailbox, e, cmflags, chflags);
436 }
The "current" mailbox.
Definition: context.h:36
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
int mutt_copy_message_ctx(FILE *fpout, struct Mailbox *src, struct Email *e, int flags, int chflags)
Copy a message from a Context.
Definition: copy.c:792
#define CH_FROM
retain the "From " message separator?
Definition: copy.h:51
static void pipe_set_flags(bool decode, bool print, int *cmflags, int *chflags)
Generate flags for copy header/message.
Definition: commands.c:393
struct Mailbox * mailbox
Definition: context.h:50
void mutt_parse_mime_message(struct Mailbox *m, struct Email *cur)
Parse a MIME email.
Definition: mutt_parse.c:50
#define ENCRYPT
Definition: ncrypt.h:119
int crypt_valid_passphrase(int flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:144
#define WithCrypto
Definition: ncrypt.h:154

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int pipe_message ( struct Email e,
char *  cmd,
bool  decode,
bool  print,
bool  split,
const char *  sep 
)
static

Pipe message to a command.

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

The following code is shared between printing and piping.

Definition at line 451 of file commands.c.

453 {
454  if (!Context)
455  return 1;
456 
457  int rc = 0;
458  pid_t thepid;
459  FILE *fpout = NULL;
460 
461  if (e)
462  {
464 
465  if ((WithCrypto != 0) && decode)
466  {
469  return 1;
470  }
471  mutt_endwin();
472 
473  thepid = mutt_create_filter(cmd, &fpout, NULL, NULL);
474  if (thepid < 0)
475  {
476  mutt_perror(_("Can't create filter process"));
477  return 1;
478  }
479 
480  OptKeepQuiet = true;
481  pipe_msg(e, fpout, decode, print);
482  mutt_file_fclose(&fpout);
483  rc = mutt_wait_filter(thepid);
484  OptKeepQuiet = false;
485  }
486  else
487  {
488  /* handle tagged messages */
489  if ((WithCrypto != 0) && decode)
490  {
491  for (int i = 0; i < Context->mailbox->msg_count; i++)
492  {
493  if (!message_is_tagged(Context, i))
494  continue;
495 
498  if (Context->mailbox->hdrs[i]->security & ENCRYPT &&
500  {
501  return 1;
502  }
503  }
504  }
505 
506  if (split)
507  {
508  for (int i = 0; i < Context->mailbox->msg_count; i++)
509  {
510  if (!message_is_tagged(Context, i))
511  continue;
512 
514  mutt_endwin();
515  thepid = mutt_create_filter(cmd, &fpout, NULL, NULL);
516  if (thepid < 0)
517  {
518  mutt_perror(_("Can't create filter process"));
519  return 1;
520  }
521  OptKeepQuiet = true;
522  pipe_msg(Context->mailbox->hdrs[i], fpout, decode, print);
523  /* add the message separator */
524  if (sep)
525  fputs(sep, fpout);
526  mutt_file_fclose(&fpout);
527  if (mutt_wait_filter(thepid) != 0)
528  rc = 1;
529  OptKeepQuiet = false;
530  }
531  }
532  else
533  {
534  mutt_endwin();
535  thepid = mutt_create_filter(cmd, &fpout, NULL, NULL);
536  if (thepid < 0)
537  {
538  mutt_perror(_("Can't create filter process"));
539  return 1;
540  }
541  OptKeepQuiet = true;
542  for (int i = 0; i < Context->mailbox->msg_count; i++)
543  {
544  if (!message_is_tagged(Context, i))
545  continue;
546 
548  pipe_msg(Context->mailbox->hdrs[i], fpout, decode, print);
549  /* add the message separator */
550  if (sep)
551  fputs(sep, fpout);
552  }
553  mutt_file_fclose(&fpout);
554  if (mutt_wait_filter(thepid) != 0)
555  rc = 1;
556  OptKeepQuiet = false;
557  }
558  }
559 
560  if (rc || WaitKey)
562  return rc;
563 }
The "current" mailbox.
Definition: context.h:36
int msg_count
total number of messages
Definition: mailbox.h:86
#define mutt_perror(...)
Definition: logging.h:89
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
#define _(a)
Definition: message.h:28
WHERE bool WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:262
#define MUTT_MESSAGE_HOOK
Definition: hook.h:48
struct Email ** hdrs
Definition: mailbox.h:93
struct Mailbox * mailbox
Definition: context.h:50
void mutt_parse_mime_message(struct Mailbox *m, struct Email *cur)
Parse a MIME email.
Definition: mutt_parse.c:50
#define ENCRYPT
Definition: ncrypt.h:119
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:498
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: curs_lib.c:1236
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:531
static void pipe_msg(struct Email *e, FILE *fp, bool decode, bool print)
Pipe a message.
Definition: commands.c:418
int mutt_file_fclose(FILE **f)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
pid_t mutt_create_filter(const char *s, FILE **in, FILE **out, FILE **err)
Set up filter program.
Definition: filter.c:216
int crypt_valid_passphrase(int flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:144
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
WHERE bool OptKeepQuiet
(pseudo) shut up the message and refresh functions while we are executing an external program...
Definition: options.h:36
void mutt_message_hook(struct Mailbox *m, struct Email *e, int type)
Perform a message hook.
Definition: hook.c:438
#define WithCrypto
Definition: ncrypt.h:154

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_pipe_message ( struct Email e)

Pipe a message.

Parameters
eEmail to pipe

Definition at line 569 of file commands.c.

570 {
571  char buffer[LONG_STRING];
572 
573  buffer[0] = '\0';
574  if (mutt_get_field(_("Pipe to command: "), buffer, sizeof(buffer), MUTT_CMD) != 0 ||
575  !buffer[0])
576  {
577  return;
578  }
579 
580  mutt_expand_path(buffer, sizeof(buffer));
581  pipe_message(e, buffer, PipeDecode, false, PipeSplit, PipeSep);
582 }
#define _(a)
Definition: message.h:28
#define LONG_STRING
Definition: string2.h:36
char * PipeSep
Config: Separator to add between multiple piped messages.
Definition: commands.c:81
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:157
bool PipeSplit
Config: Run the pipe command on each message separately.
Definition: commands.c:82
static int pipe_message(struct Email *e, char *cmd, bool decode, bool print, bool split, const char *sep)
Pipe message to a command.
Definition: commands.c:451
#define MUTT_CMD
do completion on previous word
Definition: mutt.h:61
bool PipeDecode
Config: Decode the message when piping it.
Definition: commands.c:80
#define mutt_get_field(A, B, C, D)
Definition: curs_lib.h:78

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_print_message ( struct Email e)

Print a message.

Parameters
eEmail to print

Definition at line 588 of file commands.c.

589 {
590  int i;
591  int msgcount; // for L10N with ngettext
592  if (e)
593  msgcount = 1;
594  else if (Context)
595  {
596  msgcount = 0; // count the precise number of messages.
597  for (i = 0; i < Context->mailbox->msg_count; i++)
598  if (message_is_tagged(Context, i))
599  msgcount++;
600  }
601  else
602  msgcount = 0;
603 
604  if (Print && (!PrintCommand || !*PrintCommand))
605  {
606  mutt_message(_("No printing command has been defined"));
607  return;
608  }
609 
610  if (query_quadoption(Print, e ? _("Print message?") : _("Print tagged messages?")) != MUTT_YES)
611  {
612  return;
613  }
614 
615  if (pipe_message(e, PrintCommand, PrintDecode, true, PrintSplit, "\f") == 0)
616  mutt_message(ngettext("Message printed", "Messages printed", msgcount));
617  else
618  {
619  mutt_message(ngettext("Message could not be printed",
620  "Messages could not be printed", msgcount));
621  }
622 }
The "current" mailbox.
Definition: context.h:36
int msg_count
total number of messages
Definition: mailbox.h:86
#define mutt_message(...)
Definition: logging.h:87
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
#define _(a)
Definition: message.h:28
WHERE unsigned char Print
Config: Confirm before printing a message.
Definition: globals.h:189
bool PrintDecode
Config: Decode message before printing it.
Definition: commands.c:83
struct Mailbox * mailbox
Definition: context.h:50
static int pipe_message(struct Email *e, char *cmd, bool decode, bool print, bool split, const char *sep)
Pipe message to a command.
Definition: commands.c:451
WHERE char * PrintCommand
Config: External command to print a message.
Definition: globals.h:139
int query_quadoption(int opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3227
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: curs_lib.c:1236
bool PrintSplit
Config: Print multiple messages separately.
Definition: commands.c:84

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_select_sort ( int  reverse)

Ask the user for a sort method.

Parameters
reverseIf true make it a reverse sort
Return values
numSort type, e.g. SORT_DATE

Definition at line 629 of file commands.c.

630 {
631  int method = Sort; /* save the current method in case of abort */
632  int new_sort = -1;
633 
634  switch (mutt_multi_choice(reverse ?
635  /* L10N: The highlighted letters must match the "Sort" options */
636  _("Rev-Sort "
637  "(d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/"
638  "(u)nsort/si(z)e/s(c)ore/s(p)am/(l)abel?: ") :
639  /* L10N: The highlighted letters must match the "Rev-Sort" options */
640  _("Sort "
641  "(d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/"
642  "(u)nsort/si(z)e/s(c)ore/s(p)am/(l)abel?: "),
643  /* L10N: These must match the highlighted letters from "Sort" and "Rev-Sort" */
644  _("dfrsotuzcpl")))
645  {
646  case -1: /* abort - don't resort */
647  return -1;
648 
649  case 1: /* (d)ate */
650  new_sort = SORT_DATE;
651  break;
652 
653  case 2: /* (f)rm */
654  new_sort = SORT_FROM;
655  break;
656 
657  case 3: /* (r)ecv */
658  new_sort = SORT_RECEIVED;
659  break;
660 
661  case 4: /* (s)ubj */
662  new_sort = SORT_SUBJECT;
663  break;
664 
665  case 5: /* t(o) */
666  new_sort = SORT_TO;
667  break;
668 
669  case 6: /* (t)hread */
670  new_sort = SORT_THREADS;
671  break;
672 
673  case 7: /* (u)nsort */
674  new_sort = SORT_ORDER;
675  break;
676 
677  case 8: /* si(z)e */
678  new_sort = SORT_SIZE;
679  break;
680 
681  case 9: /* s(c)ore */
682  new_sort = SORT_SCORE;
683  break;
684 
685  case 10: /* s(p)am */
686  new_sort = SORT_SPAM;
687  break;
688 
689  case 11: /* (l)abel */
690  new_sort = SORT_LABEL;
691  break;
692  }
693  if (reverse)
694  new_sort |= SORT_REVERSE;
695 
696  cs_str_native_set(Config, "sort", new_sort, NULL);
697  return (Sort != method) ? 0 : -1; /* no need to resort if it's the same */
698 }
#define SORT_FROM
Sort by the email&#39;s From field.
Definition: sort.h:49
#define SORT_SCORE
Sort by the email&#39;s score.
Definition: sort.h:54
#define _(a)
Definition: message.h:28
WHERE struct ConfigSet * Config
Wrapper around the user&#39;s config settings.
Definition: globals.h:39
#define SORT_LABEL
Sort by the emails label.
Definition: sort.h:64
#define SORT_TO
Sort by the email&#39;s To field.
Definition: sort.h:53
#define SORT_SIZE
Sort by the size of the email.
Definition: sort.h:46
#define SORT_DATE
Sort by the date the email was sent.
Definition: sort.h:45
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:792
#define SORT_THREADS
Sort by email threads.
Definition: sort.h:51
#define SORT_SPAM
Sort by the email&#39;s spam score.
Definition: sort.h:59
#define SORT_SUBJECT
Sort by the email&#39;s subject.
Definition: sort.h:48
WHERE short Sort
Config: Sort method for the index.
Definition: sort.h:58
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort.h:78
#define SORT_RECEIVED
Sort by when the message were delivered locally.
Definition: sort.h:52
int cs_str_native_set(const struct ConfigSet *cs, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: set.c:800
#define SORT_ORDER
Sort by the order the messages appear in the mailbox.
Definition: sort.h:50

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_shell_escape ( void  )

invoke a command in a subshell

Definition at line 703 of file commands.c.

704 {
705  char buf[LONG_STRING];
706 
707  buf[0] = '\0';
708  if (mutt_get_field(_("Shell command: "), buf, sizeof(buf), MUTT_CMD) != 0)
709  return;
710 
711  if (!buf[0] && Shell)
712  mutt_str_strfcpy(buf, Shell, sizeof(buf));
713  if (!buf[0])
714  return;
715 
717  mutt_endwin();
718  fflush(stdout);
719  int rc = mutt_system(buf);
720  if (rc == -1)
721  mutt_debug(1, "Error running \"%s\"!", buf);
722 
723  if ((rc != 0) || WaitKey)
726 }
#define _(a)
Definition: message.h:28
WHERE char * Shell
Config: External command to run subshells in.
Definition: globals.h:142
WHERE bool WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:262
#define LONG_STRING
Definition: string2.h:36
int mutt_mailbox_check(int force)
Check all AllMailboxes for new mail.
Definition: mailbox.c:538
void mutt_window_clearline(struct MuttWindow *win, int row)
Clear a row of a Window.
Definition: mutt_window.c:69
#define MUTT_CMD
do completion on previous word
Definition: mutt.h:61
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:498
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mailbox.h:160
#define mutt_get_field(A, B, C, D)
Definition: curs_lib.h:78
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:531
struct MuttWindow * MuttMessageWindow
Message Window.
Definition: mutt_window.c:41
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_enter_command ( void  )

enter a neomutt command

Definition at line 731 of file commands.c.

732 {
733  struct Buffer err, token;
734  char buffer[LONG_STRING];
735  int r;
736 
737  buffer[0] = '\0';
738  if (mutt_get_field(":", buffer, sizeof(buffer), MUTT_COMMAND) != 0 || !buffer[0])
739  return;
740  mutt_buffer_init(&err);
741  err.dsize = STRING;
742  err.data = mutt_mem_malloc(err.dsize);
743  err.dptr = err.data;
744  mutt_buffer_init(&token);
745  r = mutt_parse_rc_line(buffer, &token, &err);
746  FREE(&token.data);
747  if (err.data[0])
748  {
749  /* since errbuf could potentially contain printf() sequences in it,
750  we must call mutt_error() in this fashion so that vsprintf()
751  doesn't expect more arguments that we passed */
752  if (r == 0)
753  mutt_message("%s", err.data);
754  else
755  mutt_error("%s", err.data);
756  }
757 
758  FREE(&err.data);
759 }
#define mutt_message(...)
Definition: logging.h:87
int mutt_parse_rc_line(char *line, struct Buffer *token, struct Buffer *err)
Parse a line of user config.
Definition: init.c:3119
String manipulation buffer.
Definition: buffer.h:33
#define LONG_STRING
Definition: string2.h:36
#define MUTT_COMMAND
do command completion
Definition: mutt.h:64
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
#define mutt_get_field(A, B, C, D)
Definition: curs_lib.h:78
#define STRING
Definition: string2.h:35
#define mutt_error(...)
Definition: logging.h:88
#define FREE(x)
Definition: memory.h:46
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:66

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_display_address ( struct Envelope env)

Display the address of a message.

Parameters
envEnvelope containing address

Definition at line 765 of file commands.c.

766 {
767  const char *pfx = NULL;
768  char buf[SHORT_STRING];
769 
770  struct Address *addr = mutt_get_address(env, &pfx);
771  if (!addr)
772  return;
773 
774  /* Note: We don't convert IDNA to local representation this time.
775  * That is intentional, so the user has an opportunity to copy &
776  * paste the on-the-wire form of the address to other, IDN-unable
777  * software.
778  */
779 
780  buf[0] = '\0';
781  mutt_addr_write(buf, sizeof(buf), addr, false);
782  mutt_message("%s: %s", pfx, buf);
783 }
#define SHORT_STRING
Definition: string2.h:34
struct Address * mutt_get_address(struct Envelope *env, const char **pfxp)
Get an Address from an Envelope.
Definition: alias.c:327
#define mutt_message(...)
Definition: logging.h:87
An email address.
Definition: address.h:32
size_t mutt_addr_write(char *buf, size_t buflen, struct Address *addr, bool display)
Write an Address to a buffer.
Definition: address.c:1146

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static void set_copy_flags ( struct Email e,
bool  decode,
bool  decrypt,
int *  cmflags,
int *  chflags 
)
static

Set the flags for a message copy.

Parameters
[in]eEmail
[in]decodeIf true, decode the message
[in]decryptIf true, decrypt the message
[out]cmflagsCopy message flags, e.g. MUTT_CM_DECODE
[out]chflagsCopy header flags, e.g. CH_DECODE

Definition at line 793 of file commands.c.

795 {
796  *cmflags = 0;
797  *chflags = CH_UPDATE_LEN;
798 
799  if ((WithCrypto != 0) && !decode && decrypt && (e->security & ENCRYPT))
800  {
802  {
803  *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
804  *cmflags = MUTT_CM_DECODE_PGP;
805  }
806  else if (((WithCrypto & APPLICATION_PGP) != 0) &&
808  {
809  decode = 1;
810  }
811  else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
813  {
814  *chflags = CH_NONEWLINE | CH_XMIT | CH_MIME;
815  *cmflags = MUTT_CM_DECODE_SMIME;
816  }
817  }
818 
819  if (decode)
820  {
821  *chflags = CH_XMIT | CH_MIME | CH_TXTPLAIN;
822  *cmflags = MUTT_CM_DECODE | MUTT_CM_CHARCONV;
823 
824  if (!decrypt) /* If decode doesn't kick in for decrypt, */
825  {
826  *chflags |= CH_DECODE; /* then decode RFC2047 headers, */
827 
828  if (Weed)
829  {
830  *chflags |= CH_WEED; /* and respect $weed. */
831  *cmflags |= MUTT_CM_WEED;
832  }
833  }
834  }
835 }
#define CH_MIME
ignore MIME fields
Definition: copy.h:56
int mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:403
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
struct Body * content
list of MIME parts
Definition: email.h:92
#define MUTT_CM_WEED
weed message/rfc822 attachment headers
Definition: copy.h:37
#define CH_WEED
weed the headers?
Definition: copy.h:48
bool Weed
Config: Filter headers when displaying/forwarding/printing/replying.
Definition: email_globals.c:38
#define CH_TXTPLAIN
generate text/plain MIME headers
Definition: copy.h:58
#define ENCRYPT
Definition: ncrypt.h:119
#define MUTT_CM_DECODE
decode the message body into text/plain
Definition: copy.h:34
#define MUTT_CM_CHARCONV
perform character set conversions
Definition: copy.h:38
#define CH_DECODE
do RFC1522 decoding?
Definition: copy.h:49
#define CH_XMIT
transmitting this message?
Definition: copy.h:50
#define CH_UPDATE_LEN
update Lines: and Content-Length:
Definition: copy.h:57
int mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:510
#define APPLICATION_PGP
Definition: ncrypt.h:129
#define MUTT_CM_DECODE_SMIME
used for decoding S/MIME messages
Definition: copy.h:42
#define MUTT_CM_DECODE_PGP
used for decoding PGP messages
Definition: copy.h:41
int mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:569
#define WithCrypto
Definition: ncrypt.h:154
#define CH_NONEWLINE
don&#39;t output terminating newline
Definition: copy.h:55
#define APPLICATION_SMIME
Definition: ncrypt.h:130

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_save_message_ctx ( struct Email e,
bool  delete,
bool  decode,
bool  decrypt,
struct Mailbox m 
)

Save a message to a given mailbox.

Parameters
eEmail
deleteIf true, delete the original
decodeIf true, decode the message
decryptIf true, decrypt the message
mMailbox to save to
Return values
0Success
-1Error

Definition at line 847 of file commands.c.

849 {
850  int cmflags, chflags;
851  int rc;
852 
853  set_copy_flags(e, decode, decrypt, &cmflags, &chflags);
854 
855  if (decode || decrypt)
857 
858  rc = mutt_append_message(m, Context->mailbox, e, cmflags, chflags);
859  if (rc != 0)
860  return rc;
861 
862  if (delete)
863  {
866  if (DeleteUntag)
868  }
869 
870  return 0;
871 }
The "current" mailbox.
Definition: context.h:36
Messages to be deleted.
Definition: mutt.h:118
struct Mailbox * mailbox
Definition: context.h:50
WHERE bool DeleteUntag
Config: Untag messages when they are marked for deletion.
Definition: globals.h:211
void mutt_parse_mime_message(struct Mailbox *m, struct Email *cur)
Parse a MIME email.
Definition: mutt_parse.c:50
Tagged messages.
Definition: mutt.h:123
Messages to be purged (bypass trash)
Definition: mutt.h:120
#define mutt_set_flag(a, b, c, d)
Definition: protos.h:54
static void set_copy_flags(struct Email *e, bool decode, bool decrypt, int *cmflags, int *chflags)
Set the flags for a message copy.
Definition: commands.c:793
int mutt_append_message(struct Mailbox *dest, struct Mailbox *src, struct Email *e, int cmflags, int chflags)
Append a message.
Definition: copy.c:862

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_save_message ( struct Email e,
bool  delete,
bool  decode,
bool  decrypt 
)

Save an email.

Parameters
eEmail
deleteIf true, delete the original (save)
decodeIf true, decode the message
decryptIf true, decrypt the message
Return values
0Copy/save was successful
-1Error/abort

Definition at line 882 of file commands.c.

883 {
884  bool need_passphrase = false;
885  int app = 0;
886  char buf[PATH_MAX];
887  const char *prompt = NULL;
888  struct Context *savectx = NULL;
889  struct stat st;
890 
891  if (delete)
892  {
893  if (decode)
894  prompt = e ? _("Decode-save to mailbox") : _("Decode-save tagged to mailbox");
895  else if (decrypt)
896  prompt = e ? _("Decrypt-save to mailbox") : _("Decrypt-save tagged to mailbox");
897  else
898  prompt = e ? _("Save to mailbox") : _("Save tagged to mailbox");
899  }
900  else
901  {
902  if (decode)
903  prompt = e ? _("Decode-copy to mailbox") : _("Decode-copy tagged to mailbox");
904  else if (decrypt)
905  prompt = e ? _("Decrypt-copy to mailbox") : _("Decrypt-copy tagged to mailbox");
906  else
907  prompt = e ? _("Copy to mailbox") : _("Copy tagged to mailbox");
908  }
909 
910  if (e)
911  {
912  if (WithCrypto)
913  {
914  need_passphrase = (e->security & ENCRYPT);
915  app = e->security;
916  }
918  mutt_default_save(buf, sizeof(buf), e);
919  }
920  else
921  {
922  /* look for the first tagged message */
923  for (int i = 0; i < Context->mailbox->msg_count; i++)
924  {
925  if (message_is_tagged(Context, i))
926  {
927  e = Context->mailbox->hdrs[i];
928  break;
929  }
930  }
931 
932  if (e)
933  {
935  mutt_default_save(buf, sizeof(buf), e);
936  if (WithCrypto)
937  {
938  need_passphrase = (e->security & ENCRYPT);
939  app = e->security;
940  }
941  e = NULL;
942  }
943  }
944 
945  mutt_pretty_mailbox(buf, sizeof(buf));
946  if (mutt_enter_fname(prompt, buf, sizeof(buf), 0) == -1)
947  return -1;
948 
949  size_t pathlen = strlen(buf);
950  if (pathlen == 0)
951  return -1;
952 
953  /* Trim any trailing '/' */
954  if (buf[pathlen - 1] == '/')
955  buf[pathlen - 1] = '\0';
956 
957  /* This is an undocumented feature of ELM pointed out to me by Felix von
958  * Leitner <leitner@prz.fu-berlin.de>
959  */
960  if (mutt_str_strcmp(buf, ".") == 0)
961  mutt_str_strfcpy(buf, LastSaveFolder, sizeof(buf));
962  else
964 
965  mutt_expand_path(buf, sizeof(buf));
966 
967  /* check to make sure that this file is really the one the user wants */
968  if (mutt_save_confirm(buf, &st) != 0)
969  return -1;
970 
971  if ((WithCrypto != 0) && need_passphrase && (decode || decrypt) &&
973  {
974  return -1;
975  }
976 
977  mutt_message(_("Copying to %s..."), buf);
978 
979 #ifdef USE_IMAP
980  if ((Context->mailbox->magic == MUTT_IMAP) && !(decode || decrypt) &&
981  (imap_path_probe(buf, NULL) == MUTT_IMAP))
982  {
983  switch (imap_copy_messages(Context, e, buf, delete))
984  {
985  /* success */
986  case 0:
988  return 0;
989  /* non-fatal error: continue to fetch/append */
990  case 1:
991  break;
992  /* fatal error, abort */
993  case -1:
994  return -1;
995  }
996  }
997 #endif
998 
999  savectx = mx_mbox_open(NULL, buf, MUTT_APPEND);
1000  if (savectx)
1001  {
1002 #ifdef USE_COMPRESSED
1003  /* If we're saving to a compressed mailbox, the stats won't be updated
1004  * until the next open. Until then, improvise. */
1005  struct Mailbox *cm = NULL;
1006  if (savectx->mailbox->compress_info)
1007  {
1008  cm = mutt_find_mailbox(savectx->mailbox->realpath);
1009  }
1010  /* We probably haven't been opened yet */
1011  if (cm && (cm->msg_count == 0))
1012  cm = NULL;
1013 #endif
1014  if (e)
1015  {
1016  if (mutt_save_message_ctx(e, delete, decode, decrypt, savectx->mailbox) != 0)
1017  {
1018  mx_mbox_close(&savectx, NULL);
1019  return -1;
1020  }
1021 #ifdef USE_COMPRESSED
1022  if (cm)
1023  {
1024  cm->msg_count++;
1025  if (!e->read)
1026  {
1027  cm->msg_unread++;
1028  if (!e->old)
1029  cm->msg_new++;
1030  }
1031  if (e->flagged)
1032  cm->msg_flagged++;
1033  }
1034 #endif
1035  }
1036  else
1037  {
1038  int rc = 0;
1039 
1040 #ifdef USE_NOTMUCH
1041  if (Context->mailbox->magic == MUTT_NOTMUCH)
1043 #endif
1044  for (int i = 0; i < Context->mailbox->msg_count; i++)
1045  {
1046  if (!message_is_tagged(Context, i))
1047  continue;
1048 
1050  rc = mutt_save_message_ctx(Context->mailbox->hdrs[i], delete, decode,
1051  decrypt, savectx->mailbox);
1052  if (rc != 0)
1053  break;
1054 #ifdef USE_COMPRESSED
1055  if (cm)
1056  {
1057  struct Email *e2 = Context->mailbox->hdrs[i];
1058  cm->msg_count++;
1059  if (!e2->read)
1060  {
1061  cm->msg_unread++;
1062  if (!e2->old)
1063  cm->msg_new++;
1064  }
1065  if (e2->flagged)
1066  cm->msg_flagged++;
1067  }
1068 #endif
1069  }
1070 #ifdef USE_NOTMUCH
1071  if (Context->mailbox->magic == MUTT_NOTMUCH)
1073 #endif
1074  if (rc != 0)
1075  {
1076  mx_mbox_close(&savectx, NULL);
1077  return -1;
1078  }
1079  }
1080 
1081  const bool need_mailbox_cleanup = ((savectx->mailbox->magic == MUTT_MBOX) ||
1082  (savectx->mailbox->magic == MUTT_MMDF));
1083 
1084  mx_mbox_close(&savectx, NULL);
1085 
1086  if (need_mailbox_cleanup)
1087  mutt_mailbox_cleanup(buf, &st);
1088 
1089  mutt_clear_error();
1090  return 0;
1091  }
1092 
1093  return -1;
1094 }
#define MUTT_APPEND
open mailbox for appending messages
Definition: mx.h:50
The "current" mailbox.
Definition: context.h:36
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: magic.h:43
int msg_count
total number of messages
Definition: mailbox.h:86
struct Mailbox * mutt_find_mailbox(const char *path)
Find the mailbox with a given path.
Definition: mailbox.c:268
The envelope/body of an email.
Definition: email.h:35
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2479
int msg_unread
number of unread messages
Definition: mailbox.h:87
void mutt_pretty_mailbox(char *s, size_t buflen)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:606
#define mutt_message(...)
Definition: logging.h:87
int msg_flagged
number of flagged messages
Definition: mailbox.h:88
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
&#39;mmdf&#39; Mailbox type
Definition: magic.h:38
void mutt_mailbox_cleanup(const char *path, struct stat *st)
Restore the timestamp of a mailbox.
Definition: mailbox.c:217
#define _(a)
Definition: message.h:28
&#39;IMAP&#39; Mailbox type
Definition: magic.h:42
#define MUTT_MESSAGE_HOOK
Definition: hook.h:48
void mutt_default_save(char *path, size_t pathlen, struct Email *e)
Find the default save path for an email.
Definition: hook.c:523
#define mutt_enter_fname(A, B, C, D)
Definition: curs_lib.h:77
struct Email ** hdrs
Definition: mailbox.h:93
int mutt_save_confirm(const char *s, struct stat *st)
Ask the user to save.
Definition: muttlib.c:1383
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:157
bool read
Definition: email.h:49
struct Context * mx_mbox_open(struct Mailbox *m, const char *path, int flags)
Open a mailbox and parse it.
Definition: mx.c:254
struct Mailbox * mailbox
Definition: context.h:50
bool old
Definition: email.h:48
enum MailboxType magic
mailbox type
Definition: mailbox.h:99
int imap_copy_messages(struct Context *ctx, struct Email *e, char *dest, bool delete)
Server COPY messages to another folder.
Definition: message.c:1518
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:141
int mx_mbox_close(struct Context **pctx, int *index_hint)
Save changes and close mailbox.
Definition: mx.c:568
#define ENCRYPT
Definition: ncrypt.h:119
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: nm_db.c:301
&#39;mbox&#39; Mailbox type
Definition: magic.h:37
A mailbox.
Definition: mailbox.h:76
#define PATH_MAX
Definition: mutt.h:46
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: curs_lib.c:1236
bool flagged
marked important?
Definition: email.h:41
int msg_new
number of new messages
Definition: mailbox.h:89
void * compress_info
compressed mbox module private data
Definition: mailbox.h:118
int mutt_save_message_ctx(struct Email *e, bool delete, bool decode, bool decrypt, struct Mailbox *m)
Save a message to a given mailbox.
Definition: commands.c:847
int crypt_valid_passphrase(int flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:144
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: nm_db.c:286
char realpath[PATH_MAX]
used for duplicate detection, context comparison, and the sidebar
Definition: mailbox.h:79
void mutt_message_hook(struct Mailbox *m, struct Email *e, int type)
Perform a message hook.
Definition: hook.c:438
#define WithCrypto
Definition: ncrypt.h:154
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:612
static char LastSaveFolder[PATH_MAX]
The folder the user last saved to.
Definition: commands.c:90

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int 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
1A structural change is made
0Otherwise

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

Definition at line 1106 of file commands.c.

1107 {
1108  char buf[LONG_STRING];
1109  char obuf[LONG_STRING];
1110  char tmp[STRING];
1111  char charset[STRING];
1112 
1113  short charset_changed = 0;
1114  short type_changed = 0;
1115  short structure_changed = 0;
1116 
1117  char *cp = mutt_param_get(&b->parameter, "charset");
1118  mutt_str_strfcpy(charset, cp, sizeof(charset));
1119 
1120  snprintf(buf, sizeof(buf), "%s/%s", TYPE(b), b->subtype);
1121  mutt_str_strfcpy(obuf, buf, sizeof(obuf));
1122  if (!TAILQ_EMPTY(&b->parameter))
1123  {
1124  size_t l = strlen(buf);
1125  struct Parameter *np = NULL;
1126  TAILQ_FOREACH(np, &b->parameter, entries)
1127  {
1128  mutt_addr_cat(tmp, sizeof(tmp), np->value, MimeSpecials);
1129  l += snprintf(buf + l, sizeof(buf) - l, "; %s=%s", np->attribute, tmp);
1130  }
1131  }
1132 
1133  if (mutt_get_field("Content-Type: ", buf, sizeof(buf), 0) != 0 || buf[0] == 0)
1134  return 0;
1135 
1136  /* clean up previous junk */
1138  FREE(&b->subtype);
1139 
1140  mutt_parse_content_type(buf, b);
1141 
1142  snprintf(tmp, sizeof(tmp), "%s/%s", TYPE(b), NONULL(b->subtype));
1143  type_changed = mutt_str_strcasecmp(tmp, obuf);
1144  charset_changed =
1145  mutt_str_strcasecmp(charset, mutt_param_get(&b->parameter, "charset"));
1146 
1147  /* if in send mode, check for conversion - current setting is default. */
1148 
1149  if (!e && b->type == TYPE_TEXT && charset_changed)
1150  {
1151  int r;
1152  snprintf(tmp, sizeof(tmp), _("Convert to %s upon sending?"),
1153  mutt_param_get(&b->parameter, "charset"));
1154  r = mutt_yesorno(tmp, !b->noconv);
1155  if (r != MUTT_ABORT)
1156  b->noconv = (r == MUTT_NO);
1157  }
1158 
1159  /* inform the user */
1160 
1161  snprintf(tmp, sizeof(tmp), "%s/%s", TYPE(b), NONULL(b->subtype));
1162  if (type_changed)
1163  mutt_message(_("Content-Type changed to %s"), tmp);
1164  if (b->type == TYPE_TEXT && charset_changed)
1165  {
1166  if (type_changed)
1167  mutt_sleep(1);
1168  mutt_message(b->noconv ? _("Character set changed to %s; not converting") :
1169  _("Character set changed to %s; converting"),
1170  mutt_param_get(&b->parameter, "charset"));
1171  }
1172 
1173  b->force_charset |= charset_changed ? 1 : 0;
1174 
1175  if (!is_multipart(b) && b->parts)
1176  {
1177  structure_changed = 1;
1178  mutt_body_free(&b->parts);
1179  }
1180  if (!mutt_is_message_type(b->type, b->subtype) && b->email)
1181  {
1182  structure_changed = 1;
1183  b->email->content = NULL;
1184  mutt_email_free(&b->email);
1185  }
1186 
1187  if (fp && !b->parts && (is_multipart(b) || mutt_is_message_type(b->type, b->subtype)))
1188  {
1189  structure_changed = 1;
1190  mutt_parse_part(fp, b);
1191  }
1192 
1193  if ((WithCrypto != 0) && e)
1194  {
1195  if (e->content == b)
1196  e->security = 0;
1197 
1198  e->security |= crypt_query(b);
1199  }
1200 
1201  return structure_changed;
1202 }
char * attribute
Definition: parameter.h:39
#define NONULL(x)
Definition: string2.h:39
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1214
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
User aborted the question (with Ctrl-G)
Definition: quad.h:37
#define mutt_message(...)
Definition: logging.h:87
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
int mutt_yesorno(const char *msg, int def)
Ask the user a Yes/No question.
Definition: curs_lib.c:330
struct Body * content
list of MIME parts
Definition: email.h:92
bool noconv
don&#39;t do character set conversion
Definition: body.h:77
#define _(a)
Definition: message.h:28
#define LONG_STRING
Definition: string2.h:36
void mutt_parse_content_type(char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:393
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1478
bool force_charset
send mode: don&#39;t adjust the character set when in send-mode.
Definition: body.h:78
char * subtype
content-type subtype
Definition: body.h:36
void mutt_param_free(struct ParameterList *p)
Free a ParameterList.
Definition: parameter.c:59
void mutt_addr_cat(char *buf, size_t buflen, const char *value, const char *specials)
Copy a string and escape the specified characters.
Definition: address.c:681
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
Type: &#39;text/*&#39;.
Definition: mime.h:38
const char MimeSpecials[]
Characters that need special treatment in MIME.
Definition: mime.c:67
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:58
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
#define TYPE(X)
Definition: mime.h:82
#define mutt_get_field(A, B, C, D)
Definition: curs_lib.h:78
void mutt_email_free(struct Email **e)
Free an Email.
Definition: email.c:41
unsigned int type
content-type primary type
Definition: body.h:67
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1229
char * mutt_param_get(const struct ParameterList *p, const char *s)
Find a matching Parameter.
Definition: parameter.c:81
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:56
char * value
Definition: parameter.h:40
int crypt_query(struct Body *m)
Check out the type of encryption used.
Definition: crypt.c:647
#define STRING
Definition: string2.h:35
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:625
Attribute associated with a MIME part.
Definition: parameter.h:37
#define FREE(x)
Definition: memory.h:46
#define TAILQ_EMPTY(head)
Definition: queue.h:715
struct ParameterList parameter
parameters of the content-type
Definition: body.h:38
struct Email * email
header information for message/rfc822
Definition: body.h:59
#define WithCrypto
Definition: ncrypt.h:154
#define is_multipart(x)
Definition: mime.h:77

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool check_traditional_pgp ( struct Email e,
int *  redraw 
)
static

Check for an inline PGP content.

Parameters
[in]eHeader of message to check
[out]redrawSet of REDRAW_FULL if the screen may need redrawing
Return values
trueIf message contains inline PGP content

Definition at line 1210 of file commands.c.

1211 {
1212  bool rc = false;
1213 
1215 
1217  struct Message *msg = mx_msg_open(Context->mailbox, e->msgno);
1218  if (!msg)
1219  return 0;
1220  if (crypt_pgp_check_traditional(msg->fp, e->content, false))
1221  {
1222  e->security = crypt_query(e->content);
1223  *redraw |= REDRAW_FULL;
1224  rc = true;
1225  }
1226 
1228  mx_msg_close(Context->mailbox, &msg);
1229  return rc;
1230 }
The "current" mailbox.
Definition: context.h:36
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
struct Body * content
list of MIME parts
Definition: email.h:92
#define PGP_TRADITIONAL_CHECKED
Definition: ncrypt.h:132
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1187
struct Mailbox * mailbox
Definition: context.h:50
void mutt_parse_mime_message(struct Mailbox *m, struct Email *cur)
Parse a MIME email.
Definition: mutt_parse.c:50
A local copy of an email.
Definition: mx.h:81
int crypt_pgp_check_traditional(FILE *fp, struct Body *b, bool just_one)
Wrapper for CryptModuleSpecs::pgp_check_traditional()
Definition: cryptglue.c:238
int crypt_query(struct Body *m)
Check out the type of encryption used.
Definition: crypt.c:647
FILE * fp
pointer to the message data
Definition: mx.h:83
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1139
int msgno
number displayed to the user
Definition: email.h:88

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool mutt_check_traditional_pgp ( struct Email e,
int *  redraw 
)

Check if a message has inline PGP content.

Parameters
[in]eHeader of message to check
[out]redrawSet of REDRAW_FULL if the screen may need redrawing
Return values
trueIf message contains inline PGP content

Definition at line 1238 of file commands.c.

1239 {
1240  bool rc = false;
1241  if (e && !(e->security & PGP_TRADITIONAL_CHECKED))
1242  rc = check_traditional_pgp(e, redraw);
1243  else
1244  {
1245  for (int i = 0; i < Context->mailbox->msg_count; i++)
1246  {
1247  if (message_is_tagged(Context, i) &&
1249  {
1250  rc = check_traditional_pgp(Context->mailbox->hdrs[i], redraw) || rc;
1251  }
1252  }
1253  }
1254  return rc;
1255 }
The "current" mailbox.
Definition: context.h:36
int msg_count
total number of messages
Definition: mailbox.h:86
unsigned int security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:37
#define PGP_TRADITIONAL_CHECKED
Definition: ncrypt.h:132
struct Email ** hdrs
Definition: mailbox.h:93
struct Mailbox * mailbox
Definition: context.h:50
bool message_is_tagged(struct Context *ctx, int index)
Is a message in the index tagged (and within limit)
Definition: curs_lib.c:1236
static bool check_traditional_pgp(struct Email *e, int *redraw)
Check for an inline PGP content.
Definition: commands.c:1210

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void mutt_check_stats ( void  )

Forcibly update mailbox stats.

Definition at line 1260 of file commands.c.

1261 {
1263 }
#define MUTT_MAILBOX_CHECK_FORCE_STATS
Definition: mailbox.h:161
int mutt_mailbox_check(int force)
Check all AllMailboxes for new mail.
Definition: mailbox.c:538
#define MUTT_MAILBOX_CHECK_FORCE
Definition: mailbox.h:160

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

unsigned char CryptVerifySig

Config: Verify PGP or SMIME signatures.

Definition at line 78 of file commands.c.

char* DisplayFilter

Config: External command to pre-process an email before display.

Definition at line 79 of file commands.c.

bool PipeDecode

Config: Decode the message when piping it.

Definition at line 80 of file commands.c.

char* PipeSep

Config: Separator to add between multiple piped messages.

Definition at line 81 of file commands.c.

bool PipeSplit

Config: Run the pipe command on each message separately.

Definition at line 82 of file commands.c.

bool PrintDecode

Config: Decode message before printing it.

Definition at line 83 of file commands.c.

bool PrintSplit

Config: Print multiple messages separately.

Definition at line 84 of file commands.c.

bool PromptAfter

Config: Pause after running an external pager.

Definition at line 85 of file commands.c.

const char* ExtPagerProgress = "all"
static

Definition at line 87 of file commands.c.

char LastSaveFolder[PATH_MAX] = ""
static

The folder the user last saved to.

Used by ci_save_message()

Definition at line 90 of file commands.c.