NeoMutt  2019-12-07-60-g0cfa53
Teaching an old dog new tricks
DOXYGEN
mutt_attach.c File Reference

Handling of email attachments. More...

#include "config.h"
#include <errno.h>
#include <fcntl.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 "core/lib.h"
#include "gui/lib.h"
#include "mutt_attach.h"
#include "context.h"
#include "copy.h"
#include "filter.h"
#include "globals.h"
#include "handler.h"
#include "mailcap.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "pager.h"
#include "protos.h"
#include "sendlib.h"
#include "state.h"
+ Include dependency graph for mutt_attach.c:

Go to the source code of this file.

Functions

int mutt_get_tmp_attachment (struct Body *a)
 Get a temporary copy of an attachment. More...
 
int mutt_compose_attachment (struct Body *a)
 Create an attachment. More...
 
int mutt_edit_attachment (struct Body *a)
 Edit an attachment. More...
 
void mutt_check_lookup_list (struct Body *b, char *type, size_t len)
 Update the mime type. More...
 
int mutt_view_attachment (FILE *fp, struct Body *a, enum ViewAttachMode mode, struct Email *e, struct AttachCtx *actx, struct MuttWindow *win)
 View an attachment. More...
 
int mutt_pipe_attachment (FILE *fp, struct Body *b, const char *path, char *outfile)
 Pipe an attachment to a command. More...
 
static FILE * save_attachment_open (const char *path, enum SaveAttach opt)
 Open a file to write an attachment to. More...
 
int mutt_save_attachment (FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
 Save an attachment. More...
 
int mutt_decode_save_attachment (FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
 Decode, then save an attachment. More...
 
int mutt_print_attachment (FILE *fp, struct Body *a)
 Print out an attachment. More...
 
void mutt_add_temp_attachment (const char *filename)
 Add file to list of temporary attachments. More...
 
void mutt_unlink_temp_attachments (void)
 Delete all temporary attachments. More...
 

Detailed Description

Handling of email attachments.

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

Function Documentation

◆ mutt_get_tmp_attachment()

int mutt_get_tmp_attachment ( struct Body a)

Get a temporary copy of an attachment.

Parameters
aAttachment to copy
Return values
0Success
-1Error

Definition at line 65 of file mutt_attach.c.

66 {
67  char type[256];
68  struct stat st;
69 
70  if (a->unlink)
71  return 0;
72 
73  struct Buffer *tmpfile = mutt_buffer_pool_get();
74  struct MailcapEntry *entry = mailcap_entry_new();
75  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
76  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS);
77  mailcap_expand_filename(entry->nametemplate, a->filename, tmpfile);
78 
79  mailcap_entry_free(&entry);
80 
81  if (stat(a->filename, &st) == -1)
82  {
83  mutt_buffer_pool_release(&tmpfile);
84  return -1;
85  }
86 
87  FILE *fp_in = NULL, *fp_out = NULL;
88  if ((fp_in = fopen(a->filename, "r")) &&
89  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
90  {
91  mutt_file_copy_stream(fp_in, fp_out);
92  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
93  a->unlink = true;
94 
95  if (a->stamp >= st.st_mtime)
97  }
98  else
99  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
100 
101  mutt_file_fclose(&fp_in);
102  mutt_file_fclose(&fp_out);
103 
104  mutt_buffer_pool_release(&tmpfile);
105 
106  return a->unlink ? 0 : -1;
107 }
A mailcap entry.
Definition: mailcap.h:38
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:428
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:1448
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
No flags set.
Definition: mailcap.h:58
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:466
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:521
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:437
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
char * nametemplate
Definition: mailcap.h:46
#define TYPE(body)
Definition: mime.h:83
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_compose_attachment()

int mutt_compose_attachment ( struct Body a)

Create an attachment.

Parameters
aBody of email
Return values
1if require full screen redraw
0otherwise

Definition at line 115 of file mutt_attach.c.

116 {
117  char type[256];
118  struct MailcapEntry *entry = mailcap_entry_new();
119  bool unlink_newfile = false;
120  int rc = 0;
121  struct Buffer *cmd = mutt_buffer_pool_get();
122  struct Buffer *newfile = mutt_buffer_pool_get();
123  struct Buffer *tmpfile = mutt_buffer_pool_get();
124 
125  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
126  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_COMPOSE))
127  {
128  if (entry->composecommand || entry->composetypecommand)
129  {
130  if (entry->composetypecommand)
132  else
133  mutt_buffer_strcpy(cmd, entry->composecommand);
134 
135  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
136  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
137  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
138  {
139  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
140  goto bailout;
141  mutt_buffer_strcpy(newfile, a->filename);
142  }
143  else
144  unlink_newfile = true;
145 
146  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
147  {
148  /* For now, editing requires a file, no piping */
149  mutt_error(_("Mailcap compose entry requires %%s"));
150  }
151  else
152  {
153  int r;
154 
155  mutt_endwin();
156  r = mutt_system(mutt_b2s(cmd));
157  if (r == -1)
158  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
159 
160  if ((r != -1) && entry->composetypecommand)
161  {
162  struct Body *b = NULL;
163 
164  FILE *fp = mutt_file_fopen(a->filename, "r");
165  if (!fp)
166  {
167  mutt_perror(_("Failure to open file to parse headers"));
168  goto bailout;
169  }
170 
171  b = mutt_read_mime_header(fp, 0);
172  if (b)
173  {
174  if (!TAILQ_EMPTY(&b->parameter))
175  {
177  a->parameter = b->parameter;
178  TAILQ_INIT(&b->parameter);
179  }
180  if (b->description)
181  {
182  FREE(&a->description);
183  a->description = b->description;
184  b->description = NULL;
185  }
186  if (b->form_name)
187  {
188  FREE(&a->form_name);
189  a->form_name = b->form_name;
190  b->form_name = NULL;
191  }
192 
193  /* Remove headers by copying out data to another file, then
194  * copying the file back */
195  fseeko(fp, b->offset, SEEK_SET);
196  mutt_body_free(&b);
197  mutt_buffer_mktemp(tmpfile);
198  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpfile), "w");
199  if (!fp_tmp)
200  {
201  mutt_perror(_("Failure to open file to strip headers"));
202  mutt_file_fclose(&fp);
203  goto bailout;
204  }
205  mutt_file_copy_stream(fp, fp_tmp);
206  mutt_file_fclose(&fp);
207  mutt_file_fclose(&fp_tmp);
209  if (mutt_file_rename(mutt_b2s(tmpfile), a->filename) != 0)
210  {
211  mutt_perror(_("Failure to rename file"));
212  goto bailout;
213  }
214  }
215  }
216  }
217  }
218  }
219  else
220  {
221  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
222  rc = 1;
223  goto bailout;
224  }
225 
226  rc = 1;
227 
228 bailout:
229 
230  if (unlink_newfile)
231  unlink(mutt_b2s(newfile));
232 
234  mutt_buffer_pool_release(&newfile);
235  mutt_buffer_pool_release(&tmpfile);
236 
237  mailcap_entry_free(&entry);
238  return rc;
239 }
A mailcap entry.
Definition: mailcap.h:38
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:428
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:78
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
#define mutt_message(...)
Definition: logging.h:83
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1338
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
char * composetypecommand
Definition: mailcap.h:43
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
String manipulation buffer.
Definition: buffer.h:33
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define _(a)
Definition: message.h:28
char * form_name
Content-Disposition form-data name param.
Definition: body.h:41
The body of an email.
Definition: body.h:34
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:466
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:69
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:521
Mailcap compose field.
Definition: mailcap.h:60
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:376
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
#define TAILQ_INIT(head)
Definition: queue.h:758
void mutt_param_free(struct ParameterList *pl)
Free a ParameterList.
Definition: parameter.c:61
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:545
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:437
char * description
content-description
Definition: body.h:40
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * nametemplate
Definition: mailcap.h:46
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:40
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
#define mutt_error(...)
Definition: logging.h:84
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
char * composecommand
Definition: mailcap.h:42
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
#define TAILQ_EMPTY(head)
Definition: queue.h:714
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:296
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:52
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1292
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_edit_attachment()

int mutt_edit_attachment ( struct Body a)

Edit an attachment.

Parameters
aEmail containing attachment
Return values
1if editor found
0if not

Currently, this only works for send mode, as it assumes that the Body->filename actually contains the information. I'm not sure we want to deal with editing attachments we've already received, so this should be ok.

Returning 0 is useful to tell the calling menu to redraw

Definition at line 254 of file mutt_attach.c.

255 {
256  char type[256];
257  struct MailcapEntry *entry = mailcap_entry_new();
258  bool unlink_newfile = false;
259  int rc = 0;
260  struct Buffer *cmd = mutt_buffer_pool_get();
261  struct Buffer *newfile = mutt_buffer_pool_get();
262 
263  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
264  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_EDIT))
265  {
266  if (entry->editcommand)
267  {
268  mutt_buffer_strcpy(cmd, entry->editcommand);
269  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
270  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
271  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
272  {
273  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
274  goto bailout;
275  mutt_buffer_strcpy(newfile, a->filename);
276  }
277  else
278  unlink_newfile = true;
279 
280  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
281  {
282  /* For now, editing requires a file, no piping */
283  mutt_error(_("Mailcap Edit entry requires %%s"));
284  goto bailout;
285  }
286  else
287  {
288  mutt_endwin();
289  if (mutt_system(mutt_b2s(cmd)) == -1)
290  {
291  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
292  goto bailout;
293  }
294  }
295  }
296  }
297  else if (a->type == TYPE_TEXT)
298  {
299  /* On text, default to editor */
301  }
302  else
303  {
304  mutt_error(_("No mailcap edit entry for %s"), type);
305  rc = 0;
306  goto bailout;
307  }
308 
309  rc = 1;
310 
311 bailout:
312 
313  if (unlink_newfile)
314  unlink(mutt_b2s(newfile));
315 
317  mutt_buffer_pool_release(&newfile);
318 
319  mailcap_entry_free(&entry);
320  return rc;
321 }
A mailcap entry.
Definition: mailcap.h:38
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:428
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:466
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:69
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:521
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:376
char * editcommand
Definition: mailcap.h:44
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:545
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:437
Type: &#39;text/*&#39;.
Definition: mime.h:38
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
unsigned int type
content-type primary type
Definition: body.h:65
char * nametemplate
Definition: mailcap.h:46
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:40
#define mutt_error(...)
Definition: logging.h:84
WHERE char * C_Editor
Config: External command to use as an email editor.
Definition: globals.h:109
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Mailcap edit field.
Definition: mailcap.h:59
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:296
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:352
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_check_lookup_list()

void mutt_check_lookup_list ( struct Body b,
char *  type,
size_t  len 
)

Update the mime type.

Parameters
bMessage attachment body
typeBuffer with mime type of attachment in "type/subtype" format
lenBuffer length

Definition at line 329 of file mutt_attach.c.

330 {
331  struct ListNode *np = NULL;
332  STAILQ_FOREACH(np, &MimeLookupList, entries)
333  {
334  const int i = mutt_str_strlen(np->data) - 1;
335  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
336  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
337  (mutt_str_strcasecmp(type, np->data) == 0))
338  {
339  struct Body tmp = { 0 };
340  enum ContentType n;
341  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
342  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
343  {
344  snprintf(type, len, "%s/%s",
345  (n == TYPE_AUDIO) ?
346  "audio" :
347  (n == TYPE_APPLICATION) ?
348  "application" :
349  (n == TYPE_IMAGE) ?
350  "image" :
351  (n == TYPE_MESSAGE) ?
352  "message" :
353  (n == TYPE_MODEL) ?
354  "model" :
355  (n == TYPE_MULTIPART) ?
356  "multipart" :
357  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
358  tmp.subtype);
359  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
360  }
361  FREE(&tmp.subtype);
362  FREE(&tmp.xtype);
363  }
364  }
365 }
Unknown Content-Type.
Definition: mime.h:31
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
Type: &#39;audio/*&#39;.
Definition: mime.h:32
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
The body of an email.
Definition: body.h:34
Type: &#39;video/*&#39;.
Definition: mime.h:39
char * subtype
content-type subtype
Definition: body.h:37
int mutt_str_strncasecmp(const char *a, const char *b, size_t l)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:656
Type: &#39;text/*&#39;.
Definition: mime.h:38
char * xtype
content-type if x-unknown
Definition: body.h:36
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * description
content-description
Definition: body.h:40
unsigned int type
content-type primary type
Definition: body.h:65
Type: &#39;message/*&#39;.
Definition: mime.h:35
char * data
String.
Definition: list.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:40
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:1121
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
Type: &#39;model/*&#39;.
Definition: mime.h:36
#define FREE(x)
Definition: memory.h:40
Type: &#39;image/*&#39;.
Definition: mime.h:34
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
A List node for strings.
Definition: list.h:33
Type: &#39;application/*&#39;.
Definition: mime.h:33
ContentType
Content-Type.
Definition: mime.h:29
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_view_attachment()

int mutt_view_attachment ( FILE *  fp,
struct Body a,
enum ViewAttachMode  mode,
struct Email e,
struct AttachCtx actx,
struct MuttWindow win 
)

View an attachment.

Parameters
fpSource file stream. Can be NULL
aThe message body containing the attachment
modeHow the attachment should be viewed, see ViewAttachMode
eCurrent Email. Can be NULL
actxAttachment context
winWindow
Return values
0If the viewer is run and exited successfully
-1Error
numReturn value of mutt_do_pager() when it is used

Display a message attachment using the viewer program configured in mailcap. If there is no mailcap entry for a file type, view the image as text. Viewer processes are opened and waited on synchronously so viewing an attachment this way will block the main neomutt process until the viewer process exits.

Definition at line 385 of file mutt_attach.c.

387 {
388  bool use_mailcap = false;
389  bool use_pipe = false;
390  bool use_pager = true;
391  char type[256];
392  char desc[256];
393  char *fname = NULL;
394  struct MailcapEntry *entry = NULL;
395  int rc = -1;
396  bool unlink_tempfile = false;
397 
398  bool is_message = mutt_is_message_type(a->type, a->subtype);
399  if ((WithCrypto != 0) && is_message && a->email &&
401  {
402  return rc;
403  }
404 
405  struct Buffer *tmpfile = mutt_buffer_pool_get();
406  struct Buffer *pagerfile = mutt_buffer_pool_get();
407  struct Buffer *cmd = mutt_buffer_pool_get();
408 
409  use_mailcap =
410  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
411  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
412 
413  char columns[16];
414  snprintf(columns, sizeof(columns), "%d", win->state.cols);
415  mutt_envlist_set("COLUMNS", columns, true);
416 
417  if (use_mailcap)
418  {
419  entry = mailcap_entry_new();
420  if (!mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS))
421  {
422  if (mode == MUTT_VA_REGULAR)
423  {
424  /* fallback to view as text */
425  mailcap_entry_free(&entry);
426  mutt_error(_("No matching mailcap entry found. Viewing as text."));
427  mode = MUTT_VA_AS_TEXT;
428  use_mailcap = false;
429  }
430  else
431  goto return_error;
432  }
433  }
434 
435  if (use_mailcap)
436  {
437  if (!entry->command)
438  {
439  mutt_error(_("MIME type not defined. Can't view attachment."));
440  goto return_error;
441  }
442  mutt_buffer_strcpy(cmd, entry->command);
443 
444  if (fp)
445  {
446  fname = mutt_str_strdup(a->filename);
447  mutt_file_sanitize_filename(fname, true);
448  }
449  else
450  fname = a->filename;
451 
452  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
453  /* send case: the file is already there; symlink to it */
454  if (!fp)
455  {
456  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
457  {
458  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
459  goto return_error;
460  mutt_buffer_strcpy(tmpfile, a->filename);
461  }
462  else
463  unlink_tempfile = true;
464  }
465  /* recv case: we need to save the attachment to a file */
466  else
467  {
468  FREE(&fname);
469  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
470  goto return_error;
471  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
472  }
473 
474  use_pipe = mailcap_expand_command(a, mutt_b2s(tmpfile), type, cmd);
475  use_pager = entry->copiousoutput;
476  }
477 
478  if (use_pager)
479  {
480  if (fp && !use_mailcap && a->filename)
481  {
482  /* recv case */
483  mutt_buffer_strcpy(pagerfile, a->filename);
484  mutt_adv_mktemp(pagerfile);
485  }
486  else
487  mutt_buffer_mktemp(pagerfile);
488  }
489 
490  if (use_mailcap)
491  {
492  pid_t pid = 0;
493  int fd_temp = -1, fd_pager = -1;
494 
495  if (!use_pager)
496  mutt_endwin();
497 
498  if (use_pager || use_pipe)
499  {
500  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
501  O_CREAT | O_EXCL | O_WRONLY)) == -1))
502  {
503  mutt_perror("open");
504  goto return_error;
505  }
506  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
507  {
508  if (fd_pager != -1)
509  close(fd_pager);
510  mutt_perror("open");
511  goto return_error;
512  }
513 
514  pid = mutt_create_filter_fd(mutt_b2s(cmd), NULL, NULL, NULL,
515  use_pipe ? fd_temp : -1,
516  use_pager ? fd_pager : -1, -1);
517 
518  if (pid == -1)
519  {
520  if (fd_pager != -1)
521  close(fd_pager);
522 
523  if (fd_temp != -1)
524  close(fd_temp);
525 
526  mutt_error(_("Can't create filter"));
527  goto return_error;
528  }
529 
530  if (use_pager)
531  {
532  if (a->description)
533  {
534  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
535  mutt_b2s(cmd), a->description);
536  }
537  else
538  {
539  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
540  mutt_b2s(cmd), type);
541  }
542  }
543 
544  if ((mutt_wait_filter(pid) || (entry->needsterminal && C_WaitKey)) && !use_pager)
546 
547  if (fd_temp != -1)
548  close(fd_temp);
549  if (fd_pager != -1)
550  close(fd_pager);
551  }
552  else
553  {
554  /* interactive cmd */
555  int rv = mutt_system(mutt_b2s(cmd));
556  if (rv == -1)
557  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
558 
559  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
561  }
562  }
563  else
564  {
565  /* Don't use mailcap; the attachment is viewed in the pager */
566 
567  if (mode == MUTT_VA_AS_TEXT)
568  {
569  /* just let me see the raw data */
570  if (fp)
571  {
572  /* Viewing from a received message.
573  *
574  * Don't use mutt_save_attachment() because we want to perform charset
575  * conversion since this will be displayed by the internal pager. */
576  struct State decode_state = { 0 };
577 
578  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
579  if (!decode_state.fp_out)
580  {
581  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
582  mutt_b2s(pagerfile), errno, strerror(errno));
583  mutt_perror(mutt_b2s(pagerfile));
584  goto return_error;
585  }
586  decode_state.fp_in = fp;
587  decode_state.flags = MUTT_CHARCONV;
588  mutt_decode_attachment(a, &decode_state);
589  if (mutt_file_fclose(&decode_state.fp_out) == EOF)
590  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
591  errno, strerror(errno));
592  }
593  else
594  {
595  /* in compose mode, just copy the file. we can't use
596  * mutt_decode_attachment() since it assumes the content-encoding has
597  * already been applied */
598  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
599  goto return_error;
600  }
601  }
602  else
603  {
604  /* Use built-in handler */
605  OptViewAttach = true; /* disable the "use 'v' to view this part"
606  * message in case of error */
608  {
609  OptViewAttach = false;
610  goto return_error;
611  }
612  OptViewAttach = false;
613  }
614 
615  if (a->description)
616  mutt_str_strfcpy(desc, a->description, sizeof(desc));
617  else if (a->filename)
618  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
619  else
620  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
621  }
622 
623  /* We only reach this point if there have been no errors */
624 
625  if (use_pager)
626  {
627  struct Pager info = { 0 };
628  info.fp = fp;
629  info.body = a;
630  info.ctx = Context;
631  info.actx = actx;
632  info.email = e;
633 
634  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
636  &info);
637  mutt_buffer_reset(pagerfile);
638  }
639  else
640  rc = 0;
641 
642 return_error:
643 
644  if (!entry || !entry->xneomuttkeep)
645  {
646  if (fp && !mutt_buffer_is_empty(tmpfile))
647  {
648  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
650  }
651  else if (unlink_tempfile)
652  {
653  unlink(mutt_b2s(tmpfile));
654  }
655  }
656 
657  mailcap_entry_free(&entry);
658 
659  if (!mutt_buffer_is_empty(pagerfile))
660  mutt_file_unlink(mutt_b2s(pagerfile));
661 
662  mutt_buffer_pool_release(&tmpfile);
663  mutt_buffer_pool_release(&pagerfile);
665  mutt_envlist_unset("COLUMNS");
666 
667  return rc;
668 }
bool xneomuttkeep
do not remove the file on command exit
Definition: mailcap.h:50
A mailcap entry.
Definition: mailcap.h:38
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1795
FILE * fp
Source stream.
Definition: pager.h:70
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:428
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:78
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1391
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define MUTT_PAGER_MESSAGE
Definition: pager.h:58
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
No flags set.
Definition: mutt_attach.h:55
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
struct Body * body
Current attachment.
Definition: pager.h:69
Force viewing as text.
Definition: mutt_attach.h:44
No flags set.
Definition: mailcap.h:58
int mutt_save_attachment(FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:796
An email being displayed.
Definition: pager.h:65
View using default method.
Definition: mutt_attach.h:42
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:122
FILE * fp_in
File to read from.
Definition: state.h:46
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: pager.h:55
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:466
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:69
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:521
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:145
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:376
bool copiousoutput
needs pager, basically
Definition: mailcap.h:49
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
int mutt_file_chmod(const char *path, mode_t mode)
Set permissions of a file.
Definition: file.c:1033
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1188
char * command
Definition: mailcap.h:40
char * subtype
content-type subtype
Definition: body.h:37
void mutt_file_sanitize_filename(char *path, bool slash)
Replace unsafe characters in a filename.
Definition: file.c:615
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:56
#define mutt_b2s(buf)
Definition: buffer.h:41
struct Context * ctx
Current mailbox.
Definition: pager.h:67
WHERE struct Context * Context
Definition: globals.h:42
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:91
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:260
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:545
bool mutt_envlist_unset(const char *name)
Unset an environment variable.
Definition: envlist.c:132
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:437
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:927
struct AttachCtx * actx
Attachment information.
Definition: pager.h:71
char * data
Pointer to data.
Definition: buffer.h:35
pid_t mutt_create_filter_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:64
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:750
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/ncrypt.h pgplib.h, smime.h
Definition: email.h:39
Force viewing using mailcap entry.
Definition: mutt_attach.h:43
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
unsigned int type
content-type primary type
Definition: body.h:65
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:578
char * nametemplate
Definition: mailcap.h:46
#define TYPE(body)
Definition: mime.h:83
struct Email * email
Current message.
Definition: pager.h:68
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:519
Log at debug level 1.
Definition: logging.h:40
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:664
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:84
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:424
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:95
#define FREE(x)
Definition: memory.h:40
Keep track when processing files.
Definition: state.h:44
WHERE bool OptViewAttach
(pseudo) signals that we are viewing attachments
Definition: options.h:53
bool mutt_envlist_set(const char *name, const char *value, bool overwrite)
Set an environment variable.
Definition: envlist.c:85
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:296
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define WithCrypto
Definition: ncrypt.h:160
bool needsterminal
endwin() and system
Definition: mailcap.h:48
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:52
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: pager.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_pipe_attachment()

int mutt_pipe_attachment ( FILE *  fp,
struct Body b,
const char *  path,
char *  outfile 
)

Pipe an attachment to a command.

Parameters
fpFile to pipe into the command
bAttachment
pathPath to command
outfileFile to save output to
Return values
1Success
0Error

Definition at line 679 of file mutt_attach.c.

680 {
681  pid_t pid;
682  int out = -1;
683  int rc = 0;
684 
685  if (outfile && *outfile)
686  {
687  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
688  if (out < 0)
689  {
690  mutt_perror("open");
691  return 0;
692  }
693  }
694 
695  mutt_endwin();
696 
697  if (fp)
698  {
699  /* recv case */
700 
701  struct State s = { 0 };
702 
703  /* perform charset conversion on text attachments when piping */
704  s.flags = MUTT_CHARCONV;
705 
706  if (outfile && *outfile)
707  pid = mutt_create_filter_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
708  else
709  pid = mutt_create_filter(path, &s.fp_out, NULL, NULL);
710 
711  if (pid < 0)
712  {
713  mutt_perror(_("Can't create filter"));
714  goto bail;
715  }
716 
717  s.fp_in = fp;
718  mutt_decode_attachment(b, &s);
720  }
721  else
722  {
723  /* send case */
724  FILE *fp_in = fopen(b->filename, "r");
725  if (!fp_in)
726  {
727  mutt_perror("fopen");
728  if (outfile && *outfile)
729  {
730  close(out);
731  unlink(outfile);
732  }
733  return 0;
734  }
735 
736  FILE *fp_out = NULL;
737  if (outfile && *outfile)
738  pid = mutt_create_filter_fd(path, &fp_out, NULL, NULL, -1, out, -1);
739  else
740  pid = mutt_create_filter(path, &fp_out, NULL, NULL);
741 
742  if (pid < 0)
743  {
744  mutt_perror(_("Can't create filter"));
745  mutt_file_fclose(&fp_in);
746  goto bail;
747  }
748 
749  mutt_file_copy_stream(fp_in, fp_out);
750  mutt_file_fclose(&fp_out);
751  mutt_file_fclose(&fp_in);
752  }
753 
754  rc = 1;
755 
756 bail:
757 
758  if (outfile && *outfile)
759  close(out);
760 
761  /* check for error exit from child process */
762  if (mutt_wait_filter(pid) != 0)
763  rc = 0;
764 
765  if ((rc == 0) || C_WaitKey)
767  return rc;
768 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:209
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1795
FILE * fp
Source stream.
Definition: pager.h:70
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
FILE * fp_in
File to read from.
Definition: state.h:46
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:260
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:545
pid_t mutt_create_filter_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:64
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:578
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:519
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
Keep track when processing files.
Definition: state.h:44
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ save_attachment_open()

static FILE* save_attachment_open ( const char *  path,
enum SaveAttach  opt 
)
static

Open a file to write an attachment to.

Parameters
pathPath to file to open
optSave option, see SaveAttach
Return values
ptrFile handle to attachment file

Definition at line 776 of file mutt_attach.c.

777 {
778  if (opt == MUTT_SAVE_APPEND)
779  return fopen(path, "a");
780  if (opt == MUTT_SAVE_OVERWRITE)
781  return fopen(path, "w");
782 
783  return mutt_file_fopen(path, "w");
784 }
Overwrite existing file.
Definition: mutt_attach.h:57
Append to existing file.
Definition: mutt_attach.h:56
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_save_attachment()

int mutt_save_attachment ( FILE *  fp,
struct Body m,
const char *  path,
enum SaveAttach  opt,
struct Email e 
)

Save an attachment.

Parameters
fpSource file stream. Can be NULL
mEmail Body
pathWhere to save the attachment
optSave option, see SaveAttach
eCurrent Email. Can be NULL
Return values
0Success
-1Error

Definition at line 796 of file mutt_attach.c.

798 {
799  if (!m)
800  return -1;
801 
802  if (fp)
803  {
804  /* recv mode */
805 
806  if (e && m->email && (m->encoding != ENC_BASE64) &&
808  {
809  /* message type attachments are written to mail folders. */
810 
811  char buf[8192];
812  struct Message *msg = NULL;
813  CopyHeaderFlags chflags = CH_NO_FLAGS;
814  int rc = -1;
815 
816  struct Email *e_new = m->email;
817  e_new->msgno = e->msgno; /* required for MH/maildir */
818  e_new->read = true;
819 
820  if (fseeko(fp, m->offset, SEEK_SET) < 0)
821  return -1;
822  if (!fgets(buf, sizeof(buf), fp))
823  return -1;
824  struct Mailbox *m_att = mx_path_resolve(path);
825  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
826  if (!ctx)
827  {
828  mailbox_free(&m_att);
829  return -1;
830  }
831  msg = mx_msg_open_new(ctx->mailbox, e_new,
832  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
833  if (!msg)
834  {
835  mx_mbox_close(&ctx);
836  return -1;
837  }
838  if ((ctx->mailbox->magic == MUTT_MBOX) || (ctx->mailbox->magic == MUTT_MMDF))
839  chflags = CH_FROM | CH_UPDATE_LEN;
840  chflags |= ((ctx->mailbox->magic == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
841  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
842  (mx_msg_commit(ctx->mailbox, msg) == 0))
843  {
844  rc = 0;
845  }
846  else
847  {
848  rc = -1;
849  }
850 
851  mx_msg_close(ctx->mailbox, &msg);
852  mx_mbox_close(&ctx);
853  return rc;
854  }
855  else
856  {
857  /* In recv mode, extract from folder and decode */
858 
859  struct State s = { 0 };
860 
861  s.fp_out = save_attachment_open(path, opt);
862  if (!s.fp_out)
863  {
864  mutt_perror("fopen");
865  return -1;
866  }
867  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
868  mutt_decode_attachment(m, &s);
869 
870  if (mutt_file_fsync_close(&s.fp_out) != 0)
871  {
872  mutt_perror("fclose");
873  return -1;
874  }
875  }
876  }
877  else
878  {
879  if (!m->filename)
880  return -1;
881 
882  /* In send mode, just copy file */
883 
884  FILE *fp_old = fopen(m->filename, "r");
885  if (!fp_old)
886  {
887  mutt_perror("fopen");
888  return -1;
889  }
890 
891  FILE *fp_new = save_attachment_open(path, opt);
892  if (!fp_new)
893  {
894  mutt_perror("fopen");
895  mutt_file_fclose(&fp_old);
896  return -1;
897  }
898 
899  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
900  {
901  mutt_error(_("Write fault"));
902  mutt_file_fclose(&fp_old);
903  mutt_file_fclose(&fp_new);
904  return -1;
905  }
906  mutt_file_fclose(&fp_old);
907  if (mutt_file_fsync_close(&fp_new) != 0)
908  {
909  mutt_error(_("Write fault"));
910  return -1;
911  }
912  }
913 
914  return 0;
915 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:52
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:63
The "current" mailbox.
Definition: context.h:36
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1795
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1391
The envelope/body of an email.
Definition: email.h:37
#define mutt_perror(...)
Definition: logging.h:85
int mx_mbox_close(struct Context **ptr)
Save changes and close mailbox.
Definition: mx.c:583
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
#define CH_FROM
Retain the "From " message separator?
Definition: copy.h:55
#define _(a)
Definition: message.h:28
#define CH_NOSTATUS
Suppress the status and x-status fields.
Definition: copy.h:57
struct Context * mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:253
FILE * fp_out
File to write to.
Definition: state.h:47
#define CH_UPDATE
Update the status and x-status fields?
Definition: copy.h:51
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
FILE * fp_in
File to read from.
Definition: state.h:46
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1140
bool read
Email is read.
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.h:50
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:104
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
struct Message * mx_msg_open_new(struct Mailbox *m, struct Email *e, MsgOpenFlags flags)
Open a new message.
Definition: mx.c:1009
Base-64 encoded text.
Definition: mime.h:52
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:50
char * subtype
content-type subtype
Definition: body.h:37
A local copy of an email.
Definition: mx.h:81
A mailbox.
Definition: mailbox.h:80
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:48
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:54
unsigned int type
content-type primary type
Definition: body.h:65
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:47
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:49
#define mutt_error(...)
Definition: logging.h:84
int mx_msg_commit(struct Mailbox *m, struct Message *msg)
Commit a message to a folder - Wrapper for MxOps::msg_commit()
Definition: mx.c:1119
Quoted-printable text.
Definition: mime.h:51
FILE * fp
pointer to the message data
Definition: mx.h:83
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1603
Keep track when processing files.
Definition: state.h:44
static FILE * save_attachment_open(const char *path, enum SaveAttach opt)
Open a file to write an attachment to.
Definition: mutt_attach.c:776
bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
Is a string a &#39;From&#39; header line?
Definition: from.c:50
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
make a copy of a message from a FILE pointer
Definition: copy.c:598
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:64
struct Email * email
header information for message/rfc822
Definition: body.h:55
int msgno
Number displayed to the user.
Definition: email.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_decode_save_attachment()

int mutt_decode_save_attachment ( FILE *  fp,
struct Body m,
const char *  path,
int  displaying,
enum SaveAttach  opt 
)

Decode, then save an attachment.

Parameters
fpFile to read from (OPTIONAL)
mAttachment
pathPath to save the Attachment to
displayingFlags, e.g. MUTT_DISPLAY
optSave option, see SaveAttach
Return values
0Success
-1Error

Definition at line 927 of file mutt_attach.c.

929 {
930  struct State s = { 0 };
931  unsigned int saved_encoding = 0;
932  struct Body *saved_parts = NULL;
933  struct Email *e_saved = NULL;
934  int rc = 0;
935 
936  s.flags = displaying;
937 
938  if (opt == MUTT_SAVE_APPEND)
939  s.fp_out = fopen(path, "a");
940  else if (opt == MUTT_SAVE_OVERWRITE)
941  s.fp_out = fopen(path, "w");
942  else
943  s.fp_out = mutt_file_fopen(path, "w");
944 
945  if (!s.fp_out)
946  {
947  mutt_perror("fopen");
948  return -1;
949  }
950 
951  if (!fp)
952  {
953  /* When called from the compose menu, the attachment isn't parsed,
954  * so we need to do it here. */
955  struct stat st;
956 
957  if (stat(m->filename, &st) == -1)
958  {
959  mutt_perror("stat");
961  return -1;
962  }
963 
964  s.fp_in = fopen(m->filename, "r");
965  if (!s.fp_in)
966  {
967  mutt_perror("fopen");
968  return -1;
969  }
970 
971  saved_encoding = m->encoding;
972  if (!is_multipart(m))
973  m->encoding = ENC_8BIT;
974 
975  m->length = st.st_size;
976  m->offset = 0;
977  saved_parts = m->parts;
978  e_saved = m->email;
979  mutt_parse_part(s.fp_in, m);
980 
981  if (m->noconv || is_multipart(m))
982  s.flags |= MUTT_CHARCONV;
983  }
984  else
985  {
986  s.fp_in = fp;
987  s.flags |= MUTT_CHARCONV;
988  }
989 
990  mutt_body_handler(m, &s);
991 
992  if (mutt_file_fsync_close(&s.fp_out) != 0)
993  {
994  mutt_perror("fclose");
995  rc = -1;
996  }
997  if (!fp)
998  {
999  m->length = 0;
1000  m->encoding = saved_encoding;
1001  if (saved_parts)
1002  {
1003  email_free(&m->email);
1004  m->parts = saved_parts;
1005  m->email = e_saved;
1006  }
1007  mutt_file_fclose(&s.fp_in);
1008  }
1009 
1010  return rc;
1011 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
The envelope/body of an email.
Definition: email.h:37
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
#define is_multipart(body)
Definition: mime.h:77
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
Overwrite existing file.
Definition: mutt_attach.h:57
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
8-bit text
Definition: mime.h:50
FILE * fp_out
File to write to.
Definition: state.h:47
FILE * fp_in
File to read from.
Definition: state.h:46
The body of an email.
Definition: body.h:34
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1406
char * path
Path of Email (for local Mailboxes)
Definition: email.h:91
Append to existing file.
Definition: mutt_attach.h:56
Keep track when processing files.
Definition: state.h:44
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1551
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
struct Email * email
header information for message/rfc822
Definition: body.h:55
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_print_attachment()

int mutt_print_attachment ( FILE *  fp,
struct Body a 
)

Print out an attachment.

Parameters
fpFile to write to
aAttachment
Return values
1Success
0Error

Ok, the difference between send and receive: recv: Body->filename is a suggested name, and Mailbox|Email points to the attachment in mailbox which is encoded send: Body->filename points to the un-encoded file which contains the attachment

Definition at line 1026 of file mutt_attach.c.

1027 {
1028  char type[256];
1029  pid_t pid;
1030  FILE *fp_in = NULL, *fp_out = NULL;
1031  bool unlink_newfile = false;
1032  struct Buffer *newfile = mutt_buffer_pool_get();
1033  struct Buffer *cmd = mutt_buffer_pool_get();
1034 
1035  int rc = 0;
1036 
1037  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1038 
1039  if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1040  {
1041  int piped = false;
1042 
1043  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1044 
1045  struct MailcapEntry *entry = mailcap_entry_new();
1046  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1047  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
1048  /* send mode: symlink from existing file to the newfile */
1049  if (!fp)
1050  {
1051  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1052  {
1053  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1054  goto mailcap_cleanup;
1055  mutt_buffer_strcpy(newfile, a->filename);
1056  }
1057  else
1058  unlink_newfile = true;
1059  }
1060  /* in recv mode, save file to newfile first */
1061  else
1062  {
1063  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), 0, NULL) == -1)
1064  goto mailcap_cleanup;
1065  }
1066 
1067  mutt_buffer_strcpy(cmd, entry->printcommand);
1068  piped = mailcap_expand_command(a, mutt_b2s(newfile), type, cmd);
1069 
1070  mutt_endwin();
1071 
1072  /* interactive program */
1073  if (piped)
1074  {
1075  fp_in = fopen(mutt_b2s(newfile), "r");
1076  if (!fp_in)
1077  {
1078  mutt_perror("fopen");
1079  mailcap_entry_free(&entry);
1080  goto mailcap_cleanup;
1081  }
1082 
1083  pid = mutt_create_filter(mutt_b2s(cmd), &fp_out, NULL, NULL);
1084  if (pid < 0)
1085  {
1086  mutt_perror(_("Can't create filter"));
1087  mailcap_entry_free(&entry);
1088  mutt_file_fclose(&fp_in);
1089  goto mailcap_cleanup;
1090  }
1091  mutt_file_copy_stream(fp_in, fp_out);
1092  mutt_file_fclose(&fp_out);
1093  mutt_file_fclose(&fp_in);
1094  if (mutt_wait_filter(pid) || C_WaitKey)
1096  }
1097  else
1098  {
1099  int rc2 = mutt_system(mutt_b2s(cmd));
1100  if (rc2 == -1)
1101  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1102 
1103  if ((rc2 != 0) || C_WaitKey)
1105  }
1106 
1107  rc = 1;
1108 
1109  mailcap_cleanup:
1110  if (fp)
1111  mutt_file_unlink(mutt_b2s(newfile));
1112  else if (unlink_newfile)
1113  unlink(mutt_b2s(newfile));
1114 
1115  mailcap_entry_free(&entry);
1116  goto out;
1117  }
1118 
1119  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1120  (mutt_str_strcasecmp("application/postscript", type) == 0))
1121  {
1122  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1123  goto out;
1124  }
1125  else if (mutt_can_decode(a))
1126  {
1127  /* decode and print */
1128 
1129  fp_in = NULL;
1130  fp_out = NULL;
1131 
1132  mutt_buffer_mktemp(newfile);
1133  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1134  {
1135  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1136  type, mutt_b2s(newfile));
1137 
1138  fp_in = fopen(mutt_b2s(newfile), "r");
1139  if (!fp_in)
1140  {
1141  mutt_perror("fopen");
1142  goto decode_cleanup;
1143  }
1144 
1145  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1146 
1147  mutt_endwin();
1148  pid = mutt_create_filter(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1149  if (pid < 0)
1150  {
1151  mutt_perror(_("Can't create filter"));
1152  goto decode_cleanup;
1153  }
1154 
1155  mutt_debug(LL_DEBUG2, "Filter created\n");
1156 
1157  mutt_file_copy_stream(fp_in, fp_out);
1158 
1159  mutt_file_fclose(&fp_out);
1160  mutt_file_fclose(&fp_in);
1161 
1162  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
1164  rc = 1;
1165  }
1166  decode_cleanup:
1167  mutt_file_fclose(&fp_in);
1168  mutt_file_fclose(&fp_out);
1169  mutt_file_unlink(mutt_b2s(newfile));
1170  }
1171  else
1172  {
1173  mutt_error(_("I don't know how to print that"));
1174  rc = 0;
1175  }
1176 
1177 out:
1178  mutt_buffer_pool_release(&newfile);
1180 
1181  return rc;
1182 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:209
A mailcap entry.
Definition: mailcap.h:38
struct MailcapEntry * mailcap_entry_new(void)
Allocate memory for a new rfc1524 entry.
Definition: mailcap.c:428
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:78
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define NONULL(x)
Definition: string2.h:37
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
#define MUTT_PRINTING
Are we printing? - MUTT_DISPLAY "light".
Definition: state.h:37
int mutt_save_attachment(FILE *fp, struct Body *m, const char *path, enum SaveAttach opt, struct Email *e)
Save an attachment.
Definition: mutt_attach.c:796
bool mailcap_lookup(struct Body *a, char *type, size_t typelen, struct MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: mailcap.c:466
int mailcap_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: mailcap.c:69
void mailcap_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: mailcap.c:521
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:376
Log at debug level 2.
Definition: logging.h:41
Mailcap print field.
Definition: mailcap.h:61
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:41
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:260
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:545
void mailcap_entry_free(struct MailcapEntry **ptr)
Deallocate an struct MailcapEntry.
Definition: mailcap.c:437
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:927
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1754
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
char * printcommand
Definition: mailcap.h:45
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:578
char * nametemplate
Definition: mailcap.h:46
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:40
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:270
#define mutt_error(...)
Definition: logging.h:84
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:136
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:296
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:220
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:679
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_add_temp_attachment()

void mutt_add_temp_attachment ( const char *  filename)

Add file to list of temporary attachments.

Parameters
filenamefilename with full path

Definition at line 1188 of file mutt_attach.c.

1189 {
1190  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1191 }
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_unlink_temp_attachments()

void mutt_unlink_temp_attachments ( void  )

Delete all temporary attachments.

Definition at line 1196 of file mutt_attach.c.

1197 {
1198  struct ListNode *np = NULL;
1199 
1200  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1201  {
1202  mutt_file_chmod_add(np->data, S_IWUSR);
1203  mutt_file_unlink(np->data);
1204  }
1205 
1206  mutt_list_free(&TempAttachmentsList);
1207 }
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * data
String.
Definition: list.h:35
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1058
A List node for strings.
Definition: list.h:33
+ Here is the call graph for this function:
+ Here is the caller graph for this function: