summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2022-04-06 20:08:07 +0300
committerSergey Poznyakoff <gray@gnu.org>2022-04-06 20:08:07 +0300
commitd19451e2c4a28b65e9ec8f3bb227d2c2ba8f0f74 (patch)
treec14ff88fe426b6badfecbc54a6c23d50ba5fd6d6
parent6f0dfc97a0484029d8719cd6fd629fa7f4af814c (diff)
downloadmailutils-d19451e2c4a28b65e9ec8f3bb227d2c2ba8f0f74.tar.gz
mail: error out if a message part is given to the command that doesn't support parts
* mail/mail.h (MSG_ALLOWPART): New flag. * mail/msgset.y: Allow message parts only if MSG_ALLOWPART is set. Rewrite as a reentrant parser. * mail/decode.c: Allow message parts in sets. * mail/write.c: Likewise.
-rw-r--r--mail/decode.c3
-rw-r--r--mail/mail.h1
-rw-r--r--mail/msgset.y292
-rw-r--r--mail/print.c3
-rw-r--r--mail/struct.c3
-rw-r--r--mail/write.c6
6 files changed, 183 insertions, 125 deletions
diff --git a/mail/decode.c b/mail/decode.c
index ba3bc44..66ead26 100644
--- a/mail/decode.c
+++ b/mail/decode.c
@@ -41,7 +41,8 @@ mail_decode (int argc, char **argv)
msgset_t *msgset;
struct decode_closure decode_closure;
- if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT, &msgset))
+ if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT|MSG_ALLOWPART,
+ &msgset))
return 1;
decode_closure.select_hdr = mu_islower (argv[0][0]);
diff --git a/mail/mail.h b/mail/mail.h
index 49c8c6c..c3ee511 100644
--- a/mail/mail.h
+++ b/mail/mail.h
@@ -593,6 +593,7 @@ char *readline (char *prompt);
#define MSG_NODELETED 0x0001
#define MSG_SILENT 0x0002
#define MSG_COUNT 0x0004
+#define MSG_ALLOWPART 0x0008
/* Message attributes */
#define MAIL_ATTRIBUTE_MBOXED 0x0001
diff --git a/mail/msgset.y b/mail/msgset.y
index c854cb2..435e576 100644
--- a/mail/msgset.y
+++ b/mail/msgset.y
@@ -42,20 +42,57 @@ static int select_header (mu_message_t msg, void *closure);
static int select_body (mu_message_t msg, void *closure);
static int select_sender (mu_message_t msg, void *closure);
static int select_deleted (mu_message_t msg, void *closure);
-static int check_set (msgset_t **pset);
+static int check_set (msgset_t **pset, int flags);
-int yyerror (const char *);
-int yylex (void);
+struct msgset_parser
+{
+ int flags;
+ size_t message_count;
+ msgset_t *result;
+};
+
+struct msgset_lexer
+{
+ int xargc;
+ char **xargv;
+ int cur_ind;
+ char *cur_p;
+ mu_opool_t tokpool;
+};
+
+int yyerror (struct msgset_parser *, struct msgset_lexer *, const char *);
+int yylex (struct msgset_lexer *);
-static int msgset_flags = MSG_NODELETED;
-static size_t message_count;
-static msgset_t *result;
-static mu_opool_t tokpool;
+static void
+msgset_parser_free (struct msgset_parser *parser)
+{
+ msgset_free (parser->result);
+}
+
+static void
+msgset_lexer_free (struct msgset_lexer *lexer)
+{
+ mu_opool_destroy (&lexer->tokpool);
+}
+static msgset_t *
+msgset_concat (msgset_t *mset, msgset_t *part)
+{
+ msgset_t *ret = msgset_expand (mset, part);
+ msgset_free (mset);
+ msgset_free (part);
+ return ret;
+}
+
typedef int (*message_selector_t) (mu_message_t, void *);
static message_selector_t find_type_selector (int type);
%}
+%parse-param { struct msgset_parser *parser } { struct msgset_lexer *lexer }
+%lex-param { struct msgset_lexer *lexer }
+
+%expect 6
+
%union {
char *string;
int number;
@@ -73,35 +110,35 @@ static message_selector_t find_type_selector (int type);
input : /* empty */
{
- result = msgset_make_1 (get_cursor ());
+ parser->result = msgset_make_1 (get_cursor ());
}
| '.'
{
- result = msgset_make_1 (get_cursor ());
+ parser->result = msgset_make_1 (get_cursor ());
}
| msgset
{
- result = $1;
+ parser->result = $1;
}
| '^'
{
- result = msgset_select (select_deleted, NULL, 0, 1);
+ parser->result = msgset_select (select_deleted, lexer, 0, 1);
}
| '$'
{
- result = msgset_select (select_deleted, NULL, 1, 1);
+ parser->result = msgset_select (select_deleted, lexer, 1, 1);
}
| '*'
{
- result = msgset_select (select_deleted, NULL, 0, total);
+ parser->result = msgset_select (select_deleted, lexer, 0, total);
}
| '-'
{
- result = msgset_select (select_deleted, NULL, 1, 1);
+ parser->result = msgset_select (select_deleted, lexer, 1, 1);
}
| '+'
{
- result = msgset_select (select_deleted, NULL, 0, 1);
+ parser->result = msgset_select (select_deleted, lexer, 0, 1);
}
;
@@ -119,7 +156,7 @@ msgset : msgexpr
msgexpr : msgspec
{
$$ = $1;
- if (check_set (&$$))
+ if (check_set (&$$, parser->flags))
YYABORT;
}
| '{' msgset '}'
@@ -133,17 +170,13 @@ msgexpr : msgspec
;
msgspec : msg
- | msg '.' rangeset
+ | msg dot rangeset
{
- $$ = msgset_expand ($1, $3);
- msgset_free ($1);
- msgset_free ($3);
+ $$ = msgset_concat ($1, $3);
}
- | msg '[' rangeset ']'
+ | msg obracket rangeset ']'
{
- $$ = msgset_expand ($1, $3);
- msgset_free ($1);
- msgset_free ($3);
+ $$ = msgset_concat ($1, $3);
}
| range
;
@@ -177,7 +210,7 @@ msg : header REGEXP /* /.../ */
message_selector_t sel = find_type_selector ($1);
if (!sel)
{
- yyerror (_("unknown message type"));
+ yyerror (parser, lexer, _("unknown message type"));
YYERROR;
}
$$ = msgset_select (sel, NULL, 0, 0);
@@ -224,36 +257,35 @@ range : number
{
if (msgset_length ($3) == 1)
{
- $$ = msgset_range ($1, msgset_msgno ($3));
+ if (($$ = msgset_range ($1, msgset_msgno ($3))) == NULL)
+ yyerror (parser, lexer, _("range error"));
}
else
{
$$ = msgset_range ($1, msgset_msgno ($3) - 1);
if (!$$)
- YYERROR;
+ {
+ yyerror (parser, lexer, _("range error"));
+ YYERROR;
+ }
msgset_append ($$, $3);
}
}
| NUMBER '-' '*'
{
- $$ = msgset_range ($1, total);
+ if (($$ = msgset_range ($1, total)) == NULL)
+ yyerror (parser, lexer, _("range error"));
}
;
number : partno
+ | partno dot rangeset
{
+ $$ = msgset_concat ($1, $3);
}
- | partno '.' rangeset
- {
- $$ = msgset_expand ($1, $3);
- msgset_free ($1);
- msgset_free ($3);
- }
- | partno '[' rangeset ']'
+ | partno obracket rangeset ']'
{
- $$ = msgset_expand ($1, $3);
- msgset_free ($1);
- msgset_free ($3);
+ $$ = msgset_concat ($1, $3);
}
;
@@ -266,149 +298,172 @@ partno : NUMBER
$$ = $2;
}
;
-%%
-static int xargc;
-static char **xargv;
-static int cur_ind;
-static char *cur_p;
+dot : '.'
+ {
+ if (!(parser->flags & MSG_ALLOWPART))
+ {
+ yyerror (parser, lexer, _("message parts not allowed"));
+ YYERROR;
+ }
+ }
+
+obracket : '['
+ {
+ if (!(parser->flags & MSG_ALLOWPART))
+ {
+ yyerror (parser, lexer, _("message parts not allowed"));
+ YYERROR;
+ }
+ }
+%%
int
-yyerror (const char *s)
+yyerror (struct msgset_parser *parser, struct msgset_lexer *lexer,
+ const char *s)
{
- mu_stream_printf (mu_strerr, "%s: ", xargv[0]);
+ mu_stream_printf (mu_strerr, "%s: ", lexer->xargv[0]);
mu_stream_printf (mu_strerr, "%s", s);
- if (!cur_p)
+ if (!lexer->cur_p)
mu_stream_printf (mu_strerr, _(" near end"));
- else if (*cur_p == 0)
+ else if (*lexer->cur_p == 0)
{
- int i = (*cur_p == 0) ? cur_ind + 1 : cur_ind;
- if (i == xargc)
+ int i = (*lexer->cur_p == 0) ? lexer->cur_ind + 1 : lexer->cur_ind;
+ if (i == lexer->xargc)
mu_stream_printf (mu_strerr, _(" near end"));
else
- mu_stream_printf (mu_strerr, _(" near %s"), xargv[i]);
+ mu_stream_printf (mu_strerr, _(" near %s"), lexer->xargv[i]);
}
else
- mu_stream_printf (mu_strerr, _(" near %s"), cur_p);
+ mu_stream_printf (mu_strerr, _(" near %s"), lexer->cur_p);
mu_stream_printf (mu_strerr, "\n");
return 0;
}
int
-yylex (void)
+yylex (struct msgset_lexer *lexer)
{
- if (cur_ind == xargc)
+ if (lexer->cur_ind == lexer->xargc)
return 0;
- if (!cur_p)
- cur_p = xargv[cur_ind];
- if (*cur_p == 0)
+ if (!lexer->cur_p)
+ lexer->cur_p = lexer->xargv[lexer->cur_ind];
+
+ if (*lexer->cur_p == 0)
{
- cur_ind++;
- cur_p = NULL;
- return yylex ();
+ lexer->cur_ind++;
+ lexer->cur_p = NULL;
+ return yylex (lexer);
}
- if (mu_isdigit (*cur_p))
+ if (mu_isdigit (*lexer->cur_p))
{
- yylval.number = strtoul (cur_p, &cur_p, 10);
+ yylval.number = strtoul (lexer->cur_p, &lexer->cur_p, 10);
return NUMBER;
}
- if (mu_isalpha (*cur_p))
+ if (mu_isalpha (*lexer->cur_p))
{
- char *p = cur_p;
-
- while (*cur_p && *cur_p != ',' && *cur_p != ':')
- cur_p++;
- mu_opool_append (tokpool, p, cur_p - p);
- mu_opool_append_char (tokpool, 0);
- yylval.string = mu_opool_finish (tokpool, NULL);
- if (*cur_p == ':')
+ char *p = lexer->cur_p;
+
+ while (*lexer->cur_p && *lexer->cur_p != ',' && *lexer->cur_p != ':')
+ lexer->cur_p++;
+ mu_opool_append (lexer->tokpool, p, lexer->cur_p - p);
+ mu_opool_append_char (lexer->tokpool, 0);
+ yylval.string = mu_opool_finish (lexer->tokpool, NULL);
+ if (*lexer->cur_p == ':')
{
- ++cur_p;
+ ++lexer->cur_p;
return HEADER;
}
return IDENT;
}
- if (*cur_p == '/')
+ if (*lexer->cur_p == '/')
{
- char *p = ++cur_p;
+ char *p = ++lexer->cur_p;
- while (*cur_p && *cur_p != '/')
- cur_p++;
+ while (*lexer->cur_p && *lexer->cur_p != '/')
+ lexer->cur_p++;
- mu_opool_append (tokpool, p, cur_p - p);
- mu_opool_append_char (tokpool, 0);
- yylval.string = mu_opool_finish (tokpool, NULL);
+ mu_opool_append (lexer->tokpool, p, lexer->cur_p - p);
+ mu_opool_append_char (lexer->tokpool, 0);
+ yylval.string = mu_opool_finish (lexer->tokpool, NULL);
- if (*cur_p)
- cur_p++;
+ if (*lexer->cur_p)
+ lexer->cur_p++;
return REGEXP;
}
- if (*cur_p == ':')
+ if (*lexer->cur_p == ':')
{
- cur_p++;
- if (*cur_p == '/')
+ lexer->cur_p++;
+ if (*lexer->cur_p == '/')
{
- char *p = ++cur_p;
+ char *p = ++lexer->cur_p;
- while (*cur_p && *cur_p != '/')
- cur_p++;
+ while (*lexer->cur_p && *lexer->cur_p != '/')
+ lexer->cur_p++;
- mu_opool_append (tokpool, p, cur_p - p);
- mu_opool_append_char (tokpool, 0);
- yylval.string = mu_opool_finish (tokpool, NULL);
+ mu_opool_append (lexer->tokpool, p, lexer->cur_p - p);
+ mu_opool_append_char (lexer->tokpool, 0);
+ yylval.string = mu_opool_finish (lexer->tokpool, NULL);
- if (*cur_p)
- cur_p++;
+ if (*lexer->cur_p)
+ lexer->cur_p++;
return BODY;
}
- if (*cur_p == 0)
+ if (*lexer->cur_p == 0)
return 0;
- yylval.type = *cur_p++;
+ yylval.type = *lexer->cur_p++;
return TYPE;
}
- return *cur_p++;
+ return *lexer->cur_p++;
}
int
msgset_parse (const int argc, char **argv, int flags, msgset_t **mset)
{
int rc;
- xargc = argc;
- xargv = argv;
- msgset_flags = flags;
- cur_ind = 1;
- cur_p = NULL;
- result = NULL;
-
- mu_opool_create (&tokpool, MU_OPOOL_ENOMEMABRT);
- mu_mailbox_messages_count (mbox, &message_count);
- rc = yyparse ();
+ struct msgset_parser parser;
+ struct msgset_lexer lexer;
+
+ lexer.xargc = argc;
+ lexer.xargv = argv;
+ lexer.cur_ind = 1;
+ lexer.cur_p = NULL;
+ mu_opool_create (&lexer.tokpool, MU_OPOOL_ENOMEMABRT);
+
+ parser.flags = flags;
+ mu_mailbox_messages_count (mbox, &parser.message_count);
+ parser.result = NULL;
+
+ rc = yyparse (&parser, &lexer);
if (rc == 0)
{
- if (!result)
+ if (!parser.result)
{
util_noapp ();
rc = 1;
}
else
{
- if (result->crd[1] > message_count)
+ if (parser.result->crd[1] > parser.message_count)
+ {
+ util_error_range (parser.result->crd[1]);
+ rc = 1;
+ }
+ else
{
- util_error_range (result->crd[1]);
- msgset_free (result);
- return 1;
+ *mset = parser.result;
+ parser.result = NULL;
}
- *mset = result;
}
}
- mu_opool_destroy (&tokpool);
+ msgset_parser_free (&parser);
+ msgset_lexer_free (&lexer);
return rc;
}
@@ -543,10 +598,7 @@ msgset_range (int low, int high)
return msgset_make_1 (low);
if (low >= high)
- {
- yyerror (_("range error"));
- return NULL;
- }
+ return NULL;
for (i = 0; low <= high; i++, low++)
{
@@ -885,20 +937,20 @@ msgtype_generator (const char *text, int state)
#endif
int
-select_deleted (mu_message_t msg, void *closure MU_ARG_UNUSED)
+select_deleted (mu_message_t msg, void *closure)
{
mu_attribute_t attr= NULL;
int rc;
-
+ struct msgset_lexer *lexer = closure;
+
mu_message_get_attribute (msg, &attr);
rc = mu_attribute_is_deleted (attr);
- return strcmp (xargv[0], "undelete") == 0 ? rc : !rc;
+ return strcmp (lexer->xargv[0], "undelete") == 0 ? rc : !rc;
}
int
-check_set (msgset_t **pset)
+check_set (msgset_t **pset, int flags)
{
- int flags = msgset_flags;
int rc = 0;
if (!*pset)
diff --git a/mail/print.c b/mail/print.c
index 5372732..bbb86f7 100644
--- a/mail/print.c
+++ b/mail/print.c
@@ -119,7 +119,8 @@ int
mail_print (int argc, char **argv)
{
int lower = mu_islower (argv[0][0]);
- int rc = util_foreach_msg (argc, argv, MSG_NODELETED|MSG_SILENT,
+ int rc = util_foreach_msg (argc, argv,
+ MSG_NODELETED|MSG_SILENT,
mail_print_msg, &lower);
return rc;
}
diff --git a/mail/struct.c b/mail/struct.c
index a308dd8..1f79c35 100644
--- a/mail/struct.c
+++ b/mail/struct.c
@@ -61,6 +61,7 @@ show_struct (msgset_t *msgset, mu_message_t msg, void *data)
int
mail_struct (int argc, char **argv)
{
- return util_foreach_msg (argc, argv, MSG_NODELETED|MSG_SILENT,
+ return util_foreach_msg (argc, argv,
+ MSG_NODELETED|MSG_SILENT,
show_struct, NULL);
}
diff --git a/mail/write.c b/mail/write.c
index 46b96ba..24ce2b4 100644
--- a/mail/write.c
+++ b/mail/write.c
@@ -34,7 +34,8 @@ mail_write (int argc, char **argv)
if (mu_isupper (argv[0][0]))
{
- if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT, &msglist))
+ if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT|MSG_ALLOWPART,
+ &msglist))
return 1;
filename = namebuf = util_get_sender (msgset_msgno (msglist), 1);
}
@@ -55,7 +56,8 @@ mail_write (int argc, char **argv)
mu_asprintf (&namebuf, "%lu", (unsigned long) n);
filename = namebuf;
}
- if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT, &msglist))
+ if (msgset_parse (argc, argv, MSG_NODELETED|MSG_SILENT|MSG_ALLOWPART,
+ &msglist))
return 1;
}