Commit 6b77e38b authored by Thomas Roessler's avatar Thomas Roessler

Adding pattern group support; see

http://does-not-exist.org/mail-archives/mutt-dev/msg05693.html
for instructions.  The ungroup command is not yet implemented,
and documentation is lacking.
parent 8b493288
......@@ -20,7 +20,8 @@ mutt_SOURCES = $(BUILT_SOURCES) \
addrbook.c alias.c attach.c base64.c browser.c buffy.c color.c \
crypt.c cryptglue.c \
commands.c complete.c compose.c copy.c curs_lib.c curs_main.c date.c \
edit.c enter.c flags.c init.c filter.c from.c getdomain.c \
edit.c enter.c flags.c init.c filter.c from.c \
getdomain.c group.c \
handler.c hash.c hdrline.c headers.c help.c hook.c keymap.c \
main.c mbox.c menu.c mh.c mx.c pager.c parse.c pattern.c \
postpone.c query.c recvattach.c recvcmd.c \
......
......@@ -139,6 +139,8 @@ WHERE char *Visual;
WHERE char *CurrentFolder;
WHERE char *LastFolder;
WHERE HASH *Groups;
WHERE LIST *AutoViewList INITVAL(0);
WHERE LIST *AlternativeOrderList INITVAL(0);
WHERE LIST *AttachAllow INITVAL(0);
......
/*
* Copyright (C) 2006 Thomas Roessler <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "mutt.h"
#include "mapping.h"
#include "mutt_curses.h"
#include "mutt_regex.h"
#include "history.h"
#include "keymap.h"
#include "mbyte.h"
#include "charset.h"
#include "mutt_crypt.h"
#include "mutt_idna.h"
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/utsname.h>
#include <errno.h>
#include <sys/wait.h>
group_t *mutt_pattern_group (const char *k)
{
group_t *p;
if (!k)
return 0;
if (!(p = hash_find (Groups, k)))
{
dprint (2, (debugfile, "mutt_pattern_group: Creating group %s.\n", k));
p = safe_calloc (1, sizeof (group_t));
p->name = safe_strdup (k);
hash_insert (Groups, p->name, p, 0);
}
return p;
}
void mutt_group_context_add (group_context_t **ctx, group_t *group)
{
for (; *ctx; ctx = &((*ctx)->next))
{
if ((*ctx)->g == group)
return;
}
*ctx = safe_calloc (1, sizeof (group_context_t));
(*ctx)->g = group;
}
void mutt_group_context_destroy (group_context_t **ctx)
{
group_context_t *p;
for (; *ctx; *ctx = p)
{
p = (*ctx)->next;
FREE (ctx);
}
}
void mutt_group_add_adrlist (group_t *g, ADDRESS *a)
{
ADDRESS **p, *q;
if (!g)
return;
if (!a)
return;
for (p = &g->as; *p; p = &((*p)->next))
;
q = rfc822_cpy_adr (a);
q = mutt_remove_xrefs (g->as, q);
*p = q;
}
int mutt_group_add_rx (group_t *g, const char *s, int flags, BUFFER *err)
{
return mutt_add_to_rx_list (&g->rs, s, flags, err);
}
void mutt_group_context_add_adrlist (group_context_t *ctx, ADDRESS *a)
{
for (; ctx; ctx = ctx->next)
mutt_group_add_adrlist (ctx->g, a);
}
int mutt_group_context_add_rx (group_context_t *ctx, const char *s, int flags, BUFFER *err)
{
int rv = 0;
for (; (!rv) && ctx; ctx = ctx->next)
rv = mutt_group_add_rx (ctx->g, s, flags, err);
return rv;
}
int mutt_group_match (group_t *g, const char *s)
{
ADDRESS *ap;
if (s && g)
{
if (mutt_match_rx_list (s, g->rs))
return 1;
for (ap = g->as; ap; ap = ap->next)
if (ap->mailbox && !mutt_strcasecmp (s, ap->mailbox))
return 1;
}
return 0;
}
......@@ -1657,13 +1657,13 @@ static int imap_compile_search (const pattern_t* pat, BUFFER* buf)
mutt_buffer_addstr (buf, "HEADER ");
/* extract header name */
if (! (delim = strchr (pat->str, ':')))
if (! (delim = strchr (pat->p.str, ':')))
{
mutt_error (_("Header search without header name: %s"), pat->str);
mutt_error (_("Header search without header name: %s"), pat->p.str);
return -1;
}
*delim = '\0';
imap_quote_string (term, sizeof (term), pat->str);
imap_quote_string (term, sizeof (term), pat->p.str);
mutt_buffer_addstr (buf, term);
mutt_buffer_addch (buf, ' ');
......@@ -1676,12 +1676,12 @@ static int imap_compile_search (const pattern_t* pat, BUFFER* buf)
break;
case M_BODY:
mutt_buffer_addstr (buf, "BODY ");
imap_quote_string (term, sizeof (term), pat->str);
imap_quote_string (term, sizeof (term), pat->p.str);
mutt_buffer_addstr (buf, term);
break;
case M_WHOLE_MSG:
mutt_buffer_addstr (buf, "TEXT ");
imap_quote_string (term, sizeof (term), pat->str);
imap_quote_string (term, sizeof (term), pat->p.str);
mutt_buffer_addstr (buf, term);
break;
}
......
......@@ -134,7 +134,7 @@ int mutt_extract_token (BUFFER *dest, BUFFER *tok, int flags)
(ch == '#' && !(flags & M_TOKEN_COMMENT)) ||
(ch == '=' && (flags & M_TOKEN_EQUAL)) ||
(ch == ';' && !(flags & M_TOKEN_SEMICOLON)) ||
((flags & M_TOKEN_PATTERN) && strchr ("~=!|", ch)))
((flags & M_TOKEN_PATTERN) && strchr ("~%=!|", ch)))
break;
}
......@@ -377,7 +377,7 @@ static void add_to_list (LIST **list, const char *str)
}
}
static int add_to_rx_list (RX_LIST **list, const char *s, int flags, BUFFER *err)
int mutt_add_to_rx_list (RX_LIST **list, const char *s, int flags, BUFFER *err)
{
RX_LIST *t, *last = NULL;
REGEXP *rx;
......@@ -652,18 +652,33 @@ static void _alternates_clean (void)
static int parse_alternates (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
group_context_t *gc = NULL;
_alternates_clean();
do
{
mutt_extract_token (buf, s, 0);
if (parse_group_context (&gc, buf, s, data, err) == -1)
goto bail;
remove_from_rx_list (&UnAlternates, buf->data);
if (add_to_rx_list (&Alternates, buf->data, REG_ICASE, err) != 0)
return -1;
if (mutt_add_to_rx_list (&Alternates, buf->data, REG_ICASE, err) != 0)
goto bail;
if (mutt_group_context_add_rx (gc, buf->data, REG_ICASE, err) != 0)
goto bail;
}
while (MoreArgs (s));
mutt_group_context_destroy (&gc);
return 0;
bail:
mutt_group_context_destroy (&gc);
return -1;
}
static int parse_unalternates (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
......@@ -675,7 +690,7 @@ static int parse_unalternates (BUFFER *buf, BUFFER *s, unsigned long data, BUFFE
remove_from_rx_list (&Alternates, buf->data);
if (mutt_strcmp (buf->data, "*") &&
add_to_rx_list (&UnAlternates, buf->data, REG_ICASE, err) != 0)
mutt_add_to_rx_list (&UnAlternates, buf->data, REG_ICASE, err) != 0)
return -1;
}
......@@ -746,7 +761,7 @@ static int parse_spam_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *
return 0;
/* Otherwise, add it to the nospam list. */
if (add_to_rx_list (&NoSpamList, buf->data, REG_ICASE, err) != 0)
if (mutt_add_to_rx_list (&NoSpamList, buf->data, REG_ICASE, err) != 0)
return -1;
return 0;
......@@ -780,17 +795,95 @@ static int parse_unlist (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err
static int parse_lists (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
group_context_t *gc = NULL;
do
{
mutt_extract_token (buf, s, 0);
if (parse_group_context (&gc, buf, s, data, err) == -1)
goto bail;
remove_from_rx_list (&UnMailLists, buf->data);
if (add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0)
return -1;
if (mutt_add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0)
goto bail;
if (mutt_group_context_add_rx (gc, buf->data, REG_ICASE, err) != 0)
goto bail;
}
while (MoreArgs (s));
mutt_group_context_destroy (&gc);
return 0;
bail:
mutt_group_context_destroy (&gc);
return -1;
}
typedef enum group_state_t {
NONE, RX, ADDR
} group_state_t;
static int parse_group (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
group_context_t *gc = NULL;
group_state_t state = NONE;
ADDRESS *addr = NULL;
char *estr = NULL;
do
{
mutt_extract_token (buf, s, 0);
if (parse_group_context (&gc, buf, s, data, err) == -1)
goto bail;
if (!mutt_strcasecmp (buf->data, "-rx"))
state = RX;
else if (!mutt_strcasecmp (buf->data, "-addr"))
state = ADDR;
else
{
switch (state)
{
case NONE:
strfcpy (err->data, _("Missing -rx or -addr."), err->dsize);
goto bail;
case RX:
if (mutt_group_context_add_rx (gc, buf->data, REG_ICASE, err) != 0)
goto bail;
break;
case ADDR:
if ((addr = mutt_parse_adrlist (NULL, buf->data)) == NULL)
goto bail;
if (mutt_addrlist_to_idna (addr, &estr))
{
snprintf (err->data, err->dsize, _("Warning: Bad IDN '%s'.\n"),
estr);
goto bail;
}
mutt_group_context_add_adrlist (gc, addr);
rfc822_free_address (&addr);
break;
}
}
} while (MoreArgs (s));
mutt_group_context_destroy (&gc);
return 0;
bail:
mutt_group_context_destroy (&gc);
return -1;
}
static int parse_ungroup (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
strfcpy (err->data, "not implemented", err->dsize);
return -1;
}
/* always wise to do what someone else did before */
......@@ -1067,7 +1160,7 @@ static int parse_unlists (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *er
remove_from_rx_list (&MailLists, buf->data);
if (mutt_strcmp (buf->data, "*") &&
add_to_rx_list (&UnMailLists, buf->data, REG_ICASE, err) != 0)
mutt_add_to_rx_list (&UnMailLists, buf->data, REG_ICASE, err) != 0)
return -1;
}
while (MoreArgs (s));
......@@ -1077,20 +1170,33 @@ static int parse_unlists (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *er
static int parse_subscribe (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
group_context_t *gc = NULL;
do
{
mutt_extract_token (buf, s, 0);
if (parse_group_context (&gc, buf, s, data, err) == -1)
goto bail;
remove_from_rx_list (&UnMailLists, buf->data);
remove_from_rx_list (&UnSubscribedLists, buf->data);
if (add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0)
return -1;
if (add_to_rx_list (&SubscribedLists, buf->data, REG_ICASE, err) != 0)
return -1;
if (mutt_add_to_rx_list (&MailLists, buf->data, REG_ICASE, err) != 0)
goto bail;
if (mutt_add_to_rx_list (&SubscribedLists, buf->data, REG_ICASE, err) != 0)
goto bail;
if (mutt_group_context_add_rx (gc, buf->data, REG_ICASE, err) != 0)
goto bail;
}
while (MoreArgs (s));
mutt_group_context_destroy (&gc);
return 0;
bail:
mutt_group_context_destroy (&gc);
return -1;
}
static int parse_unsubscribe (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
......@@ -1101,7 +1207,7 @@ static int parse_unsubscribe (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER
remove_from_rx_list (&SubscribedLists, buf->data);
if (mutt_strcmp (buf->data, "*") &&
add_to_rx_list (&UnSubscribedLists, buf->data, REG_ICASE, err) != 0)
mutt_add_to_rx_list (&UnSubscribedLists, buf->data, REG_ICASE, err) != 0)
return -1;
}
while (MoreArgs (s));
......@@ -1161,6 +1267,7 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
ALIAS *tmp = Aliases;
ALIAS *last = NULL;
char *estr = NULL;
group_context_t *gc = NULL;
if (!MoreArgs (s))
{
......@@ -1170,8 +1277,8 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
mutt_extract_token (buf, s, 0);
dprint (2, (debugfile, "parse_alias: First token is '%s'.\n",
buf->data));
if (parse_group_context (&gc, buf, s, data, err) == -1)
return -1;
/* check to see if an alias with this name already exists */
for (; tmp; tmp = tmp->next)
......@@ -1202,7 +1309,9 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
mutt_extract_token (buf, s, M_TOKEN_QUOTE | M_TOKEN_SPACE | M_TOKEN_SEMICOLON);
dprint (2, (debugfile, "parse_alias: Second token is '%s'.\n",
buf->data));
tmp->addr = mutt_parse_adrlist (tmp->addr, buf->data);
if (last)
last->next = tmp;
else
......@@ -1211,8 +1320,12 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
snprintf (err->data, err->dsize, _("Warning: Bad IDN '%s' in alias '%s'.\n"),
estr, tmp->name);
return -1;
goto bail;
}
mutt_group_context_add_adrlist (gc, tmp->addr);
#ifdef DEBUG
if (debuglevel >= 2)
{
......@@ -1229,7 +1342,12 @@ static int parse_alias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
}
}
#endif
mutt_group_context_destroy (&gc);
return 0;
bail:
mutt_group_context_destroy (&gc);
return -1;
}
static int
......@@ -2541,6 +2659,8 @@ void mutt_init (int skip_sys_rc, LIST *commands)
err.data = error;
err.dsize = sizeof (error);
Groups = hash_create (1031);
/*
* XXX - use something even more difficult to predict?
*/
......@@ -2802,3 +2922,33 @@ int mutt_get_hook_type (const char *name)
return c->data;
return 0;
}
static int parse_group_context (group_context_t **ctx, BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
while (!mutt_strcasecmp (buf->data, "-group"))
{
if (!MoreArgs (s))
{
strfcpy (err->data, _("-group: no group name"), err->dsize);
goto bail;
}
mutt_extract_token (buf, s, 0);
mutt_group_context_add (ctx, mutt_pattern_group (buf->data));
if (!MoreArgs (s))
{
strfcpy (err->data, _("out of arguments"), err->dsize);
goto bail;
}
mutt_extract_token (buf, s, 0);
}
return 0;
bail:
mutt_group_context_destroy (ctx);
return -1;
}
......@@ -2989,6 +2989,9 @@ 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_group (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_ungroup (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 *);
......@@ -3008,6 +3011,10 @@ static int parse_unattachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_alternates (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_unalternates (BUFFER *, BUFFER *, unsigned long, BUFFER *);
/* Parse -group arguments */
static int parse_group_context (group_context_t **ctx, BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err);
struct command_t
{
char *name;
......@@ -3037,6 +3044,8 @@ struct command_t Commands[] = {
{ "fcc-hook", mutt_parse_hook, M_FCCHOOK },
{ "fcc-save-hook", mutt_parse_hook, M_FCCHOOK | M_SAVEHOOK },
{ "folder-hook", mutt_parse_hook, M_FOLDERHOOK },
{ "group", parse_group, 0 },
{ "ungroup", parse_ungroup, 0 },
{ "hdr_order", parse_list, UL &HeaderOrderList },
#ifdef HAVE_ICONV
{ "iconv-hook", mutt_parse_hook, M_ICONVHOOK },
......
......@@ -798,18 +798,36 @@ typedef enum {
M_MATCH_FULL_ADDRESS = 1
} pattern_exec_flag;
typedef struct group_t
{
ADDRESS *as;
RX_LIST *rs;
char *name;
} group_t;
typedef struct group_context_t
{
group_t *g;
struct group_context_t *next;
} group_context_t;
typedef struct pattern_t
{
short op;
unsigned int not : 1;
unsigned int alladdr : 1;
unsigned int stringmatch : 1;
unsigned int groupmatch : 1;
int min;
int max;
struct pattern_t *next;
struct pattern_t *child; /* arguments to logical op */
char *str;
regex_t *rx;
union
{
regex_t *rx;
group_t *g;
char *str;
} p;
} pattern_t;
typedef struct
......
......@@ -278,19 +278,24 @@ int eat_regexp (pattern_t *pat, BUFFER *s, BUFFER *err)
if (pat->stringmatch)
{
pat->str = safe_strdup (buf.data);
pat->p.str = safe_strdup (buf.data);
FREE (&buf.data);
}
else if (pat->groupmatch)
{
pat->p.g = mutt_pattern_group (buf.data);
FREE (&buf.data);
}
else
{
pat->rx = safe_malloc (sizeof (regex_t));
r = REGCOMP (pat->rx, buf.data, REG_NEWLINE | REG_NOSUB | mutt_which_case (buf.data));
pat->p.rx = safe_malloc (sizeof (regex_t));
r = REGCOMP (pat->p.rx, buf.data, REG_NEWLINE | REG_NOSUB | mutt_which_case (buf.data));
FREE (&buf.data);
if (r)
{
regerror (r, pat->rx, err->data, err->dsize);
regfree (pat->rx);
FREE (&pat->rx);
regerror (r, pat->p.rx, err->data, err->dsize);
regfree (pat->p.rx);
FREE (&pat->p.rx);
return (-1);
}
}
......@@ -697,9 +702,11 @@ static int eat_date (pattern_t *pat, BUFFER *s, BUFFER *err)
static int patmatch (const pattern_t* pat, const char* buf)
{
if (pat->stringmatch)
return !strstr (buf, pat->str);
return !strstr (buf, pat->p.str);
else if (pat->groupmatch)
return !mutt_group_match (pat->p.g, buf);
else
return regexec (pat->rx, buf, 0, NULL, 0);
return regexec (pat->p.rx, buf, 0, NULL, 0);
}
static struct pattern_flags *lookup_tag (char tag)
......@@ -739,12 +746,16 @@ void mutt_pattern_free (pattern_t **pat)
tmp = *pat;
*pat = (*pat)->next;
if (tmp->rx)
if (tmp->stringmatch)
FREE (&tmp->p.str);
else if (tmp->groupmatch)
tmp->p.g = NULL;
else if (tmp->p.rx)
{
regfree (tmp->rx);
FREE (&tmp->rx);
regfree (tmp->p.rx);
FREE (&tmp->p.rx);
}
FREE (&tmp->str);
if (tmp->child)
mutt_pattern_free (&tmp->child);
FREE (&tmp);
......@@ -808,6 +819,7 @@ pattern_t *mutt_pattern_comp (/* const */ char *s, int flags, BUFFER *err)
not = 0;
alladdr = 0;
break;
case '%':
case '=':
case '~':
if (implicit && or)
......@@ -825,6 +837,7 @@ pattern_t *mutt_pattern_comp (/* const */ char *s, int flags, BUFFER *err)
tmp->not = not;
tmp->alladdr = alladdr;
tmp->stringmatch = (*ps.dptr == '=') ? 1 : 0;
tmp->groupmatch = (*ps.dptr == '%') ? 1 : 0;
not = 0;
alladdr = 0;
......@@ -1164,7 +1177,7 @@ void mutt_check_simple (char *s, size_t len, const char *simple)
* equivalences?
*/
if (!strchr (s, '~') && !strchr (s, '=')) /* yup, so spoof a real request */
if (!strchr (s, '~') && !strchr (s, '=') && !strchr (s, '%')) /* yup, so spoof a real request */
{
/* convert old tokens into the new format */
if (ascii_strcasecmp ("all", s) == 0 ||
......
......@@ -72,6 +72,11 @@ typedef const char * format_t (char *, size_t, char, const char *, const char *,
void mutt_FormatString (char *, size_t, const char *, format_t *, unsigned long, format_flag);
void mutt_parse_content_type (char *, BODY *);
void mutt_generate_boundary (PARAMETER **);
void mutt_group_add_adrlist (group_t *, ADDRESS *);
void mutt_group_context_add (group_context_t **ctx, group_t *group);
void mutt_group_context_destroy (group_context_t **ctx);
void mutt_group_add_adrlist (group_t *g, ADDRESS *a);
void mutt_group_context_add_adrlist (group_context_t *ctx, ADDRESS *a);
void mutt_delete_parameter (const char *attribute, PARAMETER **p);
void mutt_set_parameter (const char *, const char *, PARAMETER **);
......@@ -86,6 +91,7 @@ ADDRESS *mutt_default_from (void);
ADDRESS *mutt_get_address (ENVELOPE *, char **);
ADDRESS *mutt_lookup_alias (const char *s);
ADDRESS *mutt_remove_duplicates (ADDRESS *);
ADDRESS *mutt_remove_xrefs (ADDRESS *, ADDRESS *);
ADDRESS *mutt_expand_aliases (ADDRESS *);
ADDRESS *mutt_parse_adrlist (ADDRESS *, const char *);
......@@ -144,6 +150,8 @@ const char *mutt_make_version (void);
const char *mutt_fqdn(short);
group_t *mutt_pattern_group (const char *);
REGEXP *mutt_compile_regexp (const char *, int);
void mutt_account_hook (const char* url);
......@@ -245,6 +253,7 @@ void mutt_view_attachments (HEADER *);
void mutt_write_address_list (ADDRESS *adr, FILE *fp, int linelen, int display);
void mutt_set_virtual (CONTEXT *);
int mutt_add_to_rx_list (RX_LIST **list, const char *s, int flags, BUFFER *err);
int mutt_addr_is_user (ADDRESS *);
int mutt_addwch (wchar_t);
int mutt_alias_complete (char *, size_t);
......@@ -291,6 +300,8 @@ int mutt_get_field_unbuffered (char *, char *, size_t, int);
#define mutt_get_password(A,B,C) mutt_get_field_unbuffered(A,B,C,M_PASS)
int mutt_get_postponed (CONTEXT *, HEADER *, HEADER **, char *, size_t);
int mutt_get_tmp_attachment (BODY *);
int mutt_group_match (group_t *g, const char *s);
int mutt_group_context_add_rx (group_context_t *ctx, const char *s, int flags, BUFFER *err);
int mutt_index_menu (void);
int mutt_invoke_sendmail (ADDRESS *, ADDRESS *, ADDRESS *, ADDRESS *, const char *, int);
int mutt_is_autoview (BODY *, const char *);
......
......@@ -87,7 +87,7 @@ static int mutt_addrsrc (ADDRESS *a, ADDRESS *lst)
}
/* removes addresses from "b" which are contained in "a" */
static ADDRESS *mutt_remove_xrefs (ADDRESS *a, ADDRESS *b)
ADDRESS *mutt_remove_xrefs (ADDRESS *a, ADDRESS *b)
{
ADDRESS *top, *p, *prev = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment