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

Handle the attachments command. More...

#include "config.h"
#include <stdbool.h>
#include <stdint.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 "attachments.h"
#include "ncrypt/lib.h"
#include "parse/lib.h"
#include "mview.h"
+ Include dependency graph for attachments.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 (const struct Mailbox *m, 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 (struct Buffer *buf, struct Buffer *s, struct ListHead *head, struct Buffer *err)
 Parse the "attachments" command.
 
static enum CommandResult parse_unattach_list (struct Buffer *buf, struct Buffer *s, 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 (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
 Parse the 'attachments' command - Implements Command::parse() -.
 
enum CommandResult parse_unattachments (struct Buffer *buf, struct Buffer *s, intptr_t data, 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 attachments.c.

Function Documentation

◆ attachmatch_new()

static struct AttachMatch * attachmatch_new ( void  )
static

Create a new AttachMatch.

Return values
ptrNew AttachMatch

Definition at line 84 of file attachments.c.

85{
86 return mutt_mem_calloc(1, sizeof(struct AttachMatch));
87}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
An attachment matching a regex for attachment counter.
Definition: attachments.c:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ attach_cleanup()

void attach_cleanup ( void  )

Free the attachments lists.

Definition at line 92 of file attachments.c.

93{
95
96 /* Lists of AttachMatch */
101}
static struct ListHead AttachAllow
List of attachment types to be counted.
Definition: attachments.c:56
static struct ListHead InlineExclude
List of inline types to ignore.
Definition: attachments.c:59
static struct ListHead AttachExclude
List of attachment types to be ignored.
Definition: attachments.c:57
static struct Notify * AttachmentsNotify
Notifications: NotifyAttach.
Definition: attachments.c:60
static struct ListHead InlineAllow
List of inline types to counted.
Definition: attachments.c:58
static void attachmatch_free(struct AttachMatch **ptr)
Free an AttachMatch - Implements list_free_t -.
Definition: attachments.c:69
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 106 of file attachments.c.

107{
109 return;
110
113}
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:42
struct Notify * notify
Notifications handler.
Definition: neomutt.h:43
+ 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 122 of file attachments.c.

123{
124 /* If list is null, use default behavior. */
125 if (!checklist || STAILQ_EMPTY(checklist))
126 {
127 return false;
128 }
129
130 struct AttachMatch *a = NULL;
131 struct ListNode *np = NULL;
132 STAILQ_FOREACH(np, checklist, entries)
133 {
134 a = (struct AttachMatch *) np->data;
135 mutt_debug(LL_DEBUG3, "%s %d/%s ?? %s/%s [%d]... ", dflt ? "[OK] " : "[EXCL] ",
136 b->type, b->subtype ? b->subtype : "*", a->major, a->minor, a->major_int);
137 if (((a->major_int == TYPE_ANY) || (a->major_int == b->type)) &&
138 (!b->subtype || (regexec(&a->minor_regex, b->subtype, 0, NULL, 0) == 0)))
139 {
140 mutt_debug(LL_DEBUG3, "yes\n");
141 return true;
142 }
143 else
144 {
145 mutt_debug(LL_DEBUG3, "no\n");
146 }
147 }
148
149 return false;
150}
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG3
Log at debug level 3.
Definition: logging2.h:45
@ TYPE_ANY
Type: '*' or '.*'.
Definition: mime.h:40
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_EMPTY(head)
Definition: queue.h:348
const char * minor
Minor mime type, e.g. "html".
Definition: attachments.c:52
regex_t minor_regex
Minor mime type regex.
Definition: attachments.c:53
const char * major
Major mime type, e.g. "text".
Definition: attachments.c:50
enum ContentType major_int
Major mime type, e.g. TYPE_TEXT.
Definition: attachments.c:51
char * subtype
content-type subtype
Definition: body.h:60
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 157 of file attachments.c.

158{
159 if (!b)
160 return 0;
161
162 int count = 0;
163
164 for (struct Body *bp = b; bp; bp = bp->next)
165 {
166 /* Initial disposition is to count and not to recurse this part. */
167 bool shallcount = true; /* default */
168 bool shallrecurse = false;
169
170 mutt_debug(LL_DEBUG5, "desc=\"%s\"; fn=\"%s\", type=\"%d/%s\"\n",
171 bp->description ? bp->description : ("none"),
172 bp->filename ? bp->filename :
173 bp->d_filename ? bp->d_filename :
174 "(none)",
175 bp->type, bp->subtype ? bp->subtype : "*");
176
177 if (bp->type == TYPE_MESSAGE)
178 {
179 shallrecurse = true;
180
181 /* If it's an external body pointer, don't recurse it. */
182 if (mutt_istr_equal(bp->subtype, "external-body"))
183 shallrecurse = false;
184 }
185 else if (bp->type == TYPE_MULTIPART)
186 {
187 /* Always recurse multiparts, except multipart/alternative. */
188 shallrecurse = true;
189 if (mutt_istr_equal(bp->subtype, "alternative"))
190 {
191 const bool c_count_alternatives = cs_subset_bool(NeoMutt->sub, "count_alternatives");
192 shallrecurse = c_count_alternatives;
193 }
194 }
195
196 if ((bp->disposition == DISP_INLINE) && (bp->type != TYPE_MULTIPART) &&
197 (bp->type != TYPE_MESSAGE) && (bp == b))
198 {
199 shallcount = false; /* ignore fundamental inlines */
200 }
201
202 /* If this body isn't scheduled for enumeration already, don't bother
203 * profiling it further. */
204 if (shallcount)
205 {
206 /* Turn off shallcount if message type is not in ok list,
207 * or if it is in except list. Check is done separately for
208 * inlines vs. attachments. */
209
210 if (bp->disposition == DISP_ATTACH)
211 {
212 if (!count_body_parts_check(&AttachAllow, bp, true))
213 shallcount = false; /* attach not allowed */
214 if (count_body_parts_check(&AttachExclude, bp, false))
215 shallcount = false; /* attach excluded */
216 }
217 else
218 {
219 if (!count_body_parts_check(&InlineAllow, bp, true))
220 shallcount = false; /* inline not allowed */
221 if (count_body_parts_check(&InlineExclude, bp, false))
222 shallcount = false; /* excluded */
223 }
224 }
225
226 if (shallcount)
227 count++;
228 bp->attach_qualifies = shallcount;
229
230 mutt_debug(LL_DEBUG3, "%p shallcount = %d\n", (void *) bp, shallcount);
231
232 if (shallrecurse)
233 {
234 mutt_debug(LL_DEBUG3, "%p pre count = %d\n", (void *) bp, count);
235 bp->attach_count = count_body_parts(bp->parts);
236 count += bp->attach_count;
237 mutt_debug(LL_DEBUG3, "%p post count = %d\n", (void *) bp, count);
238 }
239 }
240
241 mutt_debug(LL_DEBUG3, "return %d\n", (count < 0) ? 0 : count);
242 return (count < 0) ? 0 : count;
243}
static int count_body_parts(struct Body *b)
Count the MIME Body parts.
Definition: attachments.c:157
static bool count_body_parts_check(struct ListHead *checklist, struct Body *b, bool dflt)
Compares mime types to the ok and except lists.
Definition: attachments.c:122
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:47
@ 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:71
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:

◆ mutt_count_body_parts()

int mutt_count_body_parts ( const struct Mailbox m,
struct Email e,
FILE *  fp 
)

Count the MIME Body parts.

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

Definition at line 252 of file attachments.c.

253{
254 if (!m || !e)
255 return 0;
256
257 bool keep_parts = false;
258
259 if (e->attach_valid)
260 return e->attach_total;
261
262 if (e->body->parts)
263 keep_parts = true;
264 else
266
269 {
271 }
272 else
273 {
274 e->attach_total = 0;
275 }
276
277 e->attach_valid = true;
278
279 if (!keep_parts)
281
282 return e->attach_total;
283}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:597
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:72
bool attach_valid
true when the attachment count is valid
Definition: email.h:103
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:118
+ 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 289 of file attachments.c.

290{
291 if (!mv || !mv->mailbox)
292 return;
293
294 struct Mailbox *m = mv->mailbox;
295
296 for (int i = 0; i < m->msg_count; i++)
297 {
298 struct Email *e = m->emails[i];
299 if (!e)
300 break;
301 e->attach_valid = false;
302 e->attach_total = 0;
303 }
304}
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 ( struct Buffer buf,
struct Buffer s,
struct ListHead *  head,
struct Buffer err 
)
static

Parse the "attachments" command.

Parameters
bufBuffer for temporary storage
sBuffer 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 314 of file attachments.c.

316{
317 struct AttachMatch *a = NULL;
318 char *p = NULL;
319 char *tmpminor = NULL;
320 size_t len;
321 int rc;
322
323 do
324 {
326
327 if (!buf->data || (*buf->data == '\0'))
328 continue;
329
330 a = attachmatch_new();
331
332 /* some cheap hacks that I expect to remove */
333 if (mutt_istr_equal(buf->data, "any"))
334 a->major = mutt_str_dup("*/.*");
335 else if (mutt_istr_equal(buf->data, "none"))
336 a->major = mutt_str_dup("cheap_hack/this_should_never_match");
337 else
338 a->major = mutt_str_dup(buf->data);
339
340 p = strchr(a->major, '/');
341 if (p)
342 {
343 *p = '\0';
344 p++;
345 a->minor = p;
346 }
347 else
348 {
349 a->minor = "unknown";
350 }
351
352 len = strlen(a->minor);
353 tmpminor = mutt_mem_malloc(len + 3);
354 strcpy(&tmpminor[1], a->minor);
355 tmpminor[0] = '^';
356 tmpminor[len + 1] = '$';
357 tmpminor[len + 2] = '\0';
358
360 rc = REG_COMP(&a->minor_regex, tmpminor, REG_ICASE);
361
362 FREE(&tmpminor);
363
364 if (rc != 0)
365 {
366 regerror(rc, &a->minor_regex, err->data, err->dsize);
367 FREE(&a->major);
368 FREE(&a);
369 return MUTT_CMD_ERROR;
370 }
371
372 mutt_debug(LL_DEBUG3, "added %s/%s [%d]\n", a->major, a->minor, a->major_int);
373
374 mutt_list_insert_tail(head, (char *) a);
375 } while (MoreArgs(s));
376
377 if (!a)
378 return MUTT_CMD_ERROR;
379
380 mutt_debug(LL_NOTIFY, "NT_ATTACH_ADD: %s/%s\n", a->major, a->minor);
382
383 return MUTT_CMD_SUCCESS;
384}
static struct AttachMatch * attachmatch_new(void)
Create a new AttachMatch.
Definition: attachments.c:84
@ NT_ATTACH_ADD
Attachment regex has been added.
Definition: attachments.h:41
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:39
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:37
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:366
int parse_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: extract.c:50
#define MoreArgs(buf)
Definition: extract.h:32
#define TOKEN_NO_FLAGS
No flags are set.
Definition: extract.h:46
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:48
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:91
#define FREE(x)
Definition: memory.h:45
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:253
@ NT_ATTACH
Attachment command changed, NotifyAttach.
Definition: notify_type.h:39
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:49
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 ( struct Buffer buf,
struct Buffer s,
struct ListHead *  head,
struct Buffer err 
)
static

Parse the "unattachments" command.

Parameters
bufBuffer for temporary storage
sBuffer containing the unattachments command
headList of AttachMatch to remove from
errBuffer for error messages
Return values
MUTT_CMD_SUCCESSAlways

Definition at line 394 of file attachments.c.

396{
397 struct AttachMatch *a = NULL;
398 char *tmp = NULL;
399 char *minor = NULL;
400
401 do
402 {
404 FREE(&tmp);
405
406 if (mutt_istr_equal(buf->data, "any"))
407 tmp = mutt_str_dup("*/.*");
408 else if (mutt_istr_equal(buf->data, "none"))
409 tmp = mutt_str_dup("cheap_hack/this_should_never_match");
410 else
411 tmp = mutt_str_dup(buf->data);
412
413 minor = strchr(tmp, '/');
414 if (minor)
415 {
416 *minor = '\0';
417 minor++;
418 }
419 else
420 {
421 minor = "unknown";
422 }
423 const enum ContentType major = mutt_check_mime_type(tmp);
424
425 struct ListNode *np = NULL, *tmp2 = NULL;
426 STAILQ_FOREACH_SAFE(np, head, entries, tmp2)
427 {
428 a = (struct AttachMatch *) np->data;
429 mutt_debug(LL_DEBUG3, "check %s/%s [%d] : %s/%s [%d]\n", a->major,
430 a->minor, a->major_int, tmp, minor, major);
431 if ((a->major_int == major) && mutt_istr_equal(minor, a->minor))
432 {
433 mutt_debug(LL_DEBUG3, "removed %s/%s [%d]\n", a->major, a->minor, a->major_int);
434 mutt_debug(LL_NOTIFY, "NT_ATTACH_DELETE: %s/%s\n", a->major, a->minor);
435
436 regfree(&a->minor_regex);
437 FREE(&a->major);
438 STAILQ_REMOVE(head, np, ListNode, entries);
439 FREE(&np->data);
440 FREE(&np);
441 }
442 }
443
444 } while (MoreArgs(s));
445
446 FREE(&tmp);
447
449
450 return MUTT_CMD_SUCCESS;
451}
@ NT_ATTACH_DELETE
Attachment regex has been deleted.
Definition: attachments.h:42
ContentType
Content-Type.
Definition: mime.h:30
#define STAILQ_REMOVE(head, elm, type, field)
Definition: queue.h:402
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:362
+ 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 460 of file attachments.c.

461{
462 struct ListNode *np = NULL;
463 STAILQ_FOREACH(np, h, entries)
464 {
465 printf("attachments %c%s %s/%s\n", op, name,
466 ((struct AttachMatch *) np->data)->major,
467 ((struct AttachMatch *) np->data)->minor);
468 }
469
470 return 0;
471}
+ 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 597 of file attachments.c.

598{
599 const bool right_type = (e->body->type == TYPE_MESSAGE) ||
600 (e->body->type == TYPE_MULTIPART);
601 const bool not_parsed = (e->body->parts == NULL);
602
603 if (right_type && fp && not_parsed)
604 {
605 mutt_parse_part(fp, e->body);
606 if (WithCrypto)
607 {
608 e->security = crypt_query(e->body);
609 }
610 }
611
612 e->attach_valid = false;
613}
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:1817
#define WithCrypto
Definition: lib.h:116
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 56 of file attachments.c.

◆ AttachExclude

struct ListHead AttachExclude = STAILQ_HEAD_INITIALIZER(AttachExclude)
static

List of attachment types to be ignored.

Definition at line 57 of file attachments.c.

◆ InlineAllow

struct ListHead InlineAllow = STAILQ_HEAD_INITIALIZER(InlineAllow)
static

List of inline types to counted.

Definition at line 58 of file attachments.c.

◆ InlineExclude

struct ListHead InlineExclude = STAILQ_HEAD_INITIALIZER(InlineExclude)
static

List of inline types to ignore.

Definition at line 59 of file attachments.c.

◆ AttachmentsNotify

struct Notify* AttachmentsNotify = NULL
static

Notifications: NotifyAttach.

Definition at line 60 of file attachments.c.