/* * Copyright (c) 2002-2006 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * * $Id: smtps.h,v 1.189 2007/11/02 04:54:58 ca Exp $ */ #ifndef SMTPS_H #define SMTPS_H 1 #include "sm/generic.h" #include "sm/rpool.h" #include "sm/time.h" #include "sm/io.h" #include "sm/rfc2821.h" #include "sm/regex.h" #include "sm/mta.h" #include "sm/cstr.h" #include "sm/rcb.h" #include "sm/net.h" #include "sm/log.h" #include "sm/cdb.h" #include "sm/hdrmod.h" #include "statethreads/st.h" #include "sm/tls.h" #include "sm/sasl.h" #include "sm/sm-conf.h" #include "sm/ssdef.h" #include "sm/sscnf.h" #if MTA_USE_PMILTER # include "sm/pmilter.h" # include "sm/pmfdef.h" #endif #include "smtps-str.h" #ifndef MTA_USE_RSAD # define MTA_USE_RSAD 2 #endif #ifndef SS_STATS # define SS_STATS 0 #endif #ifndef SSSE_S2Q_IDX # define SSSE_S2Q_IDX 1 #endif #ifndef SS_CHECK_LINE_LEN # define SS_CHECK_LINE_LEN 0 #endif #ifndef SS_CTX_CHECK # define SS_CTX_CHECK 1 #endif #ifndef SS_SESS_CHECK # define SS_SESS_CHECK 1 #endif #include "sm/sscnfdef.h" #ifndef SS_TA_CHECK /* ** Currently not useful because it's neither allocated nor freed, it's only ** cleaned out and it's a local variable in ss_hdl_session(). */ # define SS_TA_CHECK 0 #endif /* SS_TA_CHECK */ #if SS_TEST /* ** Values to trigger errors in certain places to test error handling. ** Currently these are used as bitflags which allows for combining them. ** Alternatively numbers might be used if there are many tests that don't ** need to be combined. */ # define SS_TEST_S2A_FAIL 0x00000001 /* cause a s2q comm. failure */ #endif #define SS_R_OK "250 2.0.0 Ok.\r\n" #define SS_R_CONT "354 Go.\r\n" #define SS_R_REJ "550 5.7.0 Rejected.\r\n" #define SS_R_EHLO_REQ "503 5.0.0 Need EHLO first\r\n" #define SS_R_SEQ "503 5.5.1 Bad sequence of commands.\r\n" #define SS_R_SYN_PAR "501 5.5.2 Syntax error in parameters or arguments.\r\n" #define SS_R_SYN_S_A "501 5.1.7 Bad sender's mailbox address syntax.\r\n" #define SS_R_SYN_R_A "501 5.1.3 Bad destination mailbox address syntax.\r\n" #define SS_R_SYN_ARG "501 5.5.2 Syntax error in argument(s).\r\n" #define SS_R_SYNE "501 5.5.2 Syntax error.\r\n" #define SS_R_NOTNOW "503 5.5.0 Not now\r\n" #define SS_R_TMP "451 4.5.0 Temporary error.\r\n" #define SS_R_SSD "421 4.3.0 Too busy.\r\n" #define SS_R_GREY "421 4.7.0 Come back later.\r\n" /* access check result structure, see sm/smar.h */ struct ss_acc_S { sm_ret_T ssa_map_result; /* result of map lookup: SM_ACC_x */ /* the next values are only valid if the map result is SM_ACC_FOUND */ sm_ret_T ssa_reply_code; /* sm/mta.h: */ sm_str_P ssa_reply_text; /* NULL by default */ }; typedef struct ss_acc_S ss_acc_T, *ss_acc_P; struct ss_ctx_S { #if SS_CTX_CHECK sm_magic_T sm_magic; #endif ss_cnf_T ssc_cnf; int ssc_id; /* smtps id */ sm_str_P ssc_hostname; /* hostname of server */ regex_t ssc_relayfrom; regex_t ssc_relayto; uint32_t ssc_flags; sm_log_ctx_P ssc_lctx; sm_logconfig_P ssc_lcfg; cdb_ctx_P ssc_cdb_ctx; st_utime_t ssc_mod_tmo; /* ss_cnf_mod_tmo as micro seconds */ /* ctx for SMTPS/QMGR communication subsystem */ s2q_ctx_P ssc_s2q_ctx; /* ctx for SMTPS/SMAR communication subsystem */ s2q_ctx_P ssc_s2a_ctx; time_t ssc_shutdown; /* when to shutdown forcefully */ #if MTA_USE_PMILTER /* ** currently only used for policy milter, could be general, ** but then the individual states of the modules need to be ** stored somewhere (QMGR, SMAR) */ sm_ret_T ssc_state; uint32_t ssc_pmcap; /* what does milter want? */ time_t ssc_pm_lasttry; uint32_t ssc_mac_names[PM_SMST_MAX][PM_MAX_MACROS]; /* ctx for SMTPS/Milter communication subsystem */ s2q_ctx_P ssc_s2m_ctx; #endif /* MTA_USE_PMILTER */ #if MTA_USE_TLS SSL_CTX *ssc_ssl_ctx; tlsl_ctx_P ssc_tlsl_ctx; #endif #if MTA_USE_SASL sm_sasl_ctx_P ssc_sasl_ctx; #endif }; /* SMTP Server Context flags */ #define SSC_FL_RELAYFROM 0x0001u /* relay from pattern ok */ #define SSC_FL_RELAYTO 0x0002u /* relay to pattern ok */ #define SSC_FL_TLS_OK 0x0004u /* TLS initialized ok */ #define SSC_FL_SASL_OK 0x0008u /* SASL initialized ok */ #define SSC_FL_TERMINATING 0x0010u /* server is terminating */ #define SSC_FL_RESTARTDEP 0x0020u /* ask to restart dependencies */ #define SSC_FL_SHUTDOWN 0x0040u /* shutdown requested */ #define SSC_FL_SHTDWN_TS 0x0080u /* shutdown timer started */ #define SSC_FL_SHTDWN_FRC 0x0100u /* shutdown forced */ #if MTA_USE_PMILTER #define SSC_FL_PM_USE 0x0100u /* use policy milter */ #define SSC_FL_PM_TRYCONN 0x0200u /* try to reconnect to policy milter */ /* it is possible to encode the milter connect state in this way: 00 do no use milter 01 use milter 10 try to reconnect to milter, tempfail on error 11 try to reconnect to milter, ssd on error but that's not worth it: it is not easily extendible for other error states. Hence the error state is stored in ssc_state */ /* trying to connect to policy milter (mutex) */ #define SSC_FL_PM_TRYING 0x0400u #endif /* MTA_USE_PMILTER */ #define SSC_SET_FLAG(ss_ctx, fl) (ss_ctx)->ssc_flags |= (fl) #define SSC_CLR_FLAG(ss_ctx, fl) (ss_ctx)->ssc_flags &= ~(fl) #define SSC_IS_FLAG(ss_ctx, fl) (((ss_ctx)->ssc_flags & (fl)) != 0) #define SSC_SET_CFLAG(ss_ctx, fl) (ss_ctx)->ssc_cnf.ss_cnf_cflags |= (fl) #define SSC_CLR_CFLAG(ss_ctx, fl) (ss_ctx)->ssc_cnf.ss_cnf_cflags &= ~(fl) #define SSC_IS_CFLAG(ss_ctx, fl) (((ss_ctx)->ssc_cnf.ss_cnf_cflags & (fl)) != 0) #define SSC_SET_MFLAG(ss_ctx, fl) (ss_ctx)->ssc_cnf.ss_cnf_mflags |= (fl) #define SSC_CLR_MFLAG(ss_ctx, fl) (ss_ctx)->ssc_cnf.ss_cnf_mflags &= ~(fl) #define SSC_IS_MFLAG(ss_ctx, fl) (((ss_ctx)->ssc_cnf.ss_cnf_mflags & (fl)) != 0) /* state of server */ #define SSC_ST_OK 0 /* everything ok */ #define SSC_ST_SSD 421 /* service shutting down */ #define SSC_ST_TEMP 450 /* answer everything with temp fail */ #define SSC_ST_PERM 550 /* permanently reject connections (unused?) */ #define SSC_SET_STATE(ss_ctx, newstate) do { \ if ((ss_ctx)->ssc_state < (newstate)) \ (ss_ctx)->ssc_state = (newstate); \ } while (0) #define SSC_SET_PMCAP(ss_ctx, fl) (ss_ctx)->ssc_pmcap |= (fl) #define SSC_CLR_PMCAP(ss_ctx, fl) (ss_ctx)->ssc_pmcap &= ~(fl) #define SSC_IS_PMCAP(ss_ctx, fl) (((ss_ctx)->ssc_pmcap & (fl)) != 0) #if MTA_USE_PMILTER # define S2s_IS_IOERR(ss_ctx) \ (S2Q_IS_IOERR(ss_ctx->ssc_s2a_ctx) \ || S2Q_IS_IOERR(ss_ctx->ssc_s2q_ctx) \ || S2Q_IS_IOERR(ss_ctx->ssc_s2m_ctx)) #else # define S2s_IS_IOERR(ss_ctx) \ (S2Q_IS_IOERR(ss_ctx->ssc_s2a_ctx) \ || S2Q_IS_IOERR(ss_ctx->ssc_s2q_ctx)) #endif /* question: put into ss_ctx_S?? */ extern uint Max_threads; extern uint Max_cur_threads; extern uint Ss_wait4srv; /* SMTP server session context */ struct ss_sess_S { #if SS_SESS_CHECK sm_magic_T sm_magic; #endif ss_ctx_P ssse_sctx; /* pointer to server context */ sm_file_T *ssse_fp; /* file to use */ sm_str_P ssse_rd; /* smtp read buffer */ sm_str_P ssse_wr; /* smtp write buffer */ sm_str_P ssse_str; /* str for general use */ sm_rpool_P ssse_rpool; uint ssse_idx; /* index for ss_sck_ctx[] array */ uint32_t ssse_flags; uint32_t ssse_cnf_flags; uint ssse_state; in_addr_T ssse_client; /* fixme: use a generic struct! */ sm_ret_T ssse_cltrslv; /* result of resolving addr/hostname */ sm_cstr_P ssse_cltname; /* resolved hostname */ sm_str_P ssse_helo; /* helo param */ ss_ta_P ssse_ta; /* current transaction */ uint ssse_badcmds; /* bad commands */ uint ssse_nopcmds; /* number of "useless" commands */ uint ssse_invldaddr; /* #cmds with invalid addresses */ sessta_id_T ssse_id; sm_rcb_P ssse_rcb; /* rcb for communication with QMGR */ st_cond_t ssse_cond_rd; /* receiving data from QMGR */ int ssse_s2q_idx; /* index in s2q_ctx->s2q_sess */ uint ssse_ta_tot; /* number of transactions */ uint ssse_rcpts_tot; /* total recipients */ uint ssse_max_line_len; /* max line length */ ss_acc_T ssse_acc; time_t ssse_connect; sm_ret_T ssse_maprescnf; /* map lookup result for session conf */ /* id of s2q "server" (qmgr/smar/pmilter) to which this session is connected */ int ssse_s2q_id[SS_MAX_COMM_SRVS]; sm_conf_T *ssse_cnf; tlsreq_cnf_T ssse_tlsreq_cnf; char *ssse_feat_name; #if MTA_USE_TLS SSL *ssse_con; sm_file_T *ssse_fptls; tlsi_ctx_P ssse_tlsi; #endif #if MTA_USE_SASL sasl_conn_t *ssse_sasl_conn; uint ssse_sasl_ext_ssf; uint ssse_sasl_tries; uint ssse_sasl_state; char *ssse_sasl_mech_list; #endif /* MTA_USE_SASL */ #if MTA_USE_PMILTER sm_str_P ssse_mac_values[PM_SMST_MAX][PM_MAX_MACROS]; sm_str_P ssse_macv; # if MTA_USE_SASL sm_str_P ssse_sasl_mech; sm_str_P ssse_sasl_authen; sm_str_P ssse_sasl_author; # endif /* MTA_USE_SASL */ #endif /* MTA_USE_PMILTER */ #if 0 session-id /* session identifier, maybe obtained from QMGR */ host /* identification of connecting host (IP address, host name, ident) */ fd /* file descriptor/handle for connection */ helo-host /* host name from HELO/EHLO */ access times /* start time, last read, last write */ status /* EHLO/HELO, AUTH, STARTTLS (see above) */ features /* features offered: AUTH, TLS, EXPN, ... */ workarounds /* work around bugs in client */ reject-msg /* message to use for rejections (nullserver) */ auth /* AUTH context */ starttls /* TLS context */ transaction /* pointer to current transaction */ #endif /* 0 */ }; #define SSSE_S2Q_IDX_NONE (-1) /* initial value for s2q_idx */ #define SSSE_S2Q_IDX_CLSD (-2) /* connection has been closed */ #define S2Q_ID_NONE (-1) /* initial value for s2q_id */ typedef struct ss_mail_S ss_mail_T, *ss_mail_P; typedef struct ss_rcpt_S ss_rcpt_T, *ss_rcpt_P; typedef struct ss_rcpts_S ss_rcpts_T, *ss_rcpts_P; struct ss_mail_S { sm_a2821_T ssm_a2821; /* mail */ /* parameters?? */ sm_str_P ssm_pa; }; /* ** Note: currently this data isn't used anywhere: the recipients ** are stored in here but the data isn't read. It could be used ** to send rcpts in "chunks" to qmgr instead of one by one. ** Only for pmilter recipient additions/deletions this data will be read. */ struct ss_rcpt_S { sm_a2821_T ssr_a2821; /* rcpt */ /* parameters?? */ rcpt_idx_T ssr_idx; /* rcpt idx */ TAILQ_ENTRY(ss_rcpt_S) ssr_link; /* links */ #if MTA_USE_PMILTER ushort ssr_type; /* rcpt type: add/delete */ # if MTA_USE_RSAD sm_ret_T ssr_rcode; /* sm/mta.h */ # endif #endif }; TAILQ_HEAD(ss_rcpts_S, ss_rcpt_S); /* operations on rcpt lists */ #define SS_RCPTS_INIT(rcpts) TAILQ_INIT(rcpts) #define SS_RCPTS_EMPTY(rcpts) TAILQ_EMPTY(rcpts) #define SS_RCPTS_FIRST(rcpts) TAILQ_FIRST(rcpts) #define SS_RCPTS_END(rcpts) TAILQ_END(rcpts) #define SS_RCPTS_NEXT(rcpt) TAILQ_NEXT(rcpt, ssr_link) #define SS_RCPTS_INSERT_TAIL(rcpts, rcpt) TAILQ_INSERT_TAIL(rcpts, rcpt, ssr_link) #define SS_RCPTS_INSERT_HEAD(rcpts, rcpt) TAILQ_INSERT_HEAD(rcpts, rcpt, ssr_link) #define SS_RCPTS_REMOVE(rcpts, rcpt) TAILQ_REMOVE(rcpts, rcpt, ssr_link) #define SS_RCPTS_REMOVE_FREE(ta, rcpts, rcpt) do { \ TAILQ_REMOVE((rcpts), (rcpt), ssr_link); \ ssr_rcpt_free((ta), (rcpt)); \ } while (0) /* ** SMTPS transaction ** Note: an SMTPS session always has an SMTP transaction associated, ** even if no transaction has been started yet. Check ssta_state ** to figure out in which state the transaction is (SSTA_ST_*). */ struct ss_ta_S { #if SS_TA_CHECK sm_magic_T sm_magic; #endif sm_rpool_P ssta_rpool; uint ssta_flags; sm_hdrmodhd_P ssta_hdrmodhd; ss_mail_P ssta_mail; /* mail from */ ss_acc_T ssta_mail_acc; /* access check for mail */ ss_rcpts_T ssta_rcpts; /* rcpts */ /* ** Access check for current recipient. If multiple recipients ** can be checked concurrently, then this must be in ss_rcpt_S. */ ss_acc_T ssta_rcpt_acc; ss_acc_T ssta_rcpt_acc2; uint ssta_rcpts_tot; /* number of recipients total */ uint ssta_rcpts_ok; /* number of recipients ok */ uint ssta_rcpts_len; /* length of all recipient addresses */ uint ssta_state; off_t ssta_msg_sz_b; /* messages size (bytes) */ sessta_id_T ssta_id; sm_file_T *ssta_dfp; /* cdb (currently: fp) */ /* message-id, used for logging and pmilter */ sm_str_P ssta_msgid; uint ssta_badcmds; /* bad commands */ uint ssta_nopcmds; /* number of "useless" commands */ uint ssta_invldaddr; /* #cmds with invalid addresses */ #if 0 transaction-id /* transaction identifier, maybe obtained from QMGR */ cdb-id /* CDB identifier (obtained from cdb?) */ cmd-failures /* number of failures for certain commands */ #endif #if SS_EHLO_ACCESS_CHK ss_acc_T ssta_ehlo_acc; /* access check for ehlo */ #endif #if MTA_USE_PMILTER sm_str_P ssta_mail_new; /* new MAIL address */ uint ssta_rcpts_tot_orig; uint ssta_rcpts_ok_orig; ss_acc_T ssta_msg_acc; /* result of msg check */ uint ssta_msg_st; /* state of message replacement */ uint ssta_eot_state; sm_file_T *ssta_msg_fp; sm_cstr_P ssta_cdb_id; /* cdb-id */ off_t ssta_rmsg_sz_b; /* new messages size (bytes) */ uint ssta_hops; # if MTA_USE_RSAD uint ssta_nreplies; /* number of replies */ uint32_t *ssta_rcodes; sm_str_P *ssta_replies; /* replies */ # endif #endif /* MTA_USE_PMILTER */ }; /* SMTP Server Session flags */ /* #define SSSE_FL_ACTIVE 0x00000001 * session is active (currently UNUSED!) */ /* local only, don't accept, don't tell QMGR (set but not checked) */ #define SSSE_FL_LOCAL_SSD 0x00000002 #define SSSE_FL_CSEID 0x00000004 /* tell QMGR about session close */ #define SSSE_FL_NULL 0x00000008 /* null server */ #define SSSE_FL_QUICK 0x00000010 /* session check returned QUICK */ #define SSSE_FL_SASL_OK 0x00000020 /* SASL initialized ok */ #define SSSE_FL_AUTH 0x00000040 /* AUTH (only once, additive) */ #define SSSE_FL_STARTTLS 0x00000080 /* STARTTLS is in use */ #define SSSE_FL_HELO 0x00000100 /* client used HELO instead of EHLO */ #define SSSE_FL_CLT_RLY_TMP 0x00001000 /* clt relay: temp.error during test */ #define SSSE_FL_CLIENT_RELAY 0x00002000 /* client can relay */ #define SSSE_FL_CLIENT_OK 0x00004000 /* client OK (access map) */ #define SSSE_FL_DISCARD 0x00008000 /* discard entire session */ #if MTA_USE_PMILTER /* use policy milter in this session */ # define SSSE_FL_PM_USE 0x00020000 /* pmilter has been called in this session */ # define SSSE_FL_PM_CALLED 0x00040000 #endif #define SSSE_FL_GREYCHKD 0x00080000 /* grey check done for session */ #define SSSE_FL_GREYLSTD 0x00100000 /* greylisted */ #define SSSE_FL_CONN_LOGGED 0x00200000 /* connection info has been logged */ #define SSSE_SET_FLAG(ss_sess, fl) (ss_sess)->ssse_flags |= (fl) #define SSSE_CLR_FLAG(ss_sess, fl) (ss_sess)->ssse_flags &= ~(fl) #define SSSE_IS_FLAG(ss_sess, fl) (((ss_sess)->ssse_flags & (fl)) != 0) #define SSSE_ARE_FLAGS(ss_sess, fl) (((ss_sess)->ssse_flags & (fl)) == (fl)) #define SSSE_SET_CFLAG(ss_sess, fl) (ss_sess)->ssse_cnf_flags |= (fl) #define SSSE_CLR_CFLAG(ss_sess, fl) (ss_sess)->ssse_cnf_flags &= ~(fl) #define SSSE_IS_CFLAG(ss_sess, fl) (((ss_sess)->ssse_cnf_flags & (fl)) != 0) /* session states (fixme: some of these belong into SSSE flags) */ #define SSSE_ST_NONE 0x0000 /* no session active */ #define SSSE_ST_CONNECTING 0x0001 /* connection attempt */ #define SSSE_ST_CONNECTED 0x0002 /* connection succeeded */ #define SSSE_ST_GREETED 0x0004 /* sent greeting */ #define SSSE_ST_EHLO 0x0010 /* EHLO; aborts transaction */ #define SSSE_ST_HELO 0x0020 /* HELO; aborts transaction */ #define SSSE_ST_QUIT 0x0800 /* QUIT command received */ /* transaction states, these must be sorted! */ #define SSTA_ST_NONE 0x00 /* must be 0 */ #define SSTA_ST_INIT 0x01 /* ta initialized, rpool created, etc */ #define SSTA_ST_MAIL 0x02 /* MAIL received */ #define SSTA_ST_RCPT 0x04 /* RCPT received */ #define SSTA_ST_DATA 0x08 /* DATA received */ #define SSTA_ST_DOT 0x10 /* Final dot received */ /* a transaction is "active" */ #define SSTA_IS_ACTIVE(ss_ta) ((ss_ta)->ssta_state >= SSTA_ST_MAIL) /* SMTP Server Transaction flags */ #define SSTA_FL_NONE 0x00000000 /* #define SSTA_FL_MAIL_QCK 0x00000001 * mail check returned QUICK */ /* #define SSTA_FL_RCPT_QCK 0x00000002 * rcpt check returned QUICK */ #define SSTA_FL_LL_EXC 0x00000004 /* maximum line length exceeded */ #define SSTA_FL_DISCARD 0x00000008 /* discard entire transaction */ #define SSTA_FL_DSCRD_RCPT 0x00000010 /* discarded at least one recipient */ #define SSTA_FL_DELAY_CHKS 0x00000020 /* delay checks */ #define SSTA_FL_CDB_EXISTS 0x00000040 /* cdb exists */ #define SSTA_FL_DSN 0x00000080 /* MAIL From:<> (DSN) */ #if MTA_USE_PMILTER #define SSTA_FL_PM_USE 0x00000100 /* use pmilter for this TA */ #define SSTA_FL_PM_CALLED 0x00000200 /* pmilter has been called for this TA */ #define SSTA_FL_PM_SKIP_MSG 0x00000400 /* pmilter has been called for this TA */ #endif #define SSTA_FL_XVERP 0x00002000 /* XVERB for MAIL */ #if MTA_USE_PMILTER #define SSTA_FL_RCPT_MOD 0x00004000 /* recipient modifications exist */ #define SSTA_FL_MAIL_MOD 0x00008000 /* MAIL modification exist */ #endif #define SSTA_FL_RSAD 0x00020000 /* RSAD for MAIL */ #define SSTA_SET_FLAG(ss_ta, fl) (ss_ta)->ssta_flags |= (fl) #define SSTA_CLR_FLAG(ss_ta, fl) (ss_ta)->ssta_flags &= ~(fl) #define SSTA_IS_FLAG(ss_ta, fl) (((ss_ta)->ssta_flags & (fl)) != 0) #if MTA_USE_PMILTER #define SSTA_ST_MR_NONE 0x0000 /* Must be 0 */ #define SSTA_ST_MR_CDB_OK 0x0001 /* cdb created */ #define SSTA_ST_MR_CDB_NONE 0x0002 /* cdb creation failed */ #define SSTA_ST_MR_CDB_WR 0x0004 /* writing to cdb */ #define SSTA_ST_MR_CDB_FAIL 0x0002 /* cdb write failed */ #define SSTA_ST_MR_CDB_CLSD 0x0008 /* cdb closed */ sm_ret_T ss_replacemsg(ss_sess_P _ss_sess, uint32_t _l); sm_ret_T ss_rplcmsg(ss_sess_P _ss_sess); #endif /* MTA_USE_PMILTER */ typedef char *ss_id_T; typedef struct ss_socket_ctx_S ss_socket_ctx_T; struct ss_socket_ctx_S { st_netfd_t sssc_lfd; /* Listening socket */ char *sssc_addr; /* Bind address */ int sssc_port; /* Port */ int sssc_wait_threads; /* threads waiting to accept */ int sssc_busy_threads; /* threads processing request */ int sssc_maxb_threads; /* max # of threads */ ulong sssc_rqst_count; /* Total # of processed requests */ ulong sssc_ta_count; /* Total # of processed transactions */ }; sm_ret_T ss_read_cnf(ss_ctx_P _ss_ctx, const char *_fn, sm_conf_T **_psmc); sm_ret_T ss_chk_cnf(ss_ctx_P _ss_ctx); sm_ret_T ss_id_init(id_count_T _id_val); sm_ret_T ss_id_end(void); sm_ret_T ss_id_next(int _smtpsid, ss_id_T _id); #if 0 sm_ret_T ss_id_set(id_count_T _id_val); #endif sm_ret_T ss_relay_to(ss_ctx_P _ss_ctx, const char *_str); sm_ret_T ss_relay_from(ss_ctx_P _ss_ctx, const char *_str); #define SS_PHASE_OTHER 0 /* no special treatment */ #define SS_PHASE_INIT 1 /* initial 220 greeting */ #define SS_PHASE_EHLO 2 /* EHLO response */ #define SS_PHASE_TLS 3 /* STARTTLS response */ #define SS_PHASE_AUTH 4 /* AUTH response */ #define SS_PHASE_MAIL 5 /* MAIL response */ #define SS_PHASE_RCPT 6 /* RCPT response */ #define SS_PHASE_DATA 7 /* DATA response */ #define SS_PHASE_DOT 8 /* response to final dot */ #define SS_PHASE_QUIT 9 /* QUIT */ #define SS_PHASE_NOREPLY 10 /* no reply requested */ sm_ret_T ss_crt_reply(sm_str_P _reply, sm_ret_T _ret, int _phase, bool _new); /* #if SSQ_DEBUG */ void dump_thrd_info(void); /* #endif */ /* useful macros */ #define WAIT_THREADS(i) (ss_sck_ctx[i].sssc_wait_threads) #define BUSY_THREADS(i) (ss_sck_ctx[i].sssc_busy_threads) #define MAXB_THREADS(i) (ss_sck_ctx[i].sssc_maxb_threads) #define TOTAL_THREADS(i) (WAIT_THREADS(i) + BUSY_THREADS(i)) #define RQST_COUNT(i) (ss_sck_ctx[i].sssc_rqst_count) #define TA_COUNT(i) (ss_sck_ctx[i].sssc_ta_count) #if SS_CTX_CHECK # define SM_IS_SS_CTX(ss_ctx) SM_REQUIRE_ISA((ss_ctx), SM_SS_CTX_MAGIC) #else # define SM_IS_SS_CTX(ss_ctx) SM_REQUIRE((ss_ctx) != NULL) #endif #if SS_SESS_CHECK # define SM_IS_SS_SESS(ss_sess) SM_REQUIRE_ISA((ss_sess), SM_SS_SESS_MAGIC) #else # define SM_IS_SS_SESS(ss_sess) SM_REQUIRE((ss_sess) != NULL) #endif #if SS_TA_CHECK # define SM_IS_SS_TA(ss_ta) SM_REQUIRE_ISA((ss_ta), SM_SS_TA_MAGIC) #else # define SM_IS_SS_TA(ss_ta) SM_REQUIRE((ss_ta) != NULL) #endif #endif /* SMTPS_H */