/* This file is part of mailfromd.
Copyright (C) 2005, 2006, 2007 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 . */
#include
#include
#include
#include
#include
#include
#include
/* Common error codes */
#ifdef HAVE_SYSEXITS_H
# include
#else
# define EX_OK 0 /* successful termination */
# define EX__BASE 64 /* base value for error messages */
# define EX_USAGE 64 /* command line usage error */
# define EX_DATAERR 65 /* data format error */
# define EX_NOINPUT 66 /* cannot open input */
# define EX_NOUSER 67 /* addressee unknown */
# define EX_NOHOST 68 /* host name unknown */
# define EX_UNAVAILABLE 69 /* service unavailable */
# define EX_SOFTWARE 70 /* internal software error */
# define EX_OSERR 71 /* system error (e.g., can't fork) */
# define EX_OSFILE 72 /* critical OS file missing */
# define EX_CANTCREAT 73 /* can't create (user) output file */
# define EX_IOERR 74 /* input/output error */
# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
# define EX_PROTOCOL 76 /* remote error in protocol */
# define EX_NOPERM 77 /* permission denied */
# define EX_CONFIG 78 /* configuration error */
# define EX__MAX 78 /* maximum listed value */
#endif
/* NLS */
#undef _
#undef N_
#undef gettext
#undef dgettext
#undef ngettext
#undef textdomain
#undef bindtextdomain
#ifdef ENABLE_NLS
# include
# define _(String) gettext(String)
# define N_(String) String
#else
# define _(String) (String)
# define N_(String) String
# define gettext(msgid) (msgid)
# define dgettext(domain, msgid) (msgid)
# define ngettext(sg,pl,cnt) (cnt == 1) ? (sg) : (pl)
# define textdomain(Domain)
# define bindtextdomain(Package, Directory) (char*) ((errno = ENOSYS),NULL)
#endif /* ENABLE_NLS */
/* Status values used throughout the program */
typedef enum mf_status_code {
mf_success,
mf_not_found,
mf_failure,
mf_temp_failure,
mf_ston_conv,
mf_divzero,
mf_regcomp,
mf_invip,
mf_invcidr,
mf_invtime,
mf_dbfailure,
mf_range,
mf_url,
mf_noresolve,
mf_ioerr,
mf_macroundef,
mf_status_count
} mf_status;
#define mf_resolved(c) ((c) == mf_success || (c) == mf_not_found)
#define EXMASK(n) ((unsigned)1<<(n))
/* SMTP (libmilter) states */
enum smtp_state {
smtp_state_none,
smtp_state_begin,
smtp_state_first=smtp_state_begin,
smtp_state_connect,
smtp_state_helo,
smtp_state_envfrom,
smtp_state_envrcpt,
smtp_state_data,
smtp_state_header,
smtp_state_eoh,
smtp_state_body,
smtp_state_eom,
smtp_state_end,
smtp_state_count
};
/* The following defines are borrowed from intprops.h (gnulib) */
/* True if the arithmetic type T is signed. */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
/* Return zero if T can be determined to be an unsigned type.
Otherwise, return 1.
When compiling with GCC, INT_STRLEN_BOUND uses this macro to obtain a
tighter bound. Otherwise, it overestimates the true bound by one byte
when applied to unsigned types of size 2, 4, 16, ... bytes.
The symbol signed_type_or_expr__ is private to this header file. */
#if __GNUC__ >= 2
# define signed_type_or_expr__(t) TYPE_SIGNED (__typeof__ (t))
#else
# define signed_type_or_expr__(t) 1
#endif
/* Bound on length of the string representing an integer type or expression T.
Subtract 1 for the sign bit if T is signed; log10 (2.0) < 146/485;
add 1 for integer division truncation; add 1 more for a minus sign
if needed. */
#define INT_STRLEN_BOUND(t) \
((sizeof (t) * CHAR_BIT - signed_type_or_expr__ (t)) * 146 / 485 \
+ signed_type_or_expr__ (t) + 1)
/* Bound on buffer size needed to represent an integer type or expression T,
including the terminating null. */
#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
/* Size of the buffer able to accomodate mailfromd numeric type */
#define NUMERIC_BUFSIZE_BOUND INT_BUFSIZE_BOUND(long)
#if defined HAVE_SYSCONF && defined _SC_OPEN_MAX
# define getmaxfd() sysconf(_SC_OPEN_MAX)
#elif defined (HAVE_GETDTABLESIZE)
# define getmaxfd() getdtablesize()
#else
# define getmaxfd() 256
#endif
mf_status dns_to_mf_status(dns_status stat);
mf_status resolve_ipstr(const char *ipstr, char **hbuf);
mf_status resolve_ipstr_domain(const char *ipstr, const char *domain,
char **phbuf);
mf_status resolve_hostname(const char *host, char **pipbuf);
mf_status getmx(char *ipstr, mxbuf_t mxbuf);
mf_status getmxip(char *ipstr, mxbuf_t mxbuf);
/* Default file names */
#define DEFAULT_PIDFILE "mailfromd.pid"
#define DEFAULT_DATABASE "mailfromd.db"
#define DEFAULT_RATE_DATABASE "rates.db"
#define DEFAULT_GREYLIST_DATABASE "greylist.db"
#define DEFAULT_DNS_DATABASE "dns.db"
#define DEFAULT_SCRIPT_FILE SYSCONFDIR "/mailfromd.rc"
#define DEFAULT_FROM_ADDRESS "<>"
/* Debugging macros */
#include "debug.h"
/* Syslog flavor */
#ifdef USE_SYSLOG_ASYNC
# include
#endif
/* FIXME */
void enable_prog_trace(const char *modlist);
void disable_prog_trace(const char *modlist);
/* Global variables declarations */
#define MAILFROMD_DAEMON 0
#define MAILFROMD_TEST 1
#define MAILFROMD_DELETE 2
#define MAILFROMD_LIST 3
#define MAILFROMD_EXPIRE 4
#define MAILFROMD_COMPACT 5
#define MAILFROMD_SHOW_DEFAULTS 6
extern char *script_file;
extern char *ext_pp;
extern int mode;
extern int mtasim_option;
extern unsigned optimization_level;
extern enum smtp_state test_state;
extern time_t negative_expire_interval;
extern int predict_next_option;
extern double predict_rate;
extern char *smtp_domain;
extern char *postmaster_email;
extern int regex_flags;
extern size_t stack_size;
extern size_t variable_count;
extern int ignore_failed_reads_option;
extern int source_info_option;
extern int do_transcript;
extern char *portspec;
extern unsigned long source_address;
extern char *pidfile;
extern time_t io_timeout;
extern time_t connect_timeout;
extern time_t response_timeout;
extern int foreground;
extern int single_process_option;
extern int force_remove;
extern int script_dump_macros;
extern int script_dump_xref;
extern size_t lock_retry_count_option;
extern time_t lock_retry_timeout_option;
extern char *mailfromd_state_dir;
extern int stack_trace_option;
extern int log_to_stderr;
/* Configuration file parser */
typedef enum {
dtype_unspecified,
dtype_string,
dtype_number
} data_type_t;
/* Parse tree node */
typedef struct node NODE;
/* Input location */
struct locus {
const char *file; /* File name */
size_t line; /* Line number */
};
#define LOCUS_EQ(a,b) \
(strcmp((a)->file, (b)->file) == 0 && (a)->line == (b)->line)
struct if_node { /* if statement */
NODE *cond; /* Condition */
NODE *if_true; /* True branch */
NODE *if_false; /* False branch */
};
struct poll_data { /* Poll test */
NODE *email;
NODE *client_addr;
NODE *ehlo;
NODE *mailfrom;
};
/* Opcodes for available binary operations */
enum bin_opcode {
bin_and,
bin_or,
bin_eq,
bin_ne,
bin_lt,
bin_le,
bin_gt,
bin_ge,
bin_match,
bin_fnmatch,
bin_add,
bin_sub,
bin_mul,
bin_div,
bin_logand,
bin_logor,
bin_logxor
};
#define QUALIFIER_MX 0x1
struct bin_node { /* A binary operation */
enum bin_opcode opcode; /* Operation code */
int qualifier; /* Used to indicate MX MATCHES/FNMATCHES */
NODE *arg[2]; /* arg[0] - left side argument,
arg[1] - right side argument */
};
/* Unary operations */
enum un_opcode {
unary_not,
unary_minus,
unary_lognot
};
struct un_node { /* A unary operation node */
enum un_opcode opcode; /* Operation code */
data_type_t result_type; /* Result type */
NODE *arg; /* Argument */
};
/* Return action node: accept/reject/tempfail/continue */
struct return_node {
sfsistat stat; /* Return status */
struct literal *code; /* Code */
struct literal *xcode; /* Extended code */
NODE *message; /* Subtree producing the textual message */
};
enum header_opcode { /* Operation on a header */
header_add, /* Add a header */
header_replace, /* Replace a header value */
header_delete /* Delete a header */
};
struct old_header_node {
enum header_opcode opcode; /* Operation code */
const char *name; /* Header name */
char *value; /* Header value */
};
struct header_node {
enum header_opcode opcode; /* Operation code */
struct literal *name; /* Header name */
NODE *value; /* Header value */
};
struct rate_node { /* Rate test */
NODE *email; /* Originator email */
double limit; /* Sending rate limit */
};
struct builtin_node { /* Call to a built-in function */
const struct builtin *builtin; /* Buit-in function */
NODE *args; /* Actual arguments */
};
struct concat_node { /* Concatenation of arg[0] and arg[1] */
NODE *arg[2];
};
struct asgn_node { /* Assignment */
struct variable *var; /* Variable */
size_t nframes; /* Number of frames to skip */
NODE *node; /* Expression to be evaluated and assigned
to it */
};
enum lexical_context {
context_none,
context_handler,
context_catch,
context_function
};
struct catch_node {
int count; /* Number of handled exceptions */
unsigned exmask; /* Exception mask */
enum lexical_context context; /* Context in which it occurs */
NODE *node; /* Subtree */
};
struct function_call {
struct function *func; /* Function description */
NODE *args; /* List of actual arguments */
};
struct value {
data_type_t type;
union {
long number;
struct literal *literal;
} v;
};
struct valist {
struct valist *next;
struct value value;
};
struct case_stmt {
struct case_stmt *next;
struct locus locus;
struct valist *valist;
NODE *node;
};
struct switch_stmt {
NODE *node; /* Condition */
struct case_stmt *cases; /* Switch branches */
/* Auxiliary data for code generation */
size_t tabsize; /* Size of the XLAT table */
size_t off; /* Offset of the table in DS */
struct switch_stmt *next; /* Link to the next switch statement */
};
struct cast_node {
data_type_t data_type;
NODE *node;
};
struct positional_arg {
data_type_t data_type;
int number;
};
struct progdecl {
enum smtp_state tag;
size_t auto_count;
NODE *tree;
};
struct funcdecl {
struct function *func;
size_t auto_count;
NODE *tree;
};
struct throw_node {
int code;
NODE *expr;
};
struct var_ref {
struct variable *variable; /* Variable being referenced */
size_t nframes; /* Number of frames to skip */
};
struct regcomp_data {
NODE *expr;
int flags;
size_t regind;
};
struct loop_node {
struct literal *ident;
NODE *stmt;
NODE *for_stmt;
NODE *beg_while;
NODE *end_while;
NODE *body;
};
#include "node-type.h"
/* Parse tree node */
struct node {
NODE *next; /* Link to the next node */
enum node_type type; /* Node type */
struct locus locus; /* Corresponding input location */
union {
struct literal *literal;
long number;
struct if_node cond;
struct bin_node bin;
struct un_node un;
struct return_node ret;
struct header_node hdr;
struct rate_node rate;
struct builtin_node builtin;
NODE *node;
struct concat_node concat;
struct var_ref var_ref;
struct asgn_node asgn;
void *val;
struct catch_node catch;
struct throw_node throw;
struct function_call call;
struct switch_stmt switch_stmt;
struct cast_node cast;
struct positional_arg arg;
struct progdecl progdecl;
struct funcdecl funcdecl;
struct regcomp_data regcomp_data;
struct sym_regex *regex;
struct loop_node loop;
} v;
};
struct stmtlist {
NODE *head;
NODE *tail;
};
/* Expressions, built-in functions and variables */
typedef struct eval_environ *eval_environ_t; /* Evaluation environment */
typedef unsigned long prog_counter_t; /* Program counter */
/* Data types */
struct builtin {
char *name; /* Built-in function name */
void (*handler) (eval_environ_t); /* C handler */
size_t parmcount; /* Number of parameters */
data_type_t *parmtype; /* Parameter types */
size_t optcount; /* Number of optional parameters
(size_t) -1 for varargs */
data_type_t rettype; /* Return type */
unsigned statemask; /* States where the function can
be used */
int capture; /* Does it need message capturing */
int varargs; /* Does it take optional number of
arguments */
};
struct function { /* User-defined function */
char *name; /* Function name */
struct locus locus; /* Location of the definition */
NODE *node; /* Function definition (syntax tree) */
prog_counter_t entry; /* Entry point to the function code */
unsigned exmask; /* Exception mask */
unsigned statemask; /* States where the function can
be used */
size_t parmcount; /* Number of parameters */
size_t optcount; /* Number of optional parameters */
data_type_t *parmtype; /* Parameter types */
data_type_t rettype; /* Return type */
};
typedef enum {
storage_extern,
storage_auto,
storage_param
} storage_class_t;
#define VAR_VOLATILE 0x1 /* Variable can change outside of the compiled
code */
#define VAR_REFERENCED 0x2 /* Variable is referenced */
#define VAR_EXTERN 0x4 /* Variable is external (for future use) */
struct variable {
char *name; /* Variable name */
data_type_t type; /* Variable type */
storage_class_t storage_class; /* Storage class */
size_t off; /* Offset in the data segment */
size_t ord; /* Ordinal number in the parmlist
(for parameters only) */
struct locus locus; /* Location of the definition */
struct variable *shadowed; /* Points to the variable shadowed by
this one */
unsigned flags; /* VAR_* flags */
mu_list_t xref; /* List of struct locus */
struct variable *next; /* Next variable in this class */
void *owner;
};
struct literal {
const char *text; /* The literal itself */
unsigned flags; /* VAR_* flags */
size_t off; /* Offset in DS */
struct sym_regex *regex; /* Any correspondig regexes */
};
struct constant {
const char *name;
struct locus locus;
struct value value;
};
#define SYM_UNDEF 0 /* The entry is not defined */
#define SYM_BUILTIN 1 /* The entry holds a builtin function */
#define SYM_FUNC 2 /* The entry holds a user-defined function */
#define SYM_VARIABLE 3 /* The entry holds a variable */
#define SYM_LITERAL 4 /* A literal */
#define SYM_CONSTANT 5 /* A constant */
typedef int (*symbol_enumerator_t)(void *sym, void *data);
int symbol_enumerate(int state, symbol_enumerator_t fun, void *data);
void *find_and_remove(int state, char *name);
void free_symbols(void);
#define REG_EXTENDED_NAME "extended"
#define REG_ICASE_NAME "icase"
#define REG_NEWLINE_NAME "newline"
#define REGEX_STRING_BUFSIZE \
(sizeof(REG_EXTENDED_NAME) + \
sizeof(REG_ICASE_NAME) + \
sizeof(REG_NEWLINE_NAME) + 1)
char *regex_flags_to_string(int flags, char *buf, size_t size);
void log_setup(int want_stderr);
void builtin_setup(void);
void builtin_post_setup(void);
void print_code(void);
void print_xref(void);
void print_used_macros(void);
void va_builtin_install (char *name, void (*handler) (eval_environ_t),
data_type_t rettype, size_t argcount, ...);
void va_builtin_install_ex (char *name, void (*handler) (eval_environ_t),
unsigned statemsk, int capture,
data_type_t rettype, size_t argcount,
size_t optcount, int varargs, ...);
const struct builtin *builtin_lookup(const char *name);
struct variable *variable_install(const char *name);
struct variable *variable_lookup(const char *name);
struct variable *variable_replace(struct variable *var,
struct variable *newvar);
void variable_remove(struct variable *var);
struct variable *builtin_variable_install(const char *name,
data_type_t type,
unsigned flags);
void defer_initialize_variable(char *arg, char *val);
struct function *function_install(const char *name,
size_t parmcnt, size_t optcnt,
data_type_t *parmtypes,
data_type_t rettype,
const struct locus *locus);
struct function *function_lookup(const char *name);
struct literal *literal_lookup(const char *text);
void define_constant(const char *name, struct value *value, struct locus *loc);
struct value *constant_lookup(const char *name);
struct sym_regex {
struct literal *lit; /* Corresponding literal */
int regflags; /* Compilation flags */
unsigned flags; /* VAR_* flags */
size_t index; /* Index in the regtab */
struct sym_regex *next; /* Next sym_regex with the same name, but
different regflags */
};
struct sym_regex *install_regex(struct literal *lit, unsigned regflags);
struct rt_regex {
int compiled;
regex_t re;
size_t expr;
int regflags;
};
void register_regex(struct sym_regex *rp);
void finalize_regex(void);
/* Preprocessor functions */
void include_path_setup(void);
void parse_line_cpp(char *text, struct locus *ploc);
int parse_line(char *text, struct locus *ploc);
size_t pp_fill_buffer(char *buf, size_t size);
int preprocess_input(char *);
int source(char *);
void pp_make_argcv(int *pargc, char ***pargv);
FILE *pp_extrn_start(int argc, char **argv, pid_t *ppid);
void pp_extrn_shutdown(pid_t pid);
int pp_init(char *name);
void pp_done(void);
/* Parser functions */
int yyparse();
int yylex();
int yyerror(char *s);
void add_include_dir(char *dir);
void onblock(int enable);
int parse_program(char *name, int ydebug);
void parse_pragma(char *text);
const struct locus *get_locus(void);
const char *header_command_str(enum header_opcode opcode);
const char *sfsistat_str(sfsistat stat);
const char *mf_status_str(mf_status stat);
const char *storage_class_str(storage_class_t sc);
int string_to_stat(const char *str, mf_status *status);
enum smtp_state string_to_state(const char *name);
const char *state_to_string(enum smtp_state state);
void parse_error(char *fmt, ...);
void parse_error_locus(const struct locus *loc, char *fmt, ...);
void parse_warning(char *fmt, ...);
void parse_warning_locus(const struct locus *loc, char *fmt, ...);
int parse_time_interval(const char *str, time_t *pint, const char **endp);
void print_syntax_tree(void);
void print_macros(void);
const char *function_name(void);
void lex_setup(void);
struct literal *string_alloc(const char *str, size_t len);
void string_begin(void);
void string_add(const char *str, size_t len);
void string_add_char(unsigned char c);
struct literal *string_finish(void);
void free_string_space(void);
void init_string_space(void);
char *mf_strdup(const char *str);
void regex_push(void);
void regex_pop(void);
/* Data types and declarations for handling compiled configuration code */
typedef void (*instr_t) (eval_environ_t env); /* Instruction */
/* Entry points for each SMTP state */
extern prog_counter_t entry_point[smtp_state_count];
/* Functions for accessing %rcpt_count */
unsigned long get_rcpt_count(eval_environ_t env);
void clear_rcpt_count(eval_environ_t env);
void incr_rcpt_count(eval_environ_t env);
void set_last_poll_result(eval_environ_t env,
const char *host_addr, const char *send,
const char *recv);
void set_cache_used(eval_environ_t env, int value);
/* Code generation and diagnostics functions */
void code_put(prog_counter_t pos, void *ptr);
instr_t code_peek(prog_counter_t pos);
prog_counter_t code_reserve(size_t count);
prog_counter_t code_immediate(const void *ptr);
prog_counter_t code_op(unsigned code);
prog_counter_t code_instr(const instr_t ptr);
prog_counter_t code_get_counter();
void dump_code(prog_counter_t start, prog_counter_t end);
void fixup_code(void);
/* Evaluation environment functions */
eval_environ_t
create_environment(SMFICTX *ctx,
char *(*getsym)(void *data, char *str),
int (*setreply)(void *data, char *code, char *xcode,
char *message),
void (*setheader)(void *data, struct old_header_node *hdr),
void *data);
void destroy_environment(eval_environ_t env);
void env_init(eval_environ_t env);
void env_save_catches(eval_environ_t env);
# ifndef ATTRIBUTE_NORETURN
# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
# endif
void env_throw(eval_environ_t env, mf_status status,
const char *fmt, ...) ATTRIBUTE_NORETURN;
void env_throw_bi(eval_environ_t env, mf_status status, const char *biname,
const char *fmt, ...) ATTRIBUTE_NORETURN;
void env_throw_0(eval_environ_t env, mf_status status,
size_t text_off) ATTRIBUTE_NORETURN;
void env_push_string(eval_environ_t env, char *arg);
void env_push_number(eval_environ_t env, long arg);
void env_make_frame(eval_environ_t env);
void env_leave_frame(eval_environ_t env, int nargs);
int env_set_variable(eval_environ_t env, char *ident, char *value);
int eval_environment(eval_environ_t env, prog_counter_t pc);
sfsistat environment_get_status(eval_environ_t env);
const char *environment_get_null_symbol(eval_environ_t env,
struct locus *locus);
SMFICTX *env_get_context(eval_environ_t env);
mu_stream_t env_get_stream(eval_environ_t env);
int env_capture_start(eval_environ_t env);
int env_capture_write(eval_environ_t env, const char *buf, size_t size);
int env_capture_write_args(eval_environ_t env, ...);
void env_final_gc(eval_environ_t env);
void capture_on(void);
/* Runtime functions */
const char *mailfromd_msgid(SMFICTX *ctx);
char *mailfromd_timestr(time_t timestamp, char *timebuf, size_t bufsize);
void logmsg(int prio, const char *fmt, ...);
void log_status(sfsistat status, SMFICTX *ctx);
void trace(const char *fmt, ...);
int convert_rate(const char *arg, double *rate);
extern void priv_setup(void);
void mailfromd_daemon(void);
void save_cmdline(int argc, char **argv);
/* DNS dictionary */
void dict_init(mu_list_t *dict);
char *dict_install(mu_list_t dict, char *name, char *value);
void dict_destroy(mu_list_t *dict);
char *dict_getsym(void *data, char *str);
void mailfromd_test(int argc, char **argv);
int set_option(char *name, char *value, int override);
int sendmail_mlreply(SMFICTX * ctx, const char *rcode, const char *xcode,
char *message);
void milter_enable_state(enum smtp_state state);
int xeval(eval_environ_t env, enum smtp_state tag);
mf_status listens_on (const char *client_addr, int port);
mf_status check_on_host(eval_environ_t env, char *email, char *client_addr,
char *ehlo, char *mailfrom);
mf_status check_mx_records(eval_environ_t env, char *email, char *client_addr,
char *ehlo, char *mailfrom, int *pcount);
mf_status method_strict(eval_environ_t env, char *email, char *client_addr,
char *ehlo, char *mailfrom);
mf_status method_standard(eval_environ_t env, char *email, char *ehlo,
char *mailfrom);
int relayed_domain_p(char *name);
int compare_string(const void *item, const void *value);
typedef struct mf_stack *mf_stack_t;
mf_stack_t mf_stack_create(size_t elsize, size_t count);
void mf_stack_destroy(mf_stack_t *pstk);
void mf_stack_push(mf_stack_t stk, void *item);
int mf_stack_pop(mf_stack_t stk, void *ptr);
int mf_stack_peek(mf_stack_t stk, size_t n, void *ptr);
size_t mf_stack_count(mf_stack_t stk);
typedef int (*mf_stack_enumerator) (void *item, void *data);
int mf_stack_enumerate_desc(mf_stack_t stk, mf_stack_enumerator fun,
void *data);
int mf_stack_enumerate_asc(mf_stack_t stk, mf_stack_enumerator fun,
void *data);
/* DBM support */
#include "mu_dbm.h"
typedef void (*db_item_printer_t)(const char *key, size_t size,
const void *content);
typedef int (*db_expire_t)(const void *content);
struct db_format {
char *name;
char *dbname;
int enabled;
time_t expire_interval;
db_item_printer_t print_item;
db_expire_t expire;
};
struct db_format *db_format_install(struct db_format *fmt);
struct db_format *db_format_lookup(const char *name);
void db_format_enumerate(symbol_enumerator_t fp, void *data);
mf_status cache_get(char *email);
void cache_insert(char *email, mf_status rc);
mf_status cache_get2(char *email, char *client_addr);
void cache_insert2(char *email, char *client_addr, mf_status rc);
mf_status dns_cache_get(int type, const char *keystr, char **rbuf,
size_t rcnt);
void dns_cache_put(int type, const char *keystr, time_t ttl, char **rbuf,
size_t rcnt);
mf_status get_rate(char *email, double *ret, size_t mincount);
int db_list_item(char *dbname, char *key, db_item_printer_t fun);
int db_list(char *dbname, db_item_printer_t fun);
int db_expire(char *dbname, db_expire_t fun);
int db_delete(char *dbname, char *id);
int db_compact(char *dbname, db_expire_t fun);
extern struct db_format *dns_cache_format;
extern struct db_format *cache_format;
extern struct db_format *rate_format;
extern struct db_format *greylist_format;
extern char *time_format_string;
size_t format_time_str(FILE *fp, time_t timestamp);
void mailfromd_version(const char *progname, FILE *stream,
struct argp_state *state);