1 /* This file is part of gacopyz.
2    Copyright (C) 2006-2021 Sergey Poznyakoff
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #ifndef __gacopyz_h__
18 # define __gacopyz_h__
19 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <netinet/in.h>
25 #include <sys/un.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <netdb.h>
29 #include <arpa/inet.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <syslog.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <signal.h>
39 #include <ctype.h>
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 #define GACOPYZ_VERSION_MAJOR 2
46 #define GACOPYZ_VERSION_MINOR 0
47 
48 /* Implementation version number */
49 #define SMFI_VERSION      0x01000000
50 
51 #define SM_LM_VRS_MAJOR(v)      (((v) & 0x7f000000) >> 24)
52 #define SM_LM_VRS_MINOR(v)      (((v) & 0x007fff00) >> 8)
53 #define SM_LM_VRS_PLVL(v)       ((v) & 0x0000007f)
54 
55 #define GACOPYZ_SM_MKVER(maj,min,pat) \
56 	((((maj) & 0x7f)<<24) | (((min) & 0x7ffff) << 8) | ((pat) & 0x7f))
57 
58 /* Milter protocol version */
59 #define SMFI_PROT_VERSION 6
60 
61 /* Minimal supported protocol version */
62 #define SMFI_PROT_VERSION_MIN 2
63 
64 /* commands: don't use anything smaller than ' ' */
65 #define SMFIC_ABORT             'A'     /* Abort */
66 #define SMFIC_BODY              'B'     /* Body chunk */
67 #define SMFIC_CONNECT           'C'     /* Connection information */
68 #define SMFIC_MACRO             'D'     /* Define macro */
69 #define SMFIC_BODYEOB           'E'     /* final body chunk (End) */
70 #define SMFIC_HELO              'H'     /* HELO/EHLO */
71 #define SMFIC_HEADER            'L'     /* Header */
72 #define SMFIC_MAIL              'M'     /* MAIL from */
73 #define SMFIC_EOH               'N'     /* EOH */
74 #define SMFIC_OPTNEG            'O'     /* Option negotiation */
75 #define SMFIC_QUIT              'Q'     /* QUIT */
76 #define SMFIC_RCPT              'R'     /* RCPT to */
77 #define SMFIC_DATA              'T'     /* DATA (SMFI_VERSION > 3) */
78 #define SMFIC_UNKNOWN           'U'     /* Any unknown command */
79 
80 /* actions (replies) */
81 #define SMFIR_ADDRCPT           '+'     /* add recipient */
82 #define SMFIR_DELRCPT           '-'     /* remove recipient */
83 #define SMFIR_ADDRCPT_PAR       '2'     /* add recipient */
84 #define SMFIR_SHUTDOWN          '4'     /* 421: shutdown (internal to MTA) */
85 #define SMFIR_ACCEPT            'a'     /* accept */
86 #define SMFIR_REPLBODY          'b'     /* replace body (chunk) */
87 #define SMFIR_CONTINUE          'c'     /* continue */
88 #define SMFIR_DISCARD           'd'     /* discard */
89 #define SMFIR_CHGFROM           'e'     /* change envelope sender (from) */
90 #define SMFIR_CONN_FAIL         'f'     /* cause a connection failure */
91 #define SMFIR_ADDHEADER         'h'     /* add header */
92 #define SMFIR_INSHEADER         'i'     /* insert header */
93 #if 0
94 #define SMFIR_SETSYMLIST        'l'     /* set list of macros (unused) */
95 #endif
96 #define SMFIR_CHGHEADER         'm'     /* change header */
97 #define SMFIR_PROGRESS          'p'     /* progress */
98 #define SMFIR_QUARANTINE        'q'     /* quarantine */
99 #define SMFIR_REJECT            'r'     /* reject */
100 #define SMFIR_SKIP              's'     /* skip */
101 #define SMFIR_TEMPFAIL          't'     /* tempfail */
102 #define SMFIR_REPLYCODE         'y'     /* reply code etc */
103 
104 /* What the MTA can send/filter wants in protocol */
105 #define SMFIP_NOCONNECT 0x00000001L     /* MTA should not send connect info */
106 #define SMFIP_NOHELO    0x00000002L     /* MTA should not send HELO info */
107 #define SMFIP_NOMAIL    0x00000004L     /* MTA should not send MAIL info */
108 #define SMFIP_NORCPT    0x00000008L     /* MTA should not send RCPT info */
109 #define SMFIP_NOBODY    0x00000010L     /* MTA should not send body */
110 #define SMFIP_NOHDRS    0x00000020L     /* MTA should not send headers */
111 #define SMFIP_NOEOH     0x00000040L     /* MTA should not send EOH */
112 #define SMFIP_NR_HDR    0x00000080L     /* No reply for headers */
113 #define SMFIP_NOHREPL   SMFIP_NR_HDR    /* No reply for headers */
114 #define SMFIP_NOUNKNOWN 0x00000100L     /* MTA should not send unknown
115                                            commands */
116 #define SMFIP_NODATA    0x00000200L     /* MTA should not send DATA */
117 #define SMFIP_SKIP      0x00000400L     /* MTA understands SMFIS_SKIP */
118 #define SMFIP_RCPT_REJ  0x00000800L     /* MTA should also send rejected
119 					   RCPTs */
120 #define SMFIP_NR_CONN   0x00001000L     /* No reply for connect */
121 #define SMFIP_NR_HELO   0x00002000L     /* No reply for HELO */
122 #define SMFIP_NR_MAIL   0x00004000L     /* No reply for MAIL */
123 #define SMFIP_NR_RCPT   0x00008000L     /* No reply for RCPT */
124 #define SMFIP_NR_DATA   0x00010000L     /* No reply for DATA */
125 #define SMFIP_NR_UNKN   0x00020000L     /* No reply for UNKN */
126 #define SMFIP_NR_EOH    0x00040000L     /* No reply for eoh */
127 #define SMFIP_NR_BODY   0x00080000L     /* No reply for body chunk */
128 #define SMFIP_HDR_LEADSPC 0x00100000L   /* header value leading space */
129 
130 /* The protocol of V1 filter */
131 #define SMFI_V1_PROT    (SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NOMAIL|\
132                          SMFIP_NORCPT|SMFIP_NOBODY|SMFIP_NOHDRS)
133 /* The protocol of V2 filter */
134 #define SMFI_V2_PROT    (SMFI_V1_PROT|SMFIP_NOEOH)
135 
136 /* All defined prot bits */
137 #define SMFI_DEFAULT_PROT  0x001FFFFFL
138 
139 /* Flags, defining milter capabilities */
140 #define SMFIF_NONE	0x00000000L	/* no flags */
141 #define SMFIF_ADDHDRS	0x00000001L	/* filter may add headers */
142 #define SMFIF_CHGBODY	0x00000002L	/* filter may replace body */
143 #define SMFIF_MODBODY	SMFIF_CHGBODY	/* backwards compatible */
144 #define SMFIF_ADDRCPT	0x00000004L	/* filter may add recipients */
145 #define SMFIF_DELRCPT	0x00000008L	/* filter may delete recipients */
146 #define SMFIF_CHGHDRS	0x00000010L	/* filter may change/delete headers */
147 #define SMFIF_QUARANTINE 0x00000020L	/* filter may quarantine envelope */
148 #define SMFIF_CHGFROM   0x00000040L     /* filter may change envelope "from" */
149 #define SMFIF_ADDRCPT_PAR 0x00000080L   /* add recipients incl. args */
150 
151 #define SMFI_V1_ACTS (SMFIF_ADDHDRS|SMFIF_CHGBODY|SMFIF_ADDRCPT|SMFIF_DELRCPT)
152 #define SMFI_V2_ACTS (SMFI_V1_ACTS|SMFIF_CHGHDRS|SMFIF_QUARANTINE)
153 #define SMFI_V6_ACTS (SMFI_V2_ACTS|SMFIF_CHGFROM|SMFIF_ADDRCPT_PAR)
154 
155 #define SMFI_DEFAULT_ACTS SMFI_V6_ACTS
156 
157 /* Log levels */
158 #define SMI_LOG_PROTO	0
159 #define SMI_LOG_DEBUG   1
160 #define SMI_LOG_INFO    2
161 #define SMI_LOG_WARN    3
162 #define SMI_LOG_ERR     4
163 #define SMI_LOG_FATAL   5
164 
165 #define SMI_LOG_MASK(n) (1<<(n))
166 #define SMI_LOG_UPTO(n) ((1 << ((n)+1))-1)  /* all levels through n */
167 #define SMI_LOG_FROM(n) (SMI_LOG_UPTO(SMI_LOG_FATAL) & \
168 			 ~((n) == 0 ? 0 : SMI_LOG_UPTO((n)-1)))
169 
170 #define SMI_DEFAULT_LOG_MASK SMI_LOG_MASK(SMI_LOG_INFO)   \
171                              | SMI_LOG_MASK(SMI_LOG_WARN) \
172                  	     | SMI_LOG_MASK(SMI_LOG_ERR)  \
173 		             | SMI_LOG_MASK(SMI_LOG_FATAL)
174 
175 /* address families */
176 #define SMFIA_UNKNOWN 'U'     /* unknown */
177 #define SMFIA_UNIX    'L'     /* unix/local */
178 #define SMFIA_INET    '4'     /* inet */
179 #define SMFIA_INET6   '6'     /* inet6 */
180 
181 /* Function return codes */
182 #define MI_SUCCESS	0
183 #define MI_FAILURE	(-1)
184 
185 /* Data types */
186 typedef struct smfi_str SMFICTX;
187 typedef struct smfi_str *SMFICTX_PTR;
188 typedef struct gacopyz_conn *gacopyz_conn_t;
189 typedef struct gacopyz_iod *gacopyz_iod_t;
190 
191 /* Return type for the callbacks */
192 typedef enum {
193 	SMFIS_CONTINUE,
194 	SMFIS_REJECT,
195 	SMFIS_DISCARD,
196 	SMFIS_ACCEPT,
197 	SMFIS_TEMPFAIL,
198 	SMFIS_NOREPLY = 7,
199 	SMFIS_SKIP = 8,
200 	SMFIS_ALL_OPTS = 10
201 } sfsistat;
202 
203 typedef union {
204 	struct sockaddr sa;
205 	struct sockaddr_in sin;
206 	struct sockaddr_un sunix;
207 #ifdef GACOPYZ_IPV6
208 	struct sockaddr_in6 sin6;
209 #endif
210 } milter_sockaddr_t;
211 
212 enum gacopyz_stage {
213 	gacopyz_stage_conn,
214 	gacopyz_stage_helo,
215 	gacopyz_stage_mail,
216 	gacopyz_stage_rcpt,
217 	gacopyz_stage_data,
218 	gacopyz_stage_eom,
219 	gacopyz_stage_eoh,
220 
221 	gacopyz_stage_max,
222 	gacopyz_stage_none = gacopyz_stage_max
223 };
224 
225 #define SMFIM_CONNECT   gacopyz_stage_conn
226 #define SMFIM_HELO      gacopyz_stage_helo
227 #define SMFIM_ENVFROM   gacopyz_stage_mail
228 #define SMFIM_ENVRCPT   gacopyz_stage_rcpt
229 #define SMFIM_DATA      gacopyz_stage_data
230 #define SMFIM_EOM       gacopyz_stage_eom
231 #define SMFIM_EOH       gacopyz_stage_eoh
232 
233 #define _SOCK_ADDR milter_sockaddr_t
234 #define smfiDesc gacopyz_milter_descr
235 
236 typedef struct gacopyz_milter_descr gacopyz_milter_descr_t;
237 
238 struct gacopyz_milter_descr
239 {
240         char          *xxfi_name;     /* filter name */
241         int           xxfi_version;   /* version code */
242         unsigned long xxfi_flags;     /* flags */
243 	  /* Filters: */
244           /* connection info */
245         sfsistat    (*xxfi_connect) (SMFICTX *, char *, milter_sockaddr_t *);
246           /* SMTP HELO command */
247         sfsistat    (*xxfi_helo) (SMFICTX *, char *);
248           /* envelope sender */
249         sfsistat    (*xxfi_envfrom) (SMFICTX *, char **);
250           /* envelope recipient */
251         sfsistat    (*xxfi_envrcpt) (SMFICTX *, char **);
252           /* header */
253         sfsistat    (*xxfi_header) (SMFICTX *, char *, char *);
254           /* end of header */
255         sfsistat    (*xxfi_eoh) (SMFICTX *);
256           /* body block */
257         sfsistat    (*xxfi_body) (SMFICTX *, unsigned char *, size_t);
258           /* end of message */
259         sfsistat     (*xxfi_eom) (SMFICTX *);
260           /* message aborted */
261         sfsistat     (*xxfi_abort) (SMFICTX *);
262           /* connection cleanup */
263         sfsistat     (*xxfi_close) (SMFICTX *);
264           /* any unrecognized or unimplemented command (SMFI_VERSION > 2) */
265         sfsistat     (*xxfi_unknown) (SMFICTX *, char *);
266           /* SMTP DATA command (SMFI_VERSION > 3) */
267         sfsistat     (*xxfi_data) (SMFICTX *);
268 	  /* Milter negotiation (SMFI_VERSION > 3) */
269 	sfsistat     (*xxfi_negotiate) (SMFICTX *,
270 					unsigned long, unsigned long,
271 		                        unsigned long, unsigned long,
272 		                        unsigned long *, unsigned long *,
273 		                        unsigned long *, unsigned long *);
274 
275 	/* Extensions: */
276 
277 	int (*xxfi_start) ();  /* Child start callback */
278 	int (*xxfi_finish) (); /* Child finish callback */
279 	int (*xxfi_idle) (gacopyz_conn_t); /* Idle handler */
280 	int (*xxfi_accept) (gacopyz_conn_t, int, const milter_sockaddr_t *,
281 			    int salen);
282 
283 	int logmask;
284 	struct timeval ctx_timeout;
285 };
286 
287 /* Standard API calls */
288 extern int smfi_version (unsigned int *, unsigned int *, unsigned int *);
289 extern int smfi_opensocket (int);
290 extern int smfi_register (struct smfiDesc);
291 extern int smfi_main (void);
292 extern int smfi_setbacklog (int);
293 extern int smfi_setdbg (int);
294 extern int smfi_settimeout (time_t);
295 extern int smfi_setconn (char *);
296 extern int smfi_stop (void);
297 
298 #define smfi_getsymval(ctx,s) ((char*) gacopyz_getsymval(ctx, (char*)s))
299 
300 int smfi_addheader (SMFICTX *, char *, char *);
301 int smfi_chgheader (SMFICTX *, char *, int, char *);
302 int smfi_insheader (SMFICTX *, int, char *, char *);
303 int smfi_addrcpt (SMFICTX *, char *);
304 int smfi_delrcpt (SMFICTX *, char *);
305 int smfi_progress (SMFICTX *);
306 int smfi_replacebody (SMFICTX *, unsigned char *, int);
307 int smfi_quarantine (SMFICTX *ctx, char *reason);
308 int smfi_addrcpt_par(SMFICTX *ctx, char *rcpt, char *args);
309 int smfi_chgfrom(SMFICTX *ctx, char *from, char *args);
310 #define smfi_setpriv gacopyz_setpriv
311 #define smfi_getpriv gacopyz_getpriv
312 size_t smfi_setmaxdatasize (size_t);
313 int smfi_setsymlist(SMFICTX *ctx, int stage, char *macros);
314 
315 /* Replies: */
316 extern int smfi_setreply (SMFICTX *, char *, char *, char *);
317 int smfi_setmlreply (SMFICTX *, const char *, const char *, ...);
318 
319 /* Extensions */
320 extern int smfi_set_foreground(int val);
321 extern int smfi_setlogmask(int logmask);
322 
323 /* New API calls: */
324 int gacopyz_init(gacopyz_conn_t *pconn, struct smfiDesc *desc);
325 void gacopyz_free(gacopyz_conn_t conn);
326 const char *gacopyz_safe_header_value(const char *input, char **poutput);
327 
328 int gacopyz_set_logmask(gacopyz_conn_t conn, int mask);
329 int gacopyz_get_logmask(gacopyz_conn_t conn, int *mask);
330 int gacopyz_set_foreground(gacopyz_conn_t conn, int fg);
331 int gacopyz_set_master_timeout(gacopyz_conn_t conn, struct timeval *timeout);
332 int gacopyz_get_master_timeout(gacopyz_conn_t conn, struct timeval *timeout);
333 int gacopyz_set_ctx_timeout(gacopyz_conn_t conn, struct timeval *timeout);
334 int gacopyz_get_ctx_timeout(gacopyz_conn_t conn, struct timeval *timeout);
335 int gacopyz_stop(gacopyz_conn_t conn);
336 
337 int gacopyz_open(gacopyz_conn_t conn, const char *cstr,
338 		  int backlog, int rmsocket);
339 
340 int gacopyz_parse_connection(const char *cstr,
341 			     char **pproto, char **pport, char **ppath);
342 
343 int gacopyz_connect(gacopyz_conn_t *, struct smfiDesc *, const char *,
344 		    int backlog, int rmsocket);
345 int gacopyz_get_fd(gacopyz_conn_t);
346 
347 int gacopyz_run(gacopyz_conn_t);
348 int gacopyz_context_loop(int fd, struct smfiDesc const *desc,
349 			 milter_sockaddr_t *addr, socklen_t addrlen,
350 			 void *calldata);
351 
352 int gacopyz_register_child(gacopyz_conn_t conn, pid_t pid);
353 void gacopyz_cleanup_children(gacopyz_conn_t conn);
354 void gacopyz_cleanup_conn(gacopyz_conn_t conn);
355 void gacopyz_setup_signals(void);
356 
357 const char *gacopyz_getsymval (SMFICTX *, const char *);
358 
359 int gacopyz_setreply(SMFICTX *ctx, const char *rcode, const char *xcode,
360 		      const char *message);
361 int gacopyz_setmlreply_v(SMFICTX *ctx, const char *rcode, const char *xcode,
362 			  ...);
363 int gacopyz_setmlreply_va(SMFICTX *ctx, const char *rcode, const char *xcode,
364 			   va_list ap);
365 int _gacopyz_setmlreply_va(SMFICTX *ctx, size_t max, const char *rcode,
366 			    const char *xcode, va_list ap);
367 
368 int gacopyz_add_header(SMFICTX *ctx, const char *headerf,
369 			const char *headerv);
370 
371 int gacopyz_insert_header(SMFICTX *ctx, int index, const char *headerf,
372 			   const char *headerv);
373 int gacopyz_change_header(SMFICTX *ctx, int index, const char *headerf,
374 			   const char *headerv);
375 int gacopyz_add_rcpt(SMFICTX *ctx, const char *rcpt);
376 int gacopyz_del_rcpt(SMFICTX *ctx, const char *rcpt);
377 int gacopyz_replace_body(SMFICTX *ctx, const unsigned char *bodyp,
378 			 size_t bodylen);
379 int gacopyz_replace_body_fn(SMFICTX *ctx,
380 			    void *bodyp,
381 			    ssize_t (*cpf)(char*,void*,size_t));
382 int gacopyz_replace_body_fd(SMFICTX *ctx, int fd);
383 int gacopyz_progress(SMFICTX *ctx);
384 int gacopyz_quarantine(SMFICTX *ctx, const char *reason);
385 int gacopyz_add_rcpt_par(SMFICTX *ctx, const char *rcpt, const char *args);
386 int gacopyz_chgfrom(SMFICTX *ctx, const char *from, const char *args);
387 
388 int gacopyz_setsymlist(SMFICTX *ctx, enum gacopyz_stage ind,
389 		       const char *macros);
390 
391 int gacopyz_setpriv (SMFICTX *ctx, void *data);
392 void *gacopyz_getpriv (SMFICTX *ctx);
393 void *gacopyz_getclosure(SMFICTX *ctx);
394 
395 int gacopyz_client_sockname(SMFICTX *ctx,
396 			    milter_sockaddr_t *name, socklen_t *namelen);
397 int gacopyz_server_sockname(SMFICTX *ctx,
398 			    milter_sockaddr_t *name, socklen_t *namelen);
399 
400 /* Logging (extensions) */
401 extern const char *gacopyz_stage_name[gacopyz_stage_max];
402 
403 #define GACOPYZ_VBUFSIZE 69
404 size_t gacopyz_format_vbuf(char vbuf[GACOPYZ_VBUFSIZE], const char *buf,
405 			   size_t size);
406 void gacopyz_log(int level, char *fmt, ...);
407 void gacopyz_logdump(int level, const char *pfx,
408 		     const char *buf, size_t size);
409 void gacopyz_io_log(gacopyz_iod_t iod, int level, char *fmt, ...);
410 void gacopyz_io_logdump(gacopyz_iod_t iod, const char *pfx,
411 			const char *buf, size_t size);
412 void gacopyz_set_logger(void (*)(int, char *, va_list));
413 
414 void gacopyz_stderr_log_printer(int level, char *fmt, va_list ap);
415 void gacopyz_syslog_log_printer(int level, char *fmt, va_list ap);
416 int gacopyz_string_to_log_level(const char *str);
417 const char *gacopyz_log_level_to_string(int level);
418 
419 
420 /* Server */
421 typedef struct gacopyz_srv *gacopyz_srv_t;
422 
423 enum gacopyz_flag_op {
424 	gacopyz_flag_rpl,
425 	gacopyz_flag_set,
426 	gacopyz_flag_clr
427 };
428 
429 #define GACOPYZ_SRV_DISABLED 0x0001
430 
431 int gacopyz_srv_create(gacopyz_srv_t *p, const char *name,
432 		       const char *portspec, unsigned logmask);
433 int gacopyz_srv_create_X(gacopyz_srv_t *p, const char *spec, unsigned logmask);
434 
435 void gacopyz_srv_destroy(gacopyz_srv_t *p);
436 int gacopyz_srv_find_macro (gacopyz_srv_t srv, const char *name,
437 			    const char **pval);
438 void gacopyz_srv_define_macro (gacopyz_srv_t srv,
439 			      const char *name, const char *value);
440 void gacopyz_srv_del_macro (gacopyz_srv_t srv, const char *name);
441 void gacopyz_srv_clear_macros (gacopyz_srv_t srv);
442 void gacopyz_srv_clear_macros_pred(gacopyz_srv_t srv,
443 				   int (*pred) (const char*, void*),
444 				   void *data);
445 
446 void gacopyz_srv_iterate_macros (gacopyz_srv_t srv,
447 				 int (*func) (const char *name,
448 					      const char *value,
449 					      void *data),
450 				 void *data);
451 void gacopyz_srv_count_macros (gacopyz_srv_t srv, size_t *count);
452 
453 const char **gacopyz_srv_get_required_macros(gacopyz_srv_t srv,
454 					     enum gacopyz_stage stage);
455 const char *gacopyz_srv_get_id(gacopyz_srv_t srv);
456 const char *gacopyz_srv_get_portspec(gacopyz_srv_t srv);
457 
458 int gacopyz_srv_flags(gacopyz_srv_t srv, int flags, enum gacopyz_flag_op op);
459 int gacopyz_srv_get_flags(gacopyz_srv_t srv);
460 
461 int gacopyz_srv_get_logmask(gacopyz_srv_t srv);
462 int gacopyz_srv_get_fd(gacopyz_srv_t srv);
463 int gacopyz_srv_get_onerr(gacopyz_srv_t srv);
464 
465 int gacopyz_srv_open(gacopyz_srv_t srv);
466 int gacopyz_srv_init(gacopyz_srv_t srv);
467 int gacopyz_srv_negotiate(gacopyz_srv_t srv);
468 int gacopyz_srv_abort(gacopyz_srv_t srv);
469 int gacopyz_srv_quit(gacopyz_srv_t srv);
470 
471 int gacopyz_srv_connect(gacopyz_srv_t srv, const char *hostname,
472 			struct sockaddr *sa);
473 int gacopyz_srv_helo (gacopyz_srv_t p, const char *domain);
474 int gacopyz_srv_envfrom (gacopyz_srv_t p, char **argv);
475 int gacopyz_srv_envrcpt (gacopyz_srv_t p, char **argv);
476 int gacopyz_srv_header (gacopyz_srv_t p, char *name, char *value);
477 int gacopyz_srv_eoh (gacopyz_srv_t p);
478 int gacopyz_srv_body (gacopyz_srv_t p, unsigned char *str, size_t size);
479 
480 int gacopyz_srv_eom (gacopyz_srv_t p, unsigned char *str, size_t size);
481 int gacopyz_srv_abort (gacopyz_srv_t p);
482 int gacopyz_srv_close (gacopyz_srv_t p);
483 int gacopyz_srv_data (gacopyz_srv_t p);
484 
485 int gacopyz_srv_onerror(gacopyz_srv_t srv, int code);
486 void gacopyz_srv_set_logmask(gacopyz_srv_t srv, int logmask);
487 void gacopyz_srv_set_memerror(gacopyz_srv_t srv,
488 			      void (*memerror)(gacopyz_srv_t, const char *,
489 					       unsigned int));
490 void gacopyz_srv_set_callback(gacopyz_srv_t srv,
491 			      int (*cb) (gacopyz_srv_t, int, int, void *));
492 void gacopyz_srv_set_callback_data(gacopyz_srv_t, void *);
493 
494 int gacopyz_srv_set_source(gacopyz_srv_t srv, struct sockaddr *sa,
495 			   socklen_t len);
496 int gacopyz_srv_set_version(gacopyz_srv_t srv, unsigned long version);
497 int gacopyz_srv_set_protocol(gacopyz_srv_t srv, unsigned long proto);
498 int gacopyz_srv_set_actions(gacopyz_srv_t srv, unsigned long acts);
499 
500 #define GACOPYZ_WRITE_TIMEOUT 10
501 #define GACOPYZ_READ_TIMEOUT 10
502 #define GACOPYZ_EOM_TIMEOUT 300
503 #define GACOPYZ_CONNECT_TIMEOUT 300
504 
505 #define GACOPYZ_TO_WRITE    0    /* Timeout for sending information */
506 #define GACOPYZ_TO_READ     1    /* Timeout waiting for a response */
507 #define GACOPYZ_TO_EOM      2    /* Timeout for ACK/NAK to EOM */
508 #define GACOPYZ_TO_CONNECT  3    /* Timeout for connect() */
509 #define GACOPYZ_TO_COUNT    4
510 
511 void gacopyz_srv_set_all_timeouts(gacopyz_srv_t srv, struct timeval *tvp);
512 int gacopyz_srv_set_timeout(gacopyz_srv_t srv, unsigned n,
513 			    struct timeval *tvp);
514 int gacopyz_srv_set_timeout_sec(gacopyz_srv_t srv, unsigned n, time_t t);
515 
516 int gacopyz_srv_reply(gacopyz_srv_t srv, char **msg, size_t *size);
517 void gacopyz_srv_reply_raw(gacopyz_srv_t srv, char **msg, size_t *size);
518 
519 #ifdef __cplusplus
520 }
521 #endif
522 
523 #endif /* __gacopyz_h__ */
524