NeoMutt  2023-05-17-33-gce4425
Teaching an old dog new tricks
DOXYGEN
postpone.c File Reference

Postponed Email Selection Dialog. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "mutt.h"
#include "lib.h"
#include "ncrypt/lib.h"
#include "send/lib.h"
#include "globals.h"
#include "handler.h"
#include "mutt_logging.h"
#include "mutt_thread.h"
#include "muttlib.h"
#include "mx.h"
#include "protos.h"
#include "rfc3676.h"
#include "imap/lib.h"
+ Include dependency graph for postpone.c:

Go to the source code of this file.

Functions

int mutt_num_postponed (struct Mailbox *m, bool force)
 Return the number of postponed messages. More...
 
void mutt_update_num_postponed (void)
 Force the update of the number of postponed messages. More...
 
static void hardclose (struct Mailbox *m)
 Try hard to close a mailbox. More...
 
SecurityFlags mutt_parse_crypt_hdr (const char *p, bool set_empty_signas, SecurityFlags crypt_app)
 Parse a crypto header string. More...
 
static int create_tmp_files_for_attachments (FILE *fp_body, struct Buffer *file, struct Email *e_new, struct Body *body, struct Envelope *protected_headers)
 Create temporary files for all attachments. More...
 
int mutt_prepare_template (FILE *fp, struct Mailbox *m, struct Email *e_new, struct Email *e, bool resend)
 Prepare a message template. More...
 
int mutt_get_postponed (struct Mailbox *m_cur, struct Email *hdr, struct Email **cur, struct Buffer *fcc)
 Recall a postponed message. More...
 

Variables

short PostCount = 0
 Number of postponed (draft) emails. More...
 
static bool UpdateNumPostponed = false
 When true, force a recount of the postponed (draft) emails. More...
 

Detailed Description

Postponed Email Selection Dialog.

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

Function Documentation

◆ mutt_num_postponed()

int mutt_num_postponed ( struct Mailbox m,
bool  force 
)

Return the number of postponed messages.

Parameters
mcurrently selected mailbox
force
  • false Use a cached value if costly to get a fresh count (IMAP)
  • true Force check
Return values
numPostponed messages

Definition at line 70 of file postpone.c.

71{
72 struct stat st = { 0 };
73
74 static time_t LastModify = 0;
75 static char *OldPostponed = NULL;
76
78 {
79 UpdateNumPostponed = false;
80 force = true;
81 }
82
83 const char *const c_postponed = cs_subset_string(NeoMutt->sub, "postponed");
84 if (!mutt_str_equal(c_postponed, OldPostponed))
85 {
86 FREE(&OldPostponed);
87 OldPostponed = mutt_str_dup(c_postponed);
88 LastModify = 0;
89 force = true;
90 }
91
92 if (!c_postponed)
93 return 0;
94
95 // We currently are in the `$postponed` mailbox so just pick the current status
96 if (m && mutt_str_equal(c_postponed, m->realpath))
97 {
99 return PostCount;
100 }
101
102#ifdef USE_IMAP
103 /* LastModify is useless for IMAP */
104 if (imap_path_probe(c_postponed, NULL) == MUTT_IMAP)
105 {
106 if (force)
107 {
108 short newpc;
109
110 newpc = imap_path_status(c_postponed, false);
111 if (newpc >= 0)
112 {
113 PostCount = newpc;
114 mutt_debug(LL_DEBUG3, "%d postponed IMAP messages found\n", PostCount);
115 }
116 else
117 {
118 mutt_debug(LL_DEBUG3, "using old IMAP postponed count\n");
119 }
120 }
121 return PostCount;
122 }
123#endif
124
125 if (stat(c_postponed, &st) == -1)
126 {
127 PostCount = 0;
128 LastModify = 0;
129 return 0;
130 }
131
132 if (S_ISDIR(st.st_mode))
133 {
134 /* if we have a maildir mailbox, we need to stat the "new" dir */
135 struct Buffer *buf = buf_pool_get();
136
137 buf_printf(buf, "%s/new", c_postponed);
138 if ((access(buf_string(buf), F_OK) == 0) && (stat(buf_string(buf), &st) == -1))
139 {
140 PostCount = 0;
141 LastModify = 0;
142 buf_pool_release(&buf);
143 return 0;
144 }
145 buf_pool_release(&buf);
146 }
147
148 if (LastModify < st.st_mtime)
149 {
150#ifdef USE_NNTP
151 int optnews = OptNews;
152#endif
153 LastModify = st.st_mtime;
154
155 if (access(c_postponed, R_OK | F_OK) != 0)
156 return PostCount = 0;
157#ifdef USE_NNTP
158 if (optnews)
159 OptNews = false;
160#endif
161 struct Mailbox *m_post = mx_path_resolve(c_postponed);
162 if (mx_mbox_open(m_post, MUTT_NOSORT | MUTT_QUIET))
163 {
164 PostCount = m_post->msg_count;
165 mx_fastclose_mailbox(m_post, false);
166 }
167 else
168 {
169 PostCount = 0;
170 }
171 mailbox_free(&m_post);
172
173#ifdef USE_NNTP
174 if (optnews)
175 OptNews = true;
176#endif
177 }
178
179 return PostCount;
180}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:171
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:79
#define mutt_debug(LEVEL,...)
Definition: logging2.h:84
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2254
int imap_path_status(const char *path, bool queue)
Refresh the number of total and new messages.
Definition: imap.c:1073
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:42
void mailbox_free(struct Mailbox **ptr)
Free a Mailbox.
Definition: mailbox.c:88
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
#define FREE(x)
Definition: memory.h:43
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
void mx_fastclose_mailbox(struct Mailbox *m, bool keep_account)
Free up memory associated with the Mailbox.
Definition: mx.c:433
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:307
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1694
#define MUTT_QUIET
Do not print any messages.
Definition: mxapi.h:65
#define MUTT_NOSORT
Do not sort the mailbox after opening it.
Definition: mxapi.h:62
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:106
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:119
short PostCount
Number of postponed (draft) emails.
Definition: postpone.c:58
static bool UpdateNumPostponed
When true, force a recount of the postponed (draft) emails.
Definition: postpone.c:60
String manipulation buffer.
Definition: buffer.h:34
A mailbox.
Definition: mailbox.h:79
char * realpath
Used for duplicate detection, context comparison, and the sidebar.
Definition: mailbox.h:81
int msg_count
Total number of messages.
Definition: mailbox.h:88
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:93
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_update_num_postponed()

void mutt_update_num_postponed ( void  )

Force the update of the number of postponed messages.

Definition at line 185 of file postpone.c.

186{
187 UpdateNumPostponed = true;
188}
+ Here is the caller graph for this function:

◆ hardclose()

static void hardclose ( struct Mailbox m)
static

Try hard to close a mailbox.

Parameters
mMailbox to close

Definition at line 194 of file postpone.c.

195{
196 /* messages might have been marked for deletion.
197 * try once more on reopen before giving up. */
198 enum MxStatus rc = mx_mbox_close(m);
199 if (rc != MX_STATUS_ERROR && rc != MX_STATUS_OK)
200 rc = mx_mbox_close(m);
201 if (rc != MX_STATUS_OK)
202 mx_fastclose_mailbox(m, false);
203}
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:618
MxStatus
Return values from mbox_check(), mbox_check_stats(), mbox_snc(), and mbox_close()
Definition: mxapi.h:84
@ MX_STATUS_ERROR
An error occurred.
Definition: mxapi.h:85
@ MX_STATUS_OK
No changes.
Definition: mxapi.h:86
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_parse_crypt_hdr()

SecurityFlags mutt_parse_crypt_hdr ( const char *  p,
bool  set_empty_signas,
SecurityFlags  crypt_app 
)

Parse a crypto header string.

Parameters
pHeader string to parse
set_empty_signasAllow an empty "Sign as"
crypt_appApp, e.g. APPLICATION_PGP
Return values
numSecurityFlags, see SecurityFlags

Definition at line 212 of file postpone.c.

213{
214 char smime_cryptalg[1024] = { 0 };
215 char sign_as[1024] = { 0 };
216 char *q = NULL;
218
219 if (!WithCrypto)
220 return SEC_NO_FLAGS;
221
223 for (; p[0] != '\0'; p++)
224 {
225 switch (p[0])
226 {
227 case 'c':
228 case 'C':
229 q = smime_cryptalg;
230
231 if (p[1] == '<')
232 {
233 for (p += 2; (p[0] != '\0') && (p[0] != '>') &&
234 (q < (smime_cryptalg + sizeof(smime_cryptalg) - 1));
235 *q++ = *p++)
236 {
237 }
238
239 if (p[0] != '>')
240 {
241 mutt_error(_("Illegal S/MIME header"));
242 return SEC_NO_FLAGS;
243 }
244 }
245
246 *q = '\0';
247 break;
248
249 case 'e':
250 case 'E':
251 flags |= SEC_ENCRYPT;
252 break;
253
254 case 'i':
255 case 'I':
256 flags |= SEC_INLINE;
257 break;
258
259 /* This used to be the micalg parameter.
260 *
261 * It's no longer needed, so we just skip the parameter in order
262 * to be able to recall old messages. */
263 case 'm':
264 case 'M':
265 if (p[1] != '<')
266 break;
267
268 for (p += 2; (p[0] != '\0') && (p[0] != '>'); p++)
269 ; // do nothing
270
271 if (p[0] != '>')
272 {
273 mutt_error(_("Illegal crypto header"));
274 return SEC_NO_FLAGS;
275 }
276 break;
277
278 case 'o':
279 case 'O':
280 flags |= SEC_OPPENCRYPT;
281 break;
282
283 case 'a':
284 case 'A':
285#ifdef USE_AUTOCRYPT
286 flags |= SEC_AUTOCRYPT;
287#endif
288 break;
289
290 case 'z':
291 case 'Z':
292#ifdef USE_AUTOCRYPT
293 flags |= SEC_AUTOCRYPT_OVERRIDE;
294#endif
295 break;
296
297 case 's':
298 case 'S':
299 flags |= SEC_SIGN;
300 q = sign_as;
301
302 if (p[1] == '<')
303 {
304 for (p += 2;
305 (p[0] != '\0') && (*p != '>') && (q < (sign_as + sizeof(sign_as) - 1));
306 *q++ = *p++)
307 {
308 }
309
310 if (p[0] != '>')
311 {
312 mutt_error(_("Illegal crypto header"));
313 return SEC_NO_FLAGS;
314 }
315 }
316
317 q[0] = '\0';
318 break;
319
320 default:
321 mutt_error(_("Illegal crypto header"));
322 return SEC_NO_FLAGS;
323 }
324 }
325
326 /* the cryptalg field must not be empty */
327 if (((WithCrypto & APPLICATION_SMIME) != 0) && *smime_cryptalg)
328 {
329 struct Buffer errmsg = buf_make(0);
330 int rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
331 smime_cryptalg, &errmsg);
332
333 if ((CSR_RESULT(rc) != CSR_SUCCESS) && !buf_is_empty(&errmsg))
334 mutt_error("%s", buf_string(&errmsg));
335
336 buf_dealloc(&errmsg);
337 }
338
339 /* Set {Smime,Pgp}SignAs, if desired. */
340
341 if (((WithCrypto & APPLICATION_PGP) != 0) && (crypt_app == APPLICATION_PGP) &&
342 (flags & SEC_SIGN) && (set_empty_signas || *sign_as))
343 {
344 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", sign_as, NULL);
345 }
346
347 if (((WithCrypto & APPLICATION_SMIME) != 0) && (crypt_app == APPLICATION_SMIME) &&
348 (flags & SEC_SIGN) && (set_empty_signas || *sign_as))
349 {
350 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", sign_as, NULL);
351 }
352
353 return flags;
354}
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:352
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:301
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:68
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
#define mutt_error(...)
Definition: logging2.h:87
#define _(a)
Definition: message.h:28
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:680
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:85
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:87
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:76
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:77
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:88
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:413
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ create_tmp_files_for_attachments()

static int create_tmp_files_for_attachments ( FILE *  fp_body,
struct Buffer file,
struct Email e_new,
struct Body body,
struct Envelope protected_headers 
)
static

Create temporary files for all attachments.

Parameters
fp_bodyfile containing the template
fileAllocated buffer for temporary file name
e_newThe new email template header
bodyFirst body in email or group
protected_headersMIME headers for email template
Return values
0Success
-1Error

Definition at line 366 of file postpone.c.

369{
370 struct Body *b = NULL;
371 struct State state = { 0 };
372
373 state.fp_in = fp_body;
374
375 for (b = body; b; b = b->next)
376 {
377 if (b->type == TYPE_MULTIPART)
378 {
379 if (create_tmp_files_for_attachments(fp_body, file, e_new, b->parts, protected_headers) < 0)
380 {
381 return -1;
382 }
383 }
384 else
385 {
386 buf_reset(file);
387 if (b->filename)
388 {
389 buf_strcpy(file, b->filename);
391 }
392 else
393 {
394 /* avoid Content-Disposition: header with temporary filename */
395 b->use_disp = false;
396 }
397
398 /* set up state flags */
399
400 state.flags = 0;
401
402 if (b->type == TYPE_TEXT)
403 {
404 if (mutt_istr_equal("yes", mutt_param_get(&b->parameter, "x-mutt-noconv")))
405 {
406 b->noconv = true;
407 }
408 else
409 {
410 state.flags |= STATE_CHARCONV;
411 b->noconv = false;
412 }
413
414 mutt_param_delete(&b->parameter, "x-mutt-noconv");
415 }
416
417 mutt_adv_mktemp(file);
418 state.fp_out = mutt_file_fopen(buf_string(file), "w");
419 if (!state.fp_out)
420 return -1;
421
422 SecurityFlags sec_type = SEC_NO_FLAGS;
423 if (((WithCrypto & APPLICATION_PGP) != 0) && sec_type == SEC_NO_FLAGS)
424 sec_type = mutt_is_application_pgp(b);
425 if (((WithCrypto & APPLICATION_SMIME) != 0) && sec_type == SEC_NO_FLAGS)
426 sec_type = mutt_is_application_smime(b);
427 if (sec_type & (SEC_ENCRYPT | SEC_SIGN))
428 {
429 if (sec_type & SEC_ENCRYPT)
430 {
431 if (!crypt_valid_passphrase(sec_type))
432 return -1;
433 if (sec_type & APPLICATION_SMIME)
434 crypt_smime_getkeys(e_new->env);
435 mutt_message(_("Decrypting message..."));
436 }
437
438 if (mutt_body_handler(b, &state) < 0)
439 {
440 mutt_error(_("Decryption failed"));
441 return -1;
442 }
443
444 /* Is this the first body part? Then save the headers. */
445 if ((b == body) && !protected_headers)
446 {
447 protected_headers = b->mime_headers;
448 b->mime_headers = NULL;
449 }
450
451 e_new->security |= sec_type;
452 b->type = TYPE_TEXT;
453 mutt_str_replace(&b->subtype, "plain");
454 if (sec_type & APPLICATION_PGP)
455 mutt_param_delete(&b->parameter, "x-action");
456 }
457 else
458 {
459 mutt_decode_attachment(b, &state);
460 }
461
462 if (mutt_file_fclose(&state.fp_out) != 0)
463 return -1;
464
466 b->unlink = true;
467
469
471 if (b->email)
472 b->email->body = NULL; /* avoid dangling pointer */
473 }
474 }
475
476 return 0;
477}
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:86
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:370
SecurityFlags mutt_is_application_pgp(struct Body *b)
Does the message use PGP?
Definition: crypt.c:538
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:599
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
void crypt_smime_getkeys(struct Envelope *env)
Wrapper for CryptModuleSpecs::smime_getkeys()
Definition: cryptglue.c:455
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:150
#define mutt_message(...)
Definition: logging2.h:86
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition: handler.c:1618
void mutt_decode_attachment(struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1892
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
#define STATE_CHARCONV
Do character set conversions.
Definition: state.h:36
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:327
void mutt_adv_mktemp(struct Buffer *buf)
Create a temporary file.
Definition: muttlib.c:85
char * mutt_param_get(const struct ParameterList *pl, const char *s)
Find a matching Parameter.
Definition: parameter.c:84
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
static int create_tmp_files_for_attachments(FILE *fp_body, struct Buffer *file, struct Email *e_new, struct Body *body, struct Envelope *protected_headers)
Create temporary files for all attachments.
Definition: postpone.c:366
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:404
The body of an email.
Definition: body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool noconv
Don't do character set conversion.
Definition: body.h:46
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
struct Email * email
header information for message/rfc822
Definition: body.h:73
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
struct Envelope * env
Envelope information.
Definition: email.h:66
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
struct Body * body
List of MIME parts.
Definition: email.h:67
Keep track when processing files.
Definition: state.h:47
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:51
FILE * fp_out
File to write to.
Definition: state.h:49
FILE * fp_in
File to read from.
Definition: state.h:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_prepare_template()

int mutt_prepare_template ( FILE *  fp,
struct Mailbox m,
struct Email e_new,
struct Email e,
bool  resend 
)

Prepare a message template.

Parameters
fpIf not NULL, file containing the template
mIf fp is NULL, the Mailbox containing the header with the template
e_newThe template is read into this Header
eEmail to recall/resend
resendSet if resending (as opposed to recalling a postponed msg) Resent messages enable header weeding, and also discard any existing Message-ID and Mail-Followup-To
Return values
0Success
-1Error

Definition at line 491 of file postpone.c.

493{
494 struct Message *msg = NULL;
495 struct Body *b = NULL;
496 FILE *fp_body = NULL;
497 int rc = -1;
498 struct Envelope *protected_headers = NULL;
499 struct Buffer *file = NULL;
500
501 if (!fp && !(msg = mx_msg_open(m, e)))
502 return -1;
503
504 if (!fp)
505 fp = msg->fp;
506
507 fp_body = fp;
508
509 /* parse the message header and MIME structure */
510
511 if (!mutt_file_seek(fp, e->offset, SEEK_SET))
512 {
513 return -1;
514 }
515 e_new->offset = e->offset;
516 /* enable header weeding for resent messages */
517 e_new->env = mutt_rfc822_read_header(fp, e_new, true, resend);
518 e_new->body->length = e->body->length;
519 mutt_parse_part(fp, e_new->body);
520
521 /* If resending a message, don't keep message_id or mail_followup_to.
522 * Otherwise, we are resuming a postponed message, and want to keep those
523 * headers if they exist. */
524 if (resend)
525 {
526 FREE(&e_new->env->message_id);
528 }
529
530 SecurityFlags sec_type = SEC_NO_FLAGS;
531 if (((WithCrypto & APPLICATION_PGP) != 0) && sec_type == SEC_NO_FLAGS)
532 sec_type = mutt_is_multipart_encrypted(e_new->body);
533 if (((WithCrypto & APPLICATION_SMIME) != 0) && sec_type == SEC_NO_FLAGS)
534 sec_type = mutt_is_application_smime(e_new->body);
535 if (sec_type != SEC_NO_FLAGS)
536 {
537 e_new->security |= sec_type;
538 if (!crypt_valid_passphrase(sec_type))
539 goto bail;
540
541 mutt_message(_("Decrypting message..."));
542 int ret = -1;
543 if (sec_type & APPLICATION_PGP)
544 ret = crypt_pgp_decrypt_mime(fp, &fp_body, e_new->body, &b);
545 else if (sec_type & APPLICATION_SMIME)
546 ret = crypt_smime_decrypt_mime(fp, &fp_body, e_new->body, &b);
547 if ((ret == -1) || !b)
548 {
549 mutt_error(_("Could not decrypt postponed message"));
550 goto bail;
551 }
552
553 /* throw away the outer layer and keep only the (now decrypted) inner part
554 * with its headers. */
555 mutt_body_free(&e_new->body);
556 e_new->body = b;
557
558 if (b->mime_headers)
559 {
560 protected_headers = b->mime_headers;
561 b->mime_headers = NULL;
562 }
563
565 }
566
567 /* remove a potential multipart/signed layer - useful when
568 * resending messages */
569 if ((WithCrypto != 0) && mutt_is_multipart_signed(e_new->body))
570 {
571 e_new->security |= SEC_SIGN;
572 if (((WithCrypto & APPLICATION_PGP) != 0) &&
573 mutt_istr_equal(mutt_param_get(&e_new->body->parameter, "protocol"), "application/pgp-signature"))
574 {
575 e_new->security |= APPLICATION_PGP;
576 }
577 else if (WithCrypto & APPLICATION_SMIME)
578 {
579 e_new->security |= APPLICATION_SMIME;
580 }
581
582 /* destroy the signature */
583 mutt_body_free(&e_new->body->parts->next);
584 e_new->body = mutt_remove_multipart(e_new->body);
585
586 if (e_new->body->mime_headers)
587 {
588 mutt_env_free(&protected_headers);
589 protected_headers = e_new->body->mime_headers;
590 e_new->body->mime_headers = NULL;
591 }
592 }
593
594 /* We don't need no primary multipart/mixed. */
595 if ((e_new->body->type == TYPE_MULTIPART) && mutt_istr_equal(e_new->body->subtype, "mixed"))
596 e_new->body = mutt_remove_multipart(e_new->body);
597
598 file = buf_pool_get();
599
600 /* create temporary files for all attachments */
601 if (create_tmp_files_for_attachments(fp_body, file, e_new, e_new->body, protected_headers) < 0)
602 {
603 goto bail;
604 }
605
606 const bool c_crypt_protected_headers_read = cs_subset_bool(NeoMutt->sub, "crypt_protected_headers_read");
607 if (c_crypt_protected_headers_read && protected_headers && protected_headers->subject &&
608 !mutt_str_equal(e_new->env->subject, protected_headers->subject))
609 {
610 mutt_str_replace(&e_new->env->subject, protected_headers->subject);
611 }
612 mutt_env_free(&protected_headers);
613
614 /* Fix encryption flags. */
615
616 /* No inline if multipart. */
617 if ((WithCrypto != 0) && (e_new->security & SEC_INLINE) && e_new->body->next)
618 e_new->security &= ~SEC_INLINE;
619
620 /* Do we even support multiple mechanisms? */
622
623 /* Theoretically, both could be set. Take the one the user wants to set by default. */
624 if ((e_new->security & APPLICATION_PGP) && (e_new->security & APPLICATION_SMIME))
625 {
626 const bool c_smime_is_default = cs_subset_bool(NeoMutt->sub, "smime_is_default");
627 if (c_smime_is_default)
628 e_new->security &= ~APPLICATION_PGP;
629 else
630 e_new->security &= ~APPLICATION_SMIME;
631 }
632
634
635 rc = 0;
636
637bail:
638
639 /* that's it. */
640 buf_pool_release(&file);
641 if (fp_body != fp)
642 mutt_file_fclose(&fp_body);
643 if (msg)
644 mx_msg_close(m, &msg);
645
646 if (rc == -1)
647 {
648 mutt_env_free(&e_new->env);
649 mutt_body_free(&e_new->body);
650 }
651
652 return rc;
653}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1450
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:398
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:433
int crypt_smime_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:433
int crypt_pgp_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Wrapper for CryptModuleSpecs::decrypt_mime()
Definition: cryptglue.c:211
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:708
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: multipart.c:126
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1210
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1164
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1772
struct Envelope * mutt_rfc822_read_header(FILE *fp, struct Email *e, bool user_hdrs, bool weed)
Parses an RFC822 header.
Definition: parse.c:1169
void mutt_rfc3676_space_unstuff(struct Email *e)
Remove RFC3676 space stuffing.
Definition: rfc3676.c:496
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
LOFF_T offset
Where in the stream does this message begin?
Definition: email.h:69
The header of an Email.
Definition: envelope.h:57
char * message_id
Message ID.
Definition: envelope.h:73
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:65
char * subject
Email's subject.
Definition: envelope.h:70
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_get_postponed()

int mutt_get_postponed ( struct Mailbox m_cur,
struct Email hdr,
struct Email **  cur,
struct Buffer fcc 
)

Recall a postponed message.

Parameters
[in]m_curCurrent mailbox
[in]hdrenvelope/attachment info for recalled message
[out]curif message was a reply, 'cur' is set to the message which 'hdr' is in reply to
[in]fccfcc for the recalled message
Return values
-1Error/no messages
0Normal exit
SEND_REPLYRecalled message is a reply

Definition at line 665 of file postpone.c.

667{
668 const char *const c_postponed = cs_subset_string(NeoMutt->sub, "postponed");
669 if (!c_postponed)
670 return -1;
671
672 struct Email *e = NULL;
673 int rc = SEND_POSTPONED;
674 const char *p = NULL;
675
676 struct Mailbox *m = mx_path_resolve(c_postponed);
677 if (m_cur != m)
678 {
679 if (!mx_mbox_open(m, MUTT_NOSORT))
680 {
681 PostCount = 0;
682 mutt_error(_("No postponed messages"));
683 mailbox_free(&m);
684 return -1;
685 }
686 }
687
688 mx_mbox_check(m);
689
690 if (m->msg_count == 0)
691 {
692 PostCount = 0;
693 mutt_error(_("No postponed messages"));
694 if (m_cur != m)
695 {
696 mx_fastclose_mailbox(m, false);
697 mailbox_free(&m);
698 }
699 return -1;
700 }
701
702 /* avoid the "purge deleted messages" prompt */
703 const enum QuadOption c_delete = cs_subset_quad(NeoMutt->sub, "delete");
704 cs_subset_str_native_set(NeoMutt->sub, "delete", MUTT_YES, NULL);
705
706 if (m->msg_count == 1)
707 {
708 /* only one message, so just use that one. */
709 e = m->emails[0];
710 }
711 else if (!(e = dlg_select_postponed_email(m)))
712 {
713 rc = -1;
714 goto cleanup;
715 }
716
717 if (mutt_prepare_template(NULL, m, hdr, e, false) < 0)
718 {
719 rc = -1;
720 goto cleanup;
721 }
722
723 /* finished with this message, so delete it. */
724 mutt_set_flag(m, e, MUTT_DELETE, true, true);
725 mutt_set_flag(m, e, MUTT_PURGE, true, true);
726
727 /* update the count for the status display */
729
730 struct ListNode *np = NULL, *tmp = NULL;
731 STAILQ_FOREACH_SAFE(np, &hdr->env->userhdrs, entries, tmp)
732 {
733 size_t plen = 0;
734 // Check for header names: most specific first
735 if ((plen = mutt_istr_startswith(np->data, "X-Mutt-References:")) ||
736 (plen = mutt_istr_startswith(np->data, "Mutt-References:")))
737 {
738 /* if a mailbox is currently open, look to see if the original message
739 * the user attempted to reply to is in this mailbox */
740 if (m_cur)
741 {
742 p = mutt_str_skip_email_wsp(np->data + plen);
743 if (!m_cur->id_hash)
744 m_cur->id_hash = mutt_make_id_hash(m_cur);
745 *cur = mutt_hash_find(m_cur->id_hash, p);
746
747 if (*cur)
748 rc |= SEND_REPLY;
749 }
750 }
751 // Check for header names: most specific first
752 else if ((plen = mutt_istr_startswith(np->data, "X-Mutt-Fcc:")) ||
753 (plen = mutt_istr_startswith(np->data, "Mutt-Fcc:")))
754 {
755 p = mutt_str_skip_email_wsp(np->data + plen);
756 buf_strcpy(fcc, p);
758
759 /* note that mutt-fcc was present. we do this because we want to add a
760 * default fcc if the header was missing, but preserve the request of the
761 * user to not make a copy if the header field is present, but empty.
762 * see http://dev.mutt.org/trac/ticket/3653 */
763 rc |= SEND_POSTPONED_FCC;
764 }
765 // Check for header names: most specific first
766 else if (((WithCrypto & APPLICATION_PGP) != 0) &&
767 ((plen = mutt_istr_startswith(np->data, "X-Mutt-PGP:")) ||
768 (plen = mutt_istr_startswith(np->data, "Mutt-PGP:")) ||
769 (plen = mutt_istr_startswith(np->data, "Pgp:"))))
770 {
771 hdr->security = mutt_parse_crypt_hdr(np->data + plen, true, APPLICATION_PGP);
773 }
774 // Check for header names: most specific first
775 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
776 ((plen = mutt_istr_startswith(np->data, "X-Mutt-SMIME:")) ||
777 (plen = mutt_istr_startswith(np->data, "Mutt-SMIME:"))))
778 {
779 hdr->security = mutt_parse_crypt_hdr(np->data + plen, true, APPLICATION_SMIME);
781 }
782#ifdef MIXMASTER
783 // Check for header names: most specific first
784 else if ((plen = mutt_istr_startswith(np->data, "X-Mutt-Mix:")) ||
785 (plen = mutt_istr_startswith(np->data, "Mutt-Mix:")))
786 {
787 mutt_list_free(&hdr->chain);
788
789 char *t = strtok(np->data + plen, " \t\n");
790 while (t)
791 {
793 t = strtok(NULL, " \t\n");
794 }
795 }
796#endif
797 else
798 {
799 // skip header removal
800 continue;
801 }
802
803 // remove the header
804 STAILQ_REMOVE(&hdr->env->userhdrs, np, ListNode, entries);
805 FREE(&np->data);
806 FREE(&np);
807 }
808
809 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
810 if (c_crypt_opportunistic_encrypt)
812
813cleanup:
814 if (m_cur != m)
815 {
816 hardclose(m);
817 mailbox_free(&m);
818 }
819
820 cs_subset_str_native_set(NeoMutt->sub, "delete", c_delete, NULL);
821 return rc;
822}
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1035
struct Email * dlg_select_postponed_email(struct Mailbox *m)
Create a Menu to select a postponed message.
Definition: dlg_postpone.c:195
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition: flags.c:52
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:240
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition: mutt.h:85
@ MUTT_DELETE
Messages to be deleted.
Definition: mutt.h:83
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1696
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:560
enum MxStatus mx_mbox_check(struct Mailbox *m)
Check for new mail - Wrapper for MxOps::mbox_check()
Definition: mx.c:1143
SecurityFlags mutt_parse_crypt_hdr(const char *p, bool set_empty_signas, SecurityFlags crypt_app)
Parse a crypto header string.
Definition: postpone.c:212
int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new, struct Email *e, bool resend)
Prepare a message template.
Definition: postpone.c:491
static void hardclose(struct Mailbox *m)
Try hard to close a mailbox.
Definition: postpone.c:194
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
#define SEND_POSTPONED_FCC
Used by mutt_get_postponed() to signal that the Mutt-Fcc header field was present.
Definition: send.h:48
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:44
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
The envelope/body of an email.
Definition: email.h:37
struct ListHead chain
Mixmaster chain.
Definition: email.h:89
struct ListHead userhdrs
user defined headers
Definition: envelope.h:87
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
struct Email ** emails
Array of Emails.
Definition: mailbox.h:96
struct HashTable * id_hash
Hash Table: "message-id" -> Email.
Definition: mailbox.h:123
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:310
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ PostCount

short PostCount = 0

Number of postponed (draft) emails.

Definition at line 58 of file postpone.c.

◆ UpdateNumPostponed

bool UpdateNumPostponed = false
static

When true, force a recount of the postponed (draft) emails.

Definition at line 60 of file postpone.c.