/* This file is part of Mailfromd. Copyright (C) 2005, 2006, 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 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 #include #include #include "libmf.h" #define SP(s) ((s) ? (s) : "(null)") #ifndef INADDR_NONE # define INADDR_NONE ((unsigned long) -1) #endif /* Status values used throughout the program */ typedef enum mf_status_code { mf_success, mf_not_found, mf_failure, mf_temp_failure, mf_status_count } mf_status; #define mf_resolved(c) ((c) == mf_success || (c) == mf_not_found) /* Exception codes. */ typedef enum mf_exception_code { mfe_success, mfe_not_found, mfe_failure, mfe_temp_failure, mfe_ston_conv, mfe_divzero, mfe_regcomp, mfe_invip, mfe_invcidr, mfe_invtime, mfe_dbfailure, mfe_range, mfe_url, mfe_noresolve, mfe_io, mfe_macroundef, mf_exception_count } mf_exception; #define mf_status_to_exception(s) ((mf_exception)(s)) #define EXMASK(n) ((unsigned)1<<(n)) /* SMTP 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 #define MAILFROMD_RUN 7 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 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; extern const char *program_version; extern mu_acl_t mailfromd_acl; extern mode_t mailfromd_umask; extern size_t stack_size; extern size_t stack_max_size; extern size_t stack_expand_incr; enum stack_expand_policy { stack_expand_twice, stack_expand_add }; extern enum stack_expand_policy stack_expand_policy; /* Configuration file parser */ typedef enum { dtype_unspecified, dtype_string, dtype_number, dtype_pointer } data_type_t; /* Parse tree node */ typedef struct node NODE; /* Input location */ struct locus { const char *file; /* File name */ unsigned long 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 msgmod_opcode { /* Message modification operation */ header_add, /* Add a header */ header_replace, /* Replace a header value */ header_delete, /* Delete a header */ header_insert, /* Insert a header */ rcpt_add, /* Add a recipient */ rcpt_delete, /* Delete a recipient */ quarantine, /* Quarantine a message */ body_repl, /* Replace message body */ }; struct msgmod_closure { enum msgmod_opcode opcode; /* Operation code */ char *name; /* Object name */ char *value; /* Object value */ unsigned idx; /* Object index */ }; struct header_node { enum msgmod_opcode opcode; /* Operation code */ struct literal *name; /* Header name */ NODE *value; /* Header value */ }; 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; }; struct argx_node { int nargs; NODE *node; }; #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 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; struct argx_node argx; } 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 */ #define MFD_BUILTIN_CAPTURE 0x01 /* Builtin needs message capturing */ #define MFD_BUILTIN_VARIADIC 0x02 /* Builtin is variadic */ #define MFD_BUILTIN_NO_PROMOTE 0x04 /* For variadic functions: do not promote varargs to string */ 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 flags; /* Flags */ }; 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 */ int varargs; /* 1 if function takes variable number of arguments */ 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 */ #define SYM_ALIAS 6 /* Function alias */ #define SYM_PRAGMA 7 /* Pragma definition */ #define _SYM_COUNT 8 #define SYM_MASK(n) (1<<(n)) #define SYM_BITS SYM_MASK(_SYM_COUNT) 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 pragma_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, data_type_t rettype, size_t argcount, size_t optcount, int flags, ...); 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(const char *arg, const char *val); int variable_or_constant_lookup(const char *name, void **dptr); struct function *function_install(const char *name, size_t parmcnt, size_t optcnt, int varargs, 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); const struct constant *constant_lookup(const char *name); const struct value *constant_lookup_value(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); void install_alias(const char *name, struct function *fun, const struct locus *locus); struct rt_regex { int compiled; regex_t re; size_t expr; int regflags; }; void register_regex(struct sym_regex *rp); void finalize_regex(void); struct pragma { char *name; int minargs; int maxargs; void (*handler) (int, char **, const char *); }; void install_pragma(const char *name, int minargs, int maxargs, void (*handler) (int, char **, const char *)); const struct pragma *lookup_pragma(const char *name); /* 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(const char *dir); void onblock(int enable); int parse_program(char *name, int ydebug); void parse_pragma(const char *text); const struct locus *get_locus(void); const char *msgmod_opcode_str(enum msgmod_opcode opcode); const char *sfsistat_str(sfsistat stat); const char *mf_exception_str(mf_exception ex); #define mf_status_str(s) mf_exception_str(mf_status_to_exception(s)) int string_to_exception(const char *str, mf_exception *status); const char *storage_class_str(storage_class_t sc); enum smtp_state string_to_state(const char *name); const char *state_to_string(enum smtp_state state); void parse_error(const char *fmt, ...) MU_PRINTFLIKE(1,2); void parse_error_locus(const struct locus *loc, const char *fmt, ...) MU_PRINTFLIKE(2,3); void parse_warning(const char *fmt, ...) MU_PRINTFLIKE(1,2); void parse_warning_locus(const struct locus *loc, const char *fmt, ...) MU_PRINTFLIKE(2,3); 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); char *get_stage_macro_string(enum gacopyz_stage i); /* 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_helo(eval_environ_t env, const char *text); void set_last_poll_greeting(eval_environ_t env, const char *text); 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, const char *(*getsym)(void *data, const char *str), int (*setreply)(void *data, char *code, char *xcode, char *message), void (*msgmod)(void *data, struct msgmod_closure *op), 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_exception exception, const char *fmt, ...) MU_PRINTFLIKE(3,4) ATTRIBUTE_NORETURN; void env_throw_bi(eval_environ_t env, mf_exception exception, const char *biname, const char *fmt, ...) MU_PRINTFLIKE(4,5) ATTRIBUTE_NORETURN; void env_throw_0(eval_environ_t env, mf_exception exception, 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_push_pointer(eval_environ_t env, void *arg); void env_make_frame(eval_environ_t env); void env_make_frame0(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); size_t env_get_line_count(eval_environ_t env); mu_stream_t env_get_stream(eval_environ_t env); void env_reposition(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 env_msgmod(eval_environ_t env, enum msgmod_opcode opcode, const char *name, const char *value, unsigned idx); void capture_on(void); const char *env_get_macro(eval_environ_t env, const char *symbol); /* 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, ...) MU_PRINTFLIKE(2,3); void vlogmsg(int prio, const char *fmt, va_list ap); void log_status(sfsistat status, SMFICTX *ctx); void trace(const char *fmt, ...) MU_PRINTFLIKE(1,2); int convert_rate(const char *arg, double *rate); extern void priv_setup(void); void mailfromd_daemon(void); void save_cmdline(int argc, char **argv); void mailfromd_test(int argc, char **argv); void mailfromd_run(prog_counter_t entry, 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); size_t mem_search(const char *str, int c, size_t size); 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, long *ret, unsigned long interval, size_t mincount, size_t threshold); mf_status check_tbf_rate(char *email, int *ret, size_t cost, size_t interval, size_t burst_size); 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 *tbf_rate_format; extern struct db_format *greylist_format; extern char *time_format_string; size_t format_time_str(FILE *fp, time_t timestamp); int mf_stream_to_message(mu_stream_t stream, mu_message_t *msg);