summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2009-05-11 18:48:14 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2009-05-11 18:48:14 (GMT)
commitf8323650568b0031f0ec4c50cde417cb10a48c56 (patch) (unidiff)
treeb0007c30366860dc079a7bf8828d254b7486630f
parentffd2cf189d926abe00de0a79f292f1ea69d02aac (diff)
downloadmailfromd-f8323650568b0031f0ec4c50cde417cb10a48c56.tar.gz
mailfromd-f8323650568b0031f0ec4c50cde417cb10a48c56.tar.bz2
Implement functional notation for reply actions
* NEWS, doc/mailfromd.texi: Update. * mfd/drivers.c (print_type_result, mark_type_result) (optimize_type_result, code_type_result): Rewrite. * mfd/gram.y: Rewrite action rules. * mfd/lex.l (CODE,XCODE): Remove. * mfd/opcodes (RESULT): Takes one immediate parameter. (instr_result): Get arguments from stack.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--NEWS19
-rw-r--r--doc/mailfromd.texi86
-rw-r--r--mfd/drivers.c115
-rw-r--r--mfd/gram.y131
-rw-r--r--mfd/lex.l4
-rw-r--r--mfd/mailfromd.h8
-rw-r--r--mfd/opcodes2
-rw-r--r--mfd/prog.c10
8 files changed, 276 insertions, 99 deletions
diff --git a/NEWS b/NEWS
index b50d87a..90b7a88 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
1Mailfromd NEWS -- history of user-visible changes. 2009-05-10 1Mailfromd NEWS -- history of user-visible changes. 2009-05-11
2Copyright (C) 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff 2Copyright (C) 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff
3See the end of file for copying conditions. 3See the end of file for copying conditions.
4 4
@@ -24,6 +24,23 @@ is not strictly necessary. However, keep in mind that due to the
24specifics of MeTA1, the number of symbols that may be exported for 24specifics of MeTA1, the number of symbols that may be exported for
25each stage is limited (Mailfromd manual, section 11.1.2). 25each stage is limited (Mailfromd manual, section 11.1.2).
26 26
27* Reject and tempfail actions: Functional notation
28
29The reply actions `reject' and `tempfail' allow functional notation,
30i.e. their arguments can be supplied as to a function:
31
32 reject(550, 5.7.7, "IP address does not resolve")
33
34An important feature of this notation is that all three arguments are
35MFL expressions, which means that you can now compute the reply codes
36at run time:
37
38 reject(550 + %n, "5.7." %x, "Transaction rejected")
39
40An argument can be omitted, in which case the default value is used, e.g.:
41
42 reject(550 + %n, , "Transaction rejected")
43
27* New functions 44* New functions
28 45
29A set of new functions is added that allow to access the headers 46A set of new functions is added that allow to access the headers
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index 3d2e43c..090222e 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -1355,16 +1355,21 @@ execution of the program to stop and to return a response code to
1355the @command{Sendmail}. There are five actions, one for each response 1355the @command{Sendmail}. There are five actions, one for each response
1356code: @code{continue}, @code{accept}, @code{reject}, @code{discard}, 1356code: @code{continue}, @code{accept}, @code{reject}, @code{discard},
1357and @code{tempfail}. Among these, @code{reject} and @code{discard} 1357and @code{tempfail}. Among these, @code{reject} and @code{discard}
1358can optionally take one to three arguments. The first 1358can optionally take one to three arguments. There are two ways of
1359argument is a three-digit @acronym{RFC} 2821 reply code. It must begin with 1359supplying the arguments.
1360@samp{5} for @code{reject} and with @samp{4} for @code{tempfail}. If 1360
1361two arguments are supplied, the second argument must be either an 1361In the first form, called @dfn{literal} or @dfn{traditional} notation,
1362@dfn{extended reply code} (@acronym{RFC} 1893/2034) or a textual string to be 1362the arguments are supplied as additional words after the action name,
1363separated by whitespace. The first argument is a three-digit
1364@acronym{RFC} 2821 reply code. It must begin with @samp{5} for
1365@code{reject} and with @samp{4} for @code{tempfail}. If two arguments
1366are supplied, the second argument must be either an @dfn{extended
1367reply code} (@acronym{RFC} 1893/2034) or a textual string to be
1363returned along with the @acronym{SMTP} reply. Finally, if all three 1368returned along with the @acronym{SMTP} reply. Finally, if all three
1364arguments are supplied, then the second one must be an extended reply 1369arguments are supplied, then the second one must be an extended reply
1365code and the third one must supply the textual string. The following 1370code and the third one must supply the textual string. The following
1366examples illustrate all possible ways of using the @code{reject} 1371examples illustrate all possible ways of using the @code{reject}
1367statement: 1372statement in literal notation:
1368 1373
1369@smallexample 1374@smallexample
1370@group 1375@group
@@ -1379,6 +1384,25 @@ reject 503 5.0.0 "Need HELO command"
1379@noindent 1384@noindent
1380Please note the quotes around the textual string. 1385Please note the quotes around the textual string.
1381 1386
1387Another form for these action is called @dfn{functional} notation,
1388because it resembles the function syntax. When used in this form, the
1389action word is followed by a parenthesized group of exactly three
1390arguments, separated by commas. The meaning and ordering of the
1391argument is the same as in literal form. Any of three arguments may
1392be absent, in which case it will be replaced by the default value. To
1393illustrate this, here are the statements from the previous example,
1394written in functional notation:
1395
1396@smallexample
1397@group
1398reject(,,)
1399reject(503,,)
1400reject(503, 5.0.0)
1401reject(503,, "Need HELO command")
1402reject(503, 5.0.0, "Need HELO command")
1403@end group
1404@end smallexample
1405
1382@node Conditional Execution 1406@node Conditional Execution
1383@section Conditional Execution 1407@section Conditional Execution
1384 1408
@@ -10253,7 +10277,8 @@ program.
10253perform a certain action over the message being processed. There are 10277perform a certain action over the message being processed. There are
10254two kinds of actions: return actions and header manipulation actions. 10278two kinds of actions: return actions and header manipulation actions.
10255 10279
10256 Return actions tell @command{Sendmail} to return given response code 10280@subsubheading Reply Actions
10281Reply actions tell @command{Sendmail} to return given response code
10257to the remote party. There are five such actions: 10282to the remote party. There are five such actions:
10258 10283
10259@table @code 10284@table @code
@@ -10263,14 +10288,16 @@ to the remote party. There are five such actions:
10263 Return an @code{accept} reply. The remote party will continue 10288 Return an @code{accept} reply. The remote party will continue
10264transmitting its message. 10289transmitting its message.
10265 10290
10266@item reject [@var{code}] [@var{excode}] [@var{message}] 10291@item reject @var{code} @var{excode} @var{message-expr}
10292@itemx reject (@var{code-expr}, @var{excode-expr}, @var{message-expr})
10267@cindex reject action, defined 10293@cindex reject action, defined
10268@kwindex reject 10294@kwindex reject
10269 Return a @code{reject} reply. The remote party will have to 10295 Return a @code{reject} reply. The remote party will have to
10270cancel transmitting its message. The three arguments are optional, 10296cancel transmitting its message. The three arguments are optional,
10271their usage is described below. 10297their usage is described below.
10272 10298
10273@item tempfail [@var{code}] [@var{excode}] [@var{message}] 10299@item tempfail @var{code} @var{excode} @var{message}
10300@itemx tempfail (@var{code-expr}, @var{excode-expr}, @var{message-expr})
10274@cindex tempfail action, defined 10301@cindex tempfail action, defined
10275@kwindex tempfail 10302@kwindex tempfail
10276 Return a @samp{temporary failure} reply. The remote party can retry 10303 Return a @samp{temporary failure} reply. The remote party can retry
@@ -10292,7 +10319,12 @@ continue processing of the message.
10292 10319
10293@anchor{reject} 10320@anchor{reject}
10294 Two actions, @code{reject} and @code{tempfail} can take up to three 10321 Two actions, @code{reject} and @code{tempfail} can take up to three
10295optional parameters. The first argument is a three-digit 10322optional parameters. There are two forms of supplying these
10323parameters.
10324
10325In the first form, called @dfn{literal} or @dfn{traditional} notation,
10326the arguments are supplied as additional words after the action name,
10327and are separated by whitespace. The first argument is a three-digit
10296@acronym{RFC} 2821 reply code. It must begin with @samp{5} for 10328@acronym{RFC} 2821 reply code. It must begin with @samp{5} for
10297@code{reject} and with @samp{4} for @code{tempfail}. If two arguments 10329@code{reject} and with @samp{4} for @code{tempfail}. If two arguments
10298are supplied, the second argument must be either an @dfn{extended 10330are supplied, the second argument must be either an @dfn{extended
@@ -10313,6 +10345,40 @@ reject 503 5.0.0 "Need HELO command"
10313@end group 10345@end group
10314@end smallexample 10346@end smallexample
10315 10347
10348The notion @dfn{textual string}, used above means either a literal
10349string or an @acronym{MFL} expression that evaluates to string.
10350However, both code and extended code must always be literal.
10351
10352The second form of supplying arguments is called @dfn{functional}
10353notation, because it resembles the function syntax. When used in this
10354form, the action word is followed by a parenthesized group of exactly
10355three arguments, separated by commas. Each argument is a
10356@acronym{MFL} expression. The meaning and ordering of the arguments is
10357the same as in literal form. Any or all of these three arguments may
10358be absent, in which case it will be replaced by the default value. To
10359illustrate this, here are the statements from the previous example,
10360written in functional notation:
10361
10362@smallexample
10363@group
10364reject(,,)
10365reject(503,,)
10366reject(503, 5.0.0)
10367reject(503, "Need HELO command",)
10368reject(503, 5.0.0, "Need HELO command")
10369@end group
10370@end smallexample
10371
10372 Notice that there is an important difference between the two
10373notations. The functional notation allows to compute both reply codes
10374at run time, e.g.:
10375
10376@smallexample
10377 reject(500 + %dig2*10 + %dig3, "5." %edig2 "." %edig2)
10378@end smallexample
10379
10380@subsubheading Header Actions
10381
10316@anchor{header manipulation} 10382@anchor{header manipulation}
10317@cindex header manipulation actions 10383@cindex header manipulation actions
10318@cindex actions, header manipulation 10384@cindex actions, header manipulation
diff --git a/mfd/drivers.c b/mfd/drivers.c
index d8dfb4b..ed8a288 100644
--- a/mfd/drivers.c
+++ b/mfd/drivers.c
@@ -889,62 +889,107 @@ code_type_un(NODE *node, struct locus **old_locus)
889void 889void
890print_type_result(NODE *node, int level) 890print_type_result(NODE *node, int level)
891{ 891{
892 if (node->v.ret.code) { 892 NODE *code, *xcode;
893 const char *s = NULL; 893
894 int expr = 0; 894 code = node->v.ret.code;
895 895 xcode = node->v.ret.xcode;
896 print_level(level); 896
897 if (node->v.ret.message) {
898 if (node->v.ret.message->type == node_type_string)
899 s = node->v.ret.message->v.literal->text;
900 else {
901 expr = 1;
902 s = "(expression)";
903 }
904 }
905 dbg_setreply(NULL,
906 (char*) LITERAL_TEXT(node->v.ret.code),
907 (char*) LITERAL_TEXT(node->v.ret.xcode),
908 (char*) s);
909 if (expr)
910 print_node(node->v.ret.message, level+1);
911 }
912 print_level(level); 897 print_level(level);
898 printf("SET REPLY ");
913 print_stat(node->v.ret.stat); 899 print_stat(node->v.ret.stat);
914 printf("\n"); 900 printf("\n");
901 print_level(level);
902 printf("CODE:\n");
903 if (code)
904 print_node(code, level+1);
905 print_level(level);
906 printf("XCODE:\n");
907 if (xcode)
908 print_node(xcode, level+1);
909 print_level(level);
910 printf("MESSAGE:\n");
911 if (node->v.ret.message)
912 print_node(node->v.ret.message, level+1);
913 printf("\n");
915} 914}
916 915
917void 916void
918mark_type_result(NODE *node) 917mark_type_result(NODE *node)
919{ 918{
920 if (node->v.ret.code) 919 mark(node->v.ret.code);
921 node->v.ret.code->flags |= VAR_REFERENCED; 920 mark(node->v.ret.xcode);
922 if (node->v.ret.xcode)
923 node->v.ret.xcode->flags |= VAR_REFERENCED;
924 mark(node->v.ret.message); 921 mark(node->v.ret.message);
925} 922}
926 923
927void 924void
928optimize_type_result(NODE *node) 925optimize_type_result(NODE *node)
929{ 926{
927 optimize(node->v.ret.code);
928 optimize(node->v.ret.xcode);
930 optimize(node->v.ret.message); 929 optimize(node->v.ret.message);
931} 930}
932 931
933void 932static void
934code_type_result(NODE *node, struct locus **old_locus) 933code_result_arg(NODE *node)
935{ 934{
936 MARK_LOCUS(); 935 if (node)
937 if (node->v.ret.message) 936 code_node(node);
938 code_node(node->v.ret.message);
939 else { 937 else {
940 code_op(opcode_push); 938 code_op(opcode_push);
941 code_immediate(NULL); 939 code_immediate(NULL);
942 } 940 }
941}
942
943static NODE *
944result_argptr(NODE *arg)
945{
946 if (arg && arg->type == node_type_string
947 && arg->v.literal->text[0] == 0)
948 arg = NULL;
949 return arg;
950}
951
952void
953code_type_result(NODE *node, struct locus **old_locus)
954{
955 NODE *code, *xcode;
956
957 code = result_argptr(node->v.ret.code);
958 xcode = result_argptr(node->v.ret.xcode);
959
960 switch (node->v.ret.stat) {
961 case SMFIS_REJECT:
962 if (code && code->type == node_type_string
963 && code->v.literal->text[0] != '5')
964 parse_error_locus(&node->locus,
965 _("Reject code should be 5xx"));
966 if (xcode && xcode->type == node_type_string
967 && xcode->v.literal->text[0] != '5')
968 parse_error_locus(&node->locus,
969 _("Reject extended code should be 5.x.x"));
970 break;
971
972 case SMFIS_TEMPFAIL:
973 if (code && code->type == node_type_string
974 && code->v.literal->text[0] != '4')
975 parse_error_locus(&node->locus,
976 _("Tempfail code should be 4xx"));
977 if (xcode && xcode->type == node_type_string
978 && xcode->v.literal->text[0] != '4')
979 parse_error_locus(&node->locus,
980 _("Tempfail extended code should be 4.x.x"));
981 break;
982 default:
983 break;
984 }
985
986 code_result_arg(node->v.ret.message);
987 code_result_arg(xcode);
988 code_result_arg(code);
989
943 MARK_LOCUS(); 990 MARK_LOCUS();
944 code_op(opcode_result); 991 code_op(opcode_result);
945 code_immediate((void*)node->v.ret.stat); 992 code_immediate((void*)node->v.ret.stat);
946 code_immediate((void*)LITERAL_OFF(node->v.ret.code));
947 code_immediate((void*)LITERAL_OFF(node->v.ret.xcode));
948 code_op(opcode_nil); 993 code_op(opcode_nil);
949} 994}
950 995
@@ -1482,13 +1527,11 @@ code_type_catch(NODE *node, struct locus **old_locus)
1482 code_op(opcode_jmp); 1527 code_op(opcode_jmp);
1483 jump_pc = code_immediate((void*)jump_pc); 1528 jump_pc = code_immediate((void*)jump_pc);
1484 } else { 1529 } else {
1485 code_op(opcode_push); 1530 code_result_arg(NULL);
1486 code_immediate(NULL); 1531 code_result_arg(NULL);
1532 code_result_arg(NULL);
1487 code_op(opcode_result); 1533 code_op(opcode_result);
1488 code_immediate(SMFIS_CONTINUE); 1534 code_immediate(SMFIS_CONTINUE);
1489 code_immediate(NULL);
1490 code_immediate(NULL);
1491 code_immediate(NULL);
1492 } 1535 }
1493 1536
1494 endpos = code_get_counter (); 1537 endpos = code_get_counter ();
diff --git a/mfd/gram.y b/mfd/gram.y
index 332a748..15ee960 100644
--- a/mfd/gram.y
+++ b/mfd/gram.y
@@ -299,7 +299,7 @@ _create_alias(void *item, void *data)
299%} 299%}
300 300
301%error-verbose 301%error-verbose
302%expect 29 302%expect 28
303 303
304%union { 304%union {
305 struct literal *literal; 305 struct literal *literal;
@@ -360,7 +360,7 @@ _create_alias(void *item, void *data)
360%token <locus> WHEN PASS SET CATCH THROW KW_ECHO RETURNS RETURN FUNC 360%token <locus> WHEN PASS SET CATCH THROW KW_ECHO RETURNS RETURN FUNC
361%token <locus> SWITCH CASE DEFAULT CONST 361%token <locus> SWITCH CASE DEFAULT CONST
362%token <locus> FOR LOOP WHILE BREAK NEXT ARGCOUNT ALIAS DOTS ARGX VAPTR 362%token <locus> FOR LOOP WHILE BREAK NEXT ARGCOUNT ALIAS DOTS ARGX VAPTR
363%token <literal> STRING CODE XCODE 363%token <literal> STRING
364%token <literal> SYMBOL IDENTIFIER 364%token <literal> SYMBOL IDENTIFIER
365%token <number> ARG NUMBER BACKREF 365%token <number> ARG NUMBER BACKREF
366%token <builtin> BUILTIN BUILTIN_PROC BUILTIN_P 366%token <builtin> BUILTIN BUILTIN_PROC BUILTIN_P
@@ -386,7 +386,8 @@ _create_alias(void *item, void *data)
386 386
387%type <node> decl stmt condition action sendmail_action header_action 387%type <node> decl stmt condition action sendmail_action header_action
388 if_cond else_cond on_cond atom argref paren_argref 388 if_cond else_cond on_cond atom argref paren_argref
389 funcall proccall expr common_expr simp_expr atom_expr 389 funcall proccall expr maybe_expr maybe_xcode_expr
390 common_expr simp_expr atom_expr
390 asgn catch throw return case_cond autodcl constdecl 391 asgn catch throw return case_cond autodcl constdecl
391 loopstmt opt_while jumpstmt 392 loopstmt opt_while jumpstmt
392%type <stmtlist> stmtlist decllist 393%type <stmtlist> stmtlist decllist
@@ -394,10 +395,9 @@ _create_alias(void *item, void *data)
394%type <poll> pollstmt pollarglist 395%type <poll> pollstmt pollarglist
395%type <pollarg> pollarg loop_parm 396%type <pollarg> pollarg loop_parm
396%type <loop> opt_loop_parms loop_parm_list 397%type <loop> opt_loop_parms loop_parm_list
397%type <number> number
398%type <arglist> arglist 398%type <arglist> arglist
399%type <var> variable 399%type <var> variable
400%type <literal> string opt_ident loop_ident alias 400%type <literal> string opt_ident loop_ident alias code xcode
401%type <state> state_ident 401%type <state> state_ident
402%type <matchtype> matches fnmatches 402%type <matchtype> matches fnmatches
403%type <type> retdecl 403%type <type> retdecl
@@ -892,24 +892,32 @@ sendmail_action:
892 } 892 }
893 | ACT_REJECT maybe_triplet 893 | ACT_REJECT maybe_triplet
894 { 894 {
895 if ($2.code && $2.code->text[0] != '5')
896 parse_error(_("Reject code should be 5xx"));
897 if ($2.xcode && $2.xcode->text[0] != '5')
898 parse_error(_("Reject extended code should be 5.x.x"));
899 $$ = alloc_node(node_type_result, &$1); 895 $$ = alloc_node(node_type_result, &$1);
900 $$->v.ret = $2; 896 $$->v.ret = $2;
901 $$->v.ret.stat = SMFIS_REJECT; 897 $$->v.ret.stat = SMFIS_REJECT;
902 } 898 }
899 | ACT_REJECT '(' maybe_expr ',' maybe_xcode_expr ',' maybe_expr ')'
900 {
901 $$ = alloc_node(node_type_result, &$1);
902 $$->v.ret.stat = SMFIS_REJECT;
903 $$->v.ret.code = $3 ? cast_to(dtype_string, $3) : NULL;
904 $$->v.ret.xcode = $5 ? cast_to(dtype_string, $5) : NULL;
905 $$->v.ret.message = $7 ? cast_to(dtype_string, $7) : NULL;
906 }
903 | ACT_TEMPFAIL maybe_triplet 907 | ACT_TEMPFAIL maybe_triplet
904 { 908 {
905 if ($2.code && $2.code->text[0] != '4')
906 parse_error(_("Tempfail code should be 4xx"));
907 if ($2.xcode && $2.xcode->text[0] != '4')
908 parse_error(_("Tempfail extended code should be 4.x.x"));
909 $$ = alloc_node(node_type_result, &$1); 909 $$ = alloc_node(node_type_result, &$1);
910 $$->v.ret = $2; 910 $$->v.ret = $2;
911 $$->v.ret.stat = SMFIS_TEMPFAIL; 911 $$->v.ret.stat = SMFIS_TEMPFAIL;
912 } 912 }
913 | ACT_TEMPFAIL '(' maybe_expr ',' maybe_xcode_expr ',' maybe_expr ')'
914 {
915 $$ = alloc_node(node_type_result, &$1);
916 $$->v.ret.stat = SMFIS_TEMPFAIL;
917 $$->v.ret.code = $3 ? cast_to(dtype_string, $3) : NULL;
918 $$->v.ret.xcode = $5 ? cast_to(dtype_string, $5) : NULL;
919 $$->v.ret.message = $7 ? cast_to(dtype_string, $7) : NULL;
920 }
913 | ACT_CONTINUE 921 | ACT_CONTINUE
914 { 922 {
915 $$ = alloc_node(node_type_result, &$1); 923 $$ = alloc_node(node_type_result, &$1);
@@ -924,6 +932,15 @@ sendmail_action:
924 } 932 }
925 ; 933 ;
926 934
935maybe_xcode_expr: maybe_expr
936 | xcode
937 {
938 $$ = alloc_node(node_type_string, get_locus());
939 $$->v.literal = $1;
940 }
941 ;
942
943
927header_action: 944header_action:
928 ADD string expr 945 ADD string expr
929 { 946 {
@@ -955,32 +972,74 @@ maybe_triplet: /* empty */
955 | triplet 972 | triplet
956 ; 973 ;
957 974
958triplet : CODE 975triplet : code
959 { 976 {
960 $$.code = $1; 977 $$.code = alloc_node(node_type_string, get_locus());
978 $$.code->v.literal = $1;
961 $$.xcode = NULL; 979 $$.xcode = NULL;
962 $$.message = NULL; 980 $$.message = NULL;
963 } 981 }
964 | CODE XCODE 982 | code xcode
965 { 983 {
966 $$.code = $1; 984 $$.code = alloc_node(node_type_string, get_locus());
967 $$.xcode = $2; 985 $$.code->v.literal = $1;
986 $$.xcode = alloc_node(node_type_string, get_locus());
987 $$.xcode->v.literal = $2;
968 $$.message = NULL; 988 $$.message = NULL;
969 } 989 }
970 | CODE XCODE expr 990 | code xcode expr
971 { 991 {
972 $$.code = $1; 992 $$.code = alloc_node(node_type_string, get_locus());
973 $$.xcode = $2; 993 $$.code->v.literal = $1;
994 $$.xcode = alloc_node(node_type_string, get_locus());
995 $$.xcode->v.literal = $2;
974 $$.message = cast_to(dtype_string, $3); 996 $$.message = cast_to(dtype_string, $3);
975 } 997 }
976 | CODE expr 998 | code expr
977 { 999 {
978 $$.code = $1; 1000 $$.code = alloc_node(node_type_string, get_locus());
1001 $$.code->v.literal = $1;
979 $$.xcode = NULL; 1002 $$.xcode = NULL;
980 $$.message = cast_to(dtype_string, $2); 1003 $$.message = cast_to(dtype_string, $2);
981 } 1004 }
982 ; 1005 ;
983 1006
1007code : NUMBER
1008 {
1009 char buf[4];
1010
1011 if ($1 < 200 || $1 > 599) {
1012 yyerror(_("Invalid SMTP reply code"));
1013 buf[0] = 0;
1014 } else
1015 snprintf(buf, sizeof(buf), "%lu", $1);
1016 $$ = string_alloc(buf, strlen(buf));
1017 }
1018 ;
1019
1020xcode : NUMBER '.' NUMBER '.' NUMBER
1021 {
1022 char buf[sizeof("5.999.999")];
1023
1024 /* RFC 1893:
1025 The syntax of the new status codes is defined as:
1026
1027 status-code = class "." subject "." detail
1028 class = "2"/"4"/"5"
1029 subject = 1*3digit
1030 detail = 1*3digit
1031 */
1032 if (($1 != 2 && $1 != 4 && $1 !=5)
1033 || $3 > 999 || $5 > 999) {
1034 yyerror(_("Invalid extended reply code"));
1035 buf[0] = 0;
1036 } else
1037 snprintf(buf, sizeof(buf), "%lu.%lu.%lu",
1038 $1, $3, $5);
1039 $$ = string_alloc(buf, strlen(buf));
1040 }
1041 ;
1042
984condition : if_cond 1043condition : if_cond
985 | case_cond 1044 | case_cond
986 | on_cond 1045 | on_cond
@@ -1121,7 +1180,7 @@ value : STRING
1121 $$.v.literal = $1; 1180 $$.v.literal = $1;
1122 } 1181 }
1123 } 1182 }
1124 | number 1183 | NUMBER
1125 { 1184 {
1126 $$.type = dtype_number; 1185 $$.type = dtype_number;
1127 $$.v.number = $1; 1186 $$.v.number = $1;
@@ -1164,19 +1223,6 @@ fnmatches : FNMATCHES
1164 } 1223 }
1165 ; 1224 ;
1166 1225
1167number : NUMBER
1168 | CODE
1169 {
1170 char *p;
1171 $$ = strtol($1->text, &p, 10);
1172 if (*p) {
1173 /* should not happen */
1174 parse_error(_("Invalid number (near `%s')"), p);
1175 YYERROR;
1176 }
1177 }
1178 ;
1179
1180 1226
1181/* Loop statements */ 1227/* Loop statements */
1182 1228
@@ -1402,6 +1448,13 @@ expr : NOT expr
1402 | common_expr 1448 | common_expr
1403 ; 1449 ;
1404 1450
1451maybe_expr : /* empty */
1452 {
1453 $$ = NULL;
1454 }
1455 | expr
1456 ;
1457
1405common_expr: simp_expr 1458common_expr: simp_expr
1406 | common_expr simp_expr %prec CONCAT 1459 | common_expr simp_expr %prec CONCAT
1407 { 1460 {
@@ -1950,13 +2003,13 @@ on_cond : on pollstmt do branches DONE
1950 2003
1951on : ON 2004on : ON
1952 { 2005 {
1953 onblock(1); 2006 tie_in_onblock(1);
1954 } 2007 }
1955 ; 2008 ;
1956 2009
1957do : DO 2010do : DO
1958 { 2011 {
1959 onblock(0); 2012 tie_in_onblock(0);
1960 } 2013 }
1961 ; 2014 ;
1962 2015
diff --git a/mfd/lex.l b/mfd/lex.l
index 3ceabfc..c1f9c3e 100644
--- a/mfd/lex.l
+++ b/mfd/lex.l
@@ -318,8 +318,6 @@ vaptr return keyword(VAPTR);
318 yylval.number = strtoul(yytext+1, NULL, 0); 318 yylval.number = strtoul(yytext+1, NULL, 0);
319 return BACKREF; } 319 return BACKREF; }
320 /* Numeric strings */ 320 /* Numeric strings */
321 {N}\.{N}\.{N} {string(yytext, yyleng); return XCODE; }
322[0-9]{3} { string(yytext, yyleng); return CODE; }
3230[xX]{X}{X}* { yylval.number = strtoul(yytext, NULL, 16); return NUMBER; }; 3210[xX]{X}{X}* { yylval.number = strtoul(yytext, NULL, 16); return NUMBER; };
3240{O}{O}* { yylval.number = strtoul(yytext, NULL, 8); return NUMBER; }; 3220{O}{O}* { yylval.number = strtoul(yytext, NULL, 8); return NUMBER; };
3250|{P} { yylval.number = strtoul(yytext, NULL, 10); return NUMBER; }; 3230|{P} { yylval.number = strtoul(yytext, NULL, 10); return NUMBER; };
@@ -791,7 +789,7 @@ isemptystr(char *text)
791} 789}
792 790
793void 791void
794onblock(int enable) 792tie_in_onblock(int enable)
795{ 793{
796 if (enable) 794 if (enable)
797 BEGIN(ONBLOCK); 795 BEGIN(ONBLOCK);
diff --git a/mfd/mailfromd.h b/mfd/mailfromd.h
index ac93cba..bdf09dc 100644
--- a/mfd/mailfromd.h
+++ b/mfd/mailfromd.h
@@ -307,9 +307,9 @@ struct un_node { /* A unary operation node */
307/* Return action node: accept/reject/tempfail/continue */ 307/* Return action node: accept/reject/tempfail/continue */
308struct return_node { 308struct return_node {
309 sfsistat stat; /* Return status */ 309 sfsistat stat; /* Return status */
310 struct literal *code; /* Code */ 310 NODE *code; /* Code */
311 struct literal *xcode; /* Extended code */ 311 NODE *xcode; /* Extended code */
312 NODE *message; /* Subtree producing the textual message */ 312 NODE *message; /* Textual message */
313}; 313};
314 314
315enum msgmod_opcode { /* Message modification operation */ 315enum msgmod_opcode { /* Message modification operation */
@@ -697,7 +697,7 @@ int yyparse();
697int yylex(); 697int yylex();
698int yyerror(char *s); 698int yyerror(char *s);
699void add_include_dir(const char *dir); 699void add_include_dir(const char *dir);
700void onblock(int enable); 700void tie_in_onblock(int enable);
701int parse_program(char *name, int ydebug); 701int parse_program(char *name, int ydebug);
702void parse_pragma(const char *text); 702void parse_pragma(const char *text);
703const struct locus *get_locus(void); 703const struct locus *get_locus(void);
diff --git a/mfd/opcodes b/mfd/opcodes
index cee68d4..dd883ea 100644
--- a/mfd/opcodes
+++ b/mfd/opcodes
@@ -90,5 +90,5 @@ RETCATCH NULL 0
90FUNCALL dump_funcall 2 90FUNCALL dump_funcall 2
91 91
92NEXT NULL 0 92NEXT NULL 0
93RESULT dump_result 3 93RESULT dump_result 1
94HEADER dump_header 2 94HEADER dump_header 2
diff --git a/mfd/prog.c b/mfd/prog.c
index 90a426e..f8e58a9 100644
--- a/mfd/prog.c
+++ b/mfd/prog.c
@@ -1487,9 +1487,9 @@ instr_result(eval_environ_t env)
1487 char *code, *xcode; 1487 char *code, *xcode;
1488 char *message; 1488 char *message;
1489 1489
1490 get_string_arg(env, 0, &message); 1490 get_string_arg(env, 2, &message);
1491 get_literal(env, 1, (const char**)&code); 1491 get_string_arg(env, 1, &xcode);
1492 get_literal(env, 2, (const char**)&xcode); 1492 get_string_arg(env, 0, &code);
1493 1493
1494 if (PROG_TRACE_ENGINE) 1494 if (PROG_TRACE_ENGINE)
1495 prog_trace(env, "RESULT %d %s %s %s", 1495 prog_trace(env, "RESULT %d %s %s %s",
@@ -1513,8 +1513,8 @@ instr_result(eval_environ_t env)
1513 1513
1514 env->status = status; 1514 env->status = status;
1515 env->setreply(env->data, code, xcode, message); 1515 env->setreply(env->data, code, xcode, message);
1516 advance_pc(env, 3); 1516 advance_pc(env, 1);
1517 adjust_stack(env, 1); 1517 adjust_stack(env, 3);
1518} 1518}
1519 1519
1520void 1520void

Return to:

Send suggestions and report system problems to the System administrator.