NeoMutt  2018-07-16 +2225-8687db
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 <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 "mutt.h"
#include "mutt_attach.h"
#include "context.h"
#include "copy.h"
#include "core/lib.h"
#include "curs_lib.h"
#include "filter.h"
#include "globals.h"
#include "handler.h"
#include "muttlib.h"
#include "mx.h"
#include "ncrypt/ncrypt.h"
#include "options.h"
#include "pager.h"
#include "protos.h"
#include "rfc1524.h"
#include "sendlib.h"
#include "state.h"

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)
 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

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 67 of file mutt_attach.c.

68 {
69  char type[256];
70  struct stat st;
71 
72  if (a->unlink)
73  return 0;
74 
75  struct Buffer *tmpfile = mutt_buffer_pool_get();
76  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
77  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
80 
81  rfc1524_free_entry(&entry);
82 
83  if (stat(a->filename, &st) == -1)
84  {
85  mutt_buffer_pool_release(&tmpfile);
86  return -1;
87  }
88 
89  FILE *fp_in = NULL, *fp_out = NULL;
90  if ((fp_in = fopen(a->filename, "r")) &&
91  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
92  {
93  mutt_file_copy_stream(fp_in, fp_out);
94  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
95  a->unlink = true;
96 
97  if (a->stamp >= st.st_mtime)
99  }
100  else
101  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
102 
103  mutt_file_fclose(&fp_in);
104  mutt_file_fclose(&fp_out);
105 
106  mutt_buffer_pool_release(&tmpfile);
107 
108  return a->unlink ? 0 : -1;
109 }
void mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:519
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:1409
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:75
#define mutt_perror(...)
Definition: logging.h:85
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:466
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
String manipulation buffer.
Definition: buffer.h:33
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:42
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:438
A mailcap entry.
Definition: rfc1524.h:37
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
#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:267
No flags set.
Definition: rfc1524.h:57
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
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:429
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
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 117 of file mutt_attach.c.

118 {
119  char type[256];
120  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
121  bool unlink_newfile = false;
122  int rc = 0;
123  struct Buffer *cmd = mutt_buffer_pool_get();
124  struct Buffer *newfile = mutt_buffer_pool_get();
125  struct Buffer *tmpfile = mutt_buffer_pool_get();
126 
127  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
128  if (rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_COMPOSE))
129  {
130  if (entry->composecommand || entry->composetypecommand)
131  {
132  if (entry->composetypecommand)
134  else
135  mutt_buffer_strcpy(cmd, entry->composecommand);
136 
138  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
139  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
140  {
141  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
142  goto bailout;
143  mutt_buffer_strcpy(newfile, a->filename);
144  }
145  else
146  unlink_newfile = true;
147 
148  if (mutt_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd))
149  {
150  /* For now, editing requires a file, no piping */
151  mutt_error(_("Mailcap compose entry requires %%s"));
152  }
153  else
154  {
155  int r;
156 
157  mutt_endwin();
158  r = mutt_system(mutt_b2s(cmd));
159  if (r == -1)
160  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
161 
162  if ((r != -1) && entry->composetypecommand)
163  {
164  struct Body *b = NULL;
165 
166  FILE *fp = mutt_file_fopen(a->filename, "r");
167  if (!fp)
168  {
169  mutt_perror(_("Failure to open file to parse headers"));
170  goto bailout;
171  }
172 
173  b = mutt_read_mime_header(fp, 0);
174  if (b)
175  {
176  if (!TAILQ_EMPTY(&b->parameter))
177  {
179  a->parameter = b->parameter;
180  TAILQ_INIT(&b->parameter);
181  }
182  if (b->description)
183  {
184  FREE(&a->description);
185  a->description = b->description;
186  b->description = NULL;
187  }
188  if (b->form_name)
189  {
190  FREE(&a->form_name);
191  a->form_name = b->form_name;
192  b->form_name = NULL;
193  }
194 
195  /* Remove headers by copying out data to another file, then
196  * copying the file back */
197  fseeko(fp, b->offset, SEEK_SET);
198  mutt_body_free(&b);
199  mutt_buffer_mktemp(tmpfile);
200  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpfile), "w");
201  if (!fp_tmp)
202  {
203  mutt_perror(_("Failure to open file to strip headers"));
204  mutt_file_fclose(&fp);
205  goto bailout;
206  }
207  mutt_file_copy_stream(fp, fp_tmp);
208  mutt_file_fclose(&fp);
209  mutt_file_fclose(&fp_tmp);
211  if (mutt_file_rename(mutt_b2s(tmpfile), a->filename) != 0)
212  {
213  mutt_perror(_("Failure to rename file"));
214  goto bailout;
215  }
216  }
217  }
218  }
219  }
220  }
221  else
222  {
223  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
224  rc = 1;
225  goto bailout;
226  }
227 
228  rc = 1;
229 
230 bailout:
231 
232  if (unlink_newfile)
233  unlink(mutt_b2s(newfile));
234 
236  mutt_buffer_pool_release(&newfile);
237  mutt_buffer_pool_release(&tmpfile);
238 
239  rfc1524_free_entry(&entry);
240  return rc;
241 }
void mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:519
int mutt_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:71
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
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:75
#define mutt_perror(...)
Definition: logging.h:85
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:466
#define mutt_message(...)
Definition: logging.h:83
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1333
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
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
Mailcap compose field.
Definition: rfc1524.h:59
char * form_name
Content-Disposition form-data name param.
Definition: body.h:41
The body of an email.
Definition: body.h:34
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define TAILQ_INIT(head)
Definition: queue.h:759
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:42
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:438
void mutt_param_free(struct ParameterList *p)
Free a ParameterList.
Definition: parameter.c:61
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
A mailcap entry.
Definition: rfc1524.h:37
char * description
content-description
Definition: body.h:40
char * composetypecommand
Definition: rfc1524.h:42
char * composecommand
Definition: rfc1524.h:41
#define TYPE(body)
Definition: mime.h:83
void mutt_body_free(struct Body **p)
Free a Body.
Definition: body.c:57
Log at debug level 1.
Definition: logging.h:56
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:267
#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
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:429
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
#define TAILQ_EMPTY(head)
Definition: queue.h:715
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:293
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
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:50
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1171
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 256 of file mutt_attach.c.

257 {
258  char type[256];
259  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
260  bool unlink_newfile = false;
261  int rc = 0;
262  struct Buffer *cmd = mutt_buffer_pool_get();
263  struct Buffer *newfile = mutt_buffer_pool_get();
264 
265  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
266  if (rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_EDIT))
267  {
268  if (entry->editcommand)
269  {
270  mutt_buffer_strcpy(cmd, entry->editcommand);
272  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
273  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
274  {
275  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
276  goto bailout;
277  mutt_buffer_strcpy(newfile, a->filename);
278  }
279  else
280  unlink_newfile = true;
281 
282  if (mutt_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd))
283  {
284  /* For now, editing requires a file, no piping */
285  mutt_error(_("Mailcap Edit entry requires %%s"));
286  goto bailout;
287  }
288  else
289  {
290  mutt_endwin();
291  if (mutt_system(mutt_b2s(cmd)) == -1)
292  {
293  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
294  goto bailout;
295  }
296  }
297  }
298  }
299  else if (a->type == TYPE_TEXT)
300  {
301  /* On text, default to editor */
303  }
304  else
305  {
306  mutt_error(_("No mailcap edit entry for %s"), type);
307  rc = 0;
308  goto bailout;
309  }
310 
311  rc = 1;
312 
313 bailout:
314 
315  if (unlink_newfile)
316  unlink(mutt_b2s(newfile));
317 
319  mutt_buffer_pool_release(&newfile);
320 
321  rfc1524_free_entry(&entry);
322  return rc;
323 }
void mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:519
int mutt_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:71
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:75
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:466
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
String manipulation buffer.
Definition: buffer.h:33
#define _(a)
Definition: message.h:28
Mailcap edit field.
Definition: rfc1524.h:58
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:42
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:438
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
Type: &#39;text/*&#39;.
Definition: mime.h:38
A mailcap entry.
Definition: rfc1524.h:37
unsigned int type
content-type primary type
Definition: body.h:65
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:56
#define mutt_error(...)
Definition: logging.h:84
WHERE char * C_Editor
Config: External command to use as an email editor.
Definition: globals.h:104
char * editcommand
Definition: rfc1524.h:43
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:429
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:293
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:308
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
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 331 of file mutt_attach.c.

332 {
333  struct ListNode *np = NULL;
334  STAILQ_FOREACH(np, &MimeLookupList, entries)
335  {
336  const int i = mutt_str_strlen(np->data) - 1;
337  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
338  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
339  (mutt_str_strcasecmp(type, np->data) == 0))
340  {
341  struct Body tmp = { 0 };
342  enum ContentType n;
343  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
344  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
345  {
346  snprintf(type, len, "%s/%s",
347  (n == TYPE_AUDIO) ?
348  "audio" :
349  (n == TYPE_APPLICATION) ?
350  "application" :
351  (n == TYPE_IMAGE) ?
352  "image" :
353  (n == TYPE_MESSAGE) ?
354  "message" :
355  (n == TYPE_MODEL) ?
356  "model" :
357  (n == TYPE_MULTIPART) ?
358  "multipart" :
359  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
360  tmp.subtype);
361  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
362  }
363  if (tmp.subtype)
364  FREE(&tmp.subtype);
365  if (tmp.xtype)
366  FREE(&tmp.xtype);
367  }
368  }
369 }
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:350
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
Definition: list.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
Log at debug level 1.
Definition: logging.h:56
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:1091
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
int mutt_view_attachment ( FILE *  fp,
struct Body a,
enum ViewAttachMode  mode,
struct Email e,
struct AttachCtx actx 
)

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
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 388 of file mutt_attach.c.

390 {
391  bool use_mailcap = false;
392  bool use_pipe = false;
393  bool use_pager = true;
394  char type[256];
395  char desc[256];
396  char *fname = NULL;
397  struct Rfc1524MailcapEntry *entry = NULL;
398  int rc = -1;
399  bool unlink_tempfile = false;
400 
401  bool is_message = mutt_is_message_type(a->type, a->subtype);
402  if ((WithCrypto != 0) && is_message && a->email &&
404  {
405  return rc;
406  }
407 
408  struct Buffer *tmpfile = mutt_buffer_pool_get();
409  struct Buffer *pagerfile = mutt_buffer_pool_get();
410  struct Buffer *cmd = mutt_buffer_pool_get();
411 
412  use_mailcap =
413  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
414  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
415 
416  if (use_mailcap)
417  {
418  entry = rfc1524_new_entry();
419  if (!rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_NO_FLAGS))
420  {
421  if (mode == MUTT_VA_REGULAR)
422  {
423  /* fallback to view as text */
424  rfc1524_free_entry(&entry);
425  mutt_error(_("No matching mailcap entry found. Viewing as text."));
426  mode = MUTT_VA_AS_TEXT;
427  use_mailcap = false;
428  }
429  else
430  goto return_error;
431  }
432  }
433 
434  if (use_mailcap)
435  {
436  if (!entry->command)
437  {
438  mutt_error(_("MIME type not defined. Can't view attachment."));
439  goto return_error;
440  }
441  mutt_buffer_strcpy(cmd, entry->command);
442 
443  if (fp)
444  {
445  fname = mutt_str_strdup(a->filename);
446  mutt_file_sanitize_filename(fname, true);
447  }
448  else
449  fname = a->filename;
450 
451  mutt_rfc1524_expand_filename(entry->nametemplate, fname, tmpfile);
452  /* send case: the file is already there; symlink to it */
453  if (!fp)
454  {
455  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
456  {
457  if (mutt_yesorno(_("Can't match nametemplate, continue?"), MUTT_YES) != MUTT_YES)
458  goto return_error;
459  mutt_buffer_strcpy(tmpfile, a->filename);
460  }
461  else
462  unlink_tempfile = true;
463  }
464  /* recv case: we need to save the attachment to a file */
465  else
466  {
467  FREE(&fname);
468  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
469  goto return_error;
470  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
471  }
472 
473  use_pipe = mutt_rfc1524_expand_command(a, mutt_b2s(tmpfile), type, cmd);
474  use_pager = entry->copiousoutput;
475  }
476 
477  if (use_pager)
478  {
479  if (fp && !use_mailcap && a->filename)
480  {
481  /* recv case */
482  mutt_buffer_strcpy(pagerfile, a->filename);
483  mutt_adv_mktemp(pagerfile);
484  }
485  else
486  mutt_buffer_mktemp(pagerfile);
487  }
488 
489  if (use_mailcap)
490  {
491  pid_t pid = 0;
492  int fd_temp = -1, fd_pager = -1;
493 
494  if (!use_pager)
495  mutt_endwin();
496 
497  if (use_pager || use_pipe)
498  {
499  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
500  O_CREAT | O_EXCL | O_WRONLY)) == -1))
501  {
502  mutt_perror("open");
503  goto return_error;
504  }
505  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
506  {
507  if (fd_pager != -1)
508  close(fd_pager);
509  mutt_perror("open");
510  goto return_error;
511  }
512 
513  pid = mutt_create_filter_fd(mutt_b2s(cmd), NULL, NULL, NULL,
514  use_pipe ? fd_temp : -1,
515  use_pager ? fd_pager : -1, -1);
516  if (pid == -1)
517  {
518  if (fd_pager != -1)
519  close(fd_pager);
520 
521  if (fd_temp != -1)
522  close(fd_temp);
523 
524  mutt_error(_("Can't create filter"));
525  goto return_error;
526  }
527 
528  if (use_pager)
529  {
530  if (a->description)
531  {
532  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
533  mutt_b2s(cmd), a->description);
534  }
535  else
536  {
537  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
538  mutt_b2s(cmd), type);
539  }
540  }
541 
542  if ((mutt_wait_filter(pid) || (entry->needsterminal && C_WaitKey)) && !use_pager)
544 
545  if (fd_temp != -1)
546  close(fd_temp);
547  if (fd_pager != -1)
548  close(fd_pager);
549  }
550  else
551  {
552  /* interactive cmd */
553  int rv = mutt_system(mutt_b2s(cmd));
554  if (rv == -1)
555  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd);
556 
557  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
559  }
560  }
561  else
562  {
563  /* Don't use mailcap; the attachment is viewed in the pager */
564 
565  if (mode == MUTT_VA_AS_TEXT)
566  {
567  /* just let me see the raw data */
568  if (fp)
569  {
570  /* Viewing from a received message.
571  *
572  * Don't use mutt_save_attachment() because we want to perform charset
573  * conversion since this will be displayed by the internal pager. */
574  struct State decode_state = { 0 };
575 
576  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
577  if (!decode_state.fp_out)
578  {
579  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
580  mutt_b2s(pagerfile), errno, strerror(errno));
581  mutt_perror(mutt_b2s(pagerfile));
582  goto return_error;
583  }
584  decode_state.fp_in = fp;
585  decode_state.flags = MUTT_CHARCONV;
586  mutt_decode_attachment(a, &decode_state);
587  if (fclose(decode_state.fp_out) == EOF)
588  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
589  errno, strerror(errno));
590  }
591  else
592  {
593  /* in compose mode, just copy the file. we can't use
594  * mutt_decode_attachment() since it assumes the content-encoding has
595  * already been applied */
596  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
597  goto return_error;
598  }
599  }
600  else
601  {
602  /* Use built-in handler */
603  OptViewAttach = true; /* disable the "use 'v' to view this part"
604  * message in case of error */
606  {
607  OptViewAttach = false;
608  goto return_error;
609  }
610  OptViewAttach = false;
611  }
612 
613  if (a->description)
614  mutt_str_strfcpy(desc, a->description, sizeof(desc));
615  else if (a->filename)
616  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
617  else
618  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
619  }
620 
621  /* We only reach this point if there have been no errors */
622 
623  if (use_pager)
624  {
625  struct Pager info = { 0 };
626  info.fp = fp;
627  info.body = a;
628  info.ctx = Context;
629  info.actx = actx;
630  info.email = e;
631 
632  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
634  &info);
635  mutt_buffer_reset(pagerfile);
636  }
637  else
638  rc = 0;
639 
640 return_error:
641 
642  if (!entry || !entry->xneomuttkeep)
643  {
644  if (fp && mutt_b2s(tmpfile)[0])
645  {
646  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
648  }
649  else if (unlink_tempfile)
650  {
651  unlink(mutt_b2s(tmpfile));
652  }
653  }
654 
655  rfc1524_free_entry(&entry);
656 
657  if (mutt_b2s(pagerfile)[0] != '\0')
658  mutt_file_unlink(mutt_b2s(pagerfile));
659 
660  mutt_buffer_pool_release(&tmpfile);
661  mutt_buffer_pool_release(&pagerfile);
663 
664  return rc;
665 }
void mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:519
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1789
FILE * fp
source stream
Definition: pager.h:70
int mutt_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:71
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
#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:76
bool mutt_is_message_type(int type, const char *subtype)
Determine if a mime type matches a message or not.
Definition: parse.c:1270
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:75
#define mutt_perror(...)
Definition: logging.h:85
#define MUTT_CHARCONV
Do character set conversions.
Definition: state.h:36
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:466
#define MUTT_PAGER_MESSAGE
Definition: pager.h:58
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
No flags set.
Definition: mutt_attach.h:54
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
String manipulation buffer.
Definition: buffer.h:33
bool needsterminal
endwin() and system
Definition: rfc1524.h:47
#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:43
bool xneomuttkeep
do not remove the file on command exit
Definition: rfc1524.h:49
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:793
An email being displayed.
Definition: pager.h:65
View using default method.
Definition: mutt_attach.h:41
#define SEC_ENCRYPT
Email is encrypted.
Definition: ncrypt.h:121
FILE * fp_in
File to read from.
Definition: state.h:46
#define MUTT_PAGER_ATTACHMENT
Attachments may exist.
Definition: pager.h:55
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:143
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
int mutt_file_chmod(const char *path, mode_t mode)
Set permissions of a file.
Definition: file.c:1032
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1185
char * nametemplate
Definition: rfc1524.h:45
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:614
#define mutt_b2s(buf)
Definition: buffer.h:42
struct Context * ctx
current mailbox
Definition: pager.h:67
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:438
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
WHERE struct Context * Context
Definition: globals.h:41
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:258
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
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:924
struct AttachCtx * actx
attachment information
Definition: pager.h:71
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
A mailcap entry.
Definition: rfc1524.h:37
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-8: flags, bit 9,10: application.
Definition: email.h:39
Force viewing using mailcap entry.
Definition: mutt_attach.h:42
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:544
#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:518
Log at debug level 1.
Definition: logging.h:56
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:582
No flags set.
Definition: rfc1524.h:57
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:408
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:90
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:429
#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:52
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:293
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
struct Email * email
header information for message/rfc822
Definition: body.h:55
#define WithCrypto
Definition: ncrypt.h:156
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: pager.h:43
bool copiousoutput
needs pager, basically
Definition: rfc1524.h:48
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 676 of file mutt_attach.c.

677 {
678  pid_t pid;
679  int out = -1;
680  int rc = 0;
681 
682  if (outfile && *outfile)
683  {
684  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
685  if (out < 0)
686  {
687  mutt_perror("open");
688  return 0;
689  }
690  }
691 
692  mutt_endwin();
693 
694  if (fp)
695  {
696  /* recv case */
697 
698  struct State s = { 0 };
699 
700  /* perform charset conversion on text attachments when piping */
701  s.flags = MUTT_CHARCONV;
702 
703  if (outfile && *outfile)
704  pid = mutt_create_filter_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
705  else
706  pid = mutt_create_filter(path, &s.fp_out, NULL, NULL);
707 
708  if (pid < 0)
709  {
710  mutt_perror(_("Can't create filter"));
711  goto bail;
712  }
713 
714  s.fp_in = fp;
715  mutt_decode_attachment(b, &s);
717  }
718  else
719  {
720  /* send case */
721  FILE *fp_in = fopen(b->filename, "r");
722  if (!fp_in)
723  {
724  mutt_perror("fopen");
725  if (outfile && *outfile)
726  {
727  close(out);
728  unlink(outfile);
729  }
730  return 0;
731  }
732 
733  FILE *fp_out = NULL;
734  if (outfile && *outfile)
735  pid = mutt_create_filter_fd(path, &fp_out, NULL, NULL, -1, out, -1);
736  else
737  pid = mutt_create_filter(path, &fp_out, NULL, NULL);
738 
739  if (pid < 0)
740  {
741  mutt_perror(_("Can't create filter"));
742  mutt_file_fclose(&fp_in);
743  goto bail;
744  }
745 
746  mutt_file_copy_stream(fp_in, fp_out);
747  mutt_file_fclose(&fp_out);
748  mutt_file_fclose(&fp_in);
749  }
750 
751  rc = 1;
752 
753 bail:
754 
755  if (outfile && *outfile)
756  close(out);
757 
758  /* check for error exit from child process */
759  if (mutt_wait_filter(pid) != 0)
760  rc = 0;
761 
762  if ((rc == 0) || C_WaitKey)
764  return rc;
765 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:216
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1789
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:149
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:258
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
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:544
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:518
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:267
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:227
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 773 of file mutt_attach.c.

774 {
775  if (opt == MUTT_SAVE_APPEND)
776  return fopen(path, "a");
777  if (opt == MUTT_SAVE_OVERWRITE)
778  return fopen(path, "w");
779 
780  return mutt_file_fopen(path, "w");
781 }
Overwrite existing file.
Definition: mutt_attach.h:56
Append to existing file.
Definition: mutt_attach.h:55
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
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 793 of file mutt_attach.c.

795 {
796  if (!m)
797  return -1;
798 
799  if (fp)
800  {
801  /* recv mode */
802 
803  if (e && m->email && (m->encoding != ENC_BASE64) &&
805  {
806  /* message type attachments are written to mail folders. */
807 
808  char buf[8192];
809  struct Message *msg = NULL;
810  CopyHeaderFlags chflags = CH_NO_FLAGS;
811  int rc = -1;
812 
813  struct Email *e_new = m->email;
814  e_new->msgno = e->msgno; /* required for MH/maildir */
815  e_new->read = true;
816 
817  if (fseeko(fp, m->offset, SEEK_SET) < 0)
818  return -1;
819  if (!fgets(buf, sizeof(buf), fp))
820  return -1;
821  struct Mailbox *m_att = mx_path_resolve(path);
822  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
823  if (!ctx)
824  {
825  mailbox_free(&m_att);
826  return -1;
827  }
828  msg = mx_msg_open_new(ctx->mailbox, e_new,
829  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
830  if (!msg)
831  {
832  mx_mbox_close(&ctx);
833  return -1;
834  }
835  if ((ctx->mailbox->magic == MUTT_MBOX) || (ctx->mailbox->magic == MUTT_MMDF))
836  chflags = CH_FROM | CH_UPDATE_LEN;
837  chflags |= ((ctx->mailbox->magic == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
838  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags) == 0) &&
839  (mx_msg_commit(ctx->mailbox, msg) == 0))
840  {
841  rc = 0;
842  }
843  else
844  {
845  rc = -1;
846  }
847 
848  mx_msg_close(ctx->mailbox, &msg);
849  mx_mbox_close(&ctx);
850  return rc;
851  }
852  else
853  {
854  /* In recv mode, extract from folder and decode */
855 
856  struct State s = { 0 };
857 
858  s.fp_out = save_attachment_open(path, opt);
859  if (!s.fp_out)
860  {
861  mutt_perror("fopen");
862  return -1;
863  }
864  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
865  mutt_decode_attachment(m, &s);
866 
867  if (mutt_file_fsync_close(&s.fp_out) != 0)
868  {
869  mutt_perror("fclose");
870  return -1;
871  }
872  }
873  }
874  else
875  {
876  if (!m->filename)
877  return -1;
878 
879  /* In send mode, just copy file */
880 
881  FILE *fp_old = fopen(m->filename, "r");
882  if (!fp_old)
883  {
884  mutt_perror("fopen");
885  return -1;
886  }
887 
888  FILE *fp_new = save_attachment_open(path, opt);
889  if (!fp_new)
890  {
891  mutt_perror("fopen");
892  mutt_file_fclose(&fp_old);
893  return -1;
894  }
895 
896  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
897  {
898  mutt_error(_("Write fault"));
899  mutt_file_fclose(&fp_old);
900  mutt_file_fclose(&fp_new);
901  return -1;
902  }
903  mutt_file_fclose(&fp_old);
904  if (mutt_file_fsync_close(&fp_new) != 0)
905  {
906  mutt_error(_("Write fault"));
907  return -1;
908  }
909  }
910 
911  return 0;
912 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:53
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:64
The "current" mailbox.
Definition: context.h:39
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1789
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:1270
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:561
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:165
int mutt_copy_message_fp(FILE *fp_out, FILE *fp_in, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags)
make a copy of a message from a FILE pointer
Definition: copy.c:593
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:264
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:1092
bool read
Email is read.
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.h:53
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:56
enum MailboxType magic
Mailbox type.
Definition: mailbox.h:117
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
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:961
Base-64 encoded text.
Definition: mime.h:52
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
char * subtype
content-type subtype
Definition: body.h:37
A local copy of an email.
Definition: mx.h:82
A mailbox.
Definition: mailbox.h:93
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:50
&#39;mmdf&#39; Mailbox type
Definition: mailbox.h:49
#define CH_UPDATE_LEN
Update Lines: and Content-Length:
Definition: copy.h:61
#define MUTT_QUIET
Do not print any messages.
Definition: mx.h:55
unsigned int type
content-type primary type
Definition: body.h:65
&#39;mbox&#39; Mailbox type
Definition: mailbox.h:48
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:267
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:1071
Quoted-printable text.
Definition: mime.h:51
FILE * fp
pointer to the message data
Definition: mx.h:84
struct Mailbox * mx_path_resolve(const char *path)
XXX.
Definition: mx.c:1544
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:773
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:49
#define MUTT_ADD_FROM
add a From_ line
Definition: mx.h:65
struct Email * email
header information for message/rfc822
Definition: body.h:55
int msgno
Number displayed to the user.
Definition: email.h:86
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 924 of file mutt_attach.c.

926 {
927  struct State s = { 0 };
928  unsigned int saved_encoding = 0;
929  struct Body *saved_parts = NULL;
930  struct Email *e_saved = NULL;
931  int rc = 0;
932 
933  s.flags = displaying;
934 
935  if (opt == MUTT_SAVE_APPEND)
936  s.fp_out = fopen(path, "a");
937  else if (opt == MUTT_SAVE_OVERWRITE)
938  s.fp_out = fopen(path, "w");
939  else
940  s.fp_out = mutt_file_fopen(path, "w");
941 
942  if (!s.fp_out)
943  {
944  mutt_perror("fopen");
945  return -1;
946  }
947 
948  if (!fp)
949  {
950  /* When called from the compose menu, the attachment isn't parsed,
951  * so we need to do it here. */
952  struct stat st;
953 
954  if (stat(m->filename, &st) == -1)
955  {
956  mutt_perror("stat");
958  return -1;
959  }
960 
961  s.fp_in = fopen(m->filename, "r");
962  if (!s.fp_in)
963  {
964  mutt_perror("fopen");
965  return -1;
966  }
967 
968  saved_encoding = m->encoding;
969  if (!is_multipart(m))
970  m->encoding = ENC_8BIT;
971 
972  m->length = st.st_size;
973  m->offset = 0;
974  saved_parts = m->parts;
975  e_saved = m->email;
976  mutt_parse_part(s.fp_in, m);
977 
978  if (m->noconv || is_multipart(m))
979  s.flags |= MUTT_CHARCONV;
980  }
981  else
982  {
983  s.fp_in = fp;
984  s.flags |= MUTT_CHARCONV;
985  }
986 
987  mutt_body_handler(m, &s);
988 
989  if (mutt_file_fsync_close(&s.fp_out) != 0)
990  {
991  mutt_perror("fclose");
992  rc = -1;
993  }
994  if (!fp)
995  {
996  m->length = 0;
997  m->encoding = saved_encoding;
998  if (saved_parts)
999  {
1000  mutt_email_free(&m->email);
1001  m->parts = saved_parts;
1002  m->email = e_saved;
1003  }
1004  mutt_file_fclose(&s.fp_in);
1005  }
1006 
1007  return rc;
1008 }
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:165
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
Overwrite existing file.
Definition: mutt_attach.h:56
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:149
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_email_free(struct Email **e)
Free an Email.
Definition: email.c:41
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1285
char * path
Path of Email (for local Mailboxes)
Definition: email.h:91
Append to existing file.
Definition: mutt_attach.h:55
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:1544
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:584
struct Email * email
header information for message/rfc822
Definition: body.h:55
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 1023 of file mutt_attach.c.

1024 {
1025  char type[256];
1026  pid_t pid;
1027  FILE *fp_in = NULL, *fp_out = NULL;
1028  bool unlink_newfile = false;
1029  struct Buffer *newfile = mutt_buffer_pool_get();
1030  struct Buffer *cmd = mutt_buffer_pool_get();
1031 
1032  int rc = 0;
1033 
1034  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1035 
1036  if (rfc1524_mailcap_lookup(a, type, NULL, MUTT_MC_PRINT))
1037  {
1038  int piped = false;
1039 
1040  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1041 
1042  struct Rfc1524MailcapEntry *entry = rfc1524_new_entry();
1043  rfc1524_mailcap_lookup(a, type, entry, MUTT_MC_PRINT);
1044  mutt_rfc1524_expand_filename(entry->nametemplate, a->filename, newfile);
1045  /* send mode: symlink from existing file to the newfile */
1046  if (!fp)
1047  {
1048  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1049  {
1050  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1051  goto mailcap_cleanup;
1052  mutt_buffer_strcpy(newfile, a->filename);
1053  }
1054  else
1055  unlink_newfile = true;
1056  }
1057  /* in recv mode, save file to newfile first */
1058  else
1059  {
1060  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), 0, NULL) == -1)
1061  goto mailcap_cleanup;
1062  }
1063 
1064  mutt_buffer_strcpy(cmd, entry->printcommand);
1065  piped = mutt_rfc1524_expand_command(a, mutt_b2s(newfile), type, cmd);
1066 
1067  mutt_endwin();
1068 
1069  /* interactive program */
1070  if (piped)
1071  {
1072  fp_in = fopen(mutt_b2s(newfile), "r");
1073  if (!fp_in)
1074  {
1075  mutt_perror("fopen");
1076  rfc1524_free_entry(&entry);
1077  goto mailcap_cleanup;
1078  }
1079 
1080  pid = mutt_create_filter(mutt_b2s(cmd), &fp_out, NULL, NULL);
1081  if (pid < 0)
1082  {
1083  mutt_perror(_("Can't create filter"));
1084  rfc1524_free_entry(&entry);
1085  mutt_file_fclose(&fp_in);
1086  goto mailcap_cleanup;
1087  }
1088  mutt_file_copy_stream(fp_in, fp_out);
1089  mutt_file_fclose(&fp_out);
1090  mutt_file_fclose(&fp_in);
1091  if (mutt_wait_filter(pid) || C_WaitKey)
1093  }
1094  else
1095  {
1096  int rc2 = mutt_system(mutt_b2s(cmd));
1097  if (rc2 == -1)
1098  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd);
1099 
1100  if ((rc2 != 0) || C_WaitKey)
1102  }
1103 
1104  rc = 1;
1105 
1106  mailcap_cleanup:
1107  if (fp)
1108  mutt_file_unlink(mutt_b2s(newfile));
1109  else if (unlink_newfile)
1110  unlink(mutt_b2s(newfile));
1111 
1112  rfc1524_free_entry(&entry);
1113  goto out;
1114  }
1115 
1116  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1117  (mutt_str_strcasecmp("application/postscript", type) == 0))
1118  {
1119  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1120  goto out;
1121  }
1122  else if (mutt_can_decode(a))
1123  {
1124  /* decode and print */
1125 
1126  fp_in = NULL;
1127  fp_out = NULL;
1128 
1129  mutt_buffer_mktemp(newfile);
1130  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1131  {
1132  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1133  type, mutt_b2s(newfile));
1134 
1135  fp_in = fopen(mutt_b2s(newfile), "r");
1136  if (!fp_in)
1137  {
1138  mutt_perror("fopen");
1139  goto decode_cleanup;
1140  }
1141 
1142  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1143 
1144  mutt_endwin();
1145  pid = mutt_create_filter(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1146  if (pid < 0)
1147  {
1148  mutt_perror(_("Can't create filter"));
1149  goto decode_cleanup;
1150  }
1151 
1152  mutt_debug(LL_DEBUG2, "Filter created\n");
1153 
1154  mutt_file_copy_stream(fp_in, fp_out);
1155 
1156  mutt_file_fclose(&fp_out);
1157  mutt_file_fclose(&fp_in);
1158 
1159  if ((mutt_wait_filter(pid) != 0) || C_WaitKey)
1161  rc = 1;
1162  }
1163  decode_cleanup:
1164  mutt_file_fclose(&fp_in);
1165  mutt_file_fclose(&fp_out);
1166  mutt_file_unlink(mutt_b2s(newfile));
1167  }
1168  else
1169  {
1170  mutt_error(_("I don't know how to print that"));
1171  rc = 0;
1172  }
1173 
1174 out:
1175  mutt_buffer_pool_release(&newfile);
1177 
1178  return rc;
1179 }
pid_t mutt_create_filter(const char *s, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:216
void mutt_rfc1524_expand_filename(const char *nametemplate, const char *oldfile, struct Buffer *newfile)
Expand a new filename from a template or existing filename.
Definition: rfc1524.c:519
int mutt_rfc1524_expand_command(struct Body *a, const char *filename, const char *type, struct Buffer *command)
Expand expandos in a command.
Definition: rfc1524.c:71
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:79
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:75
#define mutt_perror(...)
Definition: logging.h:85
bool rfc1524_mailcap_lookup(struct Body *a, char *type, struct Rfc1524MailcapEntry *entry, enum MailcapLookup opt)
Find given type in the list of mailcap files.
Definition: rfc1524.c:466
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:86
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
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:793
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
Log at debug level 2.
Definition: logging.h:57
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
Mailcap print field.
Definition: rfc1524.h:60
char * nametemplate
Definition: rfc1524.h:45
char * subtype
content-type subtype
Definition: body.h:37
#define mutt_b2s(buf)
Definition: buffer.h:42
void rfc1524_free_entry(struct Rfc1524MailcapEntry **entry)
Deallocate an struct Rfc1524MailcapEntry.
Definition: rfc1524.c:438
void mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:314
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:258
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:499
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:924
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1748
A mailcap entry.
Definition: rfc1524.h:37
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:544
#define TYPE(body)
Definition: mime.h:83
Log at debug level 1.
Definition: logging.h:56
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:267
#define mutt_error(...)
Definition: logging.h:84
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:134
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
struct Rfc1524MailcapEntry * rfc1524_new_entry(void)
Allocate memory for a new rfc1524 entry.
Definition: rfc1524.c:429
char * printcommand
Definition: rfc1524.h:44
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:293
int mutt_wait_filter(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:227
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:676
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:50
void mutt_add_temp_attachment ( const char *  filename)

Add file to list of temporary attachments.

Parameters
filenamefilename with full path

Definition at line 1185 of file mutt_attach.c.

1186 {
1187  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1188 }
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
void mutt_unlink_temp_attachments ( void  )

Delete all temporary attachments.

Definition at line 1193 of file mutt_attach.c.

1194 {
1195  struct ListNode *np = NULL;
1196 
1197  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1198  {
1199  mutt_file_chmod_add(np->data, S_IWUSR);
1200  mutt_file_unlink(np->data);
1201  }
1202 
1203  mutt_list_free(&TempAttachmentsList);
1204 }
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:191
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:350
char * data
Definition: list.h:35
int mutt_file_chmod_add(const char *path, mode_t mode)
Add permissions to a file.
Definition: file.c:1056
A List node for strings.
Definition: list.h:33