/*****************************************************************************

  POPular -- A POP3 server and proxy for large mail systems

  $Id: popular.h,v 1.60 2002/11/28 13:56:03 sqrt Exp $

  http://www.remote.org/jochen/mail/popular/

******************************************************************************

  Copyright (C) 1999-2002  Jochen Topf <jochen@remote.org>

  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 2 of the License, 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, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA

*****************************************************************************/

#include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#ifdef USE_TLS
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/rand.h>
#endif

#ifdef USE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif

#ifndef HAVE_STRLCAT
# include "../lib/strl.h"
#endif

#ifdef HAVE_GETOPT
# include <getopt.h>
#else
# include "../lib/getopt.h"
#endif

#include "pconfig.h"


extern int debug;


#define PP_FLAGS_M 1

#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))


/*****************************************************************************

  Results of a mail check from pcheckd.

*****************************************************************************/
typedef enum {
  mcrMail        = 0,
  mcrEmpty       = 1,
  mcrTimeout     = 2,
  mcrLoadTooHigh = 3,
  mcrMaxSession  = 4,
  mcrError       = -1
} mailcheck_result_t;


/*****************************************************************************

  The different types of config parameters.

*****************************************************************************/
typedef enum {
  ctNone = 0,			/* end-of-list designator */
  ctInt,			/* integer value */
  ctStr,			/* string */
  ctFile,			/* file name */
  ctDir,			/* directory name */
  ctId,				/* some kind of id */
  ctBool,			/* boolean (0=no=off=false, 1=yes=on=true) */
  ctTime,			/* a time interval (ie. 10h3m4s) */
  ctIgn				/* unsupported in this configuration */
} config_type_t;



/*****************************************************************************

  Format of a mail.

*****************************************************************************/
typedef enum {
  mfLF = 0,			/* linefeed on end-of-line */
  mfCRLF,			/* carriage return + linefeed on end-of-line */
  mfNET,			/* like mfCRLF plus dot stuffing */
} mail_format_t;


/*****************************************************************************

  These are the different kinds of protocols that the POPular proxy
  supports (or might at some point support).

*****************************************************************************/
typedef enum {
  ptPOP3 = 0,			/* POP3 (RFC 1939) */
  ptIMAP4,			/* IMAP4 */
  ptXPOP,			/* XPOP (see POPular documentation) */
  ptCXPOP,			/* Check and XPOP (see POPular doc) */
  ptPOP3TLS,			/* POP3 over TLS */
  ptIMAP4TLS,			/* IMAP4 over TLS */
  ptPOP3STLS,			/* POP3 with STLS */
} protocol_t;


struct protocol_info {
  protocol_t type;		/* type (see above) */
  char *name;			/* descriptive name */
  int tls;			/* does this protocol use TLS? */
  int port;			/* default port for this protocol */
  int support_client_side;	/* protocol supported on client connection */
  int support_backend_side;	/* protocol supported on backend connection */
};


/*****************************************************************************

  Different kind of states a proxy or server session can be in.

*****************************************************************************/
typedef enum {
  sstFree =  0,			/* proxy and backend: slot free */
  sstNew,			/* proxy and backend: new connection */
  sstIdle,			/* backend: idle */
  sstRead,			/* backend: reading mail */
  sstDone,			/* proxy: closing down */
  sstAuthPhase,			/* proxy: authenticating user */
  sstVirtServDisabled,		/* proxy: virt server is disabled */
  sstVirtServFake,		/* proxy: virt server is to be faked */
  sstCheck,			/* proxy: checking for mails in mailbox */
  sstConnecting,		/* proxy: connecting to backend */
  sstBackendUnreachable,	/* proxy: backend unreachable */
  sstBackendDisabled,		/* proxy: backend disabled */
  sstBackendFake,		/* proxy: backend is to be faked */
  sstProxy,			/* proxy: transfering data back and forth */
  sstMailboxEmpty,		/* proxy: mailbox is empty */
  sstUnknownBackend,		/* proxy: unknown backend */
  sstConnQuit,     		/* backend: connection properly closed */
  sstConnBroken,		/* backend: connection not properly closed */
} session_state_t;


struct session_state_info {
  session_state_t type;		/* type (see above) */
  char *name;			/* descriptive name */
};


/*****************************************************************************

  States a virtual server can be in.

*****************************************************************************/
typedef enum {
  vsstFree = 0,			/* this virtual server slot is unused */
  vsstOffline,			/* virtual server doesn't listen on port */
  vsstDisabled,			/* server listens, but sends error msg on */
				/* connect */
  vsstFake,			/* server listens, all connections are faked */
  vsstOnline			/* virtual server is online */
} virt_serv_state_t;


struct virt_serv_state_info {
  virt_serv_state_t type;	/* type (see above) */
  char *name;			/* descriptive name */
  int listen;			/* listen on port in this state ? */
};


/*****************************************************************************

  States a backend can be in.

*****************************************************************************/
typedef enum {
  bstFree = 0,			/* this backend slot is unused */
  bstOffline,			/* backend is offline, send error msg */
  bstFake,			/* backend is offline, fake connection */
  bstOnline			/* backend is online */
} backend_state_t;


struct backend_state_info {
  backend_state_t type;		/* type (see above) */
  char *name;			/* descriptive name */
};


/*****************************************************************************

  Capability types for virtual servers.

*****************************************************************************/
typedef enum {
  capa_error,
  capa_none,
  capa_default,
  capa_user
} capa_t;


/*****************************************************************************

  STARTTLS types for virtual servers.

*****************************************************************************/
typedef enum {
  starttls_off,
  starttls_optional,
  starttls_force
} starttls_t;


/*****************************************************************************

  Description of a virtual server.

*****************************************************************************/
struct virt_serv {
  char id[MAXLEN_ID+1];
  protocol_t prot; 
  struct sockaddr_in local_addr;
  char namespace[MAXLEN_ID+1];
  virt_serv_state_t state;
  capa_t capa_type;
  starttls_t starttls_type;
  struct capa *capa_ptr;
  char banner_ok[MAXLEN_BANNER+1];
  char banner_err[MAXLEN_BANNER+1];
  int fd;				/* file descriptor for listen */
#if USE_TLS
  SSL_CTX *ssl_ctx;
#endif
};


/*****************************************************************************

  Description of a backend.

*****************************************************************************/
struct backend {
  char id[MAXLEN_ID+1];
  protocol_t prot;
  struct sockaddr_in backend_addr;
  backend_state_t state;
};


/*****************************************************************************

  struct proxy_session

*****************************************************************************/
struct proxy_session {
  session_state_t state;		/* state of this session */
  pid_t pid;				/* process id of child process
					   handling this session */
  time_t starttime;			/* start time of this session */
  time_t statetime;			/* time when the server switched
					   into the current state */
  long mailcheck_time;			/* time in usecs for mail check */
  int mailcheck_retry;			/* number of retries for mail check */
  struct sockaddr_in sin_client_remote;	/* remote side of conn. to client */
  struct sockaddr_in sin_client_local;  /* local side of conn. to client */
  struct sockaddr_in sin_backend_remote; /* remote side of conn. to backend */
  struct sockaddr_in sin_backend_local;  /* local side of conn. to backend */
  int fd_client;			/* file descriptor to client */
  struct io_ctx *ioc_client;		/* IO context to client */
  struct io_ctx *ioc_backend;		/* IO context to backend */
  struct virt_serv vs;			/* virtual server for this session */
  struct backend backend;		/* backend for this session */
  char namespace[MAXLEN_ID+1];		/* namespace for this session */
  char username[MAXLEN_USERNAME+1];	/* username sent by client */
  char password[MAXLEN_PASSWORD+1];	/* password sent by client */
  char mailbox[MAXLEN_MAILBOX+1];	/* name of mailbox for backend */
  char id[MAXLEN_SESSION_ID+1];		/* session id */
  unsigned long bytesin;		/* bytes from client to backend */
  unsigned long bytesout;		/* bytes from backend to client */
};


/*****************************************************************************

  struct backend_session

*****************************************************************************/
struct backend_session {
  session_state_t state;		/* state of this session */
  pid_t pid;				/* process id of child process
					   handling this session */
  time_t starttime;			/* start time */
  time_t statetime;			/* time when the server switched
					   into the current state */
  struct sockaddr_in sin_proxy;		/* remote side of conn. to proxy */
  char username[MAXLEN_USERNAME+1];	/* username sent by client */
  char mailbox[MAXLEN_MAILBOX+1];	/* name of mailbox for backend */
  char id[MAXLEN_SESSION_ID+1];		/* session id */
  char flags[MAXLEN_FLAGS+1];		/* flags for this session */
  unsigned long msgnum;			/* number of mails in mailbox */
  unsigned long msgnew;			/* number of new mails in mailbox */
  unsigned long msgread;		/* number of messages read */
  unsigned long msgdel;			/* number of messages deleted */
};


/*****************************************************************************

  struct capa

*****************************************************************************/
struct capa {
  struct capa *next;			/* next capa struct in linked list */
  char name[MAXLEN_ID+1];		/* name of this capability list */
  char text[MAXLEN_CAPA+1];		/* text of capabilities */
};


struct pserv_capa {
  capa_t capa_type;
  char name[MAXLEN_ID+1];		/* name of this capability list */
  char text[MAXLEN_CAPA+1];		/* text of capabilities */
};


/*****************************************************************************


*****************************************************************************/
struct auth_request {
  char *user;
  char *pass;
  char *peer;
  char *namespace;
};

struct auth_result_data {
  int flags;
  char backend[MAXLEN_ID];
  char user[MAXLEN_USERNAME];
  char pass[MAXLEN_PASSWORD];
};


/*****************************************************************************

  struct configdesc

*****************************************************************************/
struct configdesc {
  char *tag;
  int readwrite;
  config_type_t type;
  void *ptr;
  int min, max, def;
  char *defstr;
};


/*****************************************************************************

  struct pproxyconfig

  All the config options for the pop proxy are saved in here.

*****************************************************************************/
struct pproxyconfig {
  int   allowsslv2;
  int   authtimeout;
  int   backlog;
  char  capadir[MAX_FILE_LEN];
  int   checkport;
  int   checktimeout;
  char  defaultns[MAXLEN_ID+1];
  char  fallback[MAXLEN_ID+1];
  char  id[20];
  int   idletimeout;
  char  logfile[80];
  int   maxlocalload;
  int   maxsession;
  char  pdmdir[MAX_FILE_LEN];
  pid_t pid;
  int   proxytimeout;
  char  rundir[MAX_FILE_LEN];
  int   sessionlimit;
  int	sessiontimeout;
  char  sidprefix[32];
  char  tlsdir[MAX_FILE_LEN];
  char  version[20];
};


/*****************************************************************************

  struct pservconfig

  All the config options for the pop server are saved in here.

*****************************************************************************/
struct pservconfig {
  int   backlog;
  char  capadir[MAX_FILE_LEN];
  char  id[20];
  int   idletimeout;
  char  localip[16];
  int   logeachmsg;
  char  logfile[80];
  int   maxlocalload;
  int   maxsession;
  pid_t pid;
  char  popdir[MAX_FILE_LEN];
  char  rundir[MAX_FILE_LEN];
  int   servport;
  int   sessionlimit;
  int	sessiontimeout;
  int	statusheader;
  char  version[20];
};


/*****************************************************************************

  struct shmem_desc

*****************************************************************************/
struct shmem_desc {
  char magic[8];		/* magic 'POPULAR\0' */
  char type[8];			/* type 'PROXY\0' oder 'SERVER\0' */
  int version;
  long starttime;
};


/*****************************************************************************

  struct shmem_proxy_stat

*****************************************************************************/
struct shmem_proxy_stat {
  unsigned long connections;	/* number of client connections */
  unsigned long bytesin;	/* bytes from client to backend */
  unsigned long bytesout;	/* bytes from backend to client */
  unsigned long mailcheck_time;	/* accumulated time for all mail checks */
  unsigned long mailcheck_retry[MAILCHECK_MAX_REQUESTS+1];
};


/*****************************************************************************

  struct shmem_proxy

*****************************************************************************/
struct shmem_proxy {
  char magic[8];		/* magic string 'POPULAR\0' */
  char type[8];			/* magic string 'PROXY\0\0\0' */
  int version;
  long starttime;
  int max_virt_serv;
  int max_backend;
  int max_sessions, n_sessions, used_sessions;
  struct shmem_proxy_stat stat;
  struct proxy_session session[MAX_SESSION];
};


/*****************************************************************************

  struct shmem_backend_stat

*****************************************************************************/
struct shmem_backend_stat {
  unsigned long connections;	/* number of connections from proxy */
  unsigned long bytesin;	/* bytes from proxy to backend */
  unsigned long bytesout;	/* bytes from backend to proxy */
  unsigned long msgread;	/* number of messages read */
  unsigned long msgdel;		/* number of messages deleted */
  unsigned long connquit;	/* number of properly closed connections */
  unsigned long connbroken;	/* number of not properly closed connections */
};


/*****************************************************************************

  struct shmem_backend

*****************************************************************************/
struct shmem_backend {
  char magic[8];		/* magic string 'POPULAR\0' */
  char type[8];			/* magic string 'SERVER\0\0' */
  int version;
  long starttime;
  struct pservconfig conf;
  struct shmem_backend_stat stat;
  int max_sessions, n_sessions, used_sessions;
  struct backend_session session[MAX_SESSION];
};


/*****************************************************************************

  for shutdown  

*****************************************************************************/
#define SHUTDOWN_SERVER   1
#define SHUTDOWN_CHILDREN 2
#define SHUTDOWN_DELAYED  4


/*****************************************************************************

  for debug

*****************************************************************************/
#define DG_MAIN   0x0001
#define DG_AUTH   0x0002
#define DG_PASS   0x0004
#define DG_POP    0x0008
#define DG_CTRL   0x0010
#define DG_NET    0x0020
#define DG_RINGD  0x0040
#define DG_TLS    0x0080
#define DG_IO     0x0100

#define DG_ALL    0x01ff

struct debug_info {
  int type;
  char *name;
};


/*****************************************************************************

  Debugging Macros

  Use like this:

  DEBUG0(DG_MISC, "main", "misc");
  DEBUGX(DG_NET, "main", "net %d", 1);
  DEBUGX(DG_AUTH, "main", "auth %d %s", 1, "xx");

*****************************************************************************/
#define DEBUG0(type, func, text) \
if (debug & (type)) do { \
  xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__); \
} while (0)

/* this isn't supported by older gccs :-(
#define DEBUGX(type, func, text, ...) \
if (debug & (type)) do { \
  xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, __VA_ARGS__); \
} while (0)
*/

#define DEBUG1(type, func, text, a1) \
if (debug & (type)) do { \
  xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1)); \
} while (0)

#define DEBUG2(type, func, text, a1, a2) \
if (debug & (type)) do { \
  xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2)); \
} while (0)

#define DEBUG3(type, func, text, a1, a2, a3) \
if (debug & (type)) do { \
  xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2), (a3)); \
} while (0)

#define DEBUG4(type, func, text, a1, a2, a3, a4) \
if (debug & (type)) do { \
  xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2), (a3), (a4)); \
} while (0)

#define DEBUG5(type, func, text, a1, a2, a3, a4, a5) \
if (debug & (type)) do { \
  xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2), (a3), (a4), (a5)); \
} while (0)

#define DEBUG6(type, func, text, a1, a2, a3, a4, a5, a6) \
if (debug & (type)) do { \
  xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2), (a3), (a4), (a5), (a6)); \
} while (0)



/*****************************************************************************
*****************************************************************************/

#include "util.h"
#include "io.h"
#include "info.h"
#include "pdm.h"
#include "pop3.h"
#include "xlog.h"
#include "sig.h"
#include "uds.h"
#include "mailbox.h"
#include "smtp_after_pop.h"


/** THE END *****************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1