NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
compose.c File Reference

Compose Email Dialog. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "lib.h"
#include "index/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "attach_data.h"
#include "browser.h"
#include "cbar.h"
#include "commands.h"
#include "context.h"
#include "env_data.h"
#include "hook.h"
#include "mutt_attach.h"
#include "mutt_globals.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "mx.h"
#include "opcodes.h"
#include "options.h"
#include "protos.h"
#include "recvattach.h"
#include "rfc3676.h"
#include "shared_data.h"
#include <libintl.h>
#include "remailer.h"
#include "nntp/lib.h"
#include "nntp/adata.h"
#include "pop/lib.h"
#include "imap/lib.h"
#include "autocrypt/lib.h"

Go to the source code of this file.

Macros

#define ALTS_TAG   "Alternatives for \"%s\""
 
#define LINGUAL_TAG   "Multilingual part for \"%s\""
 

Functions

static void calc_header_width_padding (int idx, const char *header, bool calc_max)
 Calculate the width needed for the compose labels. More...
 
static void init_header_padding (void)
 Calculate how much padding the compose table will need. More...
 
static int compose_config_observer (struct NotifyCallback *nc)
 Notification that a Config Variable has changed - Implements observer_t. More...
 
static int compose_window_observer (struct NotifyCallback *nc)
 Notification that a Window has changed - Implements observer_t. More...
 
static bool check_count (struct AttachCtx *actx)
 Check if there are any attachments. More...
 
static struct AttachPtrcurrent_attachment (struct AttachCtx *actx, struct Menu *menu)
 Get the current attachment. More...
 
static void autocrypt_compose_menu (struct Email *e, const struct ConfigSubset *sub)
 Autocrypt compose settings. More...
 
static void update_crypt_info (struct ComposeSharedData *shared)
 Update the crypto info. More...
 
static int check_attachments (struct AttachCtx *actx, struct ConfigSubset *sub)
 Check if any attachments have changed or been deleted. More...
 
static bool edit_address_list (int field, struct AddressList *al)
 Let the user edit the address list. More...
 
static int delete_attachment (struct AttachCtx *actx, int x)
 Delete an attachment. More...
 
static void gen_attach_list (struct AttachCtx *actx, struct Body *m, int parent_type, int level)
 Generate the attachment list for the compose screen. More...
 
void update_menu (struct AttachCtx *actx, struct Menu *menu, bool init)
 Redraw the compose window. More...
 
static void update_idx (struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
 Add a new attchment to the message. More...
 
static void compose_attach_swap (struct Body *msg, struct AttachPtr **idx, short first)
 Swap two adjacent entries in the attachment list. More...
 
static struct MuttWindowcompose_dlg_init (struct ConfigSubset *sub, struct Email *e, struct Buffer *fcc)
 Allocate the Windows for Compose. More...
 
int mutt_compose_menu (struct Email *e, struct Buffer *fcc, uint8_t flags, struct ConfigSubset *sub)
 Allow the user to edit the message envelope. More...
 

Variables

int HeaderPadding [HDR_ATTACH_TITLE] = { 0 }
 
int MaxHeaderWidth = 0
 
const char *const Prompts []
 
static const struct Mapping ComposeHelp []
 Help Bar for the Compose dialog. More...
 
static const struct Mapping ComposeNewsHelp []
 Help Bar for the News Compose dialog. More...
 

Detailed Description

Compose Email Dialog.

Authors
  • Michael R. Elkins
  • g10 Code GmbH
  • Pietro Cerutti
  • Richard Russon

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

Macro Definition Documentation

◆ ALTS_TAG

#define ALTS_TAG   "Alternatives for \"%s\""

◆ LINGUAL_TAG

#define LINGUAL_TAG   "Multilingual part for \"%s\""

Function Documentation

◆ calc_header_width_padding()

static void calc_header_width_padding ( int  idx,
const char *  header,
bool  calc_max 
)
static

Calculate the width needed for the compose labels.

Parameters
idxStore the result at this index of HeaderPadding
headerHeader string
calc_maxIf true, calculate the maximum width

Definition at line 218 of file compose.c.

219 {
220  int width;
221 
222  HeaderPadding[idx] = mutt_str_len(header);
223  width = mutt_strwidth(header);
224  if (calc_max && (MaxHeaderWidth < width))
225  MaxHeaderWidth = width;
226  HeaderPadding[idx] -= width;
227 }
size_t idx
Definition: mailbox.c:257
int MaxHeaderWidth
Definition: compose.c:134
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:983
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
int HeaderPadding[HDR_ATTACH_TITLE]
Definition: compose.c:133
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ init_header_padding()

static void init_header_padding ( void  )
static

Calculate how much padding the compose table will need.

The padding needed for each header is strlen() + max_width - strwidth().

calc_header_width_padding sets each entry in HeaderPadding to strlen - width. Then, afterwards, we go through and add max_width to each entry.

Definition at line 237 of file compose.c.

238 {
239  static bool done = false;
240 
241  if (done)
242  return;
243  done = true;
244 
245  for (int i = 0; i < HDR_ATTACH_TITLE; i++)
246  {
247  if (i == HDR_CRYPTINFO)
248  continue;
249  calc_header_width_padding(i, _(Prompts[i]), true);
250  }
251 
252  /* Don't include "Sign as: " in the MaxHeaderWidth calculation. It
253  * doesn't show up by default, and so can make the indentation of
254  * the other fields look funny. */
256 
257  for (int i = 0; i < HDR_ATTACH_TITLE; i++)
258  {
260  if (HeaderPadding[i] < 0)
261  HeaderPadding[i] = 0;
262  }
263 }
The "-- Attachments" line.
Definition: private.h:67
static void calc_header_width_padding(int idx, const char *header, bool calc_max)
Calculate the width needed for the compose labels.
Definition: compose.c:218
int MaxHeaderWidth
Definition: compose.c:134
#define _(a)
Definition: message.h:28
"Sign as:" field (encryption/signing info)
Definition: private.h:57
const char *const Prompts[]
Definition: compose.c:136
int HeaderPadding[HDR_ATTACH_TITLE]
Definition: compose.c:133
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compose_config_observer()

static int compose_config_observer ( struct NotifyCallback nc)
static

Notification that a Config Variable has changed - Implements observer_t.

Definition at line 268 of file compose.c.

269 {
270  if ((nc->event_type != NT_CONFIG) || !nc->global_data || !nc->event_data)
271  return -1;
272 
273  struct EventConfig *ev_c = nc->event_data;
274  struct MuttWindow *dlg = nc->global_data;
275 
276  if (!mutt_str_equal(ev_c->name, "status_on_top"))
277  return 0;
278 
279  struct MuttWindow *win_cbar = window_find_child(dlg, WT_STATUS_BAR);
280  if (!win_cbar)
281  return 0;
282 
283  TAILQ_REMOVE(&dlg->children, win_cbar, entries);
284 
285  const bool c_status_on_top = cs_subset_bool(ev_c->sub, "status_on_top");
286  if (c_status_on_top)
287  TAILQ_INSERT_HEAD(&dlg->children, win_cbar, entries);
288  else
289  TAILQ_INSERT_TAIL(&dlg->children, win_cbar, entries);
290 
291  mutt_window_reflow(dlg);
292  mutt_debug(LL_DEBUG5, "config done, request WA_REFLOW\n");
293  return 0;
294 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
struct MuttWindow * window_find_child(struct MuttWindow *win, enum WindowType type)
Recursively find a child Window of a given type.
Definition: mutt_window.c:550
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
A config-change event.
Definition: subset.h:69
Status Bar containing extra info about the Index/Pager/etc.
Definition: mutt_window.h:102
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
void * global_data
Data from notify_observer_add()
Definition: observer.h:45
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
void * event_data
Data from notify_send()
Definition: observer.h:44
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:796
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:361
struct MuttWindowList children
Children Windows.
Definition: mutt_window.h:136
Log at debug level 5.
Definition: logging.h:44
const struct ConfigSubset * sub
Config Subset.
Definition: subset.h:71
const char * name
Name of config item that changed.
Definition: subset.h:72
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compose_window_observer()

static int compose_window_observer ( struct NotifyCallback nc)
static

Notification that a Window has changed - Implements observer_t.

Definition at line 299 of file compose.c.

300 {
301  if ((nc->event_type != NT_WINDOW) || !nc->global_data || !nc->event_data)
302  return -1;
303 
304  if (nc->event_subtype != NT_WINDOW_DELETE)
305  return 0;
306 
307  struct MuttWindow *dlg = nc->global_data;
308  struct EventWindow *ev_w = nc->event_data;
309  if (ev_w->win != dlg)
310  return 0;
311 
314  mutt_debug(LL_DEBUG5, "window delete done\n");
315 
316  return 0;
317 }
struct MuttWindow * win
Window that changed.
Definition: mutt_window.h:217
An Event that happened to a Window.
Definition: mutt_window.h:215
Window is about to be deleted.
Definition: mutt_window.h:206
Container for Accounts, Notifications.
Definition: neomutt.h:36
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:53
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:43
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:42
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
static int compose_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t.
Definition: compose.c:299
void * global_data
Data from notify_observer_add()
Definition: observer.h:45
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
void * event_data
Data from notify_send()
Definition: observer.h:44
static int compose_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: compose.c:268
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:228
Log at debug level 5.
Definition: logging.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_count()

static bool check_count ( struct AttachCtx actx)
static

Check if there are any attachments.

Parameters
actxAttachment context
Return values
trueThere are attachments

Definition at line 324 of file compose.c.

325 {
326  if (actx->idxlen == 0)
327  {
328  mutt_error(_("There are no attachments"));
329  return false;
330  }
331 
332  return true;
333 }
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
short idxlen
Number of attachmentes.
Definition: attach.h:55
+ Here is the caller graph for this function:

◆ current_attachment()

static struct AttachPtr* current_attachment ( struct AttachCtx actx,
struct Menu menu 
)
static

Get the current attachment.

Parameters
actxAttachment context
menuMenu
Return values
ptrCurrent Attachment

Definition at line 341 of file compose.c.

342 {
343  const int virt = menu_get_index(menu);
344  const int index = actx->v2r[virt];
345 
346  return actx->idx[index];
347 }
short * v2r
Mapping from virtual to real attachment.
Definition: attach.h:58
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ autocrypt_compose_menu()

static void autocrypt_compose_menu ( struct Email e,
const struct ConfigSubset sub 
)
static

Autocrypt compose settings.

Parameters
eEmail
subConfigSubset

Definition at line 355 of file compose.c.

356 {
357  /* L10N: The compose menu autocrypt prompt.
358  (e)ncrypt enables encryption via autocrypt.
359  (c)lear sets cleartext.
360  (a)utomatic defers to the recommendation. */
361  const char *prompt = _("Autocrypt: (e)ncrypt, (c)lear, (a)utomatic?");
362 
364 
365  /* L10N: The letter corresponding to the compose menu autocrypt prompt
366  (e)ncrypt, (c)lear, (a)utomatic */
367  const char *letters = _("eca");
368 
369  int choice = mutt_multi_choice(prompt, letters);
370  switch (choice)
371  {
372  case 1:
375  break;
376  case 2:
377  e->security &= ~SEC_AUTOCRYPT;
379  break;
380  case 3:
381  {
383  const bool c_crypt_opportunistic_encrypt =
384  cs_subset_bool(sub, "crypt_opportunistic_encrypt");
385  if (c_crypt_opportunistic_encrypt)
386  e->security |= SEC_OPPENCRYPT;
387  break;
388  }
389  }
390 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define _(a)
Definition: message.h:28
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:84
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:82
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:85
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:49
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:83
#define SEC_SIGN
Email is signed.
Definition: lib.h:76
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_crypt_info()

static void update_crypt_info ( struct ComposeSharedData shared)
static

Update the crypto info.

Parameters
sharedShared compose data

Definition at line 397 of file compose.c.

398 {
399  struct Email *e = shared->email;
400  struct Mailbox *m = shared->mailbox;
401 
402  const bool c_crypt_opportunistic_encrypt =
403  cs_subset_bool(shared->sub, "crypt_opportunistic_encrypt");
404  if (c_crypt_opportunistic_encrypt)
406 
407 #ifdef USE_AUTOCRYPT
408  const bool c_autocrypt = cs_subset_bool(shared->sub, "autocrypt");
409  if (c_autocrypt)
410  {
411  struct ComposeEnvelopeData *edata = shared->edata;
412  edata->autocrypt_rec = mutt_autocrypt_ui_recommendation(m, e, NULL);
413 
414  /* Anything that enables SEC_ENCRYPT or SEC_SIGN, or turns on SMIME
415  * overrides autocrypt, be it oppenc or the user having turned on
416  * those flags manually. */
419  else
420  {
421  if (!(e->security & SEC_AUTOCRYPT_OVERRIDE))
422  {
423  if (edata->autocrypt_rec == AUTOCRYPT_REC_YES)
424  {
427  }
428  else
429  e->security &= ~SEC_AUTOCRYPT;
430  }
431  }
432  }
433 #endif
434 }
enum AutocryptRec mutt_autocrypt_ui_recommendation(struct Mailbox *m, struct Email *e, char **keylist)
Get the recommended action for an Email.
Definition: autocrypt.c:575
enum AutocryptRec autocrypt_rec
Autocrypt recommendation.
Definition: env_data.h:51
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
The envelope/body of an email.
Definition: email.h:37
Autocrypt should be used.
Definition: lib.h:160
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:84
Data to fill the Compose Envelope Window.
Definition: env_data.h:37
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:82
void crypt_opportunistic_encrypt(struct Mailbox *m, struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1054
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
A mailbox.
Definition: mailbox.h:81
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:85
struct Mailbox * mailbox
Current Mailbox.
Definition: shared_data.h:32
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define SEC_SIGN
Email is signed.
Definition: lib.h:76
struct ComposeEnvelopeData * edata
Envelope data.
Definition: shared_data.h:35
struct Email * email
Email being composed.
Definition: shared_data.h:33
struct ConfigSubset * sub
Config set to use.
Definition: shared_data.h:31
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_attachments()

static int check_attachments ( struct AttachCtx actx,
struct ConfigSubset sub 
)
static

Check if any attachments have changed or been deleted.

Parameters
actxAttachment context
subConfigSubset
Return values
0Success
-1Error

Definition at line 443 of file compose.c.

444 {
445  int rc = -1;
446  struct stat st;
447  struct Buffer *pretty = NULL, *msg = NULL;
448 
449  for (int i = 0; i < actx->idxlen; i++)
450  {
451  if (actx->idx[i]->body->type == TYPE_MULTIPART)
452  continue;
453  if (stat(actx->idx[i]->body->filename, &st) != 0)
454  {
455  if (!pretty)
456  pretty = mutt_buffer_pool_get();
457  mutt_buffer_strcpy(pretty, actx->idx[i]->body->filename);
459  /* L10N: This message is displayed in the compose menu when an attachment
460  doesn't stat. %d is the attachment number and %s is the attachment
461  filename. The filename is located last to avoid a long path hiding
462  the error message. */
463  mutt_error(_("Attachment #%d no longer exists: %s"), i + 1,
464  mutt_buffer_string(pretty));
465  goto cleanup;
466  }
467 
468  if (actx->idx[i]->body->stamp < st.st_mtime)
469  {
470  if (!pretty)
471  pretty = mutt_buffer_pool_get();
472  mutt_buffer_strcpy(pretty, actx->idx[i]->body->filename);
474 
475  if (!msg)
476  msg = mutt_buffer_pool_get();
477  /* L10N: This message is displayed in the compose menu when an attachment
478  is modified behind the scenes. %d is the attachment number and %s is
479  the attachment filename. The filename is located last to avoid a long
480  path hiding the prompt question. */
481  mutt_buffer_printf(msg, _("Attachment #%d modified. Update encoding for %s?"),
482  i + 1, mutt_buffer_string(pretty));
483 
485  if (ans == MUTT_YES)
486  mutt_update_encoding(actx->idx[i]->body, sub);
487  else if (ans == MUTT_ABORT)
488  goto cleanup;
489  }
490  }
491 
492  rc = 0;
493 
494 cleanup:
495  mutt_buffer_pool_release(&pretty);
497  return rc;
498 }
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
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:904
#define mutt_error(...)
Definition: logging.h:88
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
short idxlen
Number of attachmentes.
Definition: attach.h:55
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:603
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
User aborted the question (with Ctrl-G)
Definition: quad.h:37
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
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, ContentType
Definition: body.h:65
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
struct Body * body
Attachment.
Definition: attach.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ edit_address_list()

static bool edit_address_list ( int  field,
struct AddressList *  al 
)
static

Let the user edit the address list.

Parameters
[in]fieldField to edit, e.g. HDR_FROM
[in,out]alAddressList to edit
Return values
trueThe address list was changed

Definition at line 506 of file compose.c.

507 {
508  char buf[8192] = { 0 }; /* needs to be large for alias expansion */
509  char old_list[8192] = { 0 };
510 
512  mutt_addrlist_write(al, buf, sizeof(buf), false);
513  mutt_str_copy(old_list, buf, sizeof(buf));
514  if (mutt_get_field(_(Prompts[field]), buf, sizeof(buf), MUTT_ALIAS, false, NULL, NULL) == 0)
515  {
517  mutt_addrlist_parse2(al, buf);
519  }
520 
521  char *err = NULL;
522  if (mutt_addrlist_to_intl(al, &err) != 0)
523  {
524  mutt_error(_("Bad IDN: '%s'"), err);
525  mutt_refresh();
526  FREE(&err);
527  }
528 
529  return !mutt_str_equal(buf, old_list);
530 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
#define MUTT_ALIAS
Do alias "completion" by calling up the alias-menu.
Definition: mutt.h:53
#define mutt_error(...)
Definition: logging.h:88
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1388
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
#define _(a)
Definition: message.h:28
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:616
void mutt_refresh(void)
Force a refresh of the screen.
Definition: curs_lib.c:115
const char *const Prompts[]
Definition: compose.c:136
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
#define FREE(x)
Definition: memory.h:40
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ delete_attachment()

static int delete_attachment ( struct AttachCtx actx,
int  x 
)
static

Delete an attachment.

Parameters
actxAttachment context
xIndex number of attachment
Return values
0Success
-1Error

Definition at line 539 of file compose.c.

540 {
541  struct AttachPtr **idx = actx->idx;
542  int rindex = actx->v2r[x];
543 
544  if ((rindex == 0) && (actx->idxlen == 1))
545  {
546  mutt_error(_("You may not delete the only attachment"));
547  idx[rindex]->body->tagged = false;
548  return -1;
549  }
550 
551  for (int y = 0; y < actx->idxlen; y++)
552  {
553  if (idx[y]->body->next == idx[rindex]->body)
554  {
555  idx[y]->body->next = idx[rindex]->body->next;
556  break;
557  }
558  }
559 
560  idx[rindex]->body->next = NULL;
561  /* mutt_make_message_attach() creates body->parts, shared by
562  * body->email->body. If we NULL out that, it creates a memory
563  * leak because mutt_free_body() frees body->parts, not
564  * body->email->body.
565  *
566  * Other mutt_send_message() message constructors are careful to free
567  * any body->parts, removing depth:
568  * - mutt_prepare_template() used by postponed, resent, and draft files
569  * - mutt_copy_body() used by the recvattach menu and $forward_attachments.
570  *
571  * I believe it is safe to completely remove the "body->parts =
572  * NULL" statement. But for safety, am doing so only for the case
573  * it must be avoided: message attachments.
574  */
575  if (!idx[rindex]->body->email)
576  idx[rindex]->body->parts = NULL;
577  mutt_body_free(&(idx[rindex]->body));
578  FREE(&idx[rindex]->tree);
579  FREE(&idx[rindex]);
580  for (; rindex < actx->idxlen - 1; rindex++)
581  idx[rindex] = idx[rindex + 1];
582  idx[actx->idxlen - 1] = NULL;
583  actx->idxlen--;
584 
585  return 0;
586 }
An email to which things will be attached.
Definition: attach.h:34
#define mutt_error(...)
Definition: logging.h:88
size_t idx
Definition: mailbox.c:257
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
short idxlen
Number of attachmentes.
Definition: attach.h:55
char * tree
Tree characters to display.
Definition: attach.h:39
bool tagged
This attachment is tagged.
Definition: body.h:70
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
short * v2r
Mapping from virtual to real attachment.
Definition: attach.h:58
#define FREE(x)
Definition: memory.h:40
struct Email * email
header information for message/rfc822
Definition: body.h:55
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
struct Body * body
Attachment.
Definition: attach.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ gen_attach_list()

static void gen_attach_list ( struct AttachCtx actx,
struct Body m,
int  parent_type,
int  level 
)
static

Generate the attachment list for the compose screen.

Parameters
actxAttachment context
mAttachment
parent_typeAttachment type, e.g TYPE_MULTIPART
levelNesting depth of attachment

Definition at line 595 of file compose.c.

596 {
597  for (; m; m = m->next)
598  {
599  if ((m->type == TYPE_MULTIPART) && m->parts &&
601  {
602  gen_attach_list(actx, m->parts, m->type, level);
603  }
604  else
605  {
606  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
607  mutt_actx_add_attach(actx, ap);
608  ap->body = m;
609  m->aptr = ap;
610  ap->parent_type = parent_type;
611  ap->level = level;
612 
613  /* We don't support multipart messages in the compose menu yet */
614  }
615  }
616 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
An email to which things will be attached.
Definition: attach.h:34
#define WithCrypto
Definition: lib.h:113
struct Body * next
next attachment in the list
Definition: body.h:53
SecurityFlags mutt_is_multipart_encrypted(struct Body *b)
Does the message have encrypted parts?
Definition: crypt.c:460
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:38
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
static void gen_attach_list(struct AttachCtx *actx, struct Body *m, int parent_type, int level)
Generate the attachment list for the compose screen.
Definition: compose.c:595
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:57
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:40
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
int level
Nesting depth of attachment.
Definition: attach.h:40
struct Body * body
Attachment.
Definition: attach.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_menu()

void update_menu ( struct AttachCtx actx,
struct Menu menu,
bool  init 
)

Redraw the compose window.

Parameters
actxAttachment context
menuCurrent menu
initIf true, initialise the attachment list

Definition at line 624 of file compose.c.

625 {
626  if (init)
627  {
628  gen_attach_list(actx, actx->email->body, -1, 0);
629  mutt_attach_init(actx);
630 
631  struct ComposeAttachData *adata = menu->mdata;
632  adata->actx = actx;
633  }
634 
635  mutt_update_tree(actx);
636 
637  menu->max = actx->vcount;
638  if (menu->max)
639  {
640  int index = menu_get_index(menu);
641  if (index >= menu->max)
642  menu_set_index(menu, menu->max - 1);
643  }
644  else
645  menu_set_index(menu, 0);
646 
648 }
struct Body * body
List of MIME parts.
Definition: email.h:91
Data to fill the Compose Attach Window.
Definition: attach_data.h:32
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
void * mdata
Private data.
Definition: lib.h:155
static void gen_attach_list(struct AttachCtx *actx, struct Body *m, int parent_type, int level)
Generate the attachment list for the compose screen.
Definition: compose.c:595
void mutt_attach_init(struct AttachCtx *actx)
Create a new Attachment context.
Definition: recvattach.c:1571
struct AttachCtx * actx
Definition: attach_data.h:34
int max
Number of entries in the menu.
Definition: lib.h:71
void mutt_update_tree(struct AttachCtx *actx)
Refresh the list of attachments.
Definition: recvattach.c:204
short vcount
The number of virtual attachments.
Definition: attach.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ update_idx()

static void update_idx ( struct Menu menu,
struct AttachCtx actx,
struct AttachPtr ap 
)
static

Add a new attchment to the message.

Parameters
menuCurrent menu
actxAttachment context
apAttachment to add

Definition at line 656 of file compose.c.

657 {
658  ap->level = (actx->idxlen > 0) ? actx->idx[actx->idxlen - 1]->level : 0;
659  if (actx->idxlen)
660  actx->idx[actx->idxlen - 1]->body->next = ap->body;
661  ap->body->aptr = ap;
662  mutt_actx_add_attach(actx, ap);
663  update_menu(actx, menu, false);
664  menu_set_index(menu, actx->vcount - 1);
665 }
struct Body * next
next attachment in the list
Definition: body.h:53
short idxlen
Number of attachmentes.
Definition: attach.h:55
void update_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Redraw the compose window.
Definition: compose.c:624
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:57
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:40
int level
Nesting depth of attachment.
Definition: attach.h:40
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
short vcount
The number of virtual attachments.
Definition: attach.h:59
struct Body * body
Attachment.
Definition: attach.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ compose_attach_swap()

static void compose_attach_swap ( struct Body msg,
struct AttachPtr **  idx,
short  first 
)
static

Swap two adjacent entries in the attachment list.

Parameters
[in]msgBody of email
[out]idxArray of Attachments
[in]firstIndex of first attachment to swap

Definition at line 673 of file compose.c.

674 {
675  /* Reorder Body pointers.
676  * Must traverse msg from top since Body has no previous ptr. */
677  for (struct Body *part = msg; part; part = part->next)
678  {
679  if (part->next == idx[first]->body)
680  {
681  idx[first]->body->next = idx[first + 1]->body->next;
682  idx[first + 1]->body->next = idx[first]->body;
683  part->next = idx[first + 1]->body;
684  break;
685  }
686  }
687 
688  /* Reorder index */
689  struct AttachPtr *saved = idx[first];
690  idx[first] = idx[first + 1];
691  idx[first + 1] = saved;
692 
693  /* Swap ptr->num */
694  int i = idx[first]->num;
695  idx[first]->num = idx[first + 1]->num;
696  idx[first + 1]->num = i;
697 }
An email to which things will be attached.
Definition: attach.h:34
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
int num
Attachment index number.
Definition: attach.h:41
struct Body * body
Attachment.
Definition: attach.h:36
+ Here is the caller graph for this function:

◆ compose_dlg_init()

static struct MuttWindow* compose_dlg_init ( struct ConfigSubset sub,
struct Email e,
struct Buffer fcc 
)
static

Allocate the Windows for Compose.

Parameters
subConfigSubset
eEmail
fccBuffer to save FCC
Return values
ptrDialog containing nested Windows

Definition at line 706 of file compose.c.

708 {
709  struct ComposeSharedData *shared = compose_shared_data_new();
710  shared->sub = sub;
711  shared->email = e;
712 
713  struct MuttWindow *dlg =
716  dlg->wdata = shared;
718 
719  struct MuttWindow *win_env = compose_env_new(dlg, shared, fcc);
720  struct MuttWindow *win_attach = attach_new(dlg, shared);
721  struct MuttWindow *win_cbar = cbar_new(dlg, shared);
722  struct MuttWindow *win_abar = sbar_new(dlg);
723  sbar_set_title(win_abar, _("-- Attachments"));
724 
725  const bool c_status_on_top = cs_subset_bool(sub, "status_on_top");
726  if (c_status_on_top)
727  {
728  mutt_window_add_child(dlg, win_cbar);
729  mutt_window_add_child(dlg, win_env);
730  mutt_window_add_child(dlg, win_abar);
731  mutt_window_add_child(dlg, win_attach);
732  }
733  else
734  {
735  mutt_window_add_child(dlg, win_env);
736  mutt_window_add_child(dlg, win_abar);
737  mutt_window_add_child(dlg, win_attach);
738  mutt_window_add_child(dlg, win_cbar);
739  }
740 
741  dlg->help_data = ComposeHelp;
742  dlg->help_menu = MENU_COMPOSE;
743 
744  return dlg;
745 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:160
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:141
Window uses all available vertical space.
Definition: mutt_window.h:38
struct MuttWindow * sbar_new(struct MuttWindow *parent)
Add the Simple Bar (status)
Definition: sbar.c:197
Shared Compose Data.
Definition: shared_data.h:29
void compose_shared_data_free(struct MuttWindow *win, void **ptr)
Create the compose shared data - Implements MuttWindow::wdata_free() -.
Definition: shared_data.c:36
#define _(a)
Definition: message.h:28
Compose an email.
Definition: type.h:42
struct ComposeSharedData * compose_shared_data_new(void)
Free the compose shared data.
Definition: shared_data.c:49
static const struct Mapping ComposeHelp[]
Help Bar for the Compose dialog.
Definition: compose.c:179
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:142
void sbar_set_title(struct MuttWindow *win, const char *title)
Set the title for the Simple Bar.
Definition: sbar.c:221
struct MuttWindow * cbar_new(struct MuttWindow *parent, struct ComposeSharedData *shared)
Create the Compose Bar (status)
Definition: cbar.c:296
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:468
struct MuttWindow * attach_new(struct MuttWindow *parent, struct ComposeSharedData *shared)
Create the Attachments Menu.
Definition: attach.c:279
Compose Dialog, mutt_compose_menu()
Definition: mutt_window.h:82
struct MuttWindow * compose_env_new(struct MuttWindow *parent, struct ComposeSharedData *shared, struct Buffer *fcc)
Create the Envelope Window.
Definition: envelope.c:877
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:180
Window wants as much space as possible.
Definition: mutt_window.h:48
void * wdata
Private data.
Definition: mutt_window.h:145
struct Email * email
Email being composed.
Definition: shared_data.h:33
struct ConfigSubset * sub
Config set to use.
Definition: shared_data.h:31
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_compose_menu()

int mutt_compose_menu ( struct Email e,
struct Buffer fcc,
uint8_t  flags,
struct ConfigSubset sub 
)

Allow the user to edit the message envelope.

Parameters
eEmail to fill
fccBuffer to save FCC
flagsFlags, e.g. MUTT_COMPOSE_NOFREEHEADER
subConfigSubset
Return values
1Message should be postponed
0Normal exit
-1Abort message

Definition at line 757 of file compose.c.

759 {
761 
762  char buf[PATH_MAX];
763  int rc = -1;
764  bool loop = true;
765  bool fcc_set = false; /* has the user edited the Fcc: field ? */
766  struct Mailbox *m = ctx_mailbox(Context);
767 
768 #ifdef USE_NNTP
769  bool news = OptNewsSend; /* is it a news article ? */
770 #endif
771 
772  struct MuttWindow *dlg = compose_dlg_init(sub, e, fcc);
773 #ifdef USE_NNTP
774  if (news)
775  dlg->help_data = ComposeNewsHelp;
776 #endif
779  dialog_push(dlg);
780 
781 #ifdef USE_NNTP
782  if (news)
783  dlg->help_data = ComposeNewsHelp;
784  else
785 #endif
786  dlg->help_data = ComposeHelp;
787  dlg->help_menu = MENU_COMPOSE;
788 
789  struct ComposeSharedData *shared = dlg->wdata;
790 
791  // win_env->req_rows = calc_envelope(win_env, shared, shared->edata);
792 
793  struct Menu *menu = shared->adata->menu;
794 
795  update_menu(shared->adata->actx, menu, true);
796  struct AttachCtx *actx = shared->adata->actx;
797 
798  update_crypt_info(shared);
799 
800  /* Since this is rather long lived, we don't use the pool */
801  struct Buffer fname = mutt_buffer_make(PATH_MAX);
802 
803  while (loop)
804  {
805 #ifdef USE_NNTP
806  OptNews = false; /* for any case */
807 #endif
808  window_redraw(NULL);
809  const int op = menu_loop(menu);
810  if (op >= 0)
811  mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", OpStrings[op][0], op);
812  switch (op)
813  {
814  case OP_COMPOSE_EDIT_FROM:
815  if (edit_address_list(HDR_FROM, &e->env->from))
816  {
817  update_crypt_info(shared);
820  }
821  break;
822 
823  case OP_COMPOSE_EDIT_TO:
824  {
825 #ifdef USE_NNTP
826  if (news)
827  break;
828 #endif
829  if (edit_address_list(HDR_TO, &e->env->to))
830  {
831  update_crypt_info(shared);
834  }
835  break;
836  }
837 
838  case OP_COMPOSE_EDIT_BCC:
839  {
840 #ifdef USE_NNTP
841  if (news)
842  break;
843 #endif
844  if (edit_address_list(HDR_BCC, &e->env->bcc))
845  {
846  update_crypt_info(shared);
849  }
850  break;
851  }
852 
853  case OP_COMPOSE_EDIT_CC:
854  {
855 #ifdef USE_NNTP
856  if (news)
857  break;
858 #endif
859  if (edit_address_list(HDR_CC, &e->env->cc))
860  {
861  update_crypt_info(shared);
864  }
865  break;
866  }
867 
868 #ifdef USE_NNTP
869  case OP_COMPOSE_EDIT_NEWSGROUPS:
870  if (!news)
871  break;
872  mutt_str_copy(buf, e->env->newsgroups, sizeof(buf));
873  if (mutt_get_field(Prompts[HDR_NEWSGROUPS], buf, sizeof(buf),
874  MUTT_COMP_NO_FLAGS, false, NULL, NULL) == 0)
875  {
876  mutt_str_replace(&e->env->newsgroups, buf);
878  }
879  break;
880 
881  case OP_COMPOSE_EDIT_FOLLOWUP_TO:
882  if (!news)
883  break;
884  mutt_str_copy(buf, e->env->followup_to, sizeof(buf));
885  if (mutt_get_field(Prompts[HDR_FOLLOWUPTO], buf, sizeof(buf),
886  MUTT_COMP_NO_FLAGS, false, NULL, NULL) == 0)
887  {
888  mutt_str_replace(&e->env->followup_to, buf);
890  }
891  break;
892 
893  case OP_COMPOSE_EDIT_X_COMMENT_TO:
894  {
895  const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
896  if (!(news && c_x_comment_to))
897  break;
898  mutt_str_copy(buf, e->env->x_comment_to, sizeof(buf));
899  if (mutt_get_field(Prompts[HDR_XCOMMENTTO], buf, sizeof(buf),
900  MUTT_COMP_NO_FLAGS, false, NULL, NULL) == 0)
901  {
902  mutt_str_replace(&e->env->x_comment_to, buf);
904  }
905  break;
906  }
907 #endif
908 
909  case OP_COMPOSE_EDIT_SUBJECT:
910  mutt_str_copy(buf, e->env->subject, sizeof(buf));
911  if (mutt_get_field(Prompts[HDR_SUBJECT], buf, sizeof(buf),
912  MUTT_COMP_NO_FLAGS, false, NULL, NULL) == 0)
913  {
914  if (!mutt_str_equal(e->env->subject, buf))
915  {
916  mutt_str_replace(&e->env->subject, buf);
919  }
920  }
921  break;
922 
923  case OP_COMPOSE_EDIT_REPLY_TO:
925  {
928  }
929  break;
930 
931  case OP_COMPOSE_EDIT_FCC:
932  mutt_buffer_copy(&fname, fcc);
934  false, NULL, NULL, NULL) == 0)
935  {
936  if (!mutt_str_equal(fcc->data, fname.data))
937  {
938  mutt_buffer_copy(fcc, &fname);
940  fcc_set = true;
943  }
944  }
945  break;
946 
947  case OP_COMPOSE_EDIT_MESSAGE:
948  {
949  const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
950  if (!c_edit_headers)
951  {
953  const char *const c_editor = cs_subset_string(sub, "editor");
954  mutt_edit_file(c_editor, e->body->filename);
956  mutt_update_encoding(e->body, sub);
958  /* Unconditional hook since editor was invoked */
960  break;
961  }
962  }
963  /* fallthrough */
964 
965  case OP_COMPOSE_EDIT_HEADERS:
966  {
968  const char *tag = NULL;
969  char *err = NULL;
971  const char *const c_editor = cs_subset_string(sub, "editor");
972  mutt_edit_headers(NONULL(c_editor), e->body->filename, e, fcc);
973  if (mutt_env_to_intl(e->env, &tag, &err))
974  {
975  mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
976  FREE(&err);
977  }
978  update_crypt_info(shared);
980 
982  mutt_update_encoding(e->body, sub);
983 
984  /* attachments may have been added */
985  if (actx->idxlen && actx->idx[actx->idxlen - 1]->body->next)
986  {
988  update_menu(actx, menu, true);
989  }
990 
992  /* Unconditional hook since editor was invoked */
994  break;
995  }
996 
997  case OP_COMPOSE_ATTACH_KEY:
998  {
999  if (!(WithCrypto & APPLICATION_PGP))
1000  break;
1001  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1003  if (ap->body)
1004  {
1005  update_idx(menu, actx, ap);
1008  }
1009  else
1010  FREE(&ap);
1011 
1013  break;
1014  }
1015 
1016  case OP_COMPOSE_MOVE_UP:
1017  {
1018  int index = menu_get_index(menu);
1019  if (index == 0)
1020  {
1021  mutt_error(_("Attachment is already at top"));
1022  break;
1023  }
1024  if (index == 1)
1025  {
1026  mutt_error(_("The fundamental part can't be moved"));
1027  break;
1028  }
1029  compose_attach_swap(e->body, actx->idx, index - 1);
1031  menu_set_index(menu, index - 1);
1032  break;
1033  }
1034 
1035  case OP_COMPOSE_MOVE_DOWN:
1036  {
1037  int index = menu_get_index(menu);
1038  if (index == (actx->idxlen - 1))
1039  {
1040  mutt_error(_("Attachment is already at bottom"));
1041  break;
1042  }
1043  if (index == 0)
1044  {
1045  mutt_error(_("The fundamental part can't be moved"));
1046  break;
1047  }
1048  compose_attach_swap(e->body, actx->idx, index);
1050  menu_set_index(menu, index + 1);
1051  break;
1052  }
1053 
1054  case OP_COMPOSE_GROUP_ALTS:
1055  {
1056  if (menu->tagged < 2)
1057  {
1058  mutt_error(
1059  _("Grouping 'alternatives' requires at least 2 tagged messages"));
1060  break;
1061  }
1062 
1063  struct Body *group = mutt_body_new();
1064  group->type = TYPE_MULTIPART;
1065  group->subtype = mutt_str_dup("alternative");
1066  group->disposition = DISP_INLINE;
1067 
1068  struct Body *alts = NULL;
1069  /* group tagged message into a multipart/alternative */
1070  struct Body *bptr = e->body;
1071  for (int i = 0; bptr;)
1072  {
1073  if (bptr->tagged)
1074  {
1075  bptr->tagged = false;
1076  bptr->disposition = DISP_INLINE;
1077 
1078  /* for first match, set group desc according to match */
1079 #define ALTS_TAG "Alternatives for \"%s\""
1080  if (!group->description)
1081  {
1082  char *p = bptr->description ? bptr->description : bptr->filename;
1083  if (p)
1084  {
1085  group->description =
1086  mutt_mem_calloc(1, strlen(p) + strlen(ALTS_TAG) + 1);
1087  sprintf(group->description, ALTS_TAG, p);
1088  }
1089  }
1090 
1091  // append bptr to the alts list, and remove from the e->body list
1092  if (alts)
1093  {
1094  alts->next = bptr;
1095  bptr = bptr->next;
1096  alts = alts->next;
1097  alts->next = NULL;
1098  }
1099  else
1100  {
1101  group->parts = bptr;
1102  alts = bptr;
1103  bptr = bptr->next;
1104  alts->next = NULL;
1105  }
1106 
1107  for (int j = i; j < actx->idxlen - 1; j++)
1108  {
1109  actx->idx[j] = actx->idx[j + 1];
1110  actx->idx[j + 1] = NULL; /* for debug reason */
1111  }
1112  actx->idxlen--;
1113  }
1114  else
1115  {
1116  bptr = bptr->next;
1117  i++;
1118  }
1119  }
1120 
1121  group->next = NULL;
1123 
1124  /* if no group desc yet, make one up */
1125  if (!group->description)
1126  group->description = mutt_str_dup("unknown alternative group");
1127 
1128  struct AttachPtr *gptr = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1129  gptr->body = group;
1130  update_idx(menu, actx, gptr);
1132  break;
1133  }
1134 
1135  case OP_COMPOSE_GROUP_LINGUAL:
1136  {
1137  if (menu->tagged < 2)
1138  {
1139  mutt_error(
1140  _("Grouping 'multilingual' requires at least 2 tagged messages"));
1141  break;
1142  }
1143 
1144  /* traverse to see whether all the parts have Content-Language: set */
1145  int tagged_with_lang_num = 0;
1146  for (struct Body *b = e->body; b; b = b->next)
1147  if (b->tagged && b->language && *b->language)
1148  tagged_with_lang_num++;
1149 
1150  if (menu->tagged != tagged_with_lang_num)
1151  {
1152  if (mutt_yesorno(
1153  _("Not all parts have 'Content-Language' set, continue?"), MUTT_YES) != MUTT_YES)
1154  {
1155  mutt_message(_("Not sending this message"));
1156  break;
1157  }
1158  }
1159 
1160  struct Body *group = mutt_body_new();
1161  group->type = TYPE_MULTIPART;
1162  group->subtype = mutt_str_dup("multilingual");
1163  group->disposition = DISP_INLINE;
1164 
1165  struct Body *alts = NULL;
1166  /* group tagged message into a multipart/multilingual */
1167  struct Body *bptr = e->body;
1168  for (int i = 0; bptr;)
1169  {
1170  if (bptr->tagged)
1171  {
1172  bptr->tagged = false;
1173  bptr->disposition = DISP_INLINE;
1174 
1175  /* for first match, set group desc according to match */
1176 #define LINGUAL_TAG "Multilingual part for \"%s\""
1177  if (!group->description)
1178  {
1179  char *p = bptr->description ? bptr->description : bptr->filename;
1180  if (p)
1181  {
1182  group->description =
1183  mutt_mem_calloc(1, strlen(p) + strlen(LINGUAL_TAG) + 1);
1184  sprintf(group->description, LINGUAL_TAG, p);
1185  }
1186  }
1187 
1188  // append bptr to the alts list, and remove from the e->body list
1189  if (alts)
1190  {
1191  alts->next = bptr;
1192  bptr = bptr->next;
1193  alts = alts->next;
1194  alts->next = NULL;
1195  }
1196  else
1197  {
1198  group->parts = bptr;
1199  alts = bptr;
1200  bptr = bptr->next;
1201  alts->next = NULL;
1202  }
1203 
1204  for (int j = i; j < actx->idxlen - 1; j++)
1205  {
1206  actx->idx[j] = actx->idx[j + 1];
1207  actx->idx[j + 1] = NULL; /* for debug reason */
1208  }
1209  actx->idxlen--;
1210  }
1211  else
1212  {
1213  bptr = bptr->next;
1214  i++;
1215  }
1216  }
1217 
1218  group->next = NULL;
1220 
1221  /* if no group desc yet, make one up */
1222  if (!group->description)
1223  group->description = mutt_str_dup("unknown multilingual group");
1224 
1225  struct AttachPtr *gptr = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1226  gptr->body = group;
1227  update_idx(menu, actx, gptr);
1229  break;
1230  }
1231 
1232  case OP_COMPOSE_ATTACH_FILE:
1233  {
1234  char *prompt = _("Attach file");
1235  int numfiles = 0;
1236  char **files = NULL;
1237 
1238  mutt_buffer_reset(&fname);
1239  if ((mutt_buffer_enter_fname(prompt, &fname, false, NULL, true, &files,
1240  &numfiles, MUTT_SEL_MULTI) == -1) ||
1241  mutt_buffer_is_empty(&fname))
1242  {
1243  for (int i = 0; i < numfiles; i++)
1244  FREE(&files[i]);
1245 
1246  FREE(&files);
1247  break;
1248  }
1249 
1250  bool error = false;
1251  bool added_attachment = false;
1252  if (numfiles > 1)
1253  {
1254  mutt_message(ngettext("Attaching selected file...",
1255  "Attaching selected files...", numfiles));
1256  }
1257  for (int i = 0; i < numfiles; i++)
1258  {
1259  char *att = files[i];
1260  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1261  ap->unowned = true;
1262  ap->body = mutt_make_file_attach(att, sub);
1263  if (ap->body)
1264  {
1265  added_attachment = true;
1266  update_idx(menu, actx, ap);
1267  }
1268  else
1269  {
1270  error = true;
1271  mutt_error(_("Unable to attach %s"), att);
1272  FREE(&ap);
1273  }
1274  FREE(&files[i]);
1275  }
1276 
1277  FREE(&files);
1278  if (!error)
1279  mutt_clear_error();
1280 
1283  if (added_attachment)
1285  break;
1286  }
1287 
1288  case OP_COMPOSE_ATTACH_MESSAGE:
1289 #ifdef USE_NNTP
1290  case OP_COMPOSE_ATTACH_NEWS_MESSAGE:
1291 #endif
1292  {
1293  mutt_buffer_reset(&fname);
1294  char *prompt = _("Open mailbox to attach message from");
1295 
1296 #ifdef USE_NNTP
1297  OptNews = false;
1298  if (Context && (op == OP_COMPOSE_ATTACH_NEWS_MESSAGE))
1299  {
1300  const char *const c_news_server =
1301  cs_subset_string(sub, "news_server");
1302  CurrentNewsSrv = nntp_select_server(Context->mailbox, c_news_server, false);
1303  if (!CurrentNewsSrv)
1304  break;
1305 
1306  prompt = _("Open newsgroup to attach message from");
1307  OptNews = true;
1308  }
1309 #endif
1310 
1311  if (Context)
1312  {
1313 #ifdef USE_NNTP
1314  if ((op == OP_COMPOSE_ATTACH_MESSAGE) ^ (Context->mailbox->type == MUTT_NNTP))
1315 #endif
1316  {
1319  }
1320  }
1321 
1322  if ((mutt_buffer_enter_fname(prompt, &fname, true, m, false, NULL, NULL,
1323  MUTT_SEL_NO_FLAGS) == -1) ||
1324  mutt_buffer_is_empty(&fname))
1325  {
1326  break;
1327  }
1328 
1329 #ifdef USE_NNTP
1330  if (OptNews)
1332  else
1333 #endif
1334  mutt_buffer_expand_path(&fname);
1335 #ifdef USE_IMAP
1336  if (imap_path_probe(mutt_buffer_string(&fname), NULL) != MUTT_IMAP)
1337 #endif
1338 #ifdef USE_POP
1339  if (pop_path_probe(mutt_buffer_string(&fname), NULL) != MUTT_POP)
1340 #endif
1341 #ifdef USE_NNTP
1342  if (!OptNews && (nntp_path_probe(mutt_buffer_string(&fname), NULL) != MUTT_NNTP))
1343 #endif
1345  {
1346  /* check to make sure the file exists and is readable */
1347  if (access(mutt_buffer_string(&fname), R_OK) == -1)
1348  {
1350  break;
1351  }
1352  }
1353 
1355 
1356  struct Mailbox *m_attach = mx_path_resolve(mutt_buffer_string(&fname));
1357  const bool old_readonly = m_attach->readonly;
1358  if (!mx_mbox_open(m_attach, MUTT_READONLY))
1359  {
1360  mutt_error(_("Unable to open mailbox %s"), mutt_buffer_string(&fname));
1361  mx_fastclose_mailbox(m_attach);
1362  m_attach = NULL;
1363  break;
1364  }
1365  if (m_attach->msg_count == 0)
1366  {
1367  mx_mbox_close(m_attach);
1368  mutt_error(_("No messages in that folder"));
1369  break;
1370  }
1371 
1372  /* `$sort`, `$sort_aux`, `$use_threads` could be changed in mutt_index_menu() */
1373  const enum SortType old_sort = cs_subset_sort(sub, "sort");
1374  const enum SortType old_sort_aux = cs_subset_sort(sub, "sort_aux");
1375  const unsigned char old_use_threads =
1376  cs_subset_enum(sub, "use_threads");
1377 
1378  OptAttachMsg = true;
1379  mutt_message(_("Tag the messages you want to attach"));
1380  struct MuttWindow *dlg_index = index_pager_init();
1381  dialog_push(dlg_index);
1382  struct Mailbox *m_attach_new = mutt_index_menu(dlg_index, m_attach);
1383  dialog_pop();
1384  mutt_window_free(&dlg_index);
1385  OptAttachMsg = false;
1386 
1387  if (!Context)
1388  {
1389  /* Restore old $sort variables */
1390  cs_subset_str_native_set(sub, "sort", old_sort, NULL);
1391  cs_subset_str_native_set(sub, "sort_aux", old_sort_aux, NULL);
1392  cs_subset_str_native_set(sub, "use_threads", old_use_threads, NULL);
1395  break;
1396  }
1397 
1398  bool added_attachment = false;
1399  for (int i = 0; i < m_attach_new->msg_count; i++)
1400  {
1401  if (!m_attach_new->emails[i])
1402  break;
1403  if (!message_is_tagged(m_attach_new->emails[i]))
1404  continue;
1405 
1406  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1407  ap->body = mutt_make_message_attach(m_attach_new,
1408  m_attach_new->emails[i], true, sub);
1409  if (ap->body)
1410  {
1411  added_attachment = true;
1412  update_idx(menu, actx, ap);
1413  }
1414  else
1415  {
1416  mutt_error(_("Unable to attach"));
1417  FREE(&ap);
1418  }
1419  }
1421 
1422  if (m_attach_new == m_attach)
1423  {
1424  m_attach->readonly = old_readonly;
1425  }
1426  mx_fastclose_mailbox(m_attach_new);
1427 
1428  /* Restore old $sort variables */
1429  cs_subset_str_native_set(sub, "sort", old_sort, NULL);
1430  cs_subset_str_native_set(sub, "sort_aux", old_sort_aux, NULL);
1431  cs_subset_str_native_set(sub, "use_threads", old_use_threads, NULL);
1432  if (added_attachment)
1434  break;
1435  }
1436 
1437  case OP_DELETE:
1438  {
1439  if (!check_count(actx))
1440  break;
1441  struct AttachPtr *cur_att = current_attachment(actx, menu);
1442  if (cur_att->unowned)
1443  cur_att->body->unlink = false;
1444  int index = menu_get_index(menu);
1445  if (delete_attachment(actx, index) == -1)
1446  break;
1447  update_menu(actx, menu, false);
1449  index = menu_get_index(menu);
1450  if (index == 0)
1451  e->body = actx->idx[0]->body;
1452 
1454  break;
1455  }
1456 
1457  case OP_COMPOSE_TOGGLE_RECODE:
1458  {
1459  if (!check_count(actx))
1460  break;
1461  struct AttachPtr *cur_att = current_attachment(actx, menu);
1462  if (!mutt_is_text_part(cur_att->body))
1463  {
1464  mutt_error(_("Recoding only affects text attachments"));
1465  break;
1466  }
1467  cur_att->body->noconv = !cur_att->body->noconv;
1468  if (cur_att->body->noconv)
1469  mutt_message(_("The current attachment won't be converted"));
1470  else
1471  mutt_message(_("The current attachment will be converted"));
1474  break;
1475  }
1476 
1477  case OP_COMPOSE_EDIT_DESCRIPTION:
1478  {
1479  if (!check_count(actx))
1480  break;
1481  struct AttachPtr *cur_att = current_attachment(actx, menu);
1482  mutt_str_copy(buf, cur_att->body->description, sizeof(buf));
1483  /* header names should not be translated */
1484  if (mutt_get_field("Description: ", buf, sizeof(buf),
1485  MUTT_COMP_NO_FLAGS, false, NULL, NULL) == 0)
1486  {
1487  if (!mutt_str_equal(cur_att->body->description, buf))
1488  {
1489  mutt_str_replace(&cur_att->body->description, buf);
1492  }
1493  }
1494  break;
1495  }
1496 
1497  case OP_COMPOSE_UPDATE_ENCODING:
1498  {
1499  if (!check_count(actx))
1500  break;
1501  bool encoding_updated = false;
1502  if (menu->tagprefix)
1503  {
1504  struct Body *top = NULL;
1505  for (top = e->body; top; top = top->next)
1506  {
1507  if (top->tagged)
1508  {
1509  encoding_updated = true;
1510  mutt_update_encoding(top, sub);
1511  }
1512  }
1514  }
1515  else
1516  {
1517  struct AttachPtr *cur_att = current_attachment(actx, menu);
1518  mutt_update_encoding(cur_att->body, sub);
1519  encoding_updated = true;
1522  }
1523  if (encoding_updated)
1525  break;
1526  }
1527 
1528  case OP_COMPOSE_TOGGLE_DISPOSITION:
1529  {
1530  /* toggle the content-disposition between inline/attachment */
1531  struct AttachPtr *cur_att = current_attachment(actx, menu);
1532  cur_att->body->disposition =
1533  (cur_att->body->disposition == DISP_INLINE) ? DISP_ATTACH : DISP_INLINE;
1535  break;
1536  }
1537 
1538  case OP_EDIT_TYPE:
1539  {
1540  if (!check_count(actx))
1541  break;
1542  {
1543  struct AttachPtr *cur_att = current_attachment(actx, menu);
1544  if (mutt_edit_content_type(NULL, cur_att->body, NULL))
1545  {
1546  /* this may have been a change to text/something */
1547  mutt_update_encoding(cur_att->body, sub);
1550  }
1551  }
1552  break;
1553  }
1554 
1555  case OP_COMPOSE_EDIT_LANGUAGE:
1556  {
1557  if (!check_count(actx))
1558  break;
1559  struct AttachPtr *cur_att = current_attachment(actx, menu);
1560  mutt_str_copy(buf, cur_att->body->language, sizeof(buf));
1561  if (mutt_get_field("Content-Language: ", buf, sizeof(buf),
1562  MUTT_COMP_NO_FLAGS, false, NULL, NULL) == 0)
1563  {
1564  if (!mutt_str_equal(cur_att->body->language, buf))
1565  {
1566  cur_att->body->language = mutt_str_dup(buf);
1570  }
1571  mutt_clear_error();
1572  }
1573  else
1574  mutt_warning(_("Empty 'Content-Language'"));
1575  break;
1576  }
1577 
1578  case OP_COMPOSE_EDIT_ENCODING:
1579  {
1580  if (!check_count(actx))
1581  break;
1582  struct AttachPtr *cur_att = current_attachment(actx, menu);
1583  mutt_str_copy(buf, ENCODING(cur_att->body->encoding), sizeof(buf));
1584  if ((mutt_get_field("Content-Transfer-Encoding: ", buf, sizeof(buf),
1585  MUTT_COMP_NO_FLAGS, false, NULL, NULL) == 0) &&
1586  (buf[0] != '\0'))
1587  {
1588  int enc = mutt_check_encoding(buf);
1589  if ((enc != ENC_OTHER) && (enc != ENC_UUENCODED))
1590  {
1591  if (enc != cur_att->body->encoding)
1592  {
1593  cur_att->body->encoding = enc;
1596  mutt_clear_error();
1598  }
1599  }
1600  else
1601  mutt_error(_("Invalid encoding"));
1602  }
1603  break;
1604  }
1605 
1606  case OP_COMPOSE_SEND_MESSAGE:
1607  /* Note: We don't invoke send2-hook here, since we want to leave
1608  * users an opportunity to change settings from the ":" prompt. */
1609  if (check_attachments(actx, sub) != 0)
1610  {
1612  break;
1613  }
1614 
1615 #ifdef MIXMASTER
1616  if (!STAILQ_EMPTY(&e->chain) && (mix_check_message(e) != 0))
1617  break;
1618 #endif
1619 
1620  if (!fcc_set && !mutt_buffer_is_empty(fcc))
1621  {
1622  const enum QuadOption c_copy = cs_subset_quad(sub, "copy");
1623  enum QuadOption ans =
1624  query_quadoption(c_copy, _("Save a copy of this message?"));
1625  if (ans == MUTT_ABORT)
1626  break;
1627  else if (ans == MUTT_NO)
1628  mutt_buffer_reset(fcc);
1629  }
1630 
1631  loop = false;
1632  rc = 0;
1633  break;
1634 
1635  case OP_COMPOSE_EDIT_FILE:
1636  {
1637  if (!check_count(actx))
1638  break;
1639  struct AttachPtr *cur_att = current_attachment(actx, menu);
1640  const char *const c_editor = cs_subset_string(sub, "editor");
1641  mutt_edit_file(NONULL(c_editor), cur_att->body->filename);
1642  mutt_update_encoding(cur_att->body, sub);
1645  /* Unconditional hook since editor was invoked */
1647  break;
1648  }
1649 
1650  case OP_COMPOSE_TOGGLE_UNLINK:
1651  {
1652  if (!check_count(actx))
1653  break;
1654  struct AttachPtr *cur_att = current_attachment(actx, menu);
1655  cur_att->body->unlink = !cur_att->body->unlink;
1656 
1658  /* No send2hook since this doesn't change the message. */
1659  break;
1660  }
1661 
1662  case OP_COMPOSE_GET_ATTACHMENT:
1663  {
1664  if (!check_count(actx))
1665  break;
1666  struct AttachPtr *cur_att = current_attachment(actx, menu);
1667  if (menu->tagprefix)
1668  {
1669  for (struct Body *top = e->body; top; top = top->next)
1670  {
1671  if (top->tagged)
1673  }
1675  }
1676  else if (mutt_get_tmp_attachment(cur_att->body) == 0)
1678 
1679  /* No send2hook since this doesn't change the message. */
1680  break;
1681  }
1682 
1683  case OP_COMPOSE_RENAME_ATTACHMENT:
1684  {
1685  if (!check_count(actx))
1686  break;
1687  char *src = NULL;
1688  struct AttachPtr *cur_att = current_attachment(actx, menu);
1689  if (cur_att->body->d_filename)
1690  src = cur_att->body->d_filename;
1691  else
1692  src = cur_att->body->filename;
1694  int ret = mutt_buffer_get_field(_("Send attachment with name: "), &fname,
1695  MUTT_FILE, false, NULL, NULL, NULL);
1696  if (ret == 0)
1697  {
1698  /* As opposed to RENAME_FILE, we don't check buf[0] because it's
1699  * valid to set an empty string here, to erase what was set */
1700  mutt_str_replace(&cur_att->body->d_filename, mutt_buffer_string(&fname));
1702  }
1703  break;
1704  }
1705 
1706  case OP_COMPOSE_RENAME_FILE:
1707  {
1708  if (!check_count(actx))
1709  break;
1710  struct AttachPtr *cur_att = current_attachment(actx, menu);
1711  mutt_buffer_strcpy(&fname, cur_att->body->filename);
1713  if ((mutt_buffer_get_field(_("Rename to: "), &fname, MUTT_FILE, false,
1714  NULL, NULL, NULL) == 0) &&
1715  !mutt_buffer_is_empty(&fname))
1716  {
1717  struct stat st;
1718  if (stat(cur_att->body->filename, &st) == -1)
1719  {
1720  /* L10N: "stat" is a system call. Do "man 2 stat" for more information. */
1721  mutt_error(_("Can't stat %s: %s"), mutt_buffer_string(&fname), strerror(errno));
1722  break;
1723  }
1724 
1725  mutt_buffer_expand_path(&fname);
1726  if (mutt_file_rename(cur_att->body->filename, mutt_buffer_string(&fname)))
1727  break;
1728 
1729  mutt_str_replace(&cur_att->body->filename, mutt_buffer_string(&fname));
1731 
1732  if (cur_att->body->stamp >= st.st_mtime)
1733  mutt_stamp_attachment(cur_att->body);
1735  }
1736  break;
1737  }
1738 
1739  case OP_COMPOSE_NEW_MIME:
1740  {
1741  mutt_buffer_reset(&fname);
1742  if ((mutt_buffer_get_field(_("New file: "), &fname, MUTT_FILE, false,
1743  NULL, NULL, NULL) != 0) ||
1744  mutt_buffer_is_empty(&fname))
1745  {
1746  continue;
1747  }
1748  mutt_buffer_expand_path(&fname);
1749 
1750  /* Call to lookup_mime_type () ? maybe later */
1751  char type[256] = { 0 };
1752  if ((mutt_get_field("Content-Type: ", type, sizeof(type),
1753  MUTT_COMP_NO_FLAGS, false, NULL, NULL) != 0) ||
1754  (type[0] == '\0'))
1755  {
1756  continue;
1757  }
1758 
1759  char *p = strchr(type, '/');
1760  if (!p)
1761  {
1762  mutt_error(_("Content-Type is of the form base/sub"));
1763  continue;
1764  }
1765  *p++ = 0;
1766  enum ContentType itype = mutt_check_mime_type(type);
1767  if (itype == TYPE_OTHER)
1768  {
1769  mutt_error(_("Unknown Content-Type %s"), type);
1770  continue;
1771  }
1772  struct AttachPtr *ap = mutt_mem_calloc(1, sizeof(struct AttachPtr));
1773  /* Touch the file */
1774  FILE *fp = mutt_file_fopen(mutt_buffer_string(&fname), "w");
1775  if (!fp)
1776  {
1777  mutt_error(_("Can't create file %s"), mutt_buffer_string(&fname));
1778  FREE(&ap);
1779  continue;
1780  }
1781  mutt_file_fclose(&fp);
1782 
1783  ap->body = mutt_make_file_attach(mutt_buffer_string(&fname), sub);
1784  if (!ap->body)
1785  {
1786  mutt_error(_("What we have here is a failure to make an attachment"));
1787  FREE(&ap);
1788  continue;
1789  }
1790  update_idx(menu, actx, ap);
1791 
1792  struct AttachPtr *cur_att = current_attachment(actx, menu);
1793  cur_att->body->type = itype;
1794  mutt_str_replace(&cur_att->body->subtype, p);
1795  cur_att->body->unlink = true;
1798 
1799  if (mutt_compose_attachment(cur_att->body))
1800  {
1801  mutt_update_encoding(cur_att->body, sub);
1803  }
1805  break;
1806  }
1807 
1808  case OP_COMPOSE_EDIT_MIME:
1809  {
1810  if (!check_count(actx))
1811  break;
1812  struct AttachPtr *cur_att = current_attachment(actx, menu);
1813  if (mutt_edit_attachment(cur_att->body))
1814  {
1815  mutt_update_encoding(cur_att->body, sub);
1818  }
1819  break;
1820  }
1821 
1822  case OP_VIEW_ATTACH:
1823  case OP_DISPLAY_HEADERS:
1824  if (!check_count(actx))
1825  break;
1826  mutt_attach_display_loop(sub, menu, op, e, actx, false);
1828  /* no send2hook, since this doesn't modify the message */
1829  break;
1830 
1831  case OP_SAVE:
1832  {
1833  if (!check_count(actx))
1834  break;
1835  struct AttachPtr *cur_att = current_attachment(actx, menu);
1836  mutt_save_attachment_list(actx, NULL, menu->tagprefix, cur_att->body, NULL, menu);
1837  /* no send2hook, since this doesn't modify the message */
1838  break;
1839  }
1840 
1841  case OP_PRINT:
1842  {
1843  if (!check_count(actx))
1844  break;
1845  struct AttachPtr *cur_att = current_attachment(actx, menu);
1846  mutt_print_attachment_list(actx, NULL, menu->tagprefix, cur_att->body);
1847  /* no send2hook, since this doesn't modify the message */
1848  break;
1849  }
1850 
1851  case OP_PIPE:
1852  case OP_FILTER:
1853  {
1854  if (!check_count(actx))
1855  break;
1856  struct AttachPtr *cur_att = current_attachment(actx, menu);
1857  mutt_pipe_attachment_list(actx, NULL, menu->tagprefix, cur_att->body,
1858  (op == OP_FILTER));
1859  if (op == OP_FILTER) /* cte might have changed */
1863  break;
1864  }
1865 
1866  case OP_EXIT:
1867  {
1868  const enum QuadOption c_postpone = cs_subset_quad(sub, "postpone");
1869  enum QuadOption ans =
1870  query_quadoption(c_postpone, _("Save (postpone) draft message?"));
1871  if (ans == MUTT_NO)
1872  {
1873  for (int i = 0; i < actx->idxlen; i++)
1874  if (actx->idx[i]->unowned)
1875  actx->idx[i]->body->unlink = false;
1876 
1877  if (!(flags & MUTT_COMPOSE_NOFREEHEADER))
1878  {
1879  for (int i = 0; i < actx->idxlen; i++)
1880  {
1881  /* avoid freeing other attachments */
1882  actx->idx[i]->body->next = NULL;
1883  /* See the comment in delete_attachment() */
1884  if (!actx->idx[i]->body->email)
1885  actx->idx[i]->body->parts = NULL;
1886  mutt_body_free(&actx->idx[i]->body);
1887  }
1888  }
1889  rc = -1;
1890  loop = false;
1891  break;
1892  }
1893  else if (ans == MUTT_ABORT)
1894  break; /* abort */
1895  }
1896  /* fallthrough */
1897 
1898  case OP_COMPOSE_POSTPONE_MESSAGE:
1899  if (check_attachments(actx, sub) != 0)
1900  {
1902  break;
1903  }
1904 
1905  loop = false;
1906  rc = 1;
1907  break;
1908 
1909  case OP_COMPOSE_ISPELL:
1910  {
1911  endwin();
1912  const char *const c_ispell = cs_subset_string(sub, "ispell");
1913  snprintf(buf, sizeof(buf), "%s -x %s", NONULL(c_ispell), e->body->filename);
1914  if (mutt_system(buf) == -1)
1915  mutt_error(_("Error running \"%s\""), buf);
1916  else
1917  {
1918  mutt_update_encoding(e->body, sub);
1920  }
1921  break;
1922  }
1923 
1924  case OP_COMPOSE_WRITE_MESSAGE:
1925  mutt_buffer_reset(&fname);
1926  if (Context)
1927  {
1930  }
1931  if (actx->idxlen)
1932  e->body = actx->idx[0]->body;
1933  if ((mutt_buffer_enter_fname(_("Write message to mailbox"), &fname, true, m,
1934  false, NULL, NULL, MUTT_SEL_NO_FLAGS) != -1) &&
1935  !mutt_buffer_is_empty(&fname))
1936  {
1937  mutt_message(_("Writing message to %s ..."), mutt_buffer_string(&fname));
1938  mutt_buffer_expand_path(&fname);
1939 
1940  if (e->body->next)
1941  e->body = mutt_make_multipart(e->body);
1942 
1943  if (mutt_write_fcc(mutt_buffer_string(&fname), e, NULL, false, NULL, NULL, sub) == 0)
1944  mutt_message(_("Message written"));
1945 
1946  e->body = mutt_remove_multipart(e->body);
1947  }
1948  break;
1949 
1950  case OP_COMPOSE_PGP_MENU:
1951  {
1952  const SecurityFlags old_flags = e->security;
1953  if (!(WithCrypto & APPLICATION_PGP))
1954  break;
1955  if (!crypt_has_module_backend(APPLICATION_PGP))
1956  {
1957  mutt_error(_("No PGP backend configured"));
1958  break;
1959  }
1960  if (((WithCrypto & APPLICATION_SMIME) != 0) && (e->security & APPLICATION_SMIME))
1961  {
1962  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1963  {
1964  if (mutt_yesorno(_("S/MIME already selected. Clear and continue?"), MUTT_YES) != MUTT_YES)
1965  {
1966  mutt_clear_error();
1967  break;
1968  }
1969  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
1970  }
1971  e->security &= ~APPLICATION_SMIME;
1972  e->security |= APPLICATION_PGP;
1973  update_crypt_info(shared);
1974  }
1975  e->security = crypt_pgp_send_menu(m, e);
1976  update_crypt_info(shared);
1977  if (old_flags != e->security)
1978  {
1981  }
1982  break;
1983  }
1984 
1985  case OP_FORGET_PASSPHRASE:
1987  break;
1988 
1989  case OP_COMPOSE_SMIME_MENU:
1990  {
1991  const SecurityFlags old_flags = e->security;
1992  if (!(WithCrypto & APPLICATION_SMIME))
1993  break;
1994  if (!crypt_has_module_backend(APPLICATION_SMIME))
1995  {
1996  mutt_error(_("No S/MIME backend configured"));
1997  break;
1998  }
1999 
2000  if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & APPLICATION_PGP))
2001  {
2002  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
2003  {
2004  if (mutt_yesorno(_("PGP already selected. Clear and continue?"), MUTT_YES) != MUTT_YES)
2005  {
2006  mutt_clear_error();
2007  break;
2008  }
2009  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2010  }
2011  e->security &= ~APPLICATION_PGP;
2013  update_crypt_info(shared);
2014  }
2015  e->security = crypt_smime_send_menu(m, e);
2016  update_crypt_info(shared);
2017  if (old_flags != e->security)
2018  {
2021  }
2022  break;
2023  }
2024 
2025 #ifdef MIXMASTER
2026  case OP_COMPOSE_MIX:
2030  break;
2031 #endif
2032 
2033 #ifdef USE_AUTOCRYPT
2034  case OP_COMPOSE_AUTOCRYPT_MENU:
2035  {
2036  const SecurityFlags old_flags = e->security;
2037  const bool c_autocrypt = cs_subset_bool(sub, "autocrypt");
2038  if (!c_autocrypt)
2039  break;
2040 
2041  if ((WithCrypto & APPLICATION_SMIME) && (e->security & APPLICATION_SMIME))
2042  {
2043  if (e->security & (SEC_ENCRYPT | SEC_SIGN))
2044  {
2045  if (mutt_yesorno(_("S/MIME already selected. Clear and continue?"), MUTT_YES) != MUTT_YES)
2046  {
2047  mutt_clear_error();
2048  break;
2049  }
2050  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2051  }
2052  e->security &= ~APPLICATION_SMIME;
2053  e->security |= APPLICATION_PGP;
2054  update_crypt_info(shared);
2055  }
2056  autocrypt_compose_menu(e, sub);
2057  update_crypt_info(shared);
2058  if (old_flags != e->security)
2059  {
2062  }
2063  break;
2064  }
2065 #endif
2066  }
2067  }
2068 
2069  mutt_buffer_dealloc(&fname);
2070 
2071 #ifdef USE_AUTOCRYPT
2072  /* This is a fail-safe to make sure the bit isn't somehow turned
2073  * on. The user could have disabled the option after setting SEC_AUTOCRYPT,
2074  * or perhaps resuming or replying to an autocrypt message. */
2075  const bool c_autocrypt = cs_subset_bool(sub, "autocrypt");
2076  if (!c_autocrypt)
2077  e->security &= ~SEC_AUTOCRYPT;
2078 #endif
2079 
2080  if (actx->idxlen)
2081  e->body = actx->idx[0]->body;
2082  else
2083  e->body = NULL;
2084 
2085  dialog_pop();
2086  mutt_window_free(&dlg);
2087 
2088  return rc;
2089 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
"Fcc:" (save folder) field
Definition: private.h:52
The "current" mailbox.
Definition: context.h:37
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:215
static int delete_attachment(struct AttachCtx *actx, int x)
Delete an attachment.
Definition: compose.c:539
void mutt_stamp_attachment(struct Body *a)
Timestamp an Attachment.
Definition: sendlib.c:892
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
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
An email to which things will be attached.
Definition: attach.h:34
int msg_count
Total number of messages.
Definition: mailbox.h:91
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
"Followup-To:" field
Definition: private.h:63
#define WithCrypto
Definition: lib.h:113
bool mx_mbox_open(struct Mailbox *m, OpenMailboxFlags flags)
Open a mailbox and parse it.
Definition: mx.c:304
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:58
SortType
Methods for sorting.
Definition: sort2.h:41
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:904
Definition: lib.h:67
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:40
struct Body * body
List of MIME parts.
Definition: email.h:91
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:444
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer&#39;s contents to another Buffer.
Definition: buffer.c:445
#define mutt_error(...)
Definition: logging.h:88
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
const char * mutt_path_basename(const char *f)
Find the last component for a pathname.
Definition: path.c:329
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:268
static struct MuttWindow * compose_dlg_init(struct ConfigSubset *sub, struct Email *e, struct Buffer *fcc)
Allocate the Windows for Compose.
Definition: compose.c:706
int help_menu
Menu for key bindings, e.g. MENU_PAGER.
Definition: mutt_window.h:141
int mutt_file_rename(const char *oldfile, const char *newfile)
Rename a file.
Definition: file.c:1350
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
enum MailboxType pop_path_probe(const char *path, const struct stat *st)
Is this a POP Mailbox? - Implements MxOps::path_probe() -.
Definition: pop.c:1165
SecurityFlags crypt_pgp_send_menu(struct Mailbox *m, struct Email *e)
Wrapper for CryptModuleSpecs::send_menu()
Definition: cryptglue.c:390
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, struct Email *e, struct Menu *menu)
Save a list of attachments.
Definition: recvattach.c:788
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
Write email to FCC mailbox.
Definition: sendlib.c:1515
bool noconv
Don&#39;t do character set conversion.
Definition: body.h:73
static struct AttachPtr * current_attachment(struct AttachCtx *actx, struct Menu *menu)
Get the current attachment.
Definition: compose.c:341
void crypt_forget_passphrase(void)
Forget a passphrase and display a message.
Definition: crypt.c:93
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope&#39;s Address fields to Punycode format.
Definition: envelope.c:309
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
int mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:258
String manipulation buffer.
Definition: buffer.h:33
Shared Compose Data.
Definition: shared_data.h:29
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define NT_COMPOSE_ENVELOPE
Envelope has changed.
Definition: private.h:37
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
short idxlen
Number of attachmentes.
Definition: attach.h:55
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:632
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope&#39;s Address fields to local format.
Definition: envelope.c:271
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: browser.h:36
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:84
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:71
Compose an email.
Definition: type.h:42
"From:" field
Definition: private.h:46
enum MxStatus mx_mbox_close(struct Mailbox *m)
Save changes and close mailbox.
Definition: mx.c:610
"Newsgroups:" field
Definition: private.h:62
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:603
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:53
The body of an email.
Definition: body.h:34
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:200
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
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:305
size_t dsize
Length of data.
Definition: buffer.h:37
void mutt_print_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top)
Print a list of Attachments.
Definition: recvattach.c:1240
int mutt_get_tmp_attachment(struct Body *a)
Get a temporary copy of an attachment.
Definition: mutt_attach.c:68
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
struct Mailbox * mailbox
Definition: context.h:49
#define MUTT_COMPOSE_NOFREEHEADER
Definition: lib.h:51
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:326
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition: context.c:350
void mutt_actx_entries_free(struct AttachCtx *actx)
Free entries in an Attachment Context.
Definition: attach.c:103
struct Envelope * env
Envelope information.
Definition: email.h:90
struct Body * mutt_make_file_attach(const char *path, struct ConfigSubset *sub)
Create a file attachment.
Definition: sendlib.c:1088
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
#define ENCODING(x)
Definition: mime.h:92
void mx_fastclose_mailbox(struct Mailbox *m)
free up memory associated with the Mailbox
Definition: mx.c:429
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
static int compose_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t.
Definition: compose.c:299
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
Content is attached.
Definition: mime.h:63
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2402
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: dialog.c:105
static void compose_attach_swap(struct Body *msg, struct AttachPtr **idx, short first)
Swap two adjacent entries in the attachment list.
Definition: compose.c:673
void mutt_rfc3676_space_unstuff(struct Email *e)
Remove RFC3676 space stuffing.
Definition: rfc3676.c:496
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
"Bcc:" field
Definition: private.h:49
bool tagged
This attachment is tagged.
Definition: body.h:70
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
User aborted the question (with Ctrl-G)
Definition: quad.h:37
void update_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Redraw the compose window.
Definition: compose.c:624
const char * OpStrings[][2]
Definition: opcodes.c:34
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:189
struct NntpAccountData * nntp_select_server(struct Mailbox *m, const char *server, bool leave_lock)
Open a connection to an NNTP server.
Definition: newsrc.c:1017
#define mutt_warning(...)
Definition: logging.h:86
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
bool unowned
Don&#39;t unlink on detach.
Definition: attach.h:42
#define NT_COMPOSE_ATTACH
Attachments have changed.
Definition: private.h:36
char * subtype
content-type subtype
Definition: body.h:37
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition: helpers.c:292
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
static const struct Mapping ComposeHelp[]
Help Bar for the Compose dialog.
Definition: compose.c:179
static int check_attachments(struct AttachCtx *actx, struct ConfigSubset *sub)
Check if any attachments have changed or been deleted.
Definition: compose.c:443
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
struct ListHead chain
Mixmaster chain.
Definition: email.h:102
void dlg_select_mixmaster_chain(struct ListHead *chainhead)
Create a Mixmaster chain.
Definition: remailer.c:641
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: multipart.c:126
static void autocrypt_compose_menu(struct Email *e, const struct ConfigSubset *sub)
Autocrypt compose settings.
Definition: compose.c:355
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
SecurityFlags crypt_smime_send_menu(struct Mailbox *m, struct Email *e)
Wrapper for CryptModuleSpecs::send_menu()
Definition: cryptglue.c:536
WHERE bool OptAttachMsg
(pseudo) used by attach-message
Definition: options.h:31
&#39;POP3&#39; Mailbox type
Definition: mailbox.h:55
int mutt_check_encoding(const char *c)
Check the encoding type.
Definition: parse.c:399
#define ALTS_TAG
A mailbox.
Definition: mailbox.h:81
#define PATH_MAX
Definition: mutt.h:40
bool tagprefix
User has pressed <tag-prefix>
Definition: lib.h:75
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
Create a message attachment.
Definition: sendlib.c:936
struct MuttWindow * index_pager_init(void)
Allocate the Windows for the Index/Pager.
Definition: dlg_index.c:1406
static bool check_count(struct AttachCtx *actx)
Check if there are any attachments.
Definition: compose.c:324
"Cc:" field
Definition: private.h:48
const struct Mapping * help_data
Data for the Help Bar.
Definition: mutt_window.h:142
char * data
Pointer to data.
Definition: buffer.h:35
static bool edit_address_list(int field, struct AddressList *al)
Let the user edit the address list.
Definition: compose.c:506
#define MUTT_READONLY
Open in read-only mode.
Definition: mxapi.h:63
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
struct Mailbox * mutt_index_menu(struct MuttWindow *dlg, struct Mailbox *m_init)
Display a list of emails.
Definition: dlg_index.c:1035
Compose data has changed, NotifyCompose.
Definition: notify_type.h:41
int mutt_attach_display_loop(struct ConfigSubset *sub, struct Menu *menu, int op, struct Email *e, struct AttachCtx *actx, bool recv)
Event loop for the Attachment menu.
Definition: recvattach.c:1373
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
char * description
content-description
Definition: body.h:40
bool mutt_is_text_part(struct Body *b)
Is this part of an email in plain text?
Definition: muttlib.c:434
const char *const Prompts[]
Definition: compose.c:136
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
struct AttachCtx * actx
Definition: attach_data.h:34
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define MUTT_SEL_MULTI
Multi-selection is enabled.
Definition: browser.h:38
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
int tagged
Number of tagged entries.
Definition: lib.h:92
#define MUTT_FILE
Do file completion.
Definition: mutt.h:54
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
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, ContentType
Definition: body.h:65
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
#define LINGUAL_TAG
"Reply-To:" field
Definition: private.h:51
Config has changed, NotifyConfig, EventConfig.
Definition: notify_type.h:42
#define SEC_SIGN
Email is signed.
Definition: lib.h:76
bool crypt_has_module_backend(SecurityFlags type)
Is there a crypto backend for a given type?
Definition: cryptglue.c:172
static void update_idx(struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
Add a new attchment to the message.
Definition: compose.c:656
struct Connection * conn
Definition: adata.h:63
static int compose_config_observer(struct NotifyCallback *nc)
Notification that a Config Variable has changed - Implements observer_t.
Definition: compose.c:268
void mutt_pipe_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, struct Body *top, bool filter)
Pipe a list of attachments to a command.
Definition: recvattach.c:1081
void mutt_edit_headers(const char *editor, const char *body, struct Email *e, struct Buffer *fcc)
Let the user edit the message header and body.
Definition: mutt_header.c:170
enum MailboxType mx_path_probe(const char *path)
Find a mailbox that understands a path.
Definition: mx.c:1317
"X-Comment-To:" field
Definition: private.h:64
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition: cryptglue.c:310
char * subject
Email&#39;s subject.
Definition: envelope.h:66
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
int mutt_buffer_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file.
Definition: curs_lib.c:513
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
Log at debug level 1.
Definition: logging.h:40
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
#define MUTT_SEND2_HOOK
send2-hook: when changing fields in the compose menu
Definition: hook.h:50
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
struct Menu * menu
Definition: attach_data.h:35
time_t stamp
Time stamp of last encoding update.
Definition: body.h:61
struct Notify * notify
Notifications: NotifyCompose.
Definition: shared_data.h:36
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition: rfc3676.c:483
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
void dialog_pop(void)
Hide a Window from the user.
Definition: dialog.c:139
enum MailboxType nntp_path_probe(const char *path, const struct stat *st)
Is this an NNTP Mailbox? - Implements MxOps::path_probe() -.
Definition: nntp.c:2709
#define mutt_message(...)
Definition: logging.h:87
static void update_crypt_info(struct ComposeSharedData *shared)
Update the crypto info.
Definition: compose.c:397
unsigned char cs_subset_enum(const struct ConfigSubset *sub, const char *name)
Get a enumeration config item by name.
Definition: helpers.c:97
#define FREE(x)
Definition: memory.h:40
struct Mailbox * mx_path_resolve(const char *path)
Get a Mailbox for a path.
Definition: mx.c:1668
char * language
content-language (RFC8255)
Definition: body.h:38
#define STAILQ_EMPTY(head)
Definition: queue.h:348
struct NntpAccountData * CurrentNewsSrv
Current NNTP news server.
Definition: nntp.c:78
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
static void init_header_padding(void)
Calculate how much padding the compose table will need.
Definition: compose.c:237
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:598
bool mutt_edit_content_type(struct Email *e, struct Body *b, FILE *fp)
Edit the content type of an attachment.
Definition: commands.c:1433
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:45
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
void nntp_expand_path(char *buf, size_t buflen, struct ConnAccount *acct)
Make fully qualified url from newsgroup name.
Definition: newsrc.c:559
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
"To:" field
Definition: private.h:47
Content is inline.
Definition: mime.h:62
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
void * wdata
Private data.
Definition: mutt_window.h:145
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
struct Email * email
header information for message/rfc822
Definition: body.h:55
A set of attachments.
Definition: attach.h:49
Encoding unknown.
Definition: mime.h:48
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:380
WHERE bool OptNews
(pseudo) used to change reader mode
Definition: options.h:44
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
UUEncoded text.
Definition: mime.h:54
"Subject:" field
Definition: private.h:50
int mutt_compose_attachment(struct Body *a)
Create an attachment.
Definition: mutt_attach.c:118
int mix_check_message(struct Email *e)
Safety-check the message before passing it to mixmaster.
Definition: remailer.c:883
static const struct Mapping ComposeNewsHelp[]
Help Bar for the News Compose dialog.
Definition: compose.c:198
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
ContentType
Content-Type.
Definition: mime.h:29
struct ComposeAttachData * adata
Attachments.
Definition: shared_data.h:34
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
struct Body * body
Attachment.
Definition: attach.h:36
+ Here is the caller graph for this function:

Variable Documentation

◆ HeaderPadding

int HeaderPadding[HDR_ATTACH_TITLE] = { 0 }

Definition at line 133 of file compose.c.

◆ MaxHeaderWidth

int MaxHeaderWidth = 0

Definition at line 134 of file compose.c.

◆ Prompts

const char* const Prompts[]

Definition at line 136 of file compose.c.

◆ ComposeHelp

const struct Mapping ComposeHelp[]
static
Initial value:
= {
{ N_("Send"), OP_COMPOSE_SEND_MESSAGE },
{ N_("Abort"), OP_EXIT },
{ N_("To"), OP_COMPOSE_EDIT_TO },
{ N_("CC"), OP_COMPOSE_EDIT_CC },
{ N_("Subj"), OP_COMPOSE_EDIT_SUBJECT },
{ N_("Attach file"), OP_COMPOSE_ATTACH_FILE },
{ N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Help Bar for the Compose dialog.

Definition at line 179 of file compose.c.

◆ ComposeNewsHelp

const struct Mapping ComposeNewsHelp[]
static
Initial value:
= {
{ N_("Send"), OP_COMPOSE_SEND_MESSAGE },
{ N_("Abort"), OP_EXIT },
{ N_("Newsgroups"), OP_COMPOSE_EDIT_NEWSGROUPS },
{ N_("Subj"), OP_COMPOSE_EDIT_SUBJECT },
{ N_("Attach file"), OP_COMPOSE_ATTACH_FILE },
{ N_("Descrip"), OP_COMPOSE_EDIT_DESCRIPTION },
{ N_("Help"), OP_HELP },
{ NULL, 0 },
}
#define N_(a)
Definition: message.h:32

Help Bar for the News Compose dialog.

Definition at line 198 of file compose.c.