+2005-10-06 06:15:00 Brendan Cully <brendan@kublai.com> (brendan)
+
+ * browser.c: Sort browser entries after every IMAP browsing
+ operation instead of just when explicitly requested. Closes:
+ #2089.
+
+2005-10-06 05:13:55 Jeff Ito <jeffi@rcn.com> (brendan)
+
+ * smime.c: Add AES ciphers to S/MIME encryption options. Closes:
+ #2103.
+
+2005-10-05 19:24:40 David Champion <dgc@uchicago.edu> (brendan)
+
+ * doc/manual.xml.head, init.c: Fix 'unattachments'. Closes: #2102.
+
+2005-10-05 19:20:22 Jeff Ito <jeffi@rcn.com> (brendan)
+
+ * smime.c: S/MIME key selection truncates the last character of
+ the selected key for no apparent reason. Removed until someone
+ can justify it. Closes: #2081.
+
+2005-10-04 19:00:05 Brendan Cully <brendan@kublai.com> (brendan)
+
+ * init.h: Tweak description of pop_checkinterval slightly. Closes:
+ #2074.
+
+ * hcache.c: Bump hcache Id for attachment counting patch.
+
+2005-10-04 06:05:39 David Champion <dgc@uchicago.edu> (brendan)
+
+ * Muttrc.head.in, doc/manual.xml.head, doc/muttrc.man.head,
+ globals.h, hdrline.c, init.c, init.h, mime.h, mutt.h, parse.c,
+ pattern.c, protos.h, recvattach.c: Attachment counting for index
+ display (patch-1.5.11.dgc.attach.6). Modifications: attach_recurse
+ and attach_ignore_fundamental stripped, some debugging code
+ removed, some bones thrown to check_sec.sh.
+
2005-10-04 05:24:00 Sebastien Hinderer <Sebastien.Hinderer@libertysurf.fr> (brendan)
* pager.c: The following patch has an effect only when the
#
# set use_8bitmime
+##
+## *** DEFAULT SETTINGS FOR THE ATTACHMENTS PATCH ***
+##
+
+##
+## Please see the manual (section "attachments") for detailed
+## documentation of the "attachments" command.
+##
+## Removing a pattern from a list removes that pattern literally. It
+## does not remove any type matching the pattern.
+##
+## attachments +A */.*
+## attachments +A image/jpeg
+## unattachments +A */.*
+##
+## This leaves "attached" image/jpeg files on the allowed attachments
+## list. It does not remove all items, as you might expect, because the
+## second */.* is not a matching expression at this time.
+##
+## Remember: "unattachments" only undoes what "attachments" has done!
+## It does not trigger any matching on actual messages.
+
+## Qualify any MIME part with an "attachment" disposition, EXCEPT for
+## text/x-vcard and application/pgp parts. (PGP parts are already known
+## to mutt, and can be searched for with ~g, ~G, and ~k.)
+##
+## I've added x-pkcs7 to this, since it functions (for S/MIME)
+## analogously to PGP signature attachments. S/MIME isn't supported
+## in a stock mutt build, but we can still treat it specially here.
+##
+attachments +A */.*
+attachments -A text/x-vcard application/pgp.*
+attachments -A application/x-pkcs7-.*
+
+## Discount all MIME parts with an "inline" disposition, unless they're
+## text/plain. (Why inline a text/plain part unless it's external to the
+## message flow?)
+##
+attachments +I text/plain
+
+## These two lines make Mutt qualify MIME containers. (So, for example,
+## a message/rfc822 forward will count as an attachment.) The first
+## line is unnecessary if you already have "attach-allow */.*", of
+## course. These are off by default! The MIME elements contained
+## within a message/* or multipart/* are still examined, even if the
+## containers themseves don't qualify.
+##
+#attachments +A message/.* multipart/.*
+#attachments +I message/.* multipart/.*
+
+## You probably don't really care to know about deleted attachments.
+attachments -A message/external-body
+attachments -I message/external-body
+
##
## More settings
##
the necessary keywords to look them up in the manual, ChangeLog or other
sources of information.
+2005-10-09:
+
+ The "attachments" and "unattachments" commands were added. The %X
+ expando has been added to $index_format. The ~X pattern has been
+ added. The %Q and %X expandos have been added to $attach_format.
+
+ As part of the above addition(s), the 'A' message status flag has been
+ removed again.
+
+2005-10-07:
+
+ When upgrading to after a revision after 528, header caches must be
+ completely removed and rebuild again. From r540 on, this problem is
+ solved so manual interaction will not be necessary any longer.
+
2005-09-14:
The $smtp_envelope_from variable has been removed in favor of the
init_state (&state, NULL);
state.imap_browse = 1;
imap_browse (LastDir, &state);
+ browser_sort (&state);
}
#endif
}
init_state (&state, NULL);
state.imap_browse = 1;
imap_browse (LastDir, &state);
+ browser_sort (&state);
menu->data = state.entry;
}
else
init_state (&state, NULL);
state.imap_browse = 1;
imap_browse (LastDir, &state);
+ browser_sort (&state);
menu->data = state.entry;
menu->current = 0;
menu->top = 0;
init_state (&state, NULL);
state.imap_browse = 1;
imap_browse (LastDir, &state);
+ browser_sort (&state);
menu->data = state.entry;
menu->current = 0;
menu->top = 0;
init_state (&state, NULL);
state.imap_browse = 1;
imap_browse (LastDir, &state);
+ browser_sort (&state);
menu->data = state.entry;
menu->current = 0;
menu->top = 0;
init_state (&state, NULL);
state.imap_browse = 1;
imap_browse (LastDir, &state);
+ browser_sort (&state);
menu->data = state.entry;
init_menu (&state, menu, title, sizeof (title), buffy);
}
init_state (&state, NULL);
state.imap_browse = 1;
imap_browse (LastDir, &state);
+ browser_sort (&state);
menu->data = state.entry;
}
#endif
</para>
</listitem>
</varlistentry>
- <varlistentry>
- <term>A</term>
- <listitem>
- <para>
- message has one or more attachments.
- </para>
- </listitem>
- </varlistentry>
-
<varlistentry>
<term>S</term>
<listitem>
</para>
</sect1>
-
+
+ <sect1 id="attachments">
+ <title>Attachment Searching and Counting</title>
+
+ <para>
+ If you ever lose track of attachments in your mailboxes, Mutt's
+ attachment-counting and -searching support might be for you. You
+ can make your message index display the number of qualifying
+ attachments in each message, or search for messages by
+ attachment count. You also can configure what kinds of
+ attachments qualify for this feature with the attachments and
+ unattachments commands.
+ </para>
+
+<para>
+The syntax is:
+</para>
+
+<para>
+ <muttng-doc:cmddef name="attachments">
+ ( {+|-}disposition mime-type | ? )
+ </muttng-doc:cmddef>
+</para>
+<para>
+ <muttng-doc:cmddef name="unattachments">
+ {+|-}disposition mime-type
+ </muttng-doc:cmddef>
+</para>
+
+<para>
+Disposition is the attachment's Content-disposition type -- either
+"inline" or "attachment". You can abbreviate this to I or A.
+</para>
+
+<para>
+Disposition is prefixed by either a + symbolor a - symbol. If it's
+a +, you're saying that you want to allow this disposition and MIME
+type to qualify. If it's a -, you're saying that this disposition
+and MIME type is an exception to previous + rules. There are examples
+below of how this is useful.
+</para>
+
+<para>
+Mime-type is, unsurprisingly, the MIME type of the attachment you want
+to affect. A MIME type is always of the format "major/minor", where
+"major" describes the broad category of document you're looking at, and
+"minor" describes the specific type within that category. The major
+part of mim-type must be literal text (or the special token "*"), but
+the minor part may be a regular expression. (Therefore, "*/.*" matches
+any MIME type.)
+</para>
+
+<para>
+The MIME types you give to the attachments directive are a kind of
+pattern. When you use the attachments directive, the patterns you
+specify are added to a list. When you use unattachments, the pattern
+is removed from the list. The patterns are not expanded and matched
+to specific MIME types at this time -- they're just text in a list.
+They're only matched when actually evaluating a message.
+</para>
+
+<para>
+Some examples might help to illustrate. The examples that are not
+commented out define the default configuration of the lists.
+</para>
+
+<screen>
+## Removing a pattern from a list removes that pattern literally. It
+## does not remove any type matching the pattern.
+##
+## attachments +A */.*
+## attachments +A image/jpeg
+## unattachments +A */.*
+##
+## This leaves "attached" image/jpeg files on the allowed attachments
+## list. It does not remove all items, as you might expect, because the
+## second */.* is not a matching expression at this time.
+##
+## Remember: "unattachments" only undoes what "attachments" has done!
+## It does not trigger any matching on actual messages.
+
+
+## Qualify any MIME part with an "attachment" disposition, EXCEPT for
+## text/x-vcard and application/pgp parts. (PGP parts are already known
+## to mutt, and can be searched for with ~g, ~G, and ~k.)
+##
+## I've added x-pkcs7 to this, since it functions (for S/MIME)
+## analogously to PGP signature attachments. S/MIME isn't supported
+## in a stock mutt build, but we can still treat it specially here.
+##
+attachments +A */.*
+attachments -A text/x-vcard application/pgp.*
+attachments -A application/x-pkcs7-.*
+
+## Discount all MIME parts with an "inline" disposition, unless they're
+## text/plain. (Why inline a text/plain part unless it's external to the
+## message flow?)
+##
+attachments +I text/plain
+
+## These two lines make Mutt qualify MIME containers. (So, for example,
+## a message/rfc822 forward will count as an attachment.) The first
+## line is unnecessary if you already have "attach-allow */.*", of
+## course. These are off by default! The MIME elements contained
+## within a message/* or multipart/* are still examined, even if the
+## containers themseves don't qualify.
+##
+#attachments +A message/.* multipart/.*
+#attachments +I message/.* multipart/.*
+
+## You probably don't really care to know about deleted attachments.
+attachments -A message/external-body
+attachments -I message/external-body
+</screen>
+
+<para>
+"attachments ?" will list your current settings in Muttrc format, so
+that it can be pasted elsewhere.
+</para>
+
+</sect1>
+
<sect1>
<title>MIME Lookup</title>
<entry><literal>EXPR</literal></entry>
<entry>messages which contain EXPR in the `References' field</entry>
</row>
+ <row>
+ <entry><muttng-doc:pattern full="1" name="X"/></entry>
+ <entry><literal>[MIN]-[MAX]</literal></entry>
+ <entry>messages with MIN to MAX attachments *)</entry>
+ </row>
<row>
<entry><muttng-doc:pattern full="1" name="y"/></entry>
<entry><literal>EXPR</literal></entry>
~u message is addressed to a subscribed mailing list
~v message is part of a collapsed thread.
~x \fIEXPR\fP messages which contain \fIEXPR\fP in the \(lqReferences\(rq field
+~X \fIMIN\fP-\fiMAX\fP messages with MIN to MAX attachments
~z \fIMIN\fP-\fIMAX\fP messages with a size in the range \fIMIN\fP to \fIMAX\fP
~= duplicated messages (see $duplicate_threads)
~$ unreferenced message (requries threaded view)
.PP
In the above, \fIEXPR\fP is a regular expression.
.PP
-With the \fB~m\fP, \fB~n\fP, and \fB~z\fP operators, you can also
+With the \fB~m\fP, \fB~n\fP, \fB~X\fP and \fB~z\fP operators, you can also
specify ranges in the forms \fB<\fP\fIMAX\fP, \fB>\fP\fIMIN\fP,
\fIMIN\fP\fB-\fP, and \fB-\fP\fIMAX\fP.
.SS Matching dates
WHERE LIST *AutoViewList INITVAL (0);
WHERE LIST *AlternativeOrderList INITVAL (0);
+WHERE LIST *AttachAllow INITVAL(0);
+WHERE LIST *AttachExclude INITVAL(0);
+WHERE LIST *InlineAllow INITVAL(0);
+WHERE LIST *InlineExclude INITVAL(0);
WHERE LIST *HeaderOrderList INITVAL (0);
WHERE LIST *Ignore INITVAL (0);
WHERE LIST *MimeLookupList INITVAL (0);
#ifdef USE_HCACHE
-#define MUTTNG_HCACHE_ID "0x001"
+#define MUTTNG_HCACHE_ID "0x002"
# if HAVE_INTTYPES_H
# include <inttypes.h>
* %u = user (login) name of author
* %v = first name of author, unless from self
* %W = where user is (organization)
+ * %X = number of MIME attachments
* %y = `x-label:' field (if present)
* %Y = `x-label:' field (if present, tree unfolded, and != parent's x-label)
* %Z = status flags */
optional = 0;
break;
+ case 'X':
+ {
+ int count, flags = 0;
+
+ if (hdr->content->parts)
+ count = mutt_count_body_parts(hdr, flags);
+ else {
+ mutt_parse_mime_message(ctx, hdr);
+ count = mutt_count_body_parts(hdr, flags);
+ mutt_free_body(&hdr->content->parts);
+ }
+
+ /* The recursion allows messages without depth to return 0. */
+ if (optional)
+ optional = count != 0;
+
+ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+ snprintf (dest, destlen, fmt, count);
+ }
+ break;
+
case 'Z':
ch = ' ';
ch = 'K';
snprintf (buf2, sizeof (buf2),
- "%c%c%c%c", (THREAD_NEW ? 'n' : (THREAD_OLD ? 'o' :
+ "%c%c%c", (THREAD_NEW ? 'n' : (THREAD_OLD ? 'o' :
((hdr->read
&& (ctx
&& ctx->msgnotreadyet !=
mutt_user_is_recipient
(hdr)) <
str_len (Tochars)) ?
- Tochars[i] : ' ')),
- (hdr->content && hdr->content->type == TYPEMULTIPART) ?
- 'A' : ' ');
+ Tochars[i] : ' ')));
mutt_format_s (dest, destlen, prefix, buf2);
break;
return 0;
}
+/* always wise to do what someone else did before */
+static void _attachments_clean (void) {
+ int i;
+ if (Context && Context->msgcount) {
+ for (i = 0; i < Context->msgcount; i++)
+ Context->hdrs[i]->attach_valid = 0;
+ }
+}
+
+static int parse_attach_list (BUFFER *buf, BUFFER *s, LIST **ldata,
+ BUFFER *err) {
+ ATTACH_MATCH *a;
+ LIST *listp, *lastp;
+ char *p;
+ char *tmpminor;
+ int len;
+
+ /* Find the last item in the list that data points to. */
+ lastp = NULL;
+ debug_print (5, ("parse_attach_list: ldata = %08x, *ldata = %08x\n",
+ (unsigned int)ldata, (unsigned int)*ldata));
+ for (listp = *ldata; listp; listp = listp->next) {
+ a = (ATTACH_MATCH *)listp->data;
+ debug_print (5, ("parse_attach_list: skipping %s/%s\n", a->major, a->minor));
+ lastp = listp;
+ }
+
+ do {
+ mutt_extract_token (buf, s, 0);
+
+ if (!buf->data || *buf->data == '\0')
+ continue;
+
+ a = mem_malloc(sizeof(ATTACH_MATCH));
+
+ /* some cheap hacks that I expect to remove */
+ if (!str_casecmp(buf->data, "any"))
+ a->major = str_dup("*/.*");
+ else if (!str_casecmp(buf->data, "none"))
+ a->major = str_dup("cheap_hack/this_should_never_match");
+ else
+ a->major = str_dup(buf->data);
+
+ if ((p = strchr(a->major, '/'))) {
+ *p = '\0';
+ ++p;
+ a->minor = p;
+ } else {
+ a->minor = "unknown";
+ }
+
+ len = str_len (a->minor);
+ tmpminor = mem_malloc(len+3);
+ strcpy(&tmpminor[1], a->minor); /* __STRCPY_CHECKED__ */
+ tmpminor[0] = '^';
+ tmpminor[len+1] = '$';
+ tmpminor[len+2] = '\0';
+
+ a->major_int = mutt_check_mime_type(a->major);
+ regcomp(&a->minor_rx, tmpminor, REG_ICASE|REG_EXTENDED);
+
+ mem_free (&tmpminor);
+
+ debug_print (5, ("parse_attach_list: added %s/%s [%d]\n",
+ a->major, a->minor, a->major_int));
+
+ listp = mem_malloc(sizeof(LIST));
+ listp->data = (char *)a;
+ listp->next = NULL;
+ if (lastp) {
+ lastp->next = listp;
+ } else {
+ *ldata = listp;
+ }
+ lastp = listp;
+ }
+ while (MoreArgs (s));
+
+ _attachments_clean();
+ return 0;
+}
+
+static int parse_unattach_list (BUFFER *buf, BUFFER *s, LIST **ldata, BUFFER *err) {
+ ATTACH_MATCH *a;
+ LIST *lp, *lastp, *newlp;
+ char *tmp;
+ int major;
+ char *minor;
+
+ do {
+ mutt_extract_token (buf, s, 0);
+
+ if (!str_casecmp(buf->data, "any"))
+ tmp = str_dup("*/.*");
+ else if (!str_casecmp(buf->data, "none"))
+ tmp = str_dup("cheap_hack/this_should_never_match");
+ else
+ tmp = str_dup(buf->data);
+
+ if ((minor = strchr(tmp, '/'))) {
+ *minor = '\0';
+ ++minor;
+ } else {
+ minor = "unknown";
+ }
+ major = mutt_check_mime_type(tmp);
+
+ /* We must do our own walk here because remove_from_list() will only
+ * remove the LIST->data, not anything pointed to by the LIST->data. */
+ lastp = NULL;
+ for(lp = *ldata; lp; ) {
+ a = (ATTACH_MATCH *)lp->data;
+ debug_print(5, ("parse_unattach_list: check %s/%s [%d] : %s/%s [%d]\n",
+ a->major, a->minor, a->major_int, tmp, minor, major));
+ if (a->major_int == major && !str_casecmp(minor, a->minor)) {
+ debug_print(5, ("parse_unattach_list: removed %s/%s [%d]\n",
+ a->major, a->minor, a->major_int));
+ regfree(&a->minor_rx);
+ mem_free(&a->major);
+
+ /* Relink backward */
+ if (lastp)
+ lastp->next = lp->next;
+ else
+ *ldata = lp->next;
+
+ newlp = lp->next;
+ mem_free(&lp->data); /* same as a */
+ mem_free(&lp);
+ lp = newlp;
+ continue;
+ }
+
+ lastp = lp;
+ lp = lp->next;
+ }
+ }
+ while (MoreArgs (s));
+
+ mem_free (&tmp);
+ _attachments_clean();
+ return 0;
+}
+
+static int print_attach_list (LIST *lp, char op, char *name) {
+ while (lp) {
+ printf("attachments %c%s %s/%s\n", op, name,
+ ((ATTACH_MATCH *)lp->data)->major,
+ ((ATTACH_MATCH *)lp->data)->minor);
+ lp = lp->next;
+ }
+
+ return 0;
+}
+
+static int parse_attachments (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) {
+ char op, *category;
+ LIST **listp;
+
+ mutt_extract_token(buf, s, 0);
+ if (!buf->data || *buf->data == '\0') {
+ strfcpy(err->data, _("attachments: no disposition"), err->dsize);
+ return -1;
+ }
+
+ category = buf->data;
+ op = *category++;
+
+ if (op == '?') {
+ mutt_endwin (NULL);
+ fflush (stdout);
+ printf("\nCurrent attachments settings:\n\n");
+ print_attach_list(AttachAllow, '+', "A");
+ print_attach_list(AttachExclude, '-', "A");
+ print_attach_list(InlineAllow, '+', "I");
+ print_attach_list(InlineExclude, '-', "I");
+ set_option (OPTFORCEREDRAWINDEX);
+ set_option (OPTFORCEREDRAWPAGER);
+ mutt_any_key_to_continue (NULL);
+ return 0;
+ }
+
+ if (op != '+' && op != '-') {
+ op = '+';
+ category--;
+ }
+ if (!str_ncasecmp(category, "attachment", strlen(category))) {
+ if (op == '+')
+ listp = &AttachAllow;
+ else
+ listp = &AttachExclude;
+ }
+ else if (!str_ncasecmp(category, "inline", strlen(category))) {
+ if (op == '+')
+ listp = &InlineAllow;
+ else
+ listp = &InlineExclude;
+ } else {
+ strfcpy(err->data, _("attachments: invalid disposition"), err->dsize);
+ return -1;
+ }
+
+ return parse_attach_list(buf, s, listp, err);
+}
+
+static int parse_unattachments (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) {
+ char op, *p;
+ LIST **listp;
+
+ mutt_extract_token(buf, s, 0);
+ if (!buf->data || *buf->data == '\0') {
+ strfcpy(err->data, _("unattachments: no disposition"), err->dsize);
+ return -1;
+ }
+
+ p = buf->data;
+ op = *p++;
+ if (op != '+' && op != '-') {
+ op = '+';
+ p--;
+ }
+ if (!str_ncasecmp(p, "attachment", strlen(p))) {
+ if (op == '+')
+ listp = &AttachAllow;
+ else
+ listp = &AttachExclude;
+ }
+ else if (!str_ncasecmp(p, "inline", strlen(p))) {
+ if (op == '+')
+ listp = &InlineAllow;
+ else
+ listp = &InlineExclude;
+ }
+ else {
+ strfcpy(err->data, _("unattachments: invalid disposition"), err->dsize);
+ return -1;
+ }
+
+ return parse_unattach_list(buf, s, listp, err);
+}
+
static int parse_unlists (BUFFER * buf, BUFFER * s, unsigned long data,
BUFFER * err)
{
** .dt %m .dd major MIME type
** .dt %M .dd MIME subtype
** .dt %n .dd attachment number
+ ** .dt %Q .dd "Q", if MIME part qualifies for attachment counting
** .dt %s .dd size
** .dt %t .dd tagged flag
** .dt %T .dd graphic tree characters
** .dt %u .dd unlink (=to delete) flag
+ ** .dt %X .dd number of qualifying MIME parts in this part and its children
** .dt %>X .dd right justify the rest of the string and pad with character "X"
** .dt %|X .dd pad to the end of the line with character "X"
** .de
** .dt %u .dd user (login) name of the author
** .dt %v .dd first name of the author, or the recipient if the message is from you
** .dt %W .dd name of organization of author (`organization:' field)
+ ** .dt %X .dd number of attachments
** .dt %y .dd `x-label:' field, if present
** .dt %Y .dd `x-label' field, if present, and (1) not at part of a thread tree,
** (2) at the top of a thread, or (3) `x-label' is different from
** If \fIset\fP, forces Mutt-ng to interpret keystrokes with the high bit (bit 8)
** set as if the user had pressed the \fTESC\fP key and whatever key remains
** after having the high bit removed. For example, if the key pressed
- ** has an ASCII value of \fT0xf4\fP, then this is treated as if the user had
+ ** has an ASCII value of \fT0xf8\fP, then this is treated as if the user had
** pressed \fTESC\fP then ``\fTx\fP''. This is because the result of removing the
- ** high bit from ``\fT0xf4\fP'' is ``\fT0x74\fP'', which is the ASCII character
+ ** high bit from ``\fT0xf8\fP'' is ``\fT0x78\fP'', which is the ASCII character
** ``\fTx\fP''.
*/
{"mh_purge", DT_BOOL, R_NONE, OPTMHPURGE, "no" },
** Availability: POP
**
** .pp
- ** This variable configures how often (in seconds) POP should look for
+ ** This variable configures how often (in seconds) Mutt-ng should look for
** new mail.
*/
{"pop_delete", DT_QUAD, R_NONE, OPT_POPDELETE, "ask-no" },
** Availability: POP
**
** .pp
- ** Controls whether or not Mutt-ng will try to reconnect to a POP server when the
+ ** Controls whether or not Mutt-ng will try to reconnect to a POP server if the
** connection is lost.
*/
{"pop_user", DT_STR, R_NONE, UL &PopUser, "" },
static int parse_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_spam_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_unlist (BUFFER *, BUFFER *, unsigned long, BUFFER *);
-
+static int parse_attachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+static int parse_unattachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_lists (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_unlists (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_alias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
struct command_t Commands[] = {
{"alternates", parse_alternates, 0},
+ {"attachments", parse_attachments, 0 },
+ {"unattachments",parse_unattachments,0 },
{"unalternates", parse_unalternates, 0},
#ifdef USE_SOCKET
{"account-hook", mutt_parse_hook, M_ACCOUNTHOOK},
TYPEMODEL,
TYPEMULTIPART,
TYPETEXT,
- TYPEVIDEO
+ TYPEVIDEO,
+ TYPEANY
};
/* Content-Transfer-Encoding */
M_CRYPT_ENCRYPT,
M_PGP_KEY,
M_XLABEL,
+ M_MIMEATTACH,
#ifdef USE_NNTP
M_NEWSGROUPS,
#endif
struct attachptr *aptr; /* Menu information, used in recvattach.c */
+ signed short attach_count;
+
time_t stamp; /* time stamp of last
* encoding update.
*/
unsigned int badsig:1; /* bad cryptographic signature (needed to check encrypted s/mime-signatures) */
unsigned int collapsed:1; /* used by recvattach */
+ unsigned int attach_qualifies:1;
} BODY;
unsigned int searched:1;
unsigned int matched:1;
+ /* tells whether the attach count is valid */
+ unsigned int attach_valid:1;
+
/* the following are used to support collapsing threads */
unsigned int collapsed:1; /* is this message part of a collapsed thread? */
unsigned int limited:1; /* is this message in a limited view? */
char *tree; /* character string to print thread tree */
struct thread *thread;
+ short attach_total;
+
#ifdef MIXMASTER
LIST *chain;
#endif
unsigned int counting:1; /* do we just want to cound? */
} CONTEXT;
+/* for attachment counter */
+typedef struct {
+ char *major;
+ int major_int;
+ char *minor;
+ regex_t minor_rx;
+} ATTACH_MATCH;
+
+/* Flags for mutt_count_body_parts() */
+#define M_PARTS_TOPLEVEL (1<<0) /* is the top-level part */
+#define M_PARTS_RECOUNT (1<<1) /* force recount */
+
#include "protos.h"
#include "lib.h"
#include "globals.h"
return TYPEVIDEO;
else if (ascii_strcasecmp ("model", s) == 0)
return TYPEMODEL;
+ else if (ascii_strcasecmp ("*", s) == 0)
+ return TYPEANY;
+ else if (ascii_strcasecmp (".*", s) == 0)
+ return TYPEANY;
else
return TYPEOTHER;
}
void mutt_parse_mime_message (CONTEXT * ctx, HEADER * cur)
{
MESSAGE *msg;
+ int flags = 0;
- if (cur->content->type != TYPEMESSAGE
- && cur->content->type != TYPEMULTIPART)
- return; /* nothing to do */
+ do {
+ if (cur->content->type != TYPEMESSAGE
+ && cur->content->type != TYPEMULTIPART)
+ break; /* nothing to do */
- if (cur->content->parts)
- return; /* The message was parsed earlier. */
+ if (cur->content->parts)
+ break; /* The message was parsed earlier. */
- if ((msg = mx_open_message (ctx, cur->msgno))) {
- mutt_parse_part (msg->fp, cur->content);
+ if ((msg = mx_open_message (ctx, cur->msgno))) {
+ mutt_parse_part (msg->fp, cur->content);
- if (WithCrypto)
- cur->security = crypt_query (cur->content);
+ if (WithCrypto)
+ cur->security = crypt_query (cur->content);
- mx_close_message (&msg);
- }
+ mx_close_message (&msg);
+ }
+ } while (0);
+ mutt_count_body_parts (cur, flags | M_PARTS_RECOUNT);
}
int mutt_parse_rfc822_line (ENVELOPE * e, HEADER * hdr, char *line, char *p,
return p;
}
+
+
+/* Compares mime types to the ok and except lists */
+int count_body_parts_check(LIST **checklist, BODY *b, int dflt) {
+ LIST *type;
+ ATTACH_MATCH *a;
+
+ /* If list is null, use default behavior. */
+ if (! *checklist) {
+ /*return dflt;*/
+ return 0;
+ }
+
+ for (type = *checklist; type; type = type->next) {
+ a = (ATTACH_MATCH *)type->data;
+ debug_print(5, ("cbpc: %s %d/%s ?? %s/%s [%d]... ",
+ dflt ? "[OK] " : "[EXCL] ",
+ b->type, b->subtype, a->major, a->minor, a->major_int));
+ if ((a->major_int == TYPEANY || a->major_int == b->type) &&
+ !regexec(&a->minor_rx, b->subtype, 0, NULL, 0)) {
+ debug_print(5, ("yes\n"));
+ return 1;
+ } else {
+ debug_print(5, ("no\n"));
+ }
+ }
+ return 0;
+}
+
+#define AT_COUNT(why) { shallcount = 1; }
+#define AT_NOCOUNT(why) { shallcount = 0; }
+
+int count_body_parts (BODY *body, int flags) {
+ int count = 0;
+ int shallcount, shallrecurse;
+ BODY *bp;
+
+ if (body == NULL)
+ return 0;
+
+ for (bp = body; bp != NULL; bp = bp->next) {
+ /* Initial disposition is to count and not to recurse this part. */
+ AT_COUNT("default");
+ shallrecurse = 0;
+
+ debug_print(5, ("bp: desc=\"%s\"; fn=\"%s\", type=\"%d/%s\"\n",
+ bp->description ? bp->description : ("none"),
+ bp->filename ? bp->filename :
+ bp->d_filename ? bp->d_filename : "(none)",
+ bp->type, bp->subtype ? bp->subtype : "*"));
+
+ if (bp->type == TYPEMESSAGE) {
+ shallrecurse = 1;
+
+ /* If it's an external body pointer, don't recurse it. */
+ if (!ascii_strcasecmp (bp->subtype, "external-body"))
+ shallrecurse = 0;
+
+ /* Don't count containers if they're top-level. */
+ if (flags & M_PARTS_TOPLEVEL)
+ AT_NOCOUNT("top-level message/*");
+ } else if (bp->type == TYPEMULTIPART) {
+ /* Always recurse multiparts, except multipart/alternative. */
+ shallrecurse = 1;
+ if (!str_casecmp(bp->subtype, "alternative"))
+ shallrecurse = 0;
+
+ /* Don't count containers if they're top-level. */
+ if (flags & M_PARTS_TOPLEVEL)
+ AT_NOCOUNT("top-level multipart");
+ }
+
+ if (bp->disposition == DISPINLINE &&
+ bp->type != TYPEMULTIPART && bp->type != TYPEMESSAGE && bp == body)
+ AT_NOCOUNT("ignore fundamental inlines");
+
+ /* If this body isn't scheduled for enumeration already, don't bother
+ * profiling it further. */
+
+ if (shallcount) {
+ /* Turn off shallcount if message type is not in ok list,
+ * or if it is in except list. Check is done separately for
+ * inlines vs. attachments.
+ */
+
+ if (bp->disposition == DISPATTACH) {
+ if (!count_body_parts_check(&AttachAllow, bp, 1))
+ AT_NOCOUNT("attach not allowed");
+ if (count_body_parts_check(&AttachExclude, bp, 0))
+ AT_NOCOUNT("attach excluded");
+ } else {
+ if (!count_body_parts_check(&InlineAllow, bp, 1))
+ AT_NOCOUNT("inline not allowed");
+ if (count_body_parts_check(&InlineExclude, bp, 0))
+ AT_NOCOUNT("excluded");
+ }
+ }
+
+ if (shallcount)
+ count++;
+ bp->attach_qualifies = shallcount ? 1 : 0;
+
+ debug_print(5, ("cbp: %08x shallcount = %d\n", (unsigned int)bp, shallcount));
+
+ if (shallrecurse) {
+ debug_print(5, ("cbp: %08x pre count = %d\n", (unsigned int)bp, count));
+ bp->attach_count = count_body_parts(bp->parts, flags & ~M_PARTS_TOPLEVEL);
+ count += bp->attach_count;
+ debug_print(5, ("cbp: %08x post count = %d\n", (unsigned int)bp, count));
+ }
+ }
+
+ debug_print(5, ("bp: return %d\n", count < 0 ? 0 : count));
+ return count < 0 ? 0 : count;
+}
+
+int mutt_count_body_parts (HEADER *hdr, int flags) {
+ if (hdr->attach_valid && !(flags & M_PARTS_RECOUNT))
+ return hdr->attach_total;
+
+ if (AttachAllow || AttachExclude || InlineAllow || InlineExclude)
+ hdr->attach_total = count_body_parts(hdr->content, flags | M_PARTS_TOPLEVEL);
+ else
+ hdr->attach_total = 0;
+
+ hdr->attach_valid = 1;
+ return hdr->attach_total;
+}
#endif
{
'x', M_REFERENCE, 0, eat_regexp}, {
+ 'X', M_MIMEATTACH, 0, eat_range}, {
'y', M_XLABEL, 0, eat_regexp}, {
'z', M_SIZE, 0, eat_range}, {
'=', M_DUPLICATED, 0, NULL}, {
&& patmatch (pat, h->env->spam->data) == 0));
case M_DUPLICATED:
return (pat->not ^ (h->thread && h->thread->duplicate_thread));
+
+ case M_MIMEATTACH:
+ {
+ int count;
+
+ if (h->content->parts)
+ count = mutt_count_body_parts(h, 0);
+ else {
+ mutt_parse_mime_message(ctx, h);
+ count = mutt_count_body_parts(h, 0);
+ mutt_free_body(&h->content->parts);
+ }
+
+ return (pat->not ^ (count >= pat->min && (pat->max == M_MAXRANGE ||
+ count <= pat->max)));
+ }
+
case M_UNREFERENCED:
return (pat->not ^ (h->thread && !h->thread->child));
case M_MULTIPART:
void mutt_block_signals_system (void);
int mutt_bounce_message (FILE * fp, HEADER *, ADDRESS *);
void mutt_canonical_charset (char *, size_t, const char *);
+int mutt_count_body_parts (HEADER *hdr, int flags);
void mutt_check_rescore (CONTEXT *);
void mutt_clear_error (void);
void mutt_default_save (char *, size_t, HEADER *);
snprintf (dest, destlen, fmt, aptr->num + 1);
}
break;
+ case 'Q':
+ if (optional)
+ optional = aptr->content->attach_qualifies;
+ else {
+ snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
+ mutt_format_s (dest, destlen, fmt, "Q");
+ }
+ break;
case 's':
if (flags & M_FORMAT_STAT_FILE) {
struct stat st;
else if (!aptr->content->unlink)
optional = 0;
break;
+ case 'X':
+ if (optional)
+ optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0;
+ else {
+ snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+ snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
+ }
+ break;
default:
*dest = 0;
}
case 3: /* encrypt (w)ith */
msg->security |= ENCRYPT;
switch (mutt_multi_choice (_("1: DES, 2: Triple-DES, 3: RC2-40,"
- " 4: RC2-64, 5: RC2-128, or (f)orget it? "),
- _("12345f"))) {
+ " 4: RC2-64, 5: RC2-128, 6: AES128,"
+ " 7: AES192, 8: AES256, or (f)orget it? "),
+ _("12345678f"))) {
case 1:
str_replace (&SmimeCryptAlg, "des");
break;
case 5:
str_replace (&SmimeCryptAlg, "rc2-128");
break;
- case 6: /* forget it */
+ case 6:
+ str_replace (&SmimeCryptAlg, "aes128");
+ break;
+ case 7:
+ str_replace (&SmimeCryptAlg, "aes192");
+ break;
+ case 8:
+ str_replace (&SmimeCryptAlg, "aes256");
+ break;
+ case 9: /* forget it */
break;
}
break;
case 4: /* sign (a)s */
if ((p = smime_ask_for_key (_("Sign as: "), NULL, 0))) {
- p[str_len (p) - 1] = '\0';
str_replace (&SmimeDefaultKey, p);
msg->security |= SIGN;