/* This file is part of gacopyz.
Copyright (C) 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 . */
#ifndef __gacopyz_h__
# define __gacopyz_h__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
#define GACOPYZ_VERSION_MAJOR 1
#define GACOPYZ_VERSION_MINOR 0
/* Implementation version number */
#define SMFI_VERSION 2
/* commands: don't use anything smaller than ' ' */
#define SMFIC_ABORT 'A' /* Abort */
#define SMFIC_BODY 'B' /* Body chunk */
#define SMFIC_CONNECT 'C' /* Connection information */
#define SMFIC_MACRO 'D' /* Define macro */
#define SMFIC_BODYEOB 'E' /* final body chunk (End) */
#define SMFIC_HELO 'H' /* HELO/EHLO */
#define SMFIC_HEADER 'L' /* Header */
#define SMFIC_MAIL 'M' /* MAIL from */
#define SMFIC_EOH 'N' /* EOH */
#define SMFIC_OPTNEG 'O' /* Option negotiation */
#define SMFIC_QUIT 'Q' /* QUIT */
#define SMFIC_RCPT 'R' /* RCPT to */
#define SMFIC_DATA 'T' /* DATA (SMFI_VERSION > 3) */
#define SMFIC_UNKNOWN 'U' /* Any unknown command */
/* actions (replies) */
#define SMFIR_ADDRCPT '+' /* add recipient */
#define SMFIR_DELRCPT '-' /* remove recipient */
#define SMFIR_ACCEPT 'a' /* accept */
#define SMFIR_REPLBODY 'b' /* replace body (chunk) */
#define SMFIR_CONTINUE 'c' /* continue */
#define SMFIR_DISCARD 'd' /* discard */
#define SMFIR_CONN_FAIL 'f' /* cause a connection failure */
#define SMFIR_CHGHEADER 'm' /* change header */
#define SMFIR_PROGRESS 'p' /* progress */
#define SMFIR_REJECT 'r' /* reject */
#define SMFIR_TEMPFAIL 't' /* tempfail */
#define SMFIR_SHUTDOWN '4' /* 421: shutdown (internal to MTA) */
#define SMFIR_ADDHEADER 'h' /* add header */
#define SMFIR_INSHEADER 'i' /* insert header */
#define SMFIR_REPLYCODE 'y' /* reply code etc */
#define SMFIR_QUARANTINE 'q' /* quarantine */
/* What the MTA can send/filter wants in protocol */
#define SMFIP_NOCONNECT 0x00000001L /* MTA should not send connect info */
#define SMFIP_NOHELO 0x00000002L /* MTA should not send HELO info */
#define SMFIP_NOMAIL 0x00000004L /* MTA should not send MAIL info */
#define SMFIP_NORCPT 0x00000008L /* MTA should not send RCPT info */
#define SMFIP_NOBODY 0x00000010L /* MTA should not send body */
#define SMFIP_NOHDRS 0x00000020L /* MTA should not send headers */
#define SMFIP_NOEOH 0x00000040L /* MTA should not send EOH */
#define SMFIP_NOHREPL 0x00000080L /* No reply for headers */
#define SMFIP_NOUNKNOWN 0x00000100L /* MTA should not send unknown
command */
#define SMFIP_NODATA 0x00000200L /* MTA should not send DATA */
/* The protocol of V1 filter */
#define SMFI_V1_PROT (SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NOMAIL|\
SMFIP_NORCPT|SMFIP_NOBODY|SMFIP_NOHDRS)
/* The protocol of V2 filter */
#define SMFI_V2_PROT (SMFI_V1_PROT|SMFIP_NOEOH)
/* Flags, defining milter capabilities */
#define SMFIF_NONE 0x00000000L /* no flags */
#define SMFIF_ADDHDRS 0x00000001L /* filter may add headers */
#define SMFIF_CHGBODY 0x00000002L /* filter may replace body */
#define SMFIF_MODBODY SMFIF_CHGBODY /* backwards compatible */
#define SMFIF_ADDRCPT 0x00000004L /* filter may add recipients */
#define SMFIF_DELRCPT 0x00000008L /* filter may delete recipients */
#define SMFIF_CHGHDRS 0x00000010L /* filter may change/delete headers */
#define SMFIF_QUARANTINE 0x00000020L /* filter may quarantine envelope */
#define SMFI_V1_ACTS (SMFIF_ADDHDRS|SMFIF_CHGBODY|SMFIF_ADDRCPT|SMFIF_DELRCPT)
#define SMFI_V2_ACTS (SMFI_V1_ACTS|SMFIF_CHGHDRS|SMFIF_QUARANTINE)
#define SMFI_DEFAULT_ACTS SMFI_V2_ACTS
#define SMFI_DEFAULT_PROT SMFI_V2_PROT
/* Log levels */
#define SMI_LOG_DEBUG 0
#define SMI_LOG_INFO 1
#define SMI_LOG_WARN 2
#define SMI_LOG_ERR 3
#define SMI_LOG_FATAL 4
#define SMI_LOG_MASK(n) (1<<(n))
#define SMI_LOG_UPTO(n) ((1 << ((n)+1))-1) /* all levels through n */
#define SMI_LOG_FROM(n) (SMI_LOG_UPTO(SMI_LOG_FATAL) & ~SMI_LOG_UPTO(n-1))
#define SMI_DEFAULT_LOG_MASK SMI_LOG_MASK(SMI_LOG_INFO) \
| SMI_LOG_MASK(SMI_LOG_WARN) \
| SMI_LOG_MASK(SMI_LOG_ERR) \
| SMI_LOG_MASK(SMI_LOG_FATAL)
/* address families */
#define SMFIA_UNKNOWN 'U' /* unknown */
#define SMFIA_UNIX 'L' /* unix/local */
#define SMFIA_INET '4' /* inet */
#define SMFIA_INET6 '6' /* inet6 */
/* Function return codes */
#define MI_SUCCESS 0
#define MI_FAILURE (-1)
/* Data types */
typedef struct smfi_str SMFICTX;
typedef struct smfi_str *SMFICTX_PTR;
typedef struct gacopyz_conn *gacopyz_conn_t;
typedef struct gacopyz_iod *gacopyz_iod_t;
/* Return type for the callbacks */
typedef enum {
SMFIS_CONTINUE,
SMFIS_REJECT,
SMFIS_DISCARD,
SMFIS_ACCEPT,
SMFIS_TEMPFAIL
} sfsistat;
typedef union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_un sunix;
} milter_sockaddr_t;
#define _SOCK_ADDR milter_sockaddr_t
struct smfiDesc
{
char *xxfi_name; /* filter name */
int xxfi_version; /* version code */
unsigned long xxfi_flags; /* flags */
/* Filters: */
/* connection info */
sfsistat (*xxfi_connect) (SMFICTX *, char *, milter_sockaddr_t *);
/* SMTP HELO command */
sfsistat (*xxfi_helo) (SMFICTX *, char *);
/* envelope sender */
sfsistat (*xxfi_envfrom) (SMFICTX *, char **);
/* envelope recipient */
sfsistat (*xxfi_envrcpt) (SMFICTX *, char **);
/* header */
sfsistat (*xxfi_header) (SMFICTX *, char *, char *);
/* end of header */
sfsistat (*xxfi_eoh) (SMFICTX *);
/* body block */
sfsistat (*xxfi_body) (SMFICTX *, unsigned char *, size_t);
/* end of message */
sfsistat (*xxfi_eom) (SMFICTX *);
/* message aborted */
sfsistat (*xxfi_abort) (SMFICTX *);
/* connection cleanup */
sfsistat (*xxfi_close) (SMFICTX *);
/* any unrecognized or unimplemented command (SMFI_VERSION > 2) */
sfsistat (*xxfi_unknown) (SMFICTX *, char *);
/* SMTP DATA command (SMFI_VERSION > 3) */
sfsistat (*xxfi_data) (SMFICTX *);
/* Extensions: */
int (*xxfi_start) (void); /* Child start callback */
int (*xxfi_finish) (void); /* Child finish callback */
int (*xxfi_idle) (gacopyz_conn_t); /* Idle handler */
};
/* Standard API calls */
extern int smfi_opensocket (int);
extern int smfi_register (struct smfiDesc);
extern int smfi_main (void);
extern int smfi_setbacklog (int);
extern int smfi_setdbg (int);
extern int smfi_settimeout (time_t);
extern int smfi_setconn (char *);
extern int smfi_stop (void);
#define smfi_getsymval gacopyz_getsymval
int smfi_addheader (SMFICTX *, char *, char *);
int smfi_chgheader (SMFICTX *, char *, int, char *);
int smfi_insheader (SMFICTX *, int, char *, char *);
int smfi_addrcpt (SMFICTX *, char *);
int smfi_delrcpt (SMFICTX *, char *);
int smfi_progress (SMFICTX *);
int smfi_replacebody (SMFICTX *, unsigned char *, int);
int smfi_quarantine (SMFICTX *ctx, char *reason);
#define smfi_setpriv gacopyz_setpriv
#define smfi_getpriv gacopyz_getpriv
size_t smfi_setmaxdatasize (size_t);
/* Replies: */
extern int smfi_setreply (SMFICTX *, char *, char *, char *);
int smfi_setmlreply (SMFICTX *, const char *, const char *, ...);
/* Extensions */
extern int smfi_set_foreground(int val);
extern int smfi_setlogmask(int logmask);
/* New API calls: */
int gacopyz_init(gacopyz_conn_t *pconn, struct smfiDesc *desc);
void gacopyz_free(gacopyz_conn_t conn);
int gacopyz_set_logmask(gacopyz_conn_t conn, int mask);
int gacopyz_get_logmask(gacopyz_conn_t conn, int *mask);
int gacopyz_set_foreground(gacopyz_conn_t conn, int fg);
int gacopyz_set_master_timeout(gacopyz_conn_t conn, struct timeval *timeout);
int gacopyz_get_master_timeout(gacopyz_conn_t conn, struct timeval *timeout);
int gacopyz_set_ctx_timeout(gacopyz_conn_t conn, struct timeval *timeout);
int gacopyz_get_ctx_timeout(gacopyz_conn_t conn, struct timeval *timeout);
int gacopyz_stop(gacopyz_conn_t conn);
int gacopyz_open(gacopyz_conn_t conn, const char *cstr,
int backlog, int rmsocket);
int gacopyz_parse_connection(const char *cstr,
char **pproto, char **pport, char **ppath);
int gacopyz_connect(gacopyz_conn_t *, struct smfiDesc *, const char *,
int backlog, int rmsocket);
int gacopyz_get_fd(gacopyz_conn_t);
int gacopyz_run(gacopyz_conn_t);
int gacopyz_register_child(gacopyz_conn_t conn, pid_t pid);
void gacopyz_cleanup_children(gacopyz_conn_t conn);
void gacopyz_cleanup_conn(gacopyz_conn_t conn);
void gacopyz_setup_signals(void);
char *gacopyz_getsymval (SMFICTX *, char *);
int gacopyz_setreply(SMFICTX *ctx, const char *rcode, const char *xcode,
const char *message);
int gacopyz_setmlreply_v(SMFICTX *ctx, const char *rcode, const char *xcode,
...);
int gacopyz_setmlreply_va(SMFICTX *ctx, const char *rcode, const char *xcode,
va_list ap);
int _gacopyz_setmlreply_va(SMFICTX *ctx, size_t max, const char *rcode,
const char *xcode, va_list ap);
int gacopyz_add_header(SMFICTX *ctx, const char *headerf,
const char *headerv);
int gacopyz_insert_header(SMFICTX *ctx, int index, const char *headerf,
const char *headerv);
int gacopyz_change_header(SMFICTX *ctx, int index, const char *headerf,
const char *headerv);
int gacopyz_add_rcpt(SMFICTX *ctx, const char *rcpt);
int gacopyz_del_rcpt(SMFICTX *ctx, const char *rcpt);
int gacopyz_replace_body(SMFICTX *ctx, unsigned char *bodyp, size_t bodylen);
int gacopyz_progress(SMFICTX *ctx);
int gacopyz_quarantine(SMFICTX *ctx, const char *reason);
int gacopyz_setpriv (SMFICTX *ctx, void *data);
void *gacopyz_getpriv (SMFICTX *ctx);
/* Logging (extensions) */
#define GACOPYZ_VBUFSIZE 69
size_t gacopyz_format_vbuf(char vbuf[GACOPYZ_VBUFSIZE], const char *buf,
size_t size);
void gacopyz_log(gacopyz_conn_t conn, int level, char *fmt, ...);
void gacopyz_io_log(gacopyz_iod_t iod, int level, char *fmt, ...);
void gacopyz_logmsg(int level, char *fmt, ...);
void _gacopyz_logdump(int logmask, int level, const char *pfx, const char *buf,
size_t size);
void gacopyz_logdump(gacopyz_conn_t conn, int level, const char *pfx,
const char *buf, size_t size);
void gacopyz_io_logdump(gacopyz_iod_t iod, int level, const char *pfx,
const char *buf, size_t size);
void gacopyz_set_logger(void (*)(int, char *, va_list));
void gacopyz_stderr_log_printer(int level, char *fmt, va_list ap);
void gacopyz_syslog_log_printer(int level, char *fmt, va_list ap);
int gacopyz_string_to_log_level(const char *str);
const char *gacopyz_log_level_to_string(int level);
/* Server */
typedef struct gacopyz_srv *gacopyz_srv_t;
int gacopyz_srv_create(gacopyz_srv_t *p, const char *name,
const char *portspec, unsigned logmask);
int gacopyz_srv_create_X(gacopyz_srv_t *p, const char *spec, unsigned logmask);
void gacopyz_srv_destroy(gacopyz_srv_t *p);
int gacopyz_srv_find_macro (gacopyz_srv_t srv, const char *name,
const char **pval);
void gacopyz_srv_define_macro (gacopyz_srv_t srv,
const char *name, const char *value);
void gacopyz_srv_define_macro0 (gacopyz_srv_t srv,
const char *name, const char *value,
int overwrite);
void gacopyz_srv_del_macro (gacopyz_srv_t srv, const char *name);
void gacopyz_srv_clear_macros (gacopyz_srv_t srv);
void gacopyz_srv_iterate_macros (gacopyz_srv_t srv,
int (*func) (const char *name,
const char *value,
void *data),
void *data);
void gacopyz_srv_count_macros (gacopyz_srv_t srv, size_t *count);
int gacopyz_srv_connect (gacopyz_srv_t srv);
int gacopyz_srv_init(gacopyz_srv_t srv);
int gacopyz_srv_negotiate(gacopyz_srv_t srv);
int gacopyz_srv_abort(gacopyz_srv_t srv);
int gacopyz_srv_quit(gacopyz_srv_t srv);
int gacopyz_srv_helo (gacopyz_srv_t p, const char *domain);
int gacopyz_srv_envfrom (gacopyz_srv_t p, char **argv);
int gacopyz_srv_envrcpt (gacopyz_srv_t p, char **argv);
int gacopyz_srv_header (gacopyz_srv_t p, char *name, char *value);
int gacopyz_srv_eoh (gacopyz_srv_t p);
int gacopyz_srv_body (gacopyz_srv_t p, unsigned char *str, size_t size);
int gacopyz_srv_eom (gacopyz_srv_t p, unsigned char *str, size_t size);
int gacopyz_srv_abort (gacopyz_srv_t p);
int gacopyz_srv_close (gacopyz_srv_t p);
int gacopyz_srv_data (gacopyz_srv_t p);
int gacopyz_srv_onerror(gacopyz_srv_t srv, int code);
void gacopyz_srv_set_memerror(gacopyz_srv_t srv,
void (*memerror)(gacopyz_srv_t, const char *,
unsigned int));
int gacopyz_srv_set_source(gacopyz_srv_t srv, unsigned long addr);
int gacopyz_srv_set_version(gacopyz_srv_t srv, int version);
int gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto);
int gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts);
#define GACOPYZ_WRITE_TIMEOUT 10
#define GACOPYZ_READ_TIMEOUT 10
#define GACOPYZ_EOM_TIMEOUT 300
#define GACOPYZ_CONNECT_TIMEOUT 300
#define GACOPYZ_TO_WRITE 0 /* Timeout for sending information */
#define GACOPYZ_TO_READ 1 /* Timeout waiting for a response */
#define GACOPYZ_TO_EOM 2 /* Timeout for ACK/NAK to EOM */
#define GACOPYZ_TO_CONNECT 3 /* Timeout for connect() */
#define GACOPYZ_TO_COUNT 4
void gacopyz_srv_set_all_timeouts(gacopyz_srv_t srv, struct timeval *tvp);
int gacopyz_srv_set_timeout(gacopyz_srv_t srv, unsigned n,
struct timeval *tvp);
int gacopyz_srv_set_timeout_sec(gacopyz_srv_t srv, unsigned n, time_t t);
void gacopyz_srv_reply(gacopyz_srv_t srv, char **msg, size_t *size);
#ifdef __cplusplus
}
#endif
#endif /* __gacopyz_h__ */