NeoMutt  2020-03-20-65-g141838
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 <sys/wait.h>
#include <unistd.h>
#include "mutt/lib.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 "globals.h"
#include "handler.h"
#include "mailcap.h"
#include "muttlib.h"
#include "mx.h"
#include "options.h"
#include "pager.h"
#include "protos.h"
#include "sendlib.h"
#include "state.h"
#include "ncrypt/lib.h"
#include "imap/lib.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...
 
static int wait_interactive_filter (pid_t pid)
 Wait after an interactive filter. 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 68 of file mutt_attach.c.

69 {
70  char type[256];
71  struct stat st;
72 
73  if (a->unlink)
74  return 0;
75 
76  struct Buffer *tmpfile = mutt_buffer_pool_get();
77  struct MailcapEntry *entry = mailcap_entry_new();
78  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
79  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS);
80  mailcap_expand_filename(entry->nametemplate, a->filename, tmpfile);
81 
82  mailcap_entry_free(&entry);
83 
84  if (stat(a->filename, &st) == -1)
85  {
86  mutt_buffer_pool_release(&tmpfile);
87  return -1;
88  }
89 
90  FILE *fp_in = NULL, *fp_out = NULL;
91  if ((fp_in = fopen(a->filename, "r")) &&
92  (fp_out = mutt_file_fopen(mutt_b2s(tmpfile), "w")))
93  {
94  mutt_file_copy_stream(fp_in, fp_out);
95  mutt_str_replace(&a->filename, mutt_b2s(tmpfile));
96  a->unlink = true;
97 
98  if (a->stamp >= st.st_mtime)
100  }
101  else
102  mutt_perror(fp_in ? mutt_b2s(tmpfile) : a->filename);
103 
104  mutt_file_fclose(&fp_in);
105  mutt_file_fclose(&fp_out);
106 
107  mutt_buffer_pool_release(&tmpfile);
108 
109  return a->unlink ? 0 : -1;
110 }
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:1443
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:153
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:271
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:588
+ 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 118 of file mutt_attach.c.

119 {
120  char type[256];
121  struct MailcapEntry *entry = mailcap_entry_new();
122  bool unlink_newfile = false;
123  int rc = 0;
124  struct Buffer *cmd = mutt_buffer_pool_get();
125  struct Buffer *newfile = mutt_buffer_pool_get();
126  struct Buffer *tmpfile = mutt_buffer_pool_get();
127 
128  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
129  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_COMPOSE))
130  {
131  if (entry->composecommand || entry->composetypecommand)
132  {
133  if (entry->composetypecommand)
135  else
136  mutt_buffer_strcpy(cmd, entry->composecommand);
137 
138  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
139  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
140  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
141  {
142  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
143  goto bailout;
144  mutt_buffer_strcpy(newfile, a->filename);
145  }
146  else
147  unlink_newfile = true;
148 
149  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
150  {
151  /* For now, editing requires a file, no piping */
152  mutt_error(_("Mailcap compose entry requires %%s"));
153  }
154  else
155  {
156  int r;
157 
158  mutt_endwin();
159  r = mutt_system(mutt_b2s(cmd));
160  if (r == -1)
161  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
162 
163  if ((r != -1) && entry->composetypecommand)
164  {
165  struct Body *b = NULL;
166 
167  FILE *fp = mutt_file_fopen(a->filename, "r");
168  if (!fp)
169  {
170  mutt_perror(_("Failure to open file to parse headers"));
171  goto bailout;
172  }
173 
174  b = mutt_read_mime_header(fp, 0);
175  if (b)
176  {
177  if (!TAILQ_EMPTY(&b->parameter))
178  {
180  a->parameter = b->parameter;
181  TAILQ_INIT(&b->parameter);
182  }
183  if (b->description)
184  {
185  FREE(&a->description);
186  a->description = b->description;
187  b->description = NULL;
188  }
189  if (b->form_name)
190  {
191  FREE(&a->form_name);
192  a->form_name = b->form_name;
193  b->form_name = NULL;
194  }
195 
196  /* Remove headers by copying out data to another file, then
197  * copying the file back */
198  fseeko(fp, b->offset, SEEK_SET);
199  mutt_body_free(&b);
200  mutt_buffer_mktemp(tmpfile);
201  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tmpfile), "w");
202  if (!fp_tmp)
203  {
204  mutt_perror(_("Failure to open file to strip headers"));
205  mutt_file_fclose(&fp);
206  goto bailout;
207  }
208  mutt_file_copy_stream(fp, fp_tmp);
209  mutt_file_fclose(&fp);
210  mutt_file_fclose(&fp_tmp);
212  if (mutt_file_rename(mutt_b2s(tmpfile), a->filename) != 0)
213  {
214  mutt_perror(_("Failure to rename file"));
215  goto bailout;
216  }
217  }
218  }
219  }
220  }
221  }
222  else
223  {
224  mutt_message(_("No mailcap compose entry for %s, creating empty file"), type);
225  rc = 1;
226  goto bailout;
227  }
228 
229  rc = 1;
230 
231 bailout:
232 
233  if (unlink_newfile)
234  unlink(mutt_b2s(newfile));
235 
237  mutt_buffer_pool_release(&newfile);
238  mutt_buffer_pool_release(&tmpfile);
239 
240  mailcap_entry_free(&entry);
241  return rc;
242 }
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:81
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:1341
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:195
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:378
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#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:547
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:271
#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:299
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
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:51
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 257 of file mutt_attach.c.

258 {
259  char type[256];
260  struct MailcapEntry *entry = mailcap_entry_new();
261  bool unlink_newfile = false;
262  int rc = 0;
263  struct Buffer *cmd = mutt_buffer_pool_get();
264  struct Buffer *newfile = mutt_buffer_pool_get();
265 
266  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
267  if (mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_EDIT))
268  {
269  if (entry->editcommand)
270  {
271  mutt_buffer_strcpy(cmd, entry->editcommand);
272  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
273  mutt_debug(LL_DEBUG1, "oldfile: %s\t newfile: %s\n", a->filename, mutt_b2s(newfile));
274  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
275  {
276  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
277  goto bailout;
278  mutt_buffer_strcpy(newfile, a->filename);
279  }
280  else
281  unlink_newfile = true;
282 
283  if (mailcap_expand_command(a, mutt_b2s(newfile), type, cmd))
284  {
285  /* For now, editing requires a file, no piping */
286  mutt_error(_("Mailcap Edit entry requires %%s"));
287  goto bailout;
288  }
289  else
290  {
291  mutt_endwin();
292  if (mutt_system(mutt_b2s(cmd)) == -1)
293  {
294  mutt_error(_("Error running \"%s\""), mutt_b2s(cmd));
295  goto bailout;
296  }
297  }
298  }
299  }
300  else if (a->type == TYPE_TEXT)
301  {
302  /* On text, default to editor */
304  }
305  else
306  {
307  mutt_error(_("No mailcap edit entry for %s"), type);
308  rc = 0;
309  goto bailout;
310  }
311 
312  rc = 1;
313 
314 bailout:
315 
316  if (unlink_newfile)
317  unlink(mutt_b2s(newfile));
318 
320  mutt_buffer_pool_release(&newfile);
321 
322  mailcap_entry_free(&entry);
323  return rc;
324 }
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:378
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:547
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:111
#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:299
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:354
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_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 332 of file mutt_attach.c.

333 {
334  struct ListNode *np = NULL;
335  STAILQ_FOREACH(np, &MimeLookupList, entries)
336  {
337  const int i = mutt_str_strlen(np->data) - 1;
338  if (((i > 0) && (np->data[i - 1] == '/') && (np->data[i] == '*') &&
339  (mutt_str_strncasecmp(type, np->data, i) == 0)) ||
340  (mutt_str_strcasecmp(type, np->data) == 0))
341  {
342  struct Body tmp = { 0 };
343  enum ContentType n;
344  if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPE_OTHER ||
345  (n = mutt_lookup_mime_type(&tmp, b->description)) != TYPE_OTHER)
346  {
347  snprintf(type, len, "%s/%s",
348  (n == TYPE_AUDIO) ?
349  "audio" :
350  (n == TYPE_APPLICATION) ?
351  "application" :
352  (n == TYPE_IMAGE) ?
353  "image" :
354  (n == TYPE_MESSAGE) ?
355  "message" :
356  (n == TYPE_MODEL) ?
357  "model" :
358  (n == TYPE_MULTIPART) ?
359  "multipart" :
360  (n == TYPE_TEXT) ? "text" : (n == TYPE_VIDEO) ? "video" : "other",
361  tmp.subtype);
362  mutt_debug(LL_DEBUG1, "\"%s\" -> %s\n", b->filename, type);
363  }
364  FREE(&tmp.subtype);
365  FREE(&tmp.xtype);
366  }
367  }
368 }
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:689
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:679
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
int n
Definition: acutest.h:477
enum ContentType mutt_lookup_mime_type(struct Body *att, const char *path)
Find the MIME type for an attachment.
Definition: sendlib.c:1119
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
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:

◆ wait_interactive_filter()

static int wait_interactive_filter ( pid_t  pid)
static

Wait after an interactive filter.

Parameters
pidProcess id of the process to wait for
Return values
numExit status of the process identified by pid
-1Error

This is used for filters that are actually interactive commands with input piped in: e.g. in mutt_view_attachment(), a mailcap entry without copiousoutput and without a s.

For those cases, we treat it like a blocking system command, and poll IMAP to keep connections open.

Definition at line 383 of file mutt_attach.c.

384 {
385  int rc;
386 
387 #ifdef USE_IMAP
388  rc = imap_wait_keepalive(pid);
389 #else
390  waitpid(pid, &rc, 0);
391 #endif
393  rc = WIFEXITED(rc) ? WEXITSTATUS(rc) : -1;
394 
395  return rc;
396 }
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:207
int imap_wait_keepalive(pid_t pid)
Wait for a process to change state.
Definition: util.c:1117
+ 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 415 of file mutt_attach.c.

417 {
418  bool use_mailcap = false;
419  bool use_pipe = false;
420  bool use_pager = true;
421  char type[256];
422  char desc[256];
423  char *fname = NULL;
424  struct MailcapEntry *entry = NULL;
425  int rc = -1;
426  bool unlink_tempfile = false;
427 
428  bool is_message = mutt_is_message_type(a->type, a->subtype);
429  if ((WithCrypto != 0) && is_message && a->email &&
431  {
432  return rc;
433  }
434 
435  struct Buffer *tmpfile = mutt_buffer_pool_get();
436  struct Buffer *pagerfile = mutt_buffer_pool_get();
437  struct Buffer *cmd = mutt_buffer_pool_get();
438 
439  use_mailcap =
440  (mode == MUTT_VA_MAILCAP || (mode == MUTT_VA_REGULAR && mutt_needs_mailcap(a)));
441  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
442 
443  char columns[16];
444  snprintf(columns, sizeof(columns), "%d", win->state.cols);
445  mutt_envlist_set("COLUMNS", columns, true);
446 
447  if (use_mailcap)
448  {
449  entry = mailcap_entry_new();
450  if (!mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_NO_FLAGS))
451  {
452  if (mode == MUTT_VA_REGULAR)
453  {
454  /* fallback to view as text */
455  mailcap_entry_free(&entry);
456  mutt_error(_("No matching mailcap entry found. Viewing as text."));
457  mode = MUTT_VA_AS_TEXT;
458  use_mailcap = false;
459  }
460  else
461  goto return_error;
462  }
463  }
464 
465  if (use_mailcap)
466  {
467  if (!entry->command)
468  {
469  mutt_error(_("MIME type not defined. Can't view attachment."));
470  goto return_error;
471  }
472  mutt_buffer_strcpy(cmd, entry->command);
473 
474  if (fp)
475  {
476  fname = mutt_str_strdup(a->filename);
477  mutt_file_sanitize_filename(fname, true);
478  }
479  else
480  fname = a->filename;
481 
482  mailcap_expand_filename(entry->nametemplate, fname, tmpfile);
483  /* send case: the file is already there; symlink to it */
484  if (!fp)
485  {
486  if (mutt_file_symlink(a->filename, mutt_b2s(tmpfile)) == -1)
487  {
488  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
489  goto return_error;
490  mutt_buffer_strcpy(tmpfile, a->filename);
491  }
492  else
493  unlink_tempfile = true;
494  }
495  /* recv case: we need to save the attachment to a file */
496  else
497  {
498  FREE(&fname);
499  if (mutt_save_attachment(fp, a, mutt_b2s(tmpfile), MUTT_SAVE_NO_FLAGS, NULL) == -1)
500  goto return_error;
501  mutt_file_chmod(mutt_b2s(tmpfile), S_IRUSR);
502  }
503 
504  use_pipe = mailcap_expand_command(a, mutt_b2s(tmpfile), type, cmd);
505  use_pager = entry->copiousoutput;
506  }
507 
508  if (use_pager)
509  {
510  if (fp && !use_mailcap && a->filename)
511  {
512  /* recv case */
513  mutt_buffer_strcpy(pagerfile, a->filename);
514  mutt_adv_mktemp(pagerfile);
515  }
516  else
517  mutt_buffer_mktemp(pagerfile);
518  }
519 
520  if (use_mailcap)
521  {
522  pid_t pid = 0;
523  int fd_temp = -1, fd_pager = -1;
524 
525  if (!use_pager)
526  mutt_endwin();
527 
528  if (use_pager || use_pipe)
529  {
530  if (use_pager && ((fd_pager = mutt_file_open(mutt_b2s(pagerfile),
531  O_CREAT | O_EXCL | O_WRONLY)) == -1))
532  {
533  mutt_perror("open");
534  goto return_error;
535  }
536  if (use_pipe && ((fd_temp = open(mutt_b2s(tmpfile), 0)) == -1))
537  {
538  if (fd_pager != -1)
539  close(fd_pager);
540  mutt_perror("open");
541  goto return_error;
542  }
543 
544  pid = filter_create_fd(mutt_b2s(cmd), NULL, NULL, NULL,
545  use_pipe ? fd_temp : -1, use_pager ? fd_pager : -1, -1);
546 
547  if (pid == -1)
548  {
549  if (fd_pager != -1)
550  close(fd_pager);
551 
552  if (fd_temp != -1)
553  close(fd_temp);
554 
555  mutt_error(_("Can't create filter"));
556  goto return_error;
557  }
558 
559  if (use_pager)
560  {
561  if (a->description)
562  {
563  snprintf(desc, sizeof(desc), _("---Command: %-20.20s Description: %s"),
564  mutt_b2s(cmd), a->description);
565  }
566  else
567  {
568  snprintf(desc, sizeof(desc), _("---Command: %-30.30s Attachment: %s"),
569  mutt_b2s(cmd), type);
570  }
571  filter_wait(pid);
572  }
573  else
574  {
575  if (wait_interactive_filter(pid) || (entry->needsterminal && C_WaitKey))
577  }
578 
579  if (fd_temp != -1)
580  close(fd_temp);
581  if (fd_pager != -1)
582  close(fd_pager);
583  }
584  else
585  {
586  /* interactive cmd */
587  int rv = mutt_system(mutt_b2s(cmd));
588  if (rv == -1)
589  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
590 
591  if ((rv != 0) || (entry->needsterminal && C_WaitKey))
593  }
594  }
595  else
596  {
597  /* Don't use mailcap; the attachment is viewed in the pager */
598 
599  if (mode == MUTT_VA_AS_TEXT)
600  {
601  /* just let me see the raw data */
602  if (fp)
603  {
604  /* Viewing from a received message.
605  *
606  * Don't use mutt_save_attachment() because we want to perform charset
607  * conversion since this will be displayed by the internal pager. */
608  struct State decode_state = { 0 };
609 
610  decode_state.fp_out = mutt_file_fopen(mutt_b2s(pagerfile), "w");
611  if (!decode_state.fp_out)
612  {
613  mutt_debug(LL_DEBUG1, "mutt_file_fopen(%s) errno=%d %s\n",
614  mutt_b2s(pagerfile), errno, strerror(errno));
615  mutt_perror(mutt_b2s(pagerfile));
616  goto return_error;
617  }
618  decode_state.fp_in = fp;
619  decode_state.flags = MUTT_CHARCONV;
620  mutt_decode_attachment(a, &decode_state);
621  if (mutt_file_fclose(&decode_state.fp_out) == EOF)
622  {
623  mutt_debug(LL_DEBUG1, "fclose(%s) errno=%d %s\n", mutt_b2s(pagerfile),
624  errno, strerror(errno));
625  }
626  }
627  else
628  {
629  /* in compose mode, just copy the file. we can't use
630  * mutt_decode_attachment() since it assumes the content-encoding has
631  * already been applied */
632  if (mutt_save_attachment(fp, a, mutt_b2s(pagerfile), MUTT_SAVE_NO_FLAGS, NULL))
633  goto return_error;
634  }
635  }
636  else
637  {
638  /* Use built-in handler */
639  OptViewAttach = true; /* disable the "use 'v' to view this part"
640  * message in case of error */
642  {
643  OptViewAttach = false;
644  goto return_error;
645  }
646  OptViewAttach = false;
647  }
648 
649  if (a->description)
650  mutt_str_strfcpy(desc, a->description, sizeof(desc));
651  else if (a->filename)
652  snprintf(desc, sizeof(desc), _("---Attachment: %s: %s"), a->filename, type);
653  else
654  snprintf(desc, sizeof(desc), _("---Attachment: %s"), type);
655  }
656 
657  /* We only reach this point if there have been no errors */
658 
659  if (use_pager)
660  {
661  struct Pager info = { 0 };
662  info.fp = fp;
663  info.body = a;
664  info.ctx = Context;
665  info.actx = actx;
666  info.email = e;
667 
668  rc = mutt_do_pager(desc, mutt_b2s(pagerfile),
670  &info);
671  mutt_buffer_reset(pagerfile);
672  }
673  else
674  rc = 0;
675 
676 return_error:
677 
678  if (!entry || !entry->xneomuttkeep)
679  {
680  if (fp && !mutt_buffer_is_empty(tmpfile))
681  {
682  /* add temporary file to TempAttachmentsList to be deleted on timeout hook */
684  }
685  else if (unlink_tempfile)
686  {
687  unlink(mutt_b2s(tmpfile));
688  }
689  }
690 
691  mailcap_entry_free(&entry);
692 
693  if (!mutt_buffer_is_empty(pagerfile))
694  mutt_file_unlink(mutt_b2s(pagerfile));
695 
696  mutt_buffer_pool_release(&tmpfile);
697  mutt_buffer_pool_release(&pagerfile);
699  mutt_envlist_unset("COLUMNS");
700 
701  return rc;
702 }
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:1794
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:81
#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
#define WithCrypto
Definition: lib.h:163
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
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:125
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:195
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:830
An email being displayed.
Definition: pager.h:65
View using default method.
Definition: mutt_attach.h:42
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:146
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:378
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:153
static int wait_interactive_filter(pid_t pid)
Wait after an interactive filter.
Definition: mutt_attach.c:383
int mutt_file_chmod(const char *path, mode_t mode)
Set permissions of a file.
Definition: file.c:1036
void mutt_add_temp_attachment(const char *filename)
Add file to list of temporary attachments.
Definition: mutt_attach.c:1222
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:618
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:58
#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:93
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:257
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:547
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:961
struct AttachCtx * actx
Attachment information.
Definition: pager.h:71
char * data
Pointer to data.
Definition: buffer.h:35
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:773
char * description
content-description
Definition: body.h:40
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
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:580
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:522
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:666
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
pid_t filter_create_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:61
#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:410
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:56
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:299
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
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
bool needsterminal
endwin() and system
Definition: mailcap.h:48
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
#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 713 of file mutt_attach.c.

714 {
715  pid_t pid;
716  int out = -1;
717  int rc = 0;
718 
719  if (outfile && *outfile)
720  {
721  out = mutt_file_open(outfile, O_CREAT | O_EXCL | O_WRONLY);
722  if (out < 0)
723  {
724  mutt_perror("open");
725  return 0;
726  }
727  }
728 
729  mutt_endwin();
730 
731  if (fp)
732  {
733  /* recv case */
734 
735  struct State s = { 0 };
736 
737  /* perform charset conversion on text attachments when piping */
738  s.flags = MUTT_CHARCONV;
739 
740  if (outfile && *outfile)
741  pid = filter_create_fd(path, &s.fp_out, NULL, NULL, -1, out, -1);
742  else
743  pid = filter_create(path, &s.fp_out, NULL, NULL);
744 
745  if (pid < 0)
746  {
747  mutt_perror(_("Can't create filter"));
748  goto bail;
749  }
750 
751  s.fp_in = fp;
752  mutt_decode_attachment(b, &s);
754  }
755  else
756  {
757  /* send case */
758  FILE *fp_in = fopen(b->filename, "r");
759  if (!fp_in)
760  {
761  mutt_perror("fopen");
762  if (outfile && *outfile)
763  {
764  close(out);
765  unlink(outfile);
766  }
767  return 0;
768  }
769 
770  FILE *fp_out = NULL;
771  if (outfile && *outfile)
772  pid = filter_create_fd(path, &fp_out, NULL, NULL, -1, out, -1);
773  else
774  pid = filter_create(path, &fp_out, NULL, NULL);
775 
776  if (pid < 0)
777  {
778  mutt_perror(_("Can't create filter"));
779  mutt_file_fclose(&fp_in);
780  goto bail;
781  }
782 
783  mutt_file_copy_stream(fp_in, fp_out);
784  mutt_file_fclose(&fp_out);
785  mutt_file_fclose(&fp_in);
786  }
787 
788  rc = 1;
789 
790 bail:
791 
792  if (outfile && *outfile)
793  close(out);
794 
795  /* check for error exit from child process */
796  if (filter_wait(pid) != 0)
797  rc = 0;
798 
799  if ((rc == 0) || C_WaitKey)
801  return rc;
802 }
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1794
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
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
#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:153
WHERE bool C_WaitKey
Config: Prompt to press a key after running external commands.
Definition: globals.h:257
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:547
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:580
int mutt_file_open(const char *path, int flags)
Open a file.
Definition: file.c:522
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
pid_t filter_create_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:61
Keep track when processing files.
Definition: state.h:44
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
+ 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 810 of file mutt_attach.c.

811 {
812  if (opt == MUTT_SAVE_APPEND)
813  return fopen(path, "a");
814  if (opt == MUTT_SAVE_OVERWRITE)
815  return fopen(path, "w");
816 
817  return mutt_file_fopen(path, "w");
818 }
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:588
+ 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 830 of file mutt_attach.c.

832 {
833  if (!m)
834  return -1;
835 
836  if (fp)
837  {
838  /* recv mode */
839 
840  if (e && m->email && (m->encoding != ENC_BASE64) &&
842  {
843  /* message type attachments are written to mail folders. */
844 
845  char buf[8192];
846  struct Message *msg = NULL;
847  CopyHeaderFlags chflags = CH_NO_FLAGS;
848  int rc = -1;
849 
850  struct Email *e_new = m->email;
851  e_new->msgno = e->msgno; /* required for MH/maildir */
852  e_new->read = true;
853 
854  if (fseeko(fp, m->offset, SEEK_SET) < 0)
855  return -1;
856  if (!fgets(buf, sizeof(buf), fp))
857  return -1;
858  struct Mailbox *m_att = mx_path_resolve(path);
859  struct Context *ctx = mx_mbox_open(m_att, MUTT_APPEND | MUTT_QUIET);
860  if (!ctx)
861  {
862  mailbox_free(&m_att);
863  return -1;
864  }
865  msg = mx_msg_open_new(ctx->mailbox, e_new,
866  is_from(buf, NULL, 0, NULL) ? MUTT_MSG_NO_FLAGS : MUTT_ADD_FROM);
867  if (!msg)
868  {
869  mx_mbox_close(&ctx);
870  return -1;
871  }
872  if ((ctx->mailbox->type == MUTT_MBOX) || (ctx->mailbox->type == MUTT_MMDF))
873  chflags = CH_FROM | CH_UPDATE_LEN;
874  chflags |= ((ctx->mailbox->type == MUTT_MAILDIR) ? CH_NOSTATUS : CH_UPDATE);
875  if ((mutt_copy_message_fp(msg->fp, fp, e_new, MUTT_CM_NO_FLAGS, chflags, 0) == 0) &&
876  (mx_msg_commit(ctx->mailbox, msg) == 0))
877  {
878  rc = 0;
879  }
880  else
881  {
882  rc = -1;
883  }
884 
885  mx_msg_close(ctx->mailbox, &msg);
886  mx_mbox_close(&ctx);
887  return rc;
888  }
889  else
890  {
891  /* In recv mode, extract from folder and decode */
892 
893  struct State s = { 0 };
894 
895  s.fp_out = save_attachment_open(path, opt);
896  if (!s.fp_out)
897  {
898  mutt_perror("fopen");
899  return -1;
900  }
901  fseeko((s.fp_in = fp), m->offset, SEEK_SET);
902  mutt_decode_attachment(m, &s);
903 
904  if (mutt_file_fsync_close(&s.fp_out) != 0)
905  {
906  mutt_perror("fclose");
907  return -1;
908  }
909  }
910  }
911  else
912  {
913  if (!m->filename)
914  return -1;
915 
916  /* In send mode, just copy file */
917 
918  FILE *fp_old = fopen(m->filename, "r");
919  if (!fp_old)
920  {
921  mutt_perror("fopen");
922  return -1;
923  }
924 
925  FILE *fp_new = save_attachment_open(path, opt);
926  if (!fp_new)
927  {
928  mutt_perror("fopen");
929  mutt_file_fclose(&fp_old);
930  return -1;
931  }
932 
933  if (mutt_file_copy_stream(fp_old, fp_new) == -1)
934  {
935  mutt_error(_("Write fault"));
936  mutt_file_fclose(&fp_old);
937  mutt_file_fclose(&fp_new);
938  return -1;
939  }
940  mutt_file_fclose(&fp_old);
941  if (mutt_file_fsync_close(&fp_new) != 0)
942  {
943  mutt_error(_("Write fault"));
944  return -1;
945  }
946  }
947 
948  return 0;
949 }
#define MUTT_APPEND
Open mailbox for appending messages.
Definition: mx.h:54
#define MUTT_MSG_NO_FLAGS
No flags are set.
Definition: mx.h:65
The "current" mailbox.
Definition: context.h:37
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1794
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
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:593
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
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:255
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:1171
bool read
Email is read.
Definition: email.h:51
struct Mailbox * mailbox
Definition: context.h:51
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:60
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
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:1036
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:83
A mailbox.
Definition: mailbox.h:81
#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:56
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:271
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:1150
Quoted-printable text.
Definition: mime.h:51
FILE * fp
pointer to the message data
Definition: mx.h:85
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1655
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:810
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:66
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 961 of file mutt_attach.c.

963 {
964  struct State s = { 0 };
965  unsigned int saved_encoding = 0;
966  struct Body *saved_parts = NULL;
967  struct Email *e_saved = NULL;
968  int rc = 0;
969 
970  s.flags = displaying;
971 
972  if (opt == MUTT_SAVE_APPEND)
973  s.fp_out = fopen(path, "a");
974  else if (opt == MUTT_SAVE_OVERWRITE)
975  s.fp_out = fopen(path, "w");
976  else
977  s.fp_out = mutt_file_fopen(path, "w");
978 
979  if (!s.fp_out)
980  {
981  mutt_perror("fopen");
982  return -1;
983  }
984 
985  if (!fp)
986  {
987  /* When called from the compose menu, the attachment isn't parsed,
988  * so we need to do it here. */
989  struct stat st;
990 
991  if (stat(m->filename, &st) == -1)
992  {
993  mutt_perror("stat");
995  return -1;
996  }
997 
998  s.fp_in = fopen(m->filename, "r");
999  if (!s.fp_in)
1000  {
1001  mutt_perror("fopen");
1002  return -1;
1003  }
1004 
1005  saved_encoding = m->encoding;
1006  if (!is_multipart(m))
1007  m->encoding = ENC_8BIT;
1008 
1009  m->length = st.st_size;
1010  m->offset = 0;
1011  saved_parts = m->parts;
1012  e_saved = m->email;
1013  mutt_parse_part(s.fp_in, m);
1014 
1015  if (m->noconv || is_multipart(m))
1016  s.flags |= MUTT_CHARCONV;
1017  }
1018  else
1019  {
1020  s.fp_in = fp;
1021  s.flags |= MUTT_CHARCONV;
1022  }
1023 
1024  mutt_body_handler(m, &s);
1025 
1026  if (mutt_file_fsync_close(&s.fp_out) != 0)
1027  {
1028  mutt_perror("fclose");
1029  rc = -1;
1030  }
1031  if (!fp)
1032  {
1033  m->length = 0;
1034  m->encoding = saved_encoding;
1035  if (saved_parts)
1036  {
1037  email_free(&m->email);
1038  m->parts = saved_parts;
1039  m->email = e_saved;
1040  }
1041  mutt_file_fclose(&s.fp_in);
1042  }
1043 
1044  return rc;
1045 }
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:169
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:153
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:1550
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
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 1060 of file mutt_attach.c.

1061 {
1062  char type[256];
1063  pid_t pid;
1064  FILE *fp_in = NULL, *fp_out = NULL;
1065  bool unlink_newfile = false;
1066  struct Buffer *newfile = mutt_buffer_pool_get();
1067  struct Buffer *cmd = mutt_buffer_pool_get();
1068 
1069  int rc = 0;
1070 
1071  snprintf(type, sizeof(type), "%s/%s", TYPE(a), a->subtype);
1072 
1073  if (mailcap_lookup(a, type, sizeof(type), NULL, MUTT_MC_PRINT))
1074  {
1075  int piped = false;
1076 
1077  mutt_debug(LL_DEBUG2, "Using mailcap\n");
1078 
1079  struct MailcapEntry *entry = mailcap_entry_new();
1080  mailcap_lookup(a, type, sizeof(type), entry, MUTT_MC_PRINT);
1081  mailcap_expand_filename(entry->nametemplate, a->filename, newfile);
1082  /* send mode: symlink from existing file to the newfile */
1083  if (!fp)
1084  {
1085  if (mutt_file_symlink(a->filename, mutt_b2s(newfile)) == -1)
1086  {
1087  if (mutt_yesorno(_("Can't match 'nametemplate', continue?"), MUTT_YES) != MUTT_YES)
1088  goto mailcap_cleanup;
1089  mutt_buffer_strcpy(newfile, a->filename);
1090  }
1091  else
1092  unlink_newfile = true;
1093  }
1094  /* in recv mode, save file to newfile first */
1095  else
1096  {
1097  if (mutt_save_attachment(fp, a, mutt_b2s(newfile), 0, NULL) == -1)
1098  goto mailcap_cleanup;
1099  }
1100 
1101  mutt_buffer_strcpy(cmd, entry->printcommand);
1102  piped = mailcap_expand_command(a, mutt_b2s(newfile), type, cmd);
1103 
1104  mutt_endwin();
1105 
1106  /* interactive program */
1107  if (piped)
1108  {
1109  fp_in = fopen(mutt_b2s(newfile), "r");
1110  if (!fp_in)
1111  {
1112  mutt_perror("fopen");
1113  mailcap_entry_free(&entry);
1114  goto mailcap_cleanup;
1115  }
1116 
1117  pid = filter_create(mutt_b2s(cmd), &fp_out, NULL, NULL);
1118  if (pid < 0)
1119  {
1120  mutt_perror(_("Can't create filter"));
1121  mailcap_entry_free(&entry);
1122  mutt_file_fclose(&fp_in);
1123  goto mailcap_cleanup;
1124  }
1125  mutt_file_copy_stream(fp_in, fp_out);
1126  mutt_file_fclose(&fp_out);
1127  mutt_file_fclose(&fp_in);
1128  if (filter_wait(pid) || C_WaitKey)
1130  }
1131  else
1132  {
1133  int rc2 = mutt_system(mutt_b2s(cmd));
1134  if (rc2 == -1)
1135  mutt_debug(LL_DEBUG1, "Error running \"%s\"", cmd->data);
1136 
1137  if ((rc2 != 0) || C_WaitKey)
1139  }
1140 
1141  rc = 1;
1142 
1143  mailcap_cleanup:
1144  if (fp)
1145  mutt_file_unlink(mutt_b2s(newfile));
1146  else if (unlink_newfile)
1147  unlink(mutt_b2s(newfile));
1148 
1149  mailcap_entry_free(&entry);
1150  goto out;
1151  }
1152 
1153  if ((mutt_str_strcasecmp("text/plain", type) == 0) ||
1154  (mutt_str_strcasecmp("application/postscript", type) == 0))
1155  {
1156  rc = (mutt_pipe_attachment(fp, a, NONULL(C_PrintCommand), NULL));
1157  goto out;
1158  }
1159  else if (mutt_can_decode(a))
1160  {
1161  /* decode and print */
1162 
1163  fp_in = NULL;
1164  fp_out = NULL;
1165 
1166  mutt_buffer_mktemp(newfile);
1167  if (mutt_decode_save_attachment(fp, a, mutt_b2s(newfile), MUTT_PRINTING, 0) == 0)
1168  {
1169  mutt_debug(LL_DEBUG2, "successfully decoded %s type attachment to %s\n",
1170  type, mutt_b2s(newfile));
1171 
1172  fp_in = fopen(mutt_b2s(newfile), "r");
1173  if (!fp_in)
1174  {
1175  mutt_perror("fopen");
1176  goto decode_cleanup;
1177  }
1178 
1179  mutt_debug(LL_DEBUG2, "successfully opened %s read-only\n", mutt_b2s(newfile));
1180 
1181  mutt_endwin();
1182  pid = filter_create(NONULL(C_PrintCommand), &fp_out, NULL, NULL);
1183  if (pid < 0)
1184  {
1185  mutt_perror(_("Can't create filter"));
1186  goto decode_cleanup;
1187  }
1188 
1189  mutt_debug(LL_DEBUG2, "Filter created\n");
1190 
1191  mutt_file_copy_stream(fp_in, fp_out);
1192 
1193  mutt_file_fclose(&fp_out);
1194  mutt_file_fclose(&fp_in);
1195 
1196  if ((filter_wait(pid) != 0) || C_WaitKey)
1198  rc = 1;
1199  }
1200  decode_cleanup:
1201  mutt_file_fclose(&fp_in);
1202  mutt_file_fclose(&fp_out);
1203  mutt_file_unlink(mutt_b2s(newfile));
1204  }
1205  else
1206  {
1207  mutt_error(_("I don't know how to print that"));
1208  rc = 0;
1209  }
1210 
1211 out:
1212  mutt_buffer_pool_release(&newfile);
1214 
1215  return rc;
1216 }
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:81
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
pid_t filter_create(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err)
Set up filter program.
Definition: filter.c:206
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:195
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:830
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:378
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:153
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:257
void mutt_endwin(void)
Shutdown curses/slang.
Definition: curs_lib.c:547
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:961
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1753
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:580
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:271
#define mutt_error(...)
Definition: logging.h:84
WHERE char * C_PrintCommand
Config: External command to print a message.
Definition: globals.h:137
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_file_symlink(const char *oldpath, const char *newpath)
Create a symlink.
Definition: file.c:299
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
int mutt_pipe_attachment(FILE *fp, struct Body *b, const char *path, char *outfile)
Pipe an attachment to a command.
Definition: mutt_attach.c:713
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_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 1222 of file mutt_attach.c.

1223 {
1224  mutt_list_insert_tail(&TempAttachmentsList, mutt_str_strdup(filename));
1225 }
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 1230 of file mutt_attach.c.

1231 {
1232  struct ListNode *np = NULL;
1233 
1234  STAILQ_FOREACH(np, &TempAttachmentsList, entries)
1235  {
1236  mutt_file_chmod_add(np->data, S_IWUSR);
1237  mutt_file_unlink(np->data);
1238  }
1239 
1240  mutt_list_free(&TempAttachmentsList);
1241 }
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:195
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:1061
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: