From fa0978a70e893bbc73d4c4816699cf241eefd3c5 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sun, 31 May 2009 20:11:19 +0300 Subject: Implement `localdomain' function + several improvements. * NEWS: Update. * etc/mailfromd.rc: Use localdomain to determine the domain name. Remove the `#error' statement. Hopefully, this file can be used as is. * mfd/bi_gethostname.m4 (gethostname): Add an optional argument. * mfd/gram.y: Handle function declarations with only optional arguments, e.g.: func foo(; string bar) (mailfromd_test): Add missing env_init calls. * mfd/lex.l: Remove trailing newline before displaying the `#error' diagnostics. * mflib/localdomain.mf: New file. * mflib/Makefile.am (inc_DATA): Add localdomain.mf. * mflib/safedb.mf4 (safedb_verbose): New variable. (safedbmap, safedbdel): New function. (safedbget, safedbput): Verbosely print exceptions caught if safedb_verbose is set. --- NEWS | 33 +++++++++++++- doc/mailfromd.texi | 119 +++++++++++++++++++++++++++++++++----------------- etc/mailfromd.rc | 17 ++++++-- mfd/bi_gethostname.m4 | 17 +++++++- mfd/gram.y | 27 +++++++++--- mfd/lex.l | 5 ++- mflib/Makefile.am | 1 + mflib/localdomain.mf | 31 +++++++++++++ mflib/safedb.mf4 | 48 +++++++++++++++++++- 9 files changed, 244 insertions(+), 54 deletions(-) create mode 100644 mflib/localdomain.mf diff --git a/NEWS b/NEWS index 2309eb87..18c168e3 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -Mailfromd NEWS -- history of user-visible changes. 2009-05-23 +Mailfromd NEWS -- history of user-visible changes. 2009-05-31 Copyright (C) 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff See the end of file for copying conditions. @@ -37,6 +37,37 @@ m4_ifdef(`WITH_GEOIP',` add "X-Originator-Country" geoip_country_code_by_addr($client_addr) ') +* The gethostname function + +The gethostname function takes an optional argument: + + string gethostname ([bool FQN]) + +If FQN is specified and is `true', the function attempts to determine +a fully qualified host name. + +* The localdomain function + +New function is defined in the library module `localdomain': + + string localdomain() + +It returns the domain name of the box mailfromd is executed on. +It is more reliable than getdomainname, because it uses DNS to +determine the fully qualified domain name. + +* `Safedb' functions. + +Two new `safedb' interfaces are implemented: + + string safedbmap (string db, string key [, string defval, number null]) + void safedbdel (string db, string key [, number null]) + +A new global variable is added, which controls the verbosity of all +safedb functions. If the variable safedb_verbose is set to 1, these +functions log the detailed diagnostics about intercepted exceptions +before returning to the caller. + * Debugging New function mailutils_set_debug_level allows to set global Mailutils diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi index 4bbbea9b..62b41a06 100644 --- a/doc/mailfromd.texi +++ b/doc/mailfromd.texi @@ -5249,6 +5249,11 @@ Spam threshold, set by @code{sa} function (@pxref{sa}). Spam keywords for the message, set by @code{sa} function (@pxref{sa}). @end deftypevr +@deftypevr {Predefined Variable} number safedb_verbose +This variable controls the verbosity of the exception-safe database +functions. @xref{safedb_verbose}. +@end deftypevr + @node Back references @section Back references @@ -7556,24 +7561,6 @@ specified, or empty string otherwise. See above for the meaning of @var{null}. @end deftypefn -@deftypefn {Library Function} string safedbget (string @var{db}, @ - string @var{key} [, string @var{default}, number @var{null}]) - - This is an exception-safe interface to @code{dbget}. If some -database error occurs while attempting to retrieve the record, -@code{safedbget} returns empty string. - -@flindex safedb.mf - To use this function, request the @file{safedb.mf} module: - -@smallexample -#require safedb -@end smallexample - -@noindent -@xref{Modules}, for a description of @acronym{MFL} module system. -@end deftypefn - @deftypefn {Built-in Function} void dbput (string @var{db}, @ string @var{key}, string @var{value} [, @ number @var{null}, number @var{mode} ]) @@ -7586,25 +7573,6 @@ to explicitly specify the file mode for this database. See also @code{#pragma dbprop}, described above. @end deftypefn -@deftypefn {Library Function} void safedbput (string @var{db}, @ - string @var{key}, string @var{value} [, number @var{null}]) - This is an exception-safe interface to @code{dbput}. If a -database error occurs while attempting to retrieve the record, -the function returns without reporting an error. - -@flindex safedb.mf - To use this function, request the @file{safedb.mf} module: - -@smallexample -#require safedb -@end smallexample - -@noindent -@xref{Modules}, for a description of @acronym{MFL} module system. -@FIXME{safedbput should probably take an optional mode argument, as -dbput does.} -@end deftypefn - @deftypefn {Built-in Function} void dbdel (string @var{db}, @ string @var{key} [, number @var{null}, number @var{mode}]) Delete from the database the record with the given @var{key}. If @@ -7617,6 +7585,60 @@ terminating null character will be included in @var{key} length. this database. See also @code{#pragma dbprop}, described above. @end deftypefn +@flindex safedb.mf +The functions above have also the corresponding exception-safe +interfaces, which return cleanly if the @samp{e_dbfailure} exception +occurs. To use these interfaces, request the @file{safedb.mf} module: + +@smallexample +#require safedb +@end smallexample + +The exception-safe interfaces are: + +@deftypefn {Library Function} string safedbmap (string @var{db}, @ + string @var{key} [, string @var{default}, number @var{null}]) + + This is an exception-safe interface to @code{dbmap}. If a +database error occurs while attempting to retrieve the record, +@code{safedbmap} returns @var{default} or @samp{0}, if it is +not defined. +@end deftypefn + +@deftypefn {Library Function} string safedbget (string @var{db}, @ + string @var{key} [, string @var{default}, number @var{null}]) + + This is an exception-safe interface to @code{dbget}. If a +database error occurs while attempting to retrieve the record, +@code{safedbget} returns @var{default} or empty string, if it is +not defined. +@end deftypefn + +@deftypefn {Library Function} void safedbput (string @var{db}, @ + string @var{key}, string @var{value} [, number @var{null}]) + + This is an exception-safe interface to @code{dbput}. If a +database error occurs while attempting to retrieve the record, +the function returns without raising exception. +@end deftypefn + +@deftypefn {Library Function} void safedbdel (string @var{db}, @ + string @var{key} [, number @var{null}]) + + This is an exception-safe interface to @code{dbdel}. If a +database error occurs while attempting to delete the record, +the function returns without raising exception. +@end deftypefn + +@anchor{safedb_verbose} +@vrindex safedb_verbose +The verbosity of @samp{safedb} interfaces in case of database error is +controlled by the value of @code{safedb_verbose} variable. If it is +@samp{0}, these functions return silently. This is the default +behavior. Otherwise, if @code{safedb_verbose} is not @samp{0}, these +functions log the detailed diagnostics about the database error and +return. + @anchor{dbm-seq} The following functions provide a sequential access to the contents of a @acronym{DBM} database: @@ -7820,8 +7842,12 @@ The function @code{revip} is defined in @ref{revip}. @node System functions @subsubsection System functions -@deftypefn {Built-in Function} string gethostname () +@deftypefn {Built-in Function} string gethostname ([bool @var{fqn}]) Return the host name of this machine. + +If the optional @var{fqn} is given and is @samp{true}, the function +will attempt to return fully-qualified host name, by attempting to +resolve it using @acronym{DNS}. @end deftypefn @deftypefn {Built-in Function} string getdomainname () @@ -7830,8 +7856,21 @@ necessarily coincide with the actual machine name in @acronym{DNS}. Depending on the underlying @samp{libc} implementation, this call may return empty string or the string @samp{(none)}. Do not rely on it to -get the real hostname of the box @command{mailfromd} runs on, use -@acronym{DNS} functions instead. +get the real domain name of the box @command{mailfromd} runs on, use +@code{localdomain} (see below) instead. +@end deftypefn + +@flindex localdomain.mf +@deftypefn {Library Function} string localdomain () +Return the local domain name of this machine. + +This function first uses @code{getdomainname} to make a first guess. +If it does not return a meaningful value, @code{localdomain} calls +@code{gethostname(1)} to determine the fully qualified host name of +the machine, and returns its domain part. + +To use this function, require @file{localdomain.mf} module +(@pxref{Modules}), e.g.: @code{#require localdomain}. @end deftypefn @deftypefn {Built-in Function} number time () diff --git a/etc/mailfromd.rc b/etc/mailfromd.rc index e19cac49..141e2632 100644 --- a/etc/mailfromd.rc +++ b/etc/mailfromd.rc @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#error "Do not use this file 'AS IS'! Tailor it to suit your site!" - #pragma option relay "/etc/mail/sendmail.cw" #pragma option relay "/etc/mail/relay-domains" #pragma regex +extended +icase @@ -24,14 +22,27 @@ #include_once #require dns +#require localdomain #require rateok set mailfrom_address "<>" -set ehlo_domain "your.domain" +# If mailfromd does not determine local domain correctly, uncomment this +# and replace DOMAIN with your local domain: +#set ehlo_domain "DOMAIN" number gltime interval("1 hour") + number need_greylist 0 +/* Begin block is executed at the beginning of each SMTP transaction. + */ +begin +do + if %ehlo_domain == "" + set ehlo_domain localdomain() + fi +done + func cachestr() returns string do if %cache_used diff --git a/mfd/bi_gethostname.m4 b/mfd/bi_gethostname.m4 index 315a2d1b..fc7af790 100644 --- a/mfd/bi_gethostname.m4 +++ b/mfd/bi_gethostname.m4 @@ -30,7 +30,7 @@ This implementation is based on xgethostname by Jim Meyering */ -MF_DEFUN(gethostname, STRING) +MF_DEFUN(gethostname, STRING, OPTIONAL, NUMBER dns) { size_t size = INITIAL_HOSTNAME_LENGTH; @@ -72,6 +72,21 @@ MF_DEFUN(gethostname, STRING) } size = nsize; } + + if (MF_OPTVAL(dns)) { + struct hostent *hp; + char *ptr = MF_OBSTACK_BASE; + + hp = gethostbyname(ptr); + if (hp) { + size_t nlen = strlen(hp->h_name); + if (nlen >= size) + MF_OBSTACK_GROW(NULL, + nlen - size + 1); + strcpy(ptr, hp->h_name); + } + } + MF_RETURN_OBSTACK(); } END diff --git a/mfd/gram.y b/mfd/gram.y index 15ee9602..812eae39 100644 --- a/mfd/gram.y +++ b/mfd/gram.y @@ -401,7 +401,7 @@ _create_alias(void *item, void *data) %type state_ident %type matches fnmatches %type retdecl -%type params parmlist fparmlist parmdecl +%type params opt_parmlist parmlist fparmlist parmdecl %type parm %type fundecl %type value @@ -669,17 +669,29 @@ params : fparmlist $$.count = $$.optcount = 0; $$.varargs = 1; } - | parmlist ';' fparmlist + | opt_parmlist ';' fparmlist { $1.count += $3.count; $1.optcount = $3.count; $1.varargs = $3.varargs; - $1.tail->next = $3.head; + if ($1.tail) + $1.tail->next = $3.head; + else + $1.head = $3.head; $1.tail = $3.tail; $$ = $1; } ; +opt_parmlist: /* empty */ + { + $$.count = 0; + $$.varargs = 0; + $$.head = $$.tail = NULL; + } + | parmlist + ; + parmlist : parm { $$.count = 1; @@ -3180,8 +3192,9 @@ mailfromd_test(int argc, char **argv) env = create_environment(NULL, dbg_dict_getsym, dbg_setreply, dbg_msgmod, dict); + env_init(env); xeval(env, smtp_state_begin); - + env_init(env); for (i = 0; i < argc; i++) { if (p = strchr(argv[i], '=')) { @@ -3220,9 +3233,11 @@ mailfromd_test(int argc, char **argv) env_leave_frame(env, state_parms[test_state].cnt); env_final_gc(env); - xeval(env, smtp_state_end); - status = environment_get_status(env); + + env_init(env); + xeval(env, smtp_state_end); + printf("State %s: ", state_to_string(test_state)); print_stat(status); printf("\n"); diff --git a/mfd/lex.l b/mfd/lex.l index c1f9c3e8..da9dd1db 100644 --- a/mfd/lex.l +++ b/mfd/lex.l @@ -221,7 +221,10 @@ ICONST {LOCUS}|{VCONST}|{STATEDIR}|{PREPROC} } } ^[ \t]*#[ \t]*pragma[ \t].*/\n parse_pragma(yytext); -^[ \t]*#[ \t]*error[ \t].*\n { parse_error("%s", yytext); advance_line(); } +^[ \t]*#[ \t]*error[ \t].*\n { + yytext[yyleng-1] = 0; /* Kill trailing newline */ + parse_error("%s", yytext); + advance_line(); } /* End-of-line comments */ #.*\n { advance_line(); } #.* /* end-of-file comment */; diff --git a/mflib/Makefile.am b/mflib/Makefile.am index 8afe000f..60c08a7f 100644 --- a/mflib/Makefile.am +++ b/mflib/Makefile.am @@ -20,6 +20,7 @@ inc_DATA =\ gettext.mf\ heloarg_test.mf\ is_ip.mf\ + localdomain.mf\ match_cidr.mf\ match_dnsbl.mf\ match_rhsbl.mf\ diff --git a/mflib/localdomain.mf b/mflib/localdomain.mf new file mode 100644 index 00000000..77f153e5 --- /dev/null +++ b/mflib/localdomain.mf @@ -0,0 +1,31 @@ +/* Local domain functions -*- mfl -*- + Copyright (C) 2009 Sergey Poznyakoff + + 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 3, 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, see . */ + +func localdomain() + returns string +do + string s getdomainname() + if %s == "" or %s == "(none)" + string h gethostname(1) + number i index(%h, ".") + if %h >= 0 + set s substr(%h, %i + 1) + fi + fi + return %s +done + + diff --git a/mflib/safedb.mf4 b/mflib/safedb.mf4 index aaf10d51..d51e00ca 100644 --- a/mflib/safedb.mf4 +++ b/mflib/safedb.mf4 @@ -1,5 +1,5 @@ /* Safe DB I/O -*- mfl -*- - Copyright (C) 2007, 2008 Sergey Poznyakoff + Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff 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 @@ -16,12 +16,17 @@ #include_once +number safedb_verbose + func safedbget(string name, string key ; string defval, number null) returns string do catch e_dbfailure do - return "" + if %safedb_verbose + echo "safedbget: exception $1: $2" + fi + return %defval done if not defined(null) set null 0 @@ -36,6 +41,9 @@ func safedbput(string name, string key, string value ; number null) do catch e_dbfailure do + if %safedb_verbose + echo "safedbput: exception $1: $2" + fi return done if not defined(null) @@ -44,3 +52,39 @@ do dbput(%name, %key, %value, %null) done + +func safedbmap(string name, string key; number defval, number null) + returns number +do + catch e_dbfailure + do + if %safedb_verbose + echo "safedbmap: exception $1: $2" + fi + return %defval + done + if not defined(defval) + set defval 0 + fi + if not defined(null) + set null 0 + fi + return dbmap(%name, %key, %null) +done + +func safedbdel(string name, string key; number null) +do + catch e_dbfailure + do + if %safedb_verbose + echo "safedbdel: exception $1: $2" + fi + return + done + if not defined(null) + set null 0 + fi + return dbdel(%name, %key, %null) +done + + -- cgit v1.2.1