diff options
| author | Sergey Poznyakoff <gray@gnu.org> | 2022-04-06 20:08:07 +0300 |
|---|---|---|
| committer | Sergey Poznyakoff <gray@gnu.org> | 2022-04-06 20:08:07 +0300 |
| commit | d19451e2c4a28b65e9ec8f3bb227d2c2ba8f0f74 (patch) | |
| tree | c14ff88fe426b6badfecbc54a6c23d50ba5fd6d6 | |
| parent | 6f0dfc97a0484029d8719cd6fd629fa7f4af814c (diff) | |
| download | mailutils-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.c | 3 | ||||
| -rw-r--r-- | mail/mail.h | 1 | ||||
| -rw-r--r-- | mail/msgset.y | 292 | ||||
| -rw-r--r-- | mail/print.c | 3 | ||||
| -rw-r--r-- | mail/struct.c | 3 | ||||
| -rw-r--r-- | mail/write.c | 6 |
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; } |
