NeoMutt  2022-04-29-215-gc12b98
Teaching an old dog new tricks
DOXYGEN
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 "mutt.h"
#include "attachments.h"
#include "ncrypt/lib.h"
#include "init.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 -. More...
 
static struct AttachMatchattachmatch_new (void)
 Create a new AttachMatch. More...
 
void attach_free (void)
 Free the attachments lists. More...
 
void attach_init (void)
 Set up the attachments lists. More...
 
static bool count_body_parts_check (struct ListHead *checklist, struct Body *b, bool dflt)
 Compares mime types to the ok and except lists. More...
 
static int count_body_parts (struct Body *body)
 Count the MIME Body parts. More...
 
int mutt_count_body_parts (const struct Mailbox *m, struct Email *e, FILE *fp)
 Count the MIME Body parts. More...
 
void mutt_attachments_reset (struct Mailbox *m)
 Reset the attachment count for all Emails. More...
 
static enum CommandResult parse_attach_list (struct Buffer *buf, struct Buffer *s, struct ListHead *head, struct Buffer *err)
 Parse the "attachments" command. More...
 
static enum CommandResult parse_unattach_list (struct Buffer *buf, struct Buffer *s, struct ListHead *head, struct Buffer *err)
 Parse the "unattachments" command. More...
 
static int print_attach_list (struct ListHead *h, const char op, const char *name)
 Print a list of attachments. More...
 
enum CommandResult parse_attachments (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
 Parse the 'attachments' command - Implements Command::parse() -. More...
 
enum CommandResult parse_unattachments (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
 Parse the 'unattachments' command - Implements Command::parse() -. More...
 
void mutt_parse_mime_message (struct Email *e, FILE *fp)
 Parse a MIME email. More...
 

Variables

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

Detailed Description

Handle the attachments command.

Authors
  • Michael R. Elkins

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 83 of file attachments.c.

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

◆ attach_free()

void attach_free ( void  )

Free the attachments lists.

Definition at line 91 of file attachments.c.

92{
94
95 /* Lists of AttachMatch */
100}
struct ListHead AttachAllow
List of attachment types to be counted.
Definition: attachments.c:55
struct ListHead InlineExclude
List of inline types to ignore.
Definition: attachments.c:58
struct ListHead AttachExclude
List of attachment types to be ignored.
Definition: attachments.c:56
static struct Notify * AttachmentsNotify
Definition: attachments.c:59
struct ListHead InlineAllow
List of inline types to counted.
Definition: attachments.c:57
static void attachmatch_free(struct AttachMatch **ptr)
Free an AttachMatch - Implements list_free_t -.
Definition: attachments.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:48
void notify_free(struct Notify **ptr)
Free a notification handler.
Definition: notify.c:73
+ 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 attachments.c.

106{
108 return;
109
112}
struct Notify * notify_new(void)
Create a new notifications handler.
Definition: notify.c:60
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:93
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
+ 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 attachments.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: logging.h:84
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ 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:51
regex_t minor_regex
Minor mime type regex.
Definition: attachments.c:52
const char * major
Major mime type, e.g. "text".
Definition: attachments.c:49
enum ContentType major_int
Major mime type, e.g. TYPE_TEXT.
Definition: attachments.c:50
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:35
char * data
String.
Definition: list.h:36
+ Here is the caller graph for this function:

◆ count_body_parts()

static int count_body_parts ( struct Body body)
static

Count the MIME Body parts.

Parameters
bodyBody of email
Return values
numNumber of MIME Body parts

Definition at line 156 of file attachments.c.

157{
158 if (!body)
159 return 0;
160
161 int count = 0;
162
163 for (struct Body *bp = body; 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 == body))
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 *body)
Count the MIME Body parts.
Definition: attachments.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: attachments.c:121
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
@ 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:819
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:39
+ 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 251 of file attachments.c.

252{
253 if (!m || !e)
254 return 0;
255
256 bool keep_parts = false;
257
258 if (e->attach_valid)
259 return e->attach_total;
260
261 if (e->body->parts)
262 keep_parts = true;
263 else
265
268 {
270 }
271 else
272 e->attach_total = 0;
273
274 e->attach_valid = true;
275
276 if (!keep_parts)
278
279 return e->attach_total;
280}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:591
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
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:100
struct Body * body
List of MIME parts.
Definition: email.h:67
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 Mailbox m)

Reset the attachment count for all Emails.

Definition at line 285 of file attachments.c.

286{
287 if (!m)
288 return;
289
290 for (int i = 0; i < m->msg_count; i++)
291 {
292 struct Email *e = m->emails[i];
293 if (!e)
294 break;
295 e->attach_valid = false;
296 e->attach_total = 0;
297 }
298}
The envelope/body of an email.
Definition: email.h:37
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 308 of file attachments.c.

310{
311 struct AttachMatch *a = NULL;
312 char *p = NULL;
313 char *tmpminor = NULL;
314 size_t len;
315 int rc;
316
317 do
318 {
320
321 if (!buf->data || (*buf->data == '\0'))
322 continue;
323
324 a = attachmatch_new();
325
326 /* some cheap hacks that I expect to remove */
327 if (mutt_istr_equal(buf->data, "any"))
328 a->major = mutt_str_dup("*/.*");
329 else if (mutt_istr_equal(buf->data, "none"))
330 a->major = mutt_str_dup("cheap_hack/this_should_never_match");
331 else
332 a->major = mutt_str_dup(buf->data);
333
334 p = strchr(a->major, '/');
335 if (p)
336 {
337 *p = '\0';
338 p++;
339 a->minor = p;
340 }
341 else
342 {
343 a->minor = "unknown";
344 }
345
346 len = strlen(a->minor);
347 tmpminor = mutt_mem_malloc(len + 3);
348 strcpy(&tmpminor[1], a->minor);
349 tmpminor[0] = '^';
350 tmpminor[len + 1] = '$';
351 tmpminor[len + 2] = '\0';
352
354 rc = REG_COMP(&a->minor_regex, tmpminor, REG_ICASE);
355
356 FREE(&tmpminor);
357
358 if (rc != 0)
359 {
360 regerror(rc, &a->minor_regex, err->data, err->dsize);
361 FREE(&a->major);
362 FREE(&a);
363 return MUTT_CMD_ERROR;
364 }
365
366 mutt_debug(LL_DEBUG3, "added %s/%s [%d]\n", a->major, a->minor, a->major_int);
367
368 mutt_list_insert_tail(head, (char *) a);
369 } while (MoreArgs(s));
370
371 if (!a)
372 return MUTT_CMD_ERROR;
373
374 mutt_debug(LL_NOTIFY, "NT_ATTACH_ADD: %s/%s\n", a->major, a->minor);
376
377 return MUTT_CMD_SUCCESS;
378}
static struct AttachMatch * attachmatch_new(void)
Create a new AttachMatch.
Definition: attachments.c:83
@ NT_ATTACH_ADD
Attachment regex has been added.
Definition: attachments.h:40
#define MoreArgs(buf)
Definition: buffer.h:40
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:37
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:35
int mutt_extract_token(struct Buffer *dest, struct Buffer *tok, TokenFlags flags)
Extract one token from a string.
Definition: init.c:273
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
#define FREE(x)
Definition: memory.h:43
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
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:67
@ NT_ATTACH
Attachment command changed, NotifyAttach.
Definition: notify_type.h:39
enum ContentType mutt_check_mime_type(const char *s)
Check a MIME type string.
Definition: parse.c:323
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
+ 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 388 of file attachments.c.

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

455{
456 struct ListNode *np = NULL;
457 STAILQ_FOREACH(np, h, entries)
458 {
459 printf("attachments %c%s %s/%s\n", op, name,
460 ((struct AttachMatch *) np->data)->major,
461 ((struct AttachMatch *) np->data)->minor);
462 }
463
464 return 0;
465}
+ 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 591 of file attachments.c.

592{
593 const bool right_type = (e->body->type == TYPE_MESSAGE) ||
594 (e->body->type == TYPE_MULTIPART);
595 const bool not_parsed = (e->body->parts == NULL);
596
597 if (right_type && fp && not_parsed)
598 {
599 mutt_parse_part(fp, e->body);
600 if (WithCrypto)
601 {
602 e->security = crypt_query(e->body);
603 }
604 }
605
606 e->attach_valid = false;
607}
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition: crypt.c:675
#define WithCrypto
Definition: lib.h:116
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1737
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
+ 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)

List of attachment types to be counted.

Definition at line 55 of file attachments.c.

◆ AttachExclude

struct ListHead AttachExclude = STAILQ_HEAD_INITIALIZER(AttachExclude)

List of attachment types to be ignored.

Definition at line 56 of file attachments.c.

◆ InlineAllow

struct ListHead InlineAllow = STAILQ_HEAD_INITIALIZER(InlineAllow)

List of inline types to counted.

Definition at line 57 of file attachments.c.

◆ InlineExclude

struct ListHead InlineExclude = STAILQ_HEAD_INITIALIZER(InlineExclude)

List of inline types to ignore.

Definition at line 58 of file attachments.c.

◆ AttachmentsNotify

struct Notify* AttachmentsNotify = NULL
static

Definition at line 59 of file attachments.c.