/* This file is part of gacopyz.
   Copyright (C) 2006-2025 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 <http://www.gnu.org/licenses/>. */

#ifndef __gacopyz_h__
# define __gacopyz_h__

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>

#ifdef __cplusplus
extern "C" {
#endif

#define GACOPYZ_VERSION_MAJOR 2
#define GACOPYZ_VERSION_MINOR 0
	
/* Implementation version number */	
#define SMFI_VERSION      0x01000000

#define SM_LM_VRS_MAJOR(v)      (((v) & 0x7f000000) >> 24)
#define SM_LM_VRS_MINOR(v)      (((v) & 0x007fff00) >> 8)
#define SM_LM_VRS_PLVL(v)       ((v) & 0x0000007f)

#define GACOPYZ_SM_MKVER(maj,min,pat) \
	((((maj) & 0x7f)<<24) | (((min) & 0x7ffff) << 8) | ((pat) & 0x7f))
	
/* Milter protocol version */	
#define SMFI_PROT_VERSION 6

/* Minimal supported protocol version */
#define SMFI_PROT_VERSION_MIN 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_ADDRCPT_PAR       '2'     /* add recipient */
#define SMFIR_SHUTDOWN          '4'     /* 421: shutdown (internal to MTA) */
#define SMFIR_ACCEPT            'a'     /* accept */
#define SMFIR_REPLBODY          'b'     /* replace body (chunk) */
#define SMFIR_CONTINUE          'c'     /* continue */
#define SMFIR_DISCARD           'd'     /* discard */
#define SMFIR_CHGFROM           'e'     /* change envelope sender (from) */
#define SMFIR_CONN_FAIL         'f'     /* cause a connection failure */
#define SMFIR_ADDHEADER         'h'     /* add header */
#define SMFIR_INSHEADER         'i'     /* insert header */
#if 0
#define SMFIR_SETSYMLIST        'l'     /* set list of macros (unused) */
#endif
#define SMFIR_CHGHEADER         'm'     /* change header */
#define SMFIR_PROGRESS          'p'     /* progress */
#define SMFIR_QUARANTINE        'q'     /* quarantine */
#define SMFIR_REJECT            'r'     /* reject */
#define SMFIR_SKIP              's'     /* skip */
#define SMFIR_TEMPFAIL          't'     /* tempfail */
#define SMFIR_REPLYCODE         'y'     /* reply code etc */

/* 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_NR_HDR    0x00000080L     /* No reply for headers */
#define SMFIP_NOHREPL   SMFIP_NR_HDR    /* No reply for headers */
#define SMFIP_NOUNKNOWN 0x00000100L     /* MTA should not send unknown
                                           commands */
#define SMFIP_NODATA    0x00000200L     /* MTA should not send DATA */
#define SMFIP_SKIP      0x00000400L     /* MTA understands SMFIS_SKIP */
#define SMFIP_RCPT_REJ  0x00000800L     /* MTA should also send rejected
					   RCPTs */
#define SMFIP_NR_CONN   0x00001000L     /* No reply for connect */
#define SMFIP_NR_HELO   0x00002000L     /* No reply for HELO */
#define SMFIP_NR_MAIL   0x00004000L     /* No reply for MAIL */
#define SMFIP_NR_RCPT   0x00008000L     /* No reply for RCPT */
#define SMFIP_NR_DATA   0x00010000L     /* No reply for DATA */
#define SMFIP_NR_UNKN   0x00020000L     /* No reply for UNKN */
#define SMFIP_NR_EOH    0x00040000L     /* No reply for eoh */
#define SMFIP_NR_BODY   0x00080000L     /* No reply for body chunk */
#define SMFIP_HDR_LEADSPC 0x00100000L   /* header value leading space */
	
/* 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)

/* All defined prot bits */	
#define SMFI_DEFAULT_PROT  0x001FFFFFL
	
/* 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 SMFIF_CHGFROM   0x00000040L     /* filter may change envelope "from" */
#define SMFIF_ADDRCPT_PAR 0x00000080L   /* add recipients incl. args */
	
#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_V6_ACTS (SMFI_V2_ACTS|SMFIF_CHGFROM|SMFIF_ADDRCPT_PAR)
	
#define SMFI_DEFAULT_ACTS SMFI_V6_ACTS
	
/* Log levels */
#define SMI_LOG_PROTO	0
#define SMI_LOG_DEBUG   1
#define SMI_LOG_INFO    2
#define SMI_LOG_WARN    3
#define SMI_LOG_ERR     4
#define SMI_LOG_FATAL   5

#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) & \
			 ~((n) == 0 ? 0 : 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,
	SMFIS_NOREPLY = 7,
	SMFIS_SKIP = 8,
	SMFIS_ALL_OPTS = 10
} sfsistat;
	
typedef union {
	struct sockaddr sa;
	struct sockaddr_in sin;
	struct sockaddr_un sunix;
	struct sockaddr_in6 sin6;
} milter_sockaddr_t;

enum gacopyz_stage {
	gacopyz_stage_conn,	
	gacopyz_stage_helo,	
	gacopyz_stage_mail,	
	gacopyz_stage_rcpt,	
	gacopyz_stage_data,
	gacopyz_stage_eom,
	gacopyz_stage_eoh,
	
	gacopyz_stage_max,
	gacopyz_stage_none = gacopyz_stage_max
};

#define SMFIM_CONNECT   gacopyz_stage_conn  
#define SMFIM_HELO      gacopyz_stage_helo  
#define SMFIM_ENVFROM   gacopyz_stage_mail  
#define SMFIM_ENVRCPT   gacopyz_stage_rcpt  
#define SMFIM_DATA      gacopyz_stage_data  
#define SMFIM_EOM       gacopyz_stage_eom   
#define SMFIM_EOH       gacopyz_stage_eoh   
	
#define _SOCK_ADDR milter_sockaddr_t	
#define smfiDesc gacopyz_milter_descr

typedef struct gacopyz_milter_descr gacopyz_milter_descr_t;
	
struct gacopyz_milter_descr
{
        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 *);
	  /* Milter negotiation (SMFI_VERSION > 3) */
	sfsistat     (*xxfi_negotiate) (SMFICTX *,
					unsigned long, unsigned long,
		                        unsigned long, unsigned long,
		                        unsigned long *, unsigned long *,
		                        unsigned long *, unsigned long *);
		
	/* Extensions: */

	int (*xxfi_start) ();  /* Child start callback */
	int (*xxfi_finish) (); /* Child finish callback */
	int (*xxfi_idle) (gacopyz_conn_t); /* Idle handler */
	int (*xxfi_accept) (gacopyz_conn_t, int, const milter_sockaddr_t *,
			    int salen);
	
	int logmask;
	struct timeval ctx_timeout;
};

/* Standard API calls */
extern int smfi_version (unsigned int *, unsigned int *, unsigned int *);
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(ctx,s) ((char*) gacopyz_getsymval(ctx, (char*)s))

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);
int smfi_addrcpt_par(SMFICTX *ctx, char *rcpt, char *args);
int smfi_chgfrom(SMFICTX *ctx, char *from, char *args);
#define smfi_setpriv gacopyz_setpriv
#define smfi_getpriv gacopyz_getpriv
size_t smfi_setmaxdatasize (size_t); 
int smfi_setsymlist(SMFICTX *ctx, int stage, char *macros);
	
/* 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);
const char *gacopyz_safe_header_value(const char *input, char **poutput);

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_context_loop(int fd, struct smfiDesc const *desc,
			 milter_sockaddr_t *addr, socklen_t addrlen,
			 void *calldata);

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);

const char *gacopyz_getsymval (SMFICTX *, const 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, const unsigned char *bodyp,
			 size_t bodylen);
int gacopyz_replace_body_fn(SMFICTX *ctx,
			    void *bodyp, 
			    ssize_t (*cpf)(char*,void*,size_t));
int gacopyz_replace_body_fd(SMFICTX *ctx, int fd);	
int gacopyz_progress(SMFICTX *ctx);
int gacopyz_quarantine(SMFICTX *ctx, const char *reason);
int gacopyz_add_rcpt_par(SMFICTX *ctx, const char *rcpt, const char *args);
int gacopyz_chgfrom(SMFICTX *ctx, const char *from, const char *args);

int gacopyz_setsymlist(SMFICTX *ctx, enum gacopyz_stage ind,
		       const char *macros);
	
int gacopyz_setpriv (SMFICTX *ctx, void *data);
void *gacopyz_getpriv (SMFICTX *ctx);
void *gacopyz_getclosure(SMFICTX *ctx);

int gacopyz_client_sockname(SMFICTX *ctx,
			    milter_sockaddr_t *name, socklen_t *namelen);
int gacopyz_server_sockname(SMFICTX *ctx,
			    milter_sockaddr_t *name, socklen_t *namelen);
	
/* Logging (extensions) */
extern const char *gacopyz_stage_name[gacopyz_stage_max];
	
#define GACOPYZ_VBUFSIZE 69
size_t gacopyz_format_vbuf(char vbuf[GACOPYZ_VBUFSIZE], const char *buf,
			   size_t size);
void gacopyz_log(int level, char *fmt, ...);
void gacopyz_logdump(int level, const char *pfx,
		     const char *buf, size_t size);
void gacopyz_io_log(gacopyz_iod_t iod, int level, char *fmt, ...);
void gacopyz_io_logdump(gacopyz_iod_t iod, 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;

enum gacopyz_flag_op {
	gacopyz_flag_rpl,
	gacopyz_flag_set,
	gacopyz_flag_clr
};

#define GACOPYZ_SRV_DISABLED 0x0001
	
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_del_macro (gacopyz_srv_t srv, const char *name);
void gacopyz_srv_clear_macros (gacopyz_srv_t srv);
void gacopyz_srv_clear_macros_pred(gacopyz_srv_t srv,
				   int (*pred) (const char*, void*),
				   void *data);

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);
	
const char **gacopyz_srv_get_required_macros(gacopyz_srv_t srv,
					     enum gacopyz_stage stage);
const char *gacopyz_srv_get_id(gacopyz_srv_t srv);
const char *gacopyz_srv_get_portspec(gacopyz_srv_t srv);

int gacopyz_srv_flags(gacopyz_srv_t srv, int flags, enum gacopyz_flag_op op);
int gacopyz_srv_get_flags(gacopyz_srv_t srv);

int gacopyz_srv_get_logmask(gacopyz_srv_t srv);
int gacopyz_srv_get_fd(gacopyz_srv_t srv);	
int gacopyz_srv_get_onerr(gacopyz_srv_t srv);
  
int gacopyz_srv_open(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_connect(gacopyz_srv_t srv, const char *hostname,
			struct sockaddr *sa);
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_logmask(gacopyz_srv_t srv, int logmask);
void gacopyz_srv_set_memerror(gacopyz_srv_t srv,
			      void (*memerror)(gacopyz_srv_t, const char *,
					       unsigned int));
void gacopyz_srv_set_callback(gacopyz_srv_t srv,
			      int (*cb) (gacopyz_srv_t, int, int, void *));
void gacopyz_srv_set_callback_data(gacopyz_srv_t, void *);

int gacopyz_srv_set_source(gacopyz_srv_t srv, struct sockaddr *sa,
			   socklen_t len);
int gacopyz_srv_set_version(gacopyz_srv_t srv, unsigned long version);
int gacopyz_srv_set_protocol(gacopyz_srv_t srv, unsigned long proto);
int gacopyz_srv_set_actions(gacopyz_srv_t srv, unsigned long 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);
	
int gacopyz_srv_reply(gacopyz_srv_t srv, char **msg, size_t *size);
void gacopyz_srv_reply_raw(gacopyz_srv_t srv, char **msg, size_t *size);
	
#ifdef __cplusplus
}
#endif

#endif /* __gacopyz_h__ */
