1#![allow(non_camel_case_types)]
4
5use libc::{c_char, c_int, c_uchar, c_uint, c_ulong, c_void, size_t};
6
7pub const SMFI_VERSION: c_int = 0x1000001;
8pub const SMFI_PROT_VERSION: c_int = 6;
9
10pub const MILTER_LEN_BYTES: size_t = 4;
11pub const MILTER_OPTLEN: size_t = MILTER_LEN_BYTES * 3;
12pub const MILTER_CHUNK_SIZE: size_t = 65535;
13pub const MILTER_MAX_DATA_SIZE: size_t = 65535;
14
15pub const SMFI_V1_ACTS: c_ulong = 0xf;
16pub const SMFI_V2_ACTS: c_ulong = 0x3f;
17pub const SMFI_CURR_ACTS: c_ulong = 0x1ff;
18
19pub const SMFIA_UNKNOWN: c_uchar = b'U';
20pub const SMFIA_UNIX: c_uchar = b'L';
21pub const SMFIA_INET: c_uchar = b'4';
22pub const SMFIA_INET6: c_uchar = b'6';
23
24pub const SMFIC_ABORT: c_uchar = b'A';
25pub const SMFIC_BODY: c_uchar = b'B';
26pub const SMFIC_CONNECT: c_uchar = b'C';
27pub const SMFIC_MACRO: c_uchar = b'D';
28pub const SMFIC_BODYEOB: c_uchar = b'E';
29pub const SMFIC_HELO: c_uchar = b'H';
30pub const SMFIC_QUIT_NC: c_uchar = b'K';
31pub const SMFIC_HEADER: c_uchar = b'L';
32pub const SMFIC_MAIL: c_uchar = b'M';
33pub const SMFIC_EOH: c_uchar = b'N';
34pub const SMFIC_OPTNEG: c_uchar = b'O';
35pub const SMFIC_QUIT: c_uchar = b'Q';
36pub const SMFIC_RCPT: c_uchar = b'R';
37pub const SMFIC_DATA: c_uchar = b'T';
38pub const SMFIC_UNKNOWN: c_uchar = b'U';
39
40pub const SMFIR_ADDRCPT: c_uchar = b'+';
41pub const SMFIR_DELRCPT: c_uchar = b'-';
42pub const SMFIR_ADDRCPT_PAR: c_uchar = b'2';
43pub const SMFIR_SHUTDOWN: c_uchar = b'4';
44pub const SMFIR_ACCEPT: c_uchar = b'a';
45pub const SMFIR_REPLBODY: c_uchar = b'b';
46pub const SMFIR_CONTINUE: c_uchar = b'c';
47pub const SMFIR_DISCARD: c_uchar = b'd';
48pub const SMFIR_CHGFROM: c_uchar = b'e';
49pub const SMFIR_CONN_FAIL: c_uchar = b'f';
50pub const SMFIR_ADDHEADER: c_uchar = b'h';
51pub const SMFIR_INSHEADER: c_uchar = b'i';
52pub const SMFIR_SETSYMLIST: c_uchar = b'l';
53pub const SMFIR_CHGHEADER: c_uchar = b'm';
54pub const SMFIR_PROGRESS: c_uchar = b'p';
55pub const SMFIR_QUARANTINE: c_uchar = b'q';
56pub const SMFIR_REJECT: c_uchar = b'r';
57pub const SMFIR_SKIP: c_uchar = b's';
58pub const SMFIR_TEMPFAIL: c_uchar = b't';
59pub const SMFIR_REPLYCODE: c_uchar = b'y';
60
61pub const SMFIP_NOCONNECT: c_ulong = 0x1;
62pub const SMFIP_NOHELO: c_ulong = 0x2;
63pub const SMFIP_NOMAIL: c_ulong = 0x4;
64pub const SMFIP_NORCPT: c_ulong = 0x8;
65pub const SMFIP_NOBODY: c_ulong = 0x10;
66pub const SMFIP_NOHDRS: c_ulong = 0x20;
67pub const SMFIP_NOEOH: c_ulong = 0x40;
68pub const SMFIP_NR_HDR: c_ulong = 0x80;
69pub const SMFIP_NOHREPL: c_ulong = SMFIP_NR_HDR;
70pub const SMFIP_NOUNKNOWN: c_ulong = 0x100;
71pub const SMFIP_NODATA: c_ulong = 0x200;
72pub const SMFIP_SKIP: c_ulong = 0x400;
73pub const SMFIP_RCPT_REJ: c_ulong = 0x800;
74pub const SMFIP_NR_CONN: c_ulong = 0x1000;
75pub const SMFIP_NR_HELO: c_ulong = 0x2000;
76pub const SMFIP_NR_MAIL: c_ulong = 0x4000;
77pub const SMFIP_NR_RCPT: c_ulong = 0x8000;
78pub const SMFIP_NR_DATA: c_ulong = 0x10000;
79pub const SMFIP_NR_UNKN: c_ulong = 0x20000;
80pub const SMFIP_NR_EOH: c_ulong = 0x40000;
81pub const SMFIP_NR_BODY: c_ulong = 0x80000;
82pub const SMFIP_HDR_LEADSPC: c_ulong = 0x100000;
83pub const SMFIP_MDS_256K: c_ulong = 0x10000000;
84pub const SMFIP_MDS_1M: c_ulong = 0x20000000;
85
86pub const SMFI_V1_PROT: c_ulong = 0x3f;
87pub const SMFI_V2_PROT: c_ulong = 0x7f;
88pub const SMFI_CURR_PROT: c_ulong = 0x1fffff;
89pub const SMFI_INTERNAL: c_ulong = 0x70000000;
90
91pub const MI_SUCCESS: c_int = 0;
92pub const MI_FAILURE: c_int = -1;
93pub const MI_CONTINUE: c_int = 1;
94
95pub const SMFIF_NONE: c_ulong = 0x0;
96pub const SMFIF_ADDHDRS: c_ulong = 0x1;
97pub const SMFIF_CHGBODY: c_ulong = 0x2;
98pub const SMFIF_MODBODY: c_ulong = SMFIF_CHGBODY;
99pub const SMFIF_ADDRCPT: c_ulong = 0x4;
100pub const SMFIF_DELRCPT: c_ulong = 0x8;
101pub const SMFIF_CHGHDRS: c_ulong = 0x10;
102pub const SMFIF_QUARANTINE: c_ulong = 0x20;
103pub const SMFIF_CHGFROM: c_ulong = 0x40;
104pub const SMFIF_ADDRCPT_PAR: c_ulong = 0x80;
105pub const SMFIF_SETSYMLIST: c_ulong = 0x100;
106
107pub const SMFIM_NOMACROS: c_int = -1;
108pub const SMFIM_FIRST: c_int = 0;
109pub const SMFIM_CONNECT: c_int = 0;
110pub const SMFIM_HELO: c_int = 1;
111pub const SMFIM_ENVFROM: c_int = 2;
112pub const SMFIM_ENVRCPT: c_int = 3;
113pub const SMFIM_DATA: c_int = 4;
114pub const SMFIM_EOM: c_int = 5;
115pub const SMFIM_EOH: c_int = 6;
116pub const SMFIM_LAST: c_int = 6;
117
118pub const SMFIS_CONTINUE: c_int = 0;
119pub const SMFIS_REJECT: c_int = 1;
120pub const SMFIS_DISCARD: c_int = 2;
121pub const SMFIS_ACCEPT: c_int = 3;
122pub const SMFIS_TEMPFAIL: c_int = 4;
123pub const SMFIS_NOREPLY: c_int = 7;
124pub const SMFIS_SKIP: c_int = 8;
125pub const SMFIS_ALL_OPTS: c_int = 10;
126
127#[repr(C)]
128#[derive(Debug, Copy, Clone)]
129pub struct smfi_str {
130 _private: [u8; 0],
131}
132
133pub type SMFICTX = smfi_str;
134pub type SMFICTX_PTR = *mut smfi_str;
135pub type smfiDesc_str = smfiDesc;
136pub type smfiDesc_ptr = *mut smfiDesc;
137pub type sfsistat = c_int;
138
139#[repr(C)]
140#[derive(Debug, Copy, Clone)]
141pub struct smfiDesc {
142 pub xxfi_name: *mut c_char,
143 pub xxfi_version: c_int,
144 pub xxfi_flags: c_ulong,
145 pub xxfi_connect: Option<unsafe extern "C" fn(ctx: *mut SMFICTX, hostname: *mut c_char, hostaddr: *mut libc::sockaddr) -> sfsistat>,
146 pub xxfi_helo: Option<unsafe extern "C" fn(ctx: *mut SMFICTX, helohost: *mut c_char) -> sfsistat>,
147 pub xxfi_envfrom: Option<unsafe extern "C" fn(ctx: *mut SMFICTX, argv: *mut *mut c_char) -> sfsistat>,
148 pub xxfi_envrcpt: Option<unsafe extern "C" fn(ctx: *mut SMFICTX, argv: *mut *mut c_char) -> sfsistat>,
149 pub xxfi_header: Option<unsafe extern "C" fn(ctx: *mut SMFICTX, headerf: *mut c_char, headerv: *mut c_char) -> sfsistat>,
150 pub xxfi_eoh: Option<unsafe extern "C" fn(ctx: *mut SMFICTX) -> sfsistat>,
151 pub xxfi_body: Option<unsafe extern "C" fn(ctx: *mut SMFICTX, bodyp: *mut c_uchar, bodylen: size_t) -> sfsistat>,
152 pub xxfi_eom: Option<unsafe extern "C" fn(ctx: *mut SMFICTX) -> sfsistat>,
153 pub xxfi_abort: Option<unsafe extern "C" fn(ctx: *mut SMFICTX) -> sfsistat>,
154 pub xxfi_close: Option<unsafe extern "C" fn(ctx: *mut SMFICTX) -> sfsistat>,
155 pub xxfi_unknown: Option<unsafe extern "C" fn(ctx: *mut SMFICTX, arg: *const c_char) -> sfsistat>,
156 pub xxfi_data: Option<unsafe extern "C" fn(ctx: *mut SMFICTX) -> sfsistat>,
157 pub xxfi_negotiate: Option<
158 unsafe extern "C" fn(
159 ctx: *mut SMFICTX,
160 f0: c_ulong,
161 f1: c_ulong,
162 f2: c_ulong,
163 f3: c_ulong,
164 pf0: *mut c_ulong,
165 pf1: *mut c_ulong,
166 pf2: *mut c_ulong,
167 pf3: *mut c_ulong,
168 ) -> sfsistat,
169 >,
170}
171
172extern "C" {
173 pub fn smfi_opensocket(rmsocket: c_int) -> c_int;
174 pub fn smfi_register(descr: smfiDesc) -> c_int;
175 pub fn smfi_main() -> c_int;
176 pub fn smfi_setbacklog(obacklog: c_int) -> c_int;
177 pub fn smfi_setdbg(level: c_int) -> c_int;
178 pub fn smfi_settimeout(otimeout: c_int) -> c_int;
179 pub fn smfi_setconn(oconn: *mut c_char) -> c_int;
180 pub fn smfi_stop() -> c_int;
181 pub fn smfi_setmaxdatasize(sz: size_t) -> size_t;
182 pub fn smfi_version(pmajor: *mut c_uint, pminor: *mut c_uint, ppl: *mut c_uint) -> c_int;
183 pub fn smfi_getsymval(ctx: *mut SMFICTX, symname: *mut c_char) -> *mut c_char;
184 pub fn smfi_setreply(ctx: *mut SMFICTX, rcode: *mut c_char, xcode: *mut c_char, message: *mut c_char) -> c_int;
185 pub fn smfi_setmlreply(ctx: *mut SMFICTX, rcode: *const c_char, xcode: *const c_char, ...) -> c_int;
186 pub fn smfi_addheader(ctx: *mut SMFICTX, headerf: *mut c_char, headerv: *mut c_char) -> c_int;
187 pub fn smfi_chgheader(ctx: *mut SMFICTX, headerf: *mut c_char, index: c_int, headerv: *mut c_char) -> c_int;
188 pub fn smfi_insheader(ctx: *mut SMFICTX, index: c_int, headerf: *mut c_char, headerv: *mut c_char) -> c_int;
189 pub fn smfi_chgfrom(ctx: *mut SMFICTX, mail: *mut c_char, args: *mut c_char) -> c_int;
190 pub fn smfi_addrcpt(ctx: *mut SMFICTX, rcpt: *mut c_char) -> c_int;
191 pub fn smfi_addrcpt_par(ctx: *mut SMFICTX, rcpt: *mut c_char, args: *mut c_char) -> c_int;
192 pub fn smfi_delrcpt(ctx: *mut SMFICTX, rcpt: *mut c_char) -> c_int;
193 pub fn smfi_progress(ctx: *mut SMFICTX) -> c_int;
194 pub fn smfi_replacebody(ctx: *mut SMFICTX, bodyp: *mut c_uchar, bodylen: c_int) -> c_int;
195 pub fn smfi_quarantine(ctx: *mut SMFICTX, reason: *mut c_char) -> c_int;
196 pub fn smfi_setpriv(ctx: *mut SMFICTX, privatedata: *mut c_void) -> c_int;
197 pub fn smfi_getpriv(ctx: *mut SMFICTX) -> *mut c_void;
198 pub fn smfi_setsymlist(ctx: *mut SMFICTX, stage: c_int, macros: *mut c_char) -> c_int;
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn all_current_protocol_opts() {
207 let protocol_opts = SMFIP_NOCONNECT
208 | SMFIP_NOHELO
209 | SMFIP_NOMAIL
210 | SMFIP_NORCPT
211 | SMFIP_NOBODY
212 | SMFIP_NOHDRS
213 | SMFIP_NOEOH
214 | SMFIP_NR_HDR
215 | SMFIP_NOUNKNOWN
216 | SMFIP_NODATA
217 | SMFIP_SKIP
218 | SMFIP_RCPT_REJ
219 | SMFIP_NR_CONN
220 | SMFIP_NR_HELO
221 | SMFIP_NR_MAIL
222 | SMFIP_NR_RCPT
223 | SMFIP_NR_DATA
224 | SMFIP_NR_UNKN
225 | SMFIP_NR_EOH
226 | SMFIP_NR_BODY
227 | SMFIP_HDR_LEADSPC;
228
229 assert_eq!(protocol_opts, SMFI_CURR_PROT);
230 }
231
232 #[test]
233 fn smfi_version_returns_version() {
234 let (mut a, mut b, mut c) = (0, 0, 0);
235
236 let result = unsafe { smfi_version(&mut a, &mut b, &mut c) };
237
238 assert_eq!(result, MI_SUCCESS);
239 assert_eq!((a, b, c), (1, 0, 1));
240 }
241
242 #[test]
243 fn register_milter() {
244 let desc = smfiDesc {
245 xxfi_name: "test\0".as_ptr() as _,
246 xxfi_version: SMFI_VERSION,
247 xxfi_flags: 0,
248 xxfi_connect: None,
249 xxfi_helo: None,
250 xxfi_envfrom: None,
251 xxfi_envrcpt: None,
252 xxfi_header: None,
253 xxfi_eoh: None,
254 xxfi_body: None,
255 xxfi_eom: None,
256 xxfi_abort: None,
257 xxfi_close: None,
258 xxfi_unknown: None,
259 xxfi_data: None,
260 xxfi_negotiate: None,
261 };
262
263 let result = unsafe { smfi_register(desc) };
264
265 assert_eq!(result, MI_SUCCESS);
266 }
267}