NeoMutt  2024-04-25-89-g194907
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c File Reference

Compose functions. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "private.h"
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "conn/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "lib.h"
#include "attach/lib.h"
#include "browser/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "imap/lib.h"
#include "index/lib.h"
#include "key/lib.h"
#include "menu/lib.h"
#include "ncrypt/lib.h"
#include "nntp/lib.h"
#include "pop/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "attach_data.h"
#include "external.h"
#include "functions.h"
#include "globals.h"
#include "hook.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "mview.h"
#include "mx.h"
#include "nntp/adata.h"
#include "protos.h"
#include "rfc3676.h"
#include "shared_data.h"
#include <libintl.h>
#include "mixmaster/lib.h"
+ Include dependency graph for functions.c:

Go to the source code of this file.

Functions

static bool check_count (struct AttachCtx *actx)
 Check if there are any attachments.
 
static char * gen_cid (void)
 Generate a random Content ID.
 
static bool check_cid (const char *cid)
 Check if a Content-ID is valid.
 
static int check_attachments (struct AttachCtx *actx, struct ConfigSubset *sub)
 Check if any attachments have changed or been deleted.
 
static int delete_attachment (struct AttachCtx *actx, int aidx)
 Delete an attachment.
 
static void update_idx (struct Menu *menu, struct AttachCtx *actx, struct AttachPtr *ap)
 Add a new attachment to the message.
 
static void compose_attach_swap (struct Email *e, struct AttachCtx *actx, int first, int second)
 Swap two adjacent entries in the attachment list.
 
static int group_attachments (struct ComposeSharedData *shared, char *subtype)
 Group tagged attachments into a multipart group.
 
static int op_attachment_attach_file (struct ComposeSharedData *shared, int op)
 Attach files to this message - Implements compose_function_t -.
 
static int op_attachment_attach_key (struct ComposeSharedData *shared, int op)
 Attach a PGP public key - Implements compose_function_t -.
 
static int op_attachment_attach_message (struct ComposeSharedData *shared, int op)
 Attach messages to this message - Implements compose_function_t -.
 
static int op_attachment_detach (struct ComposeSharedData *shared, int op)
 Delete the current entry - Implements compose_function_t -.
 
static int op_attachment_edit_content_id (struct ComposeSharedData *shared, int op)
 Edit the 'Content-ID' of the attachment - Implements compose_function_t -.
 
static int op_attachment_edit_description (struct ComposeSharedData *shared, int op)
 Edit attachment description - Implements compose_function_t -.
 
static int op_attachment_edit_encoding (struct ComposeSharedData *shared, int op)
 Edit attachment transfer-encoding - Implements compose_function_t -.
 
static int op_attachment_edit_language (struct ComposeSharedData *shared, int op)
 Edit the 'Content-Language' of the attachment - Implements compose_function_t -.
 
static int op_attachment_edit_mime (struct ComposeSharedData *shared, int op)
 Edit attachment using mailcap entry - Implements compose_function_t -.
 
static int op_attachment_edit_type (struct ComposeSharedData *shared, int op)
 Edit attachment content type - Implements compose_function_t -.
 
static int op_attachment_filter (struct ComposeSharedData *shared, int op)
 Filter attachment through a shell command - Implements compose_function_t -.
 
static int op_attachment_get_attachment (struct ComposeSharedData *shared, int op)
 Get a temporary copy of an attachment - Implements compose_function_t -.
 
static int op_attachment_group_alts (struct ComposeSharedData *shared, int op)
 Group tagged attachments as 'multipart/alternative' - Implements compose_function_t -.
 
static int op_attachment_group_lingual (struct ComposeSharedData *shared, int op)
 Group tagged attachments as 'multipart/multilingual' - Implements compose_function_t -.
 
static int op_attachment_group_related (struct ComposeSharedData *shared, int op)
 Group tagged attachments as 'multipart/related' - Implements compose_function_t -.
 
static int op_attachment_move_down (struct ComposeSharedData *shared, int op)
 Move an attachment down in the attachment list - Implements compose_function_t -.
 
static int op_attachment_move_up (struct ComposeSharedData *shared, int op)
 Move an attachment up in the attachment list - Implements compose_function_t -.
 
static int op_attachment_new_mime (struct ComposeSharedData *shared, int op)
 Compose new attachment using mailcap entry - Implements compose_function_t -.
 
static int op_attachment_print (struct ComposeSharedData *shared, int op)
 Print the current entry - Implements compose_function_t -.
 
static int op_attachment_rename_attachment (struct ComposeSharedData *shared, int op)
 Send attachment with a different name - Implements compose_function_t -.
 
static int op_attachment_save (struct ComposeSharedData *shared, int op)
 Save message/attachment to a mailbox/file - Implements compose_function_t -.
 
static int op_attachment_toggle_disposition (struct ComposeSharedData *shared, int op)
 Toggle disposition between inline/attachment - Implements compose_function_t -.
 
static int op_attachment_toggle_recode (struct ComposeSharedData *shared, int op)
 Toggle recoding of this attachment - Implements compose_function_t -.
 
static int op_attachment_toggle_unlink (struct ComposeSharedData *shared, int op)
 Toggle whether to delete file after sending it - Implements compose_function_t -.
 
static int op_attachment_ungroup (struct ComposeSharedData *shared, int op)
 Ungroup a 'multipart' attachment - Implements compose_function_t -.
 
static int op_attachment_update_encoding (struct ComposeSharedData *shared, int op)
 Update an attachment's encoding info - Implements compose_function_t -.
 
static int op_envelope_edit_headers (struct ComposeSharedData *shared, int op)
 Edit the message with headers - Implements compose_function_t -.
 
static int op_compose_edit_file (struct ComposeSharedData *shared, int op)
 Edit the file to be attached - Implements compose_function_t -.
 
static int op_compose_edit_message (struct ComposeSharedData *shared, int op)
 Edit the message - Implements compose_function_t -.
 
static int op_compose_ispell (struct ComposeSharedData *shared, int op)
 Run ispell on the message - Implements compose_function_t -.
 
static int op_compose_postpone_message (struct ComposeSharedData *shared, int op)
 Save this message to send later - Implements compose_function_t -.
 
static int op_compose_rename_file (struct ComposeSharedData *shared, int op)
 Rename/move an attached file - Implements compose_function_t -.
 
static int op_compose_send_message (struct ComposeSharedData *shared, int op)
 Send the message - Implements compose_function_t -.
 
static int op_compose_write_message (struct ComposeSharedData *shared, int op)
 Write the message to a folder - Implements compose_function_t -.
 
static int op_display_headers (struct ComposeSharedData *shared, int op)
 Display message and toggle header weeding - Implements compose_function_t -.
 
static int op_exit (struct ComposeSharedData *shared, int op)
 Exit this menu - Implements compose_function_t -.
 
static int op_forget_passphrase (struct ComposeSharedData *shared, int op)
 Wipe passphrases from memory - Implements compose_function_t -.
 
int compose_function_dispatcher (struct MuttWindow *win, int op)
 Perform a Compose function - Implements function_dispatcher_t -.
 

Variables

const struct MenuFuncOp OpCompose []
 Functions for the Compose Menu.
 
const struct MenuOpSeq ComposeDefaultBindings []
 Key bindings for the Compose Menu.
 
static const struct ComposeFunction ComposeFunctions []
 All the NeoMutt functions that the Compose supports.
 

Detailed Description

Compose functions.

Authors
  • Pietro Cerutti
  • Richard Russon
  • David Purton

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

Function Documentation

◆ 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 225 of file functions.c.

226{
227 if (actx->idxlen == 0)
228 {
229 mutt_error(_("There are no attachments"));
230 return false;
231 }
232
233 return true;
234}
#define mutt_error(...)
Definition: logging2.h:92
#define _(a)
Definition: message.h:28
short idxlen
Number of attachmentes.
Definition: attach.h:70
+ Here is the caller graph for this function:

◆ gen_cid()

static char * gen_cid ( void  )
static

Generate a random Content ID.

Return values
ptrContent ID
Note
The caller should free the string

Definition at line 242 of file functions.c.

243{
244 char rndid[MUTT_RANDTAG_LEN + 1];
245
246 mutt_rand_base32(rndid, sizeof(rndid) - 1);
247 rndid[MUTT_RANDTAG_LEN] = 0;
248
249 return mutt_str_dup(rndid);
250}
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
void mutt_rand_base32(char *buf, size_t buflen)
Fill a buffer with a base32-encoded random string.
Definition: random.c:106
#define MUTT_RANDTAG_LEN
Definition: sendlib.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_cid()

static bool check_cid ( const char *  cid)
static

Check if a Content-ID is valid.

Parameters
cidContent-ID to check
Return values
trueContent-ID is valid
falseContent-ID is not valid

Definition at line 258 of file functions.c.

259{
260 static const char *check = "^[-\\.0-9@A-Z_a-z]+$";
261
262 struct Regex *check_cid_regex = mutt_regex_new(check, 0, NULL);
263
264 const bool valid = mutt_regex_match(check_cid_regex, cid);
265
266 mutt_regex_free(&check_cid_regex);
267
268 return valid;
269}
struct Regex * mutt_regex_new(const char *str, uint32_t flags, struct Buffer *err)
Create an Regex from a string.
Definition: regex.c:80
void mutt_regex_free(struct Regex **ptr)
Free a Regex object.
Definition: regex.c:118
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:614
Cached regular expression.
Definition: regex3.h:85
+ 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 278 of file functions.c.

279{
280 int rc = -1;
281 struct stat st = { 0 };
282 struct Buffer *pretty = NULL, *msg = NULL;
283
284 for (int i = 0; i < actx->idxlen; i++)
285 {
286 if (actx->idx[i]->body->type == TYPE_MULTIPART)
287 continue;
288 if (stat(actx->idx[i]->body->filename, &st) != 0)
289 {
290 if (!pretty)
291 pretty = buf_pool_get();
292 buf_strcpy(pretty, actx->idx[i]->body->filename);
293 buf_pretty_mailbox(pretty);
294 /* L10N: This message is displayed in the compose menu when an attachment
295 doesn't stat. %d is the attachment number and %s is the attachment
296 filename. The filename is located last to avoid a long path hiding
297 the error message. */
298 mutt_error(_("Attachment #%d no longer exists: %s"), i + 1, buf_string(pretty));
299 goto cleanup;
300 }
301
302 if (actx->idx[i]->body->stamp < st.st_mtime)
303 {
304 if (!pretty)
305 pretty = buf_pool_get();
306 buf_strcpy(pretty, actx->idx[i]->body->filename);
307 buf_pretty_mailbox(pretty);
308
309 if (!msg)
310 msg = buf_pool_get();
311 /* L10N: This message is displayed in the compose menu when an attachment
312 is modified behind the scenes. %d is the attachment number and %s is
313 the attachment filename. The filename is located last to avoid a long
314 path hiding the prompt question. */
315 buf_printf(msg, _("Attachment #%d modified. Update encoding for %s?"),
316 i + 1, buf_string(pretty));
317
319 if (ans == MUTT_YES)
320 mutt_update_encoding(actx->idx[i]->body, sub);
321 else if (ans == MUTT_ABORT)
322 goto cleanup;
323 }
324 }
325
326 rc = 0;
327
328cleanup:
329 buf_pool_release(&pretty);
330 buf_pool_release(&msg);
331 return rc;
332}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
void buf_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:519
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:326
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:422
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:69
struct Body * body
Attachment.
Definition: attach.h:38
time_t stamp
Time stamp of last encoding update.
Definition: body.h:76
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
String manipulation buffer.
Definition: buffer.h:36
+ 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  aidx 
)
static

Delete an attachment.

Parameters
actxAttachment context
aidxIndex number of attachment to delete
Return values
0Success
-1Error

Definition at line 341 of file functions.c.

342{
343 if (!actx || (aidx < 0) || (aidx >= actx->idxlen))
344 return -1;
345
346 struct AttachPtr **idx = actx->idx;
347 struct Body *b_previous = NULL;
348 struct Body *b_parent = NULL;
349
350 if (aidx == 0)
351 {
352 struct Body *b = actx->idx[0]->body;
353 if (!b->next) // There's only one attachment left
354 {
355 mutt_error(_("You may not delete the only attachment"));
356 return -1;
357 }
358
359 if (cs_subset_bool(NeoMutt->sub, "compose_confirm_detach_first"))
360 {
361 /* L10N: Prompt when trying to hit <detach-file> on the first entry in
362 the compose menu. This entry is most likely the message they just
363 typed. Hitting yes will remove the entry and unlink the file, so
364 it's worth confirming they really meant to do it. */
365 enum QuadOption ans = query_yesorno_help(_("Really delete the main message?"),
367 "compose_confirm_detach_first");
368 if (ans == MUTT_NO)
369 {
370 idx[aidx]->body->tagged = false;
371 return -1;
372 }
373 }
374 }
375
376 if (idx[aidx]->level > 0)
377 {
378 if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
379 {
380 if (attach_body_count(b_parent->parts, false) < 3)
381 {
382 mutt_error(_("Can't leave group with only one attachment"));
383 return -1;
384 }
385 }
386 }
387
388 // reorder body pointers
389 if (aidx > 0)
390 {
391 if (attach_body_previous(idx[0]->body, idx[aidx]->body, &b_previous))
392 b_previous->next = idx[aidx]->body->next;
393 else if (attach_body_parent(idx[0]->body, NULL, idx[aidx]->body, &b_parent))
394 b_parent->parts = idx[aidx]->body->next;
395 }
396
397 // free memory
398 int part_count = 1;
399 if (aidx < (actx->idxlen - 1))
400 {
401 if ((idx[aidx]->body->type == TYPE_MULTIPART) &&
402 (idx[aidx + 1]->level > idx[aidx]->level))
403 {
404 part_count += attach_body_count(idx[aidx]->body->parts, true);
405 }
406 }
407 idx[aidx]->body->next = NULL;
408 mutt_body_free(&(idx[aidx]->body));
409 for (int i = 0; i < part_count; i++)
410 {
411 FREE(&idx[aidx + i]->tree);
412 FREE(&idx[aidx + i]);
413 }
414
415 // reorder attachment list
416 for (int i = aidx; i < (actx->idxlen - part_count); i++)
417 idx[i] = idx[i + part_count];
418 for (int i = 0; i < part_count; i++)
419 idx[actx->idxlen - i - 1] = NULL;
420 actx->idxlen -= part_count;
421
422 return 0;
423}
bool attach_body_parent(struct Body *start, struct Body *start_parent, struct Body *body, struct Body **body_parent)
Find the parent of a body.
Definition: lib.c:71
int attach_body_count(struct Body *body, bool recurse)
Count bodies.
Definition: lib.c:42
bool attach_body_previous(struct Body *start, struct Body *body, struct Body **previous)
Find the previous body of a body.
Definition: lib.c:142
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:47
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:58
#define FREE(x)
Definition: memory.h:45
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition: question.c:341
An email to which things will be attached.
Definition: attach.h:37
The body of an email.
Definition: body.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool tagged
This attachment is tagged.
Definition: body.h:89
struct Body * next
next attachment in the list
Definition: body.h:71
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 attachment to the message.

Parameters
menuCurrent menu
actxAttachment context
apAttachment to add

Definition at line 431 of file functions.c.

432{
433 ap->level = 0;
434 for (int i = actx->idxlen; i > 0; i--)
435 {
436 if (ap->level == actx->idx[i - 1]->level)
437 {
438 actx->idx[i - 1]->body->next = ap->body;
439 break;
440 }
441 }
442
443 ap->body->aptr = ap;
444 mutt_actx_add_attach(actx, ap);
445 update_menu(actx, menu, false);
446 menu_set_index(menu, actx->vcount - 1);
447}
void mutt_actx_add_attach(struct AttachCtx *actx, struct AttachPtr *attach)
Add an Attachment to an Attachment Context.
Definition: attach.c:65
void update_menu(struct AttachCtx *actx, struct Menu *menu, bool init)
Redraw the compose window.
Definition: dlg_compose.c:217
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:174
short vcount
The number of virtual attachments.
Definition: attach.h:74
int level
Nesting depth of attachment.
Definition: attach.h:42
struct AttachPtr * aptr
Menu information, used in recvattach.c.
Definition: body.h:74
+ 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 Email e,
struct AttachCtx actx,
int  first,
int  second 
)
static

Swap two adjacent entries in the attachment list.

Parameters
eEmail
actxAttachment information
firstIndex of first attachment to swap
secondIndex of second attachment to swap

Definition at line 456 of file functions.c.

457{
458 struct AttachPtr **idx = actx->idx;
459
460 // check that attachments really are adjacent
461 if (idx[first]->body->next != idx[second]->body)
462 return;
463
464 // reorder Body pointers
465 if (first == 0)
466 {
467 // first attachment is the fundamental part
468 idx[first]->body->next = idx[second]->body->next;
469 idx[second]->body->next = idx[first]->body;
470 e->body = idx[second]->body;
471 }
472 else
473 {
474 // find previous attachment
475 struct Body *b_previous = NULL;
476 struct Body *b_parent = NULL;
477 if (attach_body_previous(e->body, idx[first]->body, &b_previous))
478 {
479 idx[first]->body->next = idx[second]->body->next;
480 idx[second]->body->next = idx[first]->body;
481 b_previous->next = idx[second]->body;
482 }
483 else if (attach_body_parent(e->body, NULL, idx[first]->body, &b_parent))
484 {
485 idx[first]->body->next = idx[second]->body->next;
486 idx[second]->body->next = idx[first]->body;
487 b_parent->parts = idx[second]->body;
488 }
489 }
490
491 // reorder attachment list
492 struct AttachPtr *saved = idx[second];
493 for (int i = second; i > first; i--)
494 idx[i] = idx[i - 1];
495 idx[first] = saved;
496
497 // if moved attachment is a group then move subparts too
498 if ((idx[first]->body->type == TYPE_MULTIPART) && (second < actx->idxlen - 1))
499 {
500 int i = second + 1;
501 while (idx[i]->level > idx[first]->level)
502 {
503 saved = idx[i];
504 int destidx = i - second + first;
505 for (int j = i; j > destidx; j--)
506 idx[j] = idx[j - 1];
507 idx[destidx] = saved;
508 i++;
509 if (i >= actx->idxlen)
510 break;
511 }
512 }
513}
struct Body * body
List of MIME parts.
Definition: email.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ group_attachments()

static int group_attachments ( struct ComposeSharedData shared,
char *  subtype 
)
static

Group tagged attachments into a multipart group.

Parameters
sharedShared compose data
subtypeMIME subtype
Return values
FR_SUCCESSSuccess
FR_ERRORFailure

Definition at line 522 of file functions.c.

523{
524 struct AttachCtx *actx = shared->adata->actx;
525 int group_level = -1;
526 struct Body *bptr_parent = NULL;
527
528 // Attachments to be grouped must have the same parent
529 for (int i = 0; i < actx->idxlen; i++)
530 {
531 // check if all tagged attachments are at same level
532 if (actx->idx[i]->body->tagged)
533 {
534 if (group_level == -1)
535 {
536 group_level = actx->idx[i]->level;
537 }
538 else
539 {
540 if (group_level != actx->idx[i]->level)
541 {
542 mutt_error(_("Attachments to be grouped must have the same parent"));
543 return FR_ERROR;
544 }
545 }
546 // if not at top level check if all tagged attachments have same parent
547 if (group_level > 0)
548 {
549 if (bptr_parent)
550 {
551 struct Body *bptr_test = NULL;
552 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_test))
553 mutt_debug(LL_DEBUG5, "can't find parent\n");
554 if (bptr_test != bptr_parent)
555 {
556 mutt_error(_("Attachments to be grouped must have the same parent"));
557 return FR_ERROR;
558 }
559 }
560 else
561 {
562 if (!attach_body_parent(actx->idx[0]->body, NULL, actx->idx[i]->body, &bptr_parent))
563 mutt_debug(LL_DEBUG5, "can't find parent\n");
564 }
565 }
566 }
567 }
568
569 // Can't group all attachments unless at top level
570 if (bptr_parent)
571 {
572 if (shared->adata->menu->num_tagged == attach_body_count(bptr_parent->parts, false))
573 {
574 mutt_error(_("Can't leave group with only one attachment"));
575 return FR_ERROR;
576 }
577 }
578
579 struct Body *group = mutt_body_new();
580 group->type = TYPE_MULTIPART;
581 group->subtype = mutt_str_dup(subtype);
582 group->encoding = ENC_7BIT;
583
584 struct Body *bptr_first = NULL; // first tagged attachment
585 struct Body *bptr = NULL; // current tagged attachment
586 struct Body *group_parent = NULL; // parent of group
587 struct Body *group_previous = NULL; // previous body to group
588 struct Body *group_part = NULL; // current attachment in group
589 int group_idx = 0; // index in attachment list where group will be inserted
590 int group_last_idx = 0; // index of last part of previous found group
591 int group_parent_type = TYPE_OTHER;
592
593 for (int i = 0; i < actx->idxlen; i++)
594 {
595 bptr = actx->idx[i]->body;
596 if (bptr->tagged)
597 {
598 // set group properties based on first tagged attachment
599 if (!bptr_first)
600 {
601 group->disposition = bptr->disposition;
602 if (bptr->language && !mutt_str_equal(subtype, "multilingual"))
603 group->language = mutt_str_dup(bptr->language);
604 group_parent_type = bptr->aptr->parent_type;
605 bptr_first = bptr;
606 if (i > 0)
607 {
608 if (!attach_body_previous(shared->email->body, bptr, &group_previous))
609 {
610 mutt_debug(LL_DEBUG5, "couldn't find previous\n");
611 }
612 if (!attach_body_parent(shared->email->body, NULL, bptr, &group_parent))
613 {
614 mutt_debug(LL_DEBUG5, "couldn't find parent\n");
615 }
616 }
617 }
618
619 shared->adata->menu->num_tagged--;
620 bptr->tagged = false;
621 bptr->aptr->level++;
623
624 // append bptr to the group parts list and remove from email body list
625 struct Body *bptr_previous = NULL;
626 if (attach_body_previous(shared->email->body, bptr, &bptr_previous))
627 bptr_previous->next = bptr->next;
628 else if (attach_body_parent(shared->email->body, NULL, bptr, &bptr_parent))
629 bptr_parent->parts = bptr->next;
630 else
631 shared->email->body = bptr->next;
632
633 if (group_part)
634 {
635 // add bptr to group parts list
636 group_part->next = bptr;
637 group_part = group_part->next;
638 group_part->next = NULL;
639
640 // reorder attachments and set levels
641 int bptr_attachments = attach_body_count(bptr, true);
642 for (int j = i + 1; j < (i + bptr_attachments); j++)
643 actx->idx[j]->level++;
644 if (i > (group_last_idx + 1))
645 {
646 for (int j = 0; j < bptr_attachments; j++)
647 {
648 struct AttachPtr *saved = actx->idx[i + bptr_attachments - 1];
649 for (int k = i + bptr_attachments - 1; k > (group_last_idx + 1); k--)
650 actx->idx[k] = actx->idx[k - 1];
651 actx->idx[group_last_idx + 1] = saved;
652 }
653 }
654 i += bptr_attachments - 1;
655 group_last_idx += bptr_attachments;
656 }
657 else
658 {
659 group_idx = i;
660 group->parts = bptr;
661 group_part = bptr;
662 group_part->next = NULL;
663 int bptr_attachments = attach_body_count(bptr, true);
664 for (int j = i + 1; j < (i + bptr_attachments); j++)
665 actx->idx[j]->level++;
666 i += bptr_attachments - 1;
667 group_last_idx = i;
668 }
669 }
670 }
671
672 if (!bptr_first)
673 {
674 mutt_body_free(&group);
675 return FR_ERROR;
676 }
677
678 // set group->next
679 int next_aidx = group_idx + attach_body_count(group->parts, true);
680 if (group_parent)
681 {
682 // find next attachment with the same parent as the group
683 struct Body *b = NULL;
684 struct Body *b_parent = NULL;
685 while (next_aidx < actx->idxlen)
686 {
687 b = actx->idx[next_aidx]->body;
688 b_parent = NULL;
689 if (attach_body_parent(shared->email->body, NULL, b, &b_parent))
690 {
691 if (group_parent == b_parent)
692 {
693 group->next = b;
694 break;
695 }
696 }
697 next_aidx++;
698 }
699 }
700 else if (next_aidx < actx->idxlen)
701 {
702 // group is at top level
703 group->next = actx->idx[next_aidx]->body;
704 }
705
706 // set previous or parent for group
707 if (group_previous)
708 group_previous->next = group;
709 else if (group_parent)
710 group_parent->parts = group;
711
713
714 struct AttachPtr *group_ap = mutt_aptr_new();
715 group_ap->body = group;
716 group_ap->body->aptr = group_ap;
717 group_ap->level = group_level;
718 group_ap->parent_type = group_parent_type;
719
720 // insert group into attachment list
721 mutt_actx_ins_attach(actx, group_ap, group_idx);
722
723 // update email body and last attachment pointers
724 shared->email->body = actx->idx[0]->body;
725 actx->idx[actx->idxlen - 1]->body->next = NULL;
726
727 update_menu(actx, shared->adata->menu, false);
728 shared->adata->menu->current = group_idx;
730
732 return FR_SUCCESS;
733}
void mutt_actx_ins_attach(struct AttachCtx *actx, struct AttachPtr *attach, int aidx)
Insert an Attachment into an Attachment Context at Specified Index.
Definition: attach.c:91
struct AttachPtr * mutt_aptr_new(void)
Create a new Attachment Pointer.
Definition: attach.c:40
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:44
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:692
#define MUTT_SEND2_HOOK
send2-hook: when changing fields in the compose menu
Definition: hook.h:48
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
#define MENU_REDRAW_INDEX
Redraw the index.
Definition: lib.h:56
void menu_queue_redraw(struct Menu *menu, MenuRedrawFlags redraw)
Queue a request for a redraw.
Definition: menu.c:184
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ TYPE_OTHER
Unknown Content-Type.
Definition: mime.h:31
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
A set of attachments.
Definition: attach.h:65
int parent_type
Type of parent attachment, e.g. TYPE_MULTIPART.
Definition: attach.h:40
char * language
content-language (RFC8255)
Definition: body.h:77
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
struct Menu * menu
Menu displaying the attachments.
Definition: attach_data.h:35
struct AttachCtx * actx
Set of attachments.
Definition: attach_data.h:34
struct ComposeAttachData * adata
Attachments.
Definition: shared_data.h:39
struct Email * email
Email being composed.
Definition: shared_data.h:38
int current
Current entry.
Definition: lib.h:80
int num_tagged
Number of tagged entries.
Definition: lib.h:93
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ OpCompose

const struct MenuFuncOp OpCompose[]

Functions for the Compose Menu.

Definition at line 90 of file functions.c.

◆ ComposeDefaultBindings

const struct MenuOpSeq ComposeDefaultBindings[]

Key bindings for the Compose Menu.

Definition at line 159 of file functions.c.

◆ ComposeFunctions

const struct ComposeFunction ComposeFunctions[]
static

All the NeoMutt functions that the Compose supports.

Definition at line 2104 of file functions.c.