NeoMutt  2025-12-11-58-g09398d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
commands.c File Reference

Handle the attachments command. More...

#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "commands.h"
#include "ncrypt/lib.h"
#include "parse/lib.h"
#include "mview.h"
+ Include dependency graph for commands.c:

Go to the source code of this file.

Data Structures

struct  AttachMatch
 An attachment matching a regex for attachment counter. More...
 

Functions

static void attachmatch_free (struct AttachMatch **ptr)
 Free an AttachMatch - Implements list_free_t -.
 
static struct AttachMatchattachmatch_new (void)
 Create a new AttachMatch.
 
void attach_cleanup (void)
 Free the attachments lists.
 
void attach_init (void)
 Set up the attachments lists.
 
static bool count_body_parts_check (struct ListHead *checklist, struct Body *b, bool dflt)
 Compares mime types to the ok and except lists.
 
static int count_body_parts (struct Body *b)
 Count the MIME Body parts.
 
int mutt_count_body_parts (struct Email *e, FILE *fp)
 Count the MIME Body parts.
 
void mutt_attachments_reset (struct MailboxView *mv)
 Reset the attachment count for all Emails.
 
static enum CommandResult parse_attach_list (const struct Command *cmd, struct Buffer *line, struct ListHead *head, struct Buffer *err)
 Parse the "attachments" command.
 
static enum CommandResult parse_unattach_list (const struct Command *cmd, struct Buffer *line, struct ListHead *head, struct Buffer *err)
 Parse the "unattachments" command.
 
static int print_attach_list (struct ListHead *h, const char op, const char *name)
 Print a list of attachments.
 
enum CommandResult parse_attachments (const struct Command *cmd, struct Buffer *line, struct Buffer *err)
 Parse the 'attachments' command - Implements Command::parse() -.
 
enum CommandResult parse_unattachments (const struct Command *cmd, struct Buffer *line, struct Buffer *err)
 Parse the 'unattachments' command - Implements Command::parse() -.
 
void mutt_parse_mime_message (struct Email *e, FILE *fp)
 Parse a MIME email.
 

Variables

static struct ListHead AttachAllow = STAILQ_HEAD_INITIALIZER(AttachAllow)
 List of attachment types to be counted.
 
static struct ListHead AttachExclude = STAILQ_HEAD_INITIALIZER(AttachExclude)
 List of attachment types to be ignored.
 
static struct ListHead InlineAllow = STAILQ_HEAD_INITIALIZER(InlineAllow)
 List of inline types to counted.
 
static struct ListHead InlineExclude = STAILQ_HEAD_INITIALIZER(InlineExclude)
 List of inline types to ignore.
 
static struct NotifyAttachmentsNotify = NULL
 Notifications: NotifyAttach.
 

Detailed Description

Handle the attachments command.

Authors
  • 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 commands.c.

Function Documentation

◆ attachmatch_new()

static struct AttachMatch * attachmatch_new ( void )
static

Create a new AttachMatch.

Return values
ptrNew AttachMatch

Definition at line 83 of file commands.c.

84{
85 return MUTT_MEM_CALLOC(1, struct AttachMatch);
86}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:47
An attachment matching a regex for attachment counter.
Definition commands.c:48
+ Here is the caller graph for this function:

◆ attach_cleanup()

void attach_cleanup ( void )

Free the attachments lists.

Definition at line 91 of file commands.c.

92{
94
95 /* Lists of AttachMatch */
100}
static struct ListHead AttachAllow
List of attachment types to be counted.
Definition commands.c:55
static struct ListHead InlineExclude
List of inline types to ignore.
Definition commands.c:58
static struct ListHead AttachExclude
List of attachment types to be ignored.
Definition commands.c:56
static struct Notify * AttachmentsNotify
Notifications: NotifyAttach.
Definition commands.c:59
static struct ListHead InlineAllow
List of inline types to counted.
Definition commands.c:57
static void attachmatch_free(struct AttachMatch **ptr)
Free an AttachMatch - Implements list_free_t -.
Definition commands.c:68
void mutt_list_free_type(struct ListHead *h, list_free_t fn)
Free a List of type.
Definition list.c:144
void(* list_free_t)(void **ptr)
Definition list.h:50
void notify_free(struct Notify **ptr)
Free a notification handler.
Definition notify.c:75
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ attach_init()

void attach_init ( void )

Set up the attachments lists.

Definition at line 105 of file commands.c.

106{
108 return;
109
112}
struct Notify * notify_new(void)
Create a new notifications handler.
Definition notify.c:62
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition notify.c:95
Container for Accounts, Notifications.
Definition neomutt.h:43
struct Notify * notify
Notifications handler.
Definition neomutt.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ count_body_parts_check()

static bool count_body_parts_check ( struct ListHead * checklist,
struct Body * b,
bool dflt )
static

Compares mime types to the ok and except lists.

Parameters
checklistList of AttachMatch
bEmail Body
dfltLog whether the matches are OK, or Excluded
Return values
trueAttachment should be counted

Definition at line 121 of file commands.c.

122{
123 /* If list is null, use default behavior. */
124 if (!checklist || STAILQ_EMPTY(checklist))
125 {
126 return false;
127 }
128
129 struct AttachMatch *a = NULL;
130 struct ListNode *np = NULL;
131 STAILQ_FOREACH(np, checklist, entries)
132 {
133 a = (struct AttachMatch *) np->data;
134 mutt_debug(LL_DEBUG3, "%s %d/%s ?? %s/%s [%d]... ", dflt ? "[OK] " : "[EXCL] ",
135 b->type, b->subtype ? b->subtype : "*", a->major, a->minor, a->major_int);
136 if (((a->major_int == TYPE_ANY) || (a->major_int == b->type)) &&
137 (!b->subtype || (regexec(&a->minor_regex, b->subtype, 0, NULL, 0) == 0)))
138 {
139 mutt_debug(LL_DEBUG3, "yes\n");
140 return true;
141 }
142 else
143 {
144 mutt_debug(LL_DEBUG3, "no\n");
145 }
146 }
147
148 return false;
149}
#define mutt_debug(LEVEL,...)
Definition logging2.h:90
@ LL_DEBUG3
Log at debug level 3.
Definition logging2.h:46
@ TYPE_ANY
Type: '' or '.'.
Definition mime.h:40
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_EMPTY(head)
Definition queue.h:382
const char * minor
Minor mime type, e.g. "html".
Definition commands.c:51
regex_t minor_regex
Minor mime type regex.
Definition commands.c:52
const char * major
Major mime type, e.g. "text".
Definition commands.c:49
enum ContentType major_int
Major mime type, e.g. TYPE_TEXT.
Definition commands.c:50
char * subtype
content-type subtype
Definition body.h:61
unsigned int type
content-type primary type, ContentType
Definition body.h:40
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
+ Here is the caller graph for this function:

◆ count_body_parts()

static int count_body_parts ( struct Body * b)
static

Count the MIME Body parts.

Parameters
bBody of email
Return values
numNumber of MIME Body parts

Definition at line 156 of file commands.c.

157{
158 if (!b)
159 return 0;
160
161 int count = 0;
162
163 for (struct Body *bp = b; bp; bp = bp->next)
164 {
165 /* Initial disposition is to count and not to recurse this part. */
166 bool shallcount = true; /* default */
167 bool shallrecurse = false;
168
169 mutt_debug(LL_DEBUG5, "desc=\"%s\"; fn=\"%s\", type=\"%d/%s\"\n",
170 bp->description ? bp->description : ("none"),
171 bp->filename ? bp->filename :
172 bp->d_filename ? bp->d_filename :
173 "(none)",
174 bp->type, bp->subtype ? bp->subtype : "*");
175
176 if (bp->type == TYPE_MESSAGE)
177 {
178 shallrecurse = true;
179
180 /* If it's an external body pointer, don't recurse it. */
181 if (mutt_istr_equal(bp->subtype, "external-body"))
182 shallrecurse = false;
183 }
184 else if (bp->type == TYPE_MULTIPART)
185 {
186 /* Always recurse multiparts, except multipart/alternative. */
187 shallrecurse = true;
188 if (mutt_istr_equal(bp->subtype, "alternative"))
189 {
190 const bool c_count_alternatives = cs_subset_bool(NeoMutt->sub, "count_alternatives");
191 shallrecurse = c_count_alternatives;
192 }
193 }
194
195 if ((bp->disposition == DISP_INLINE) && (bp->type != TYPE_MULTIPART) &&
196 (bp->type != TYPE_MESSAGE) && (bp == b))
197 {
198 shallcount = false; /* ignore fundamental inlines */
199 }
200
201 /* If this body isn't scheduled for enumeration already, don't bother
202 * profiling it further. */
203 if (shallcount)
204 {
205 /* Turn off shallcount if message type is not in ok list,
206 * or if it is in except list. Check is done separately for
207 * inlines vs. attachments. */
208
209 if (bp->disposition == DISP_ATTACH)
210 {
211 if (!count_body_parts_check(&AttachAllow, bp, true))
212 shallcount = false; /* attach not allowed */
213 if (count_body_parts_check(&AttachExclude, bp, false))
214 shallcount = false; /* attach excluded */
215 }
216 else
217 {
218 if (!count_body_parts_check(&InlineAllow, bp, true))
219 shallcount = false; /* inline not allowed */
220 if (count_body_parts_check(&InlineExclude, bp, false))
221 shallcount = false; /* excluded */
222 }
223 }
224
225 if (shallcount)
226 count++;
227 bp->attach_qualifies = shallcount;
228
229 mutt_debug(LL_DEBUG3, "%p shallcount = %d\n", (void *) bp, shallcount);
230
231 if (shallrecurse)
232 {
233 mutt_debug(LL_DEBUG3, "%p pre count = %d\n", (void *) bp, count);
234 bp->attach_count = count_body_parts(bp->parts);
235 count += bp->attach_count;
236 mutt_debug(LL_DEBUG3, "%p post count = %d\n", (void *) bp, count);
237 }
238 }
239
240 mutt_debug(LL_DEBUG3, "return %d\n", (count < 0) ? 0 : count);
241 return (count < 0) ? 0 : count;
242}
static int count_body_parts(struct Body *b)
Count the MIME Body parts.
Definition commands.c:156
static bool count_body_parts_check(struct ListHead *checklist, struct Body *b, bool dflt)
Compares mime types to the ok and except lists.
Definition commands.c:121
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:48
@ TYPE_MESSAGE
Type: 'message/*'.
Definition mime.h:35
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition mime.h:37
@ DISP_ATTACH
Content is attached.
Definition mime.h:63
@ DISP_INLINE
Content is inline.
Definition mime.h:62
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:672
The body of an email.
Definition body.h:36
struct Body * next
next attachment in the list
Definition body.h:72
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_count_body_parts()

int mutt_count_body_parts ( struct Email * e,
FILE * fp )

Count the MIME Body parts.

Parameters
eEmail
fpFile to parse
Return values
numNumber of MIME Body parts

Definition at line 250 of file commands.c.

251{
252 if (!e)
253 return 0;
254
255 bool keep_parts = false;
256
257 if (e->attach_valid)
258 return e->attach_total;
259
260 if (e->body->parts)
261 keep_parts = true;
262 else
264
267 {
269 }
270 else
271 {
272 e->attach_total = 0;
273 }
274
275 e->attach_valid = true;
276
277 if (!keep_parts)
279
280 return e->attach_total;
281}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition commands.c:629
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
bool attach_valid
true when the attachment count is valid
Definition email.h:100
struct Body * body
List of MIME parts.
Definition email.h:69
short attach_total
Number of qualifying attachments in message, if attach_valid.
Definition email.h:115
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_attachments_reset()

void mutt_attachments_reset ( struct MailboxView * mv)

Reset the attachment count for all Emails.

Parameters
mvMailbox view

Definition at line 287 of file commands.c.

288{
289 if (!mv || !mv->mailbox)
290 return;
291
292 struct Mailbox *m = mv->mailbox;
293
294 for (int i = 0; i < m->msg_count; i++)
295 {
296 struct Email *e = m->emails[i];
297 if (!e)
298 break;
299 e->attach_valid = false;
300 e->attach_total = 0;
301 }
302}
The envelope/body of an email.
Definition email.h:39
struct Mailbox * mailbox
Current Mailbox.
Definition mview.h:51
A mailbox.
Definition mailbox.h:79
int msg_count
Total number of messages.
Definition mailbox.h:88
struct Email ** emails
Array of Emails.
Definition mailbox.h:96
+ Here is the caller graph for this function:

◆ parse_attach_list()

static enum CommandResult parse_attach_list ( const struct Command * cmd,
struct Buffer * line,
struct ListHead * head,
struct Buffer * err )
static

Parse the "attachments" command.

Parameters
cmdCommand being parsed
lineBuffer containing the attachments command
headList of AttachMatch to add to
errBuffer for error messages
Return values
CommandResultResult e.g. MUTT_CMD_SUCCESS

Definition at line 312 of file commands.c.

314{
315 struct AttachMatch *a = NULL;
316 char *p = NULL;
317 char *tmpminor = NULL;
318 size_t len;
319 struct Buffer *token = buf_pool_get();
321
322 do
323 {
325
326 if (buf_is_empty(token))
327 continue;
328
329 a = attachmatch_new();
330
331 /* some cheap hacks that I expect to remove */
332 if (mutt_istr_equal(token->data, "any"))
333 a->major = mutt_str_dup("*/.*");
334 else if (mutt_istr_equal(token->data, "none"))
335 a->major = mutt_str_dup("cheap_hack/this_should_never_match");
336 else
337 a->major = buf_strdup(token);
338
339 p = strchr(a->major, '/');
340 if (p)
341 {
342 *p = '\0';
343 p++;
344 a->minor = p;
345 }
346 else
347 {
348 a->minor = "unknown";
349 }
350
351 len = strlen(a->minor);
352 tmpminor = MUTT_MEM_MALLOC(len + 3, char);
353 strcpy(&tmpminor[1], a->minor);
354 tmpminor[0] = '^';
355 tmpminor[len + 1] = '$';
356 tmpminor[len + 2] = '\0';
357
359 int rc_regex = REG_COMP(&a->minor_regex, tmpminor, REG_ICASE);
360
361 FREE(&tmpminor);
362
363 if (rc_regex != 0)
364 {
365 regerror(rc_regex, &a->minor_regex, err->data, err->dsize);
366 FREE(&a->major);
367 FREE(&a);
368 goto done;
369 }
370
371 mutt_debug(LL_DEBUG3, "added %s/%s [%d]\n", a->major, a->minor, a->major_int);
372
373 mutt_list_insert_tail(head, (char *) a);
374 } while (MoreArgs(line));
375
376 if (!a)
377 goto done;
378
379 mutt_debug(LL_NOTIFY, "NT_ATTACH_ADD: %s/%s\n", a->major, a->minor);
381
382 rc = MUTT_CMD_SUCCESS;
383
384done:
385 buf_pool_release(&token);
386 return rc;
387}
static struct AttachMatch * attachmatch_new(void)
Create a new AttachMatch.
Definition commands.c:83
@ NT_ATTACH_ADD
Attachment regex has been added.
Definition commands.h:40
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
CommandResult
Error codes for command_t parse functions.
Definition command.h:35
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition command.h:38
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:36
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition parse.c:365
int parse_extract_token(struct Buffer *dest, struct Buffer *line, TokenFlags flags)
Extract one token from a string.
Definition extract.c:48
#define MoreArgs(buf)
Definition extract.h:30
#define TOKEN_NO_FLAGS
No flags are set.
Definition extract.h:44
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition list.c:65
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:49
#define FREE(x)
Definition memory.h:62
#define MUTT_MEM_MALLOC(n, type)
Definition memory.h:48
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:255
@ NT_ATTACH
Attachment command changed, NotifyAttach.
Definition notify_type.h:39
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition regex3.h:50
String manipulation buffer.
Definition buffer.h:36
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_unattach_list()

static enum CommandResult parse_unattach_list ( const struct Command * cmd,
struct Buffer * line,
struct ListHead * head,
struct Buffer * err )
static

Parse the "unattachments" command.

Parameters
cmdCommand being parsed
lineBuffer containing the unattachments command
headList of AttachMatch to remove from
errBuffer for error messages
Return values
MUTT_CMD_SUCCESSAlways

Definition at line 397 of file commands.c.

399{
400 struct Buffer *token = buf_pool_get();
401
402 struct AttachMatch *a = NULL;
403 char *tmp = NULL;
404 char *minor = NULL;
405
406 do
407 {
409 FREE(&tmp);
410
411 if (mutt_istr_equal(token->data, "any"))
412 tmp = mutt_str_dup("*/.*");
413 else if (mutt_istr_equal(token->data, "none"))
414 tmp = mutt_str_dup("cheap_hack/this_should_never_match");
415 else
416 tmp = buf_strdup(token);
417
418 minor = strchr(tmp, '/');
419 if (minor)
420 {
421 *minor = '\0';
422 minor++;
423 }
424 else
425 {
426 minor = "unknown";
427 }
428 const enum ContentType major = mutt_check_mime_type(tmp);
429
430 struct ListNode *np = NULL, *tmp2 = NULL;
431 STAILQ_FOREACH_SAFE(np, head, entries, tmp2)
432 {
433 a = (struct AttachMatch *) np->data;
434 mutt_debug(LL_DEBUG3, "check %s/%s [%d] : %s/%s [%d]\n", a->major,
435 a->minor, a->major_int, tmp, minor, major);
436 if ((a->major_int == major) && mutt_istr_equal(minor, a->minor))
437 {
438 mutt_debug(LL_DEBUG3, "removed %s/%s [%d]\n", a->major, a->minor, a->major_int);
439 mutt_debug(LL_NOTIFY, "NT_ATTACH_DELETE: %s/%s\n", a->major, a->minor);
440
441 regfree(&a->minor_regex);
442 FREE(&a->major);
443 STAILQ_REMOVE(head, np, ListNode, entries);
444 FREE(&np->data);
445 FREE(&np);
446 }
447 }
448
449 } while (MoreArgs(line));
450
451 FREE(&tmp);
452
454
455 buf_pool_release(&token);
456 return MUTT_CMD_SUCCESS;
457}
@ NT_ATTACH_DELETE
Attachment regex has been deleted.
Definition commands.h:41
ContentType
Content-Type.
Definition mime.h:30
#define STAILQ_REMOVE(head, elm, type, field)
Definition queue.h:441
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:400
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ print_attach_list()

static int print_attach_list ( struct ListHead * h,
const char op,
const char * name )
static

Print a list of attachments.

Parameters
hList of attachments
opOperation, e.g. '+', '-'
nameAttached/Inline, 'A', 'I'
Return values
0Always

Definition at line 466 of file commands.c.

467{
468 struct ListNode *np = NULL;
469 STAILQ_FOREACH(np, h, entries)
470 {
471 printf("attachments %c%s %s/%s\n", op, name,
472 ((struct AttachMatch *) np->data)->major,
473 ((struct AttachMatch *) np->data)->minor);
474 }
475
476 return 0;
477}
+ Here is the caller graph for this function:

◆ mutt_parse_mime_message()

void mutt_parse_mime_message ( struct Email * e,
FILE * fp )

Parse a MIME email.

Parameters
eEmail
fpFile to parse

Definition at line 629 of file commands.c.

630{
631 const bool right_type = (e->body->type == TYPE_MESSAGE) ||
632 (e->body->type == TYPE_MULTIPART);
633 const bool not_parsed = (e->body->parts == NULL);
634
635 if (right_type && fp && not_parsed)
636 {
637 mutt_parse_part(fp, e->body);
638 if (WithCrypto)
639 {
640 e->security = crypt_query(e->body);
641 }
642 }
643
644 e->attach_valid = false;
645}
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition crypt.c:687
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1821
#define WithCrypto
Definition lib.h:122
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ AttachAllow

struct ListHead AttachAllow = STAILQ_HEAD_INITIALIZER(AttachAllow)
static

List of attachment types to be counted.

Definition at line 55 of file commands.c.

◆ AttachExclude

struct ListHead AttachExclude = STAILQ_HEAD_INITIALIZER(AttachExclude)
static

List of attachment types to be ignored.

Definition at line 56 of file commands.c.

◆ InlineAllow

struct ListHead InlineAllow = STAILQ_HEAD_INITIALIZER(InlineAllow)
static

List of inline types to counted.

Definition at line 57 of file commands.c.

◆ InlineExclude

struct ListHead InlineExclude = STAILQ_HEAD_INITIALIZER(InlineExclude)
static

List of inline types to ignore.

Definition at line 58 of file commands.c.

◆ AttachmentsNotify

struct Notify* AttachmentsNotify = NULL
static

Notifications: NotifyAttach.

Definition at line 59 of file commands.c.