/*  $Id: innd.h 10263 2018-03-10 14:51:53Z iulius $
**
**  Many of the data types used here have abbreviations, such as CT for a
**  channel type.  Here are a list of the conventions and meanings:
**
**    ART   A news article
**    CHAN  An I/O channel
**    CS    Channel state
**    CT    Channel type
**    FNL   Funnel, into which other feeds pour
**    FT    Feed type -- how a site gets told about new articles
**    ICD   In-core data (primarily the active and sys files)
**    LC    Local NNTP connection-receiving channel
**    CC    Control channel (used by ctlinnd)
**    NC    NNTP client channel
**    NG    Newsgroup
**    NGH   Newgroup hashtable
**    PROC  A process (used to feed a site)
**    PS    Process state
**    RC    Remote NNTP connection-receiving channel
**    RCHAN A channel in "read" state
**    SITE  Something that gets told when we get an article
**    WCHAN A channel in "write" state
**    WIP   Work-In-Progress, keeps track of articles before committed.
*/

#ifndef INND_H
#define INND_H 1

#include "config.h"
#include "portable/macros.h"
#include "portable/socket.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <syslog.h> 
#include <sys/stat.h>

#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <time.h>

#include "inn/buffer.h"
#include "inn/history.h"
#include "inn/messages.h"
#include "inn/timer.h"
#include "inn/libinn.h"
#include "inn/nntp.h"
#include "inn/paths.h"
#include "inn/storage.h"
#include "inn/vector.h"

BEGIN_DECLS

typedef short	SITEIDX;
#define NOSITE ((SITEIDX) -1)

/*
**  Various constants.
*/

/* Used for storing group subscriptions for feeds. */
#define SUB_DEFAULT		false
#define SUB_NEGATE		'!'
#define SUB_POISON		'@'

/* Special characters for newsfeeds entries. */
#define NF_FIELD_SEP            ':'
#define NF_SUBFIELD_SEP         '/'


/*
**  Server's operating mode.  Note that OMshutdown is only used internally
**  while shutting down in CCshutdown or CCxexec and does not need to be
**  handled outside of the Perl and Python filtering code.
*/
typedef enum _OPERATINGMODE {
  OMrunning,
  OMpaused,
  OMthrottled,
  OMshutdown
} OPERATINGMODE;


typedef struct _LISTBUFFER {
  char	*   Data;
  int	    DataLength;
  char  **  List;
  int	    ListLength;
} LISTBUFFER;

/*
**  What program to handoff a connection to.
*/
typedef enum _HANDOFF {
  HOnnrpd,
  HOnntpd
} HANDOFF;


/*
**  Header types.
*/
typedef enum _ARTHEADERTYPE {
  HTreq,  /* Drop article if this is missing		  */
  HTobs,  /* obsolete header but keep untouched		  */
  HTstd,  /* Standard optional header			  */
  HTsav	  /* Save header, but may be deleted from article */
} ARTHEADERTYPE;


/*
**  Entry in the header table.
*/
typedef struct _ARTHEADER {
  const char     *  Name;
  ARTHEADERTYPE	    Type;
  int		    Size;  /* Length of Name. */
} ARTHEADER;


/*
**  Header content.
*/
typedef struct _HDRCONTENT {
  char  *  Value;     /* Don't copy, shows where it begins. */
  int      Length;    /* Length of Value(tailing CRLF is not
                         included.  -1 if duplicated. */
  char     LastChar;  /* Saved char when the last one is cut during parsing.
                         Usually '\r' but it may be another char. */
} HDRCONTENT;


/*
**  A way to index into the header table.
*/
#define HDR_FOUND(_x)           (hc[(_x)].Length > 0)
#define HDR_LASTCHAR_SAVE(_x)   hc[(_x)].LastChar = hc[(_x)].Value[hc[_x].Length]
#define HDR_PARSE_START(_x)     hc[(_x)].Value[hc[_x].Length] = '\0'
#define HDR(_x)                 (hc[(_x)].Value)
/* HDR_LEN does not includes trailing "\r\n" */
#define HDR_LEN(_x)             (hc[(_x)].Length)
#define HDR_PARSE_END(_x)       hc[(_x)].Value[hc[_x].Length] = hc[(_x)].LastChar


#define HDR__APPROVED		0
#define HDR__CONTROL		1
#define HDR__DATE		2
#define HDR__DISTRIBUTION	3
#define HDR__EXPIRES		4
#define HDR__FROM		5
#define HDR__LINES		6
#define HDR__MESSAGE_ID		7
#define HDR__NEWSGROUPS		8
#define HDR__PATH		9
#define HDR__REPLY_TO		10
#define HDR__SENDER		11
#define HDR__SUBJECT		12
#define HDR__SUPERSEDES		13
#define HDR__BYTES		14
#define HDR__ALSOCONTROL	15
#define HDR__REFERENCES		16
#define HDR__XREF		17
#define HDR__KEYWORDS		18
#define HDR__XTRACE		19
#define HDR__DATERECEIVED	20
#define HDR__POSTED		21
#define HDR__POSTINGVERSION	22
#define HDR__RECEIVED		23
#define HDR__RELAYVERSION	24
#define HDR__NNTPPOSTINGHOST	25
#define HDR__FOLLOWUPTO		26
#define HDR__ORGANIZATION	27
#define HDR__CONTENTTYPE	28
#define HDR__CONTENTBASE	29
#define HDR__CONTENTDISPOSITION	30
#define HDR__XNEWSREADER	31
#define HDR__XMAILER		32
#define HDR__XNEWSPOSTER	33
#define HDR__XCANCELLEDBY	34
#define HDR__XCANCELEDBY	35
#define HDR__CANCELKEY		36
#define HDR__USER_AGENT		37
#define HDR__X_ORIGINAL_MESSAGE_ID	38
#define HDR__CANCEL_LOCK	39
#define HDR__CONTENT_TRANSFER_ENCODING	40
#define HDR__FACE		41
#define HDR__INJECTION_INFO	42
#define HDR__LIST_ID		43
#define HDR__MIME_VERSION	44
#define HDR__ORIGINATOR		45
#define HDR__X_AUTH		46
#define HDR__X_COMPLAINTS_TO	47
#define HDR__X_FACE		48
#define HDR__X_HTTP_USERAGENT	49
#define HDR__X_HTTP_VIA		50
#define HDR__X_MODBOT		51
#define HDR__X_MODTRACE		52
#define HDR__X_NO_ARCHIVE	53
#define HDR__X_ORIGINAL_TRACE	54
#define HDR__X_ORIGINATING_IP	55
#define HDR__X_PGP_KEY		56
#define HDR__X_PGP_SIG		57
#define HDR__X_POSTER_TRACE	58
#define HDR__X_POSTFILTER	59
#define HDR__X_PROXY_USER	60
#define HDR__X_SUBMISSIONS_TO	61
#define HDR__X_USENET_PROVIDER	62
#define HDR__IN_REPLY_TO	63
#define HDR__INJECTION_DATE	64
#define HDR__NNTP_POSTING_DATE	65
#define HDR__X_USER_ID          66
#define HDR__X_AUTH_SENDER      67
#define HDR__X_ORIGINAL_NNTP_POSTING_HOST       68
#define HDR__ORIGINAL_SENDER    69
#define HDR__NNTP_POSTING_PATH  70
#define HDR__ARCHIVE            71
#define HDR__ARCHIVED_AT        72
#define HDR__SUMMARY            73
#define HDR__COMMENTS           74
#define HDR__JABBER_ID          75

#define MAX_ARTHEADER           76

/*
**  Miscellaneous data we want to keep on an article.  All the fields
**  are not always valid.
*/
typedef struct _ARTDATA {
  size_t	  Body;			/* where body begins in article
					   it indicates offset from bp->Data */
  time_t	  Posted;		/* when article posted */
  time_t	  Arrived;		/* when article arrived */
  time_t	  Expires;		/* when article should be expired */
  int		  Lines;		/* number of body lines */
  int		  HeaderLines;		/* number of header lines */
  char            LinesBuffer[SMBUF];   /* Generated Lines: header. */
  long		  BytesValue;		/* size of stored article, "\r\n" is
					   counted as 2 bytes */
  char            Bytes[SMBUF];         /* Generated Bytes: header. */
  int             BytesLength;          /* Generated Bytes: header length. */
  char        *   BytesHeader;          /* Where Bytes: header begins in
                                           received article. */
  char		  TokenText[(sizeof(TOKEN) * 2) + 3];
					/* token of stored article */
  LISTBUFFER	  Newsgroups;		/* newsgroup list */
  int		  Groupcount;		/* number of newsgroups */
  int		  Followcount;		/* number of folloup to newsgroups */
  char	      *   Xref;			/* generated Xref header */
  int		  XrefLength;		/* generated Xref header length */
  int		  XrefBufLength;	/* buffer length of generated Xref
					   header */
  LISTBUFFER	  Distribution;		/* distribution list */
  const char  *   Feedsite;		/* who gives me this article */
  int		  FeedsiteLength;	/* length of Feedsite */
  LISTBUFFER	  Path;			/* path name list */
  int		  StoredGroupLength;	/* 1st newsgroup name in Xref */
  char	      *   Replic;		/* replication data */
  int		  ReplicLength;		/* length of Replic */
  HASH	      *   Hash;			/* Message-ID hash */
  struct buffer	  Headers;		/* buffer for headers which will be sent
					   to site */
  struct buffer	  Overview;		/* buffer for overview data */
  int		  CRwithoutLF;		/* counter for '\r' without '\n' */
  int		  LFwithoutCR;		/* counter for '\n' without '\r' */
  int             DotStuffedLines;      /* counter for lines beginning with '.' */
  size_t	  CurHeader;		/* where current header starts.
					   this is used for folded header
					   it indicates offset from bp->Data */
  HDRCONTENT	  HdrContent[MAX_ARTHEADER];
					/* includes system headers info */
  bool            AddAlias;             /* Whether Pathalias should be added
                                           to this article */
  bool            Hassamepath;          /* Whether this article matches Path */
  bool            Hassamecluster;       /* Whether this article matches 
                                           Pathcluster */
} ARTDATA;


/* Set of channel types. */
enum channel_type {
    CTany,
    CTfree,
    CTremconn,
    CTreject,
    CTnntp,
    CTlocalconn,
    CTcontrol,
    CTfile,
    CTexploder,
    CTprocess
};

/* The state a channel is in.  Interpretation of this depends on the channel's
   type.  Used mostly by CTnntp channels. */
enum channel_state {
    CSerror,
    CSwaiting,
    CSgetcmd,
    CSgetauth,
    CSwritegoodbye,
    CSwriting,
    CSpaused,
    CSgetheader,
    CSgetbody,
    CSgotarticle,
    CSgotlargearticle,
    CSnoarticle,
    CSeatarticle,
    CSeatcommand,
    CSgetxbatch,
    CScancel
};


#define SAVE_AMT	10	/* used for eating article/command */
#define PRECOMMITCACHESIZE 128

/*
**  I/O channel, the heart of the program.  A channel has input and output
**  buffers, and functions to call when there is input to be read, or when
**  all the output was been written.  Many callback functions take a
**  pointer to a channel, so set up a typedef for that.
*/
struct _CHANNEL;
typedef void (*innd_callback_func)     (struct _CHANNEL *);
typedef void (*innd_callback_nntp_func)(struct _CHANNEL *);

typedef struct _CHANNEL {
  enum channel_type    Type;
  enum channel_state   State;
  int		       fd;
  int                  ac; /* Number of arguments in NNTP command. */
  char              ** av; /* List of arguments in NNTP command. */
  bool		       Skip;
  bool                 Ignore;
  bool		       Streaming;
  bool		       NoResendId;
  bool		       privileged;
  bool		       Nolist;
  bool                 CanAuthenticate; /* Can use AUTHINFO? */
  bool                 IsAuthenticated; /* No need to use AUTHINFO? */
  bool                 HasSentUsername; /* Has used AUTHINFO USER? */
  unsigned long        Duplicate;
  unsigned long        Duplicate_checkpoint;
  unsigned long	       Unwanted_s;
  unsigned long	       Unwanted_f;
  unsigned long	       Unwanted_d;
  unsigned long	       Unwanted_g;
  unsigned long	       Unwanted_u;
  unsigned long	       Unwanted_o;
  float                Size;
  float                Size_checkpoint;
  float                DuplicateSize;
  float                DuplicateSize_checkpoint;
  float                RejectSize;
  float                RejectSize_checkpoint;
  unsigned long	       Check;
  unsigned long	       Check_send;
  unsigned long	       Check_deferred;
  unsigned long	       Check_got;
  unsigned long	       Check_cybercan;
  unsigned long	       Takethis;
  unsigned long	       Takethis_Ok;
  unsigned long	       Takethis_Err;
  unsigned long	       Ihave;
  unsigned long	       Ihave_Duplicate;
  unsigned long	       Ihave_Deferred;
  unsigned long	       Ihave_SendIt;
  unsigned long	       Ihave_Cybercan;
  unsigned long        Reported;
  unsigned long        Received;
  unsigned long        Received_checkpoint;
  unsigned long        Refused;
  unsigned long        Refused_checkpoint;
  unsigned long        Rejected;
  unsigned long        Rejected_checkpoint;
  unsigned long        BadWrites;
  unsigned long        BadReads;
  unsigned long        BlockedWrites;
  unsigned int         BadCommands;
  time_t	       LastActive;
  time_t	       NextLog;
  struct sockaddr_storage Address;
  innd_callback_func   Reader;
  innd_callback_func   WriteDone;
  time_t	       Waketime;
  time_t               Started;
  time_t               Started_checkpoint;
  innd_callback_func   Waker;
  void		    *  Argument;
  void		    *  Event;
  struct buffer	       In;
  struct buffer	       Out;
  bool		       Tracing;
  struct buffer	       Sendid;
  HASH		       CurrentMessageIDHash;
  struct _WIP	    *  PrecommitWIP[PRECOMMITCACHESIZE];
  int		       PrecommitiCachenext;
  int		       XBatchSize;
  int		       LargeArtSize;
  int		       LargeCmdSize;
  int		       ActiveCnx;
  int		       MaxCnx;
  int		       HoldTime;
  time_t	       ArtBeg;
  int		       ArtMax;
  size_t	       Start;		/* where current cmd/article starts
					   it indicates offset from bp->Data */
  size_t	       Next;		/* next pointer to read
					   it indicates offset from bp->Data */
  char		       Error[SMBUF];	/* error buffer */
  ARTDATA	       Data;		/* used for processing article */
  char                 Name[SMBUF];     /* storage for CHANname */
} CHANNEL;

#define	DEFAULTNGBOXSIZE	64

/*
**  Different types of rejected articles.
*/
typedef enum {REJECT_DUPLICATE, REJECT_SITE, REJECT_FILTER, REJECT_DISTRIB,
	      REJECT_GROUP, REJECT_UNAPP, REJECT_OTHER} Reject_type;

/*
**  A newsgroup has a name in different formats, and a high water count,
**  also kept in different formats.  It also has a list of sites that
**  get this group.
*/
typedef struct _NEWSGROUP {
  long			Start;	     /* Offset into the active file  */
  char		     *  Name;
  int			NameLength;
  ARTNUM		Last;
  ARTNUM		Filenum;     /* File name to use             */
  int			Lastwidth;
  int			PostCount;   /* Have we already put it here? */
  char		     *  LastString;
  char		     *  Rest;	     /* Flags, NOT NULL TERMINATED   */
  SITEIDX		nSites;
  int		     *  Sites;
  SITEIDX		nPoison;
  int		     *  Poison;
  struct _NEWSGROUP  *  Alias;
} NEWSGROUP;


/*
**  How a site is fed.
*/
typedef enum _FEEDTYPE {
  FTerror,
  FTfile,
  FTchannel,
  FTexploder,
  FTfunnel,
  FTlogonly,
  FTprogram
} FEEDTYPE;

/*
**  Diablo-style hashed feeds or hashfeeds.
*/
#define HASHFEED_QH 1
#define HASHFEED_MD5 2

typedef struct _HASHFEEDLIST {
  int type;
  unsigned int begin;
  unsigned int end;
  unsigned int mod;
  unsigned int offset;
  struct _HASHFEEDLIST *next;
} HASHFEEDLIST;

/*
**  A site may reject something in its subscription list if it has
**  too many hops, or a bad distribution.
*/
typedef struct _SITE {
  const char  *   Name;
  char	      *   Entry;
  int		  NameLength;
  char	      **  Exclusions;
  char	      **  Distributions;
  char	      **  Patterns;
  bool		  Poison;
  bool		  PoisonEntry;
  bool		  Sendit;
  bool		  Seenit;
  bool		  IgnoreControl;
  bool		  DistRequired;
  bool		  IgnorePath;
  bool		  ControlOnly;
  bool		  DontWantNonExist;
  bool		  NeedOverviewCreation;
  bool		  FeedwithoutOriginator;
  bool		  DropFiltered;
  bool            FeedTrash;
  int		  Hops;
  int		  Groupcount;
  int		  Followcount;
  int		  Crosscount;
  FEEDTYPE	  Type;
  NEWSGROUP   *   ng;
  bool		  Spooling;
  char	      *   SpoolName;
  bool		  Working;
  long		  StartWriting;
  long		  StopWriting;
  long		  StartSpooling;
  char	      *   Param;
  char		  FileFlags[FEED_MAXFLAGS + 1];
  long		  MaxSize;
  long		  MinSize;
  int		  Nice;
  CHANNEL     *   Channel;
  bool		  IsMaster;
  int		  Master;
  int		  Funnel;
  bool		  FNLwantsnames;
  struct buffer	  FNLnames;
  int		  Process;
  pid_t		  pid;
  size_t	  Flushpoint;
  struct buffer	  Buffer;
  bool		  Buffered;
  char	      **  Originator;
  HASHFEEDLIST *  HashFeedList;
  int		  Next;
  int		  Prev;
} SITE;


/*
**  A process is something we start up to send articles.
*/
typedef enum _PROCSTATE {
  PSfree,
  PSrunning,
  PSdead
} PROCSTATE;


/*
**  We track our children and collect them synchronously.
*/
typedef struct _PROCESS {
  PROCSTATE	State;
  pid_t		Pid;
  int		Status;
  time_t	Started;
  time_t	Collected;
  int		Site;
} PROCESS;

/*
**  A work in progress entry, an article that we've been offered but haven't
**  received yet.
*/
typedef struct _WIP {
  HASH		MessageID;	/* Hash of the messageid.  Doing it like
				   this saves us from haveing to allocate
				   and deallocate memory a lot, and also
				   means lookups are faster. */ 
  time_t	Timestamp;	/* Time we last looked at this MessageID */
  CHANNEL	*Chan;		/* Channel that this message is associated
				   with */
  struct _WIP	*Next;		/* Next item in this bucket */
} WIP;

/*
**  Supported timers.  If you add new timers to this list, also add them to
**  the list of tags in chan.c.
*/
enum timer {
    TMR_IDLE = TMR_APPLICATION, /* Server is completely idle. */
    TMR_ARTCLEAN,               /* Analyzing an incoming article. */
    TMR_ARTWRITE,               /* Writing an article. */
    TMR_ARTCNCL,                /* Processing a cancel message. */
    TMR_SITESEND,               /* Sending an article to feeds. */
    TMR_OVERV,                  /* Generating overview information. */
    TMR_PERL,                   /* Perl filter. */
    TMR_PYTHON,                 /* Python filter. */
    TMR_NNTPREAD,               /* Reading NNTP data from the network. */
    TMR_ARTPARSE,               /* Parsing an article. */
    TMR_ARTLOG,                 /* Logging article disposition. */
    TMR_DATAMOVE,               /* Moving data. */
    TMR_MAX
};



/*
**  In-line macros for efficiency.
**
**  Set or append data to a channel's output buffer.
*/
#define WCHANset(cp, p, l)      buffer_set(&(cp)->Out, (p), (l))
#define WCHANappend(cp, p, l)   buffer_append(&(cp)->Out, (p), (l))

/*
**  Mark that an I/O error occurred, and block if we got too many.
*/
#define IOError(WHEN, e)                    \
  do {                                      \
    if (--ErrorCount <= 0 || (e) == ENOSPC) \
      ThrottleIOError(WHEN);                \
  } while (0)


/*
**  Global data.
**
** Do not change "extern" to "EXTERN" in the Global data.  The ones
** marked with "extern" are initialized in innd.c.  The ones marked
** with "EXTERN" are not explicitly initialized in innd.c.
*/
#if defined(DEFINE_DATA)
# define EXTERN		/* NULL */
#else
# define EXTERN		extern
#endif
extern const ARTHEADER	ARTheaders[MAX_ARTHEADER];
extern bool		BufferedLogs;
EXTERN bool		AnyIncoming;
extern bool		Debug;
EXTERN bool		ICDneedsetup;
EXTERN bool		NeedHeaders;
EXTERN bool		NeedOverview;
EXTERN bool		NeedPath;
EXTERN bool		NeedStoredGroup;
EXTERN bool		NeedReplicdata;
extern bool		NNRPTracing;
extern bool		StreamingOff;
extern bool		Tracing;
EXTERN struct buffer	Path;
EXTERN struct buffer	Pathalias;
EXTERN struct buffer    Pathcluster;
EXTERN char	     *  ModeReason;	/* NNTP reject message   */
EXTERN char	     *  NNRPReason;	/* NNRP reject message   */
EXTERN char	     *  Reservation;	/* Reserved lock message */
EXTERN char	     *  RejectReason;	/* NNTP reject message   */
EXTERN FILE	     *  Errlog;
EXTERN FILE	     *  Log;
extern char		LogName[];
extern int		ErrorCount;
EXTERN unsigned long    ICDactivedirty;
EXTERN int		MaxOutgoing;
EXTERN int		nGroups;
EXTERN SITEIDX		nSites;
EXTERN int		PROCneedscan;
EXTERN NEWSGROUP    **	GroupPointers;
EXTERN NEWSGROUP    *	Groups;
extern OPERATINGMODE	Mode;
EXTERN sig_atomic_t	GotTerminate;
EXTERN SITE	    *	Sites;
EXTERN SITE		ME;
EXTERN struct timeval	TimeOut;
EXTERN struct timeval	Now;		/* Reasonably accurate time     */
EXTERN bool		ThrottledbyIOError;
EXTERN char	    *   NCgreeting;
EXTERN struct history   *History;

/*
** Table size for limiting incoming connects.  Do not change the table
** size unless you look at the code manipulating it in rc.c.
*/
#define REMOTETABLESIZE	128

/*
** Setup the default values.  The REMOTETIMER being zero turns off the
** code to limit incoming connects.
*/
#define REMOTELIMIT	2
#define REMOTETIMER	0
#define REMOTETOTAL	60
#define REJECT_TIMEOUT	10
extern int		RemoteLimit;	/* Per host limit. */
extern time_t		RemoteTimer;	/* How long to remember connects. */
extern int		RemoteTotal;	/* Total limit. */


/*
**  Function declarations.
*/
extern void	        InndHisOpen(void);
extern void             InndHisClose(void);
extern bool             InndHisWrite(const char *key, time_t arrived,
				     time_t posted, time_t expires,
				     TOKEN *token);
extern bool             InndHisRemember(const char *key, time_t posted);
extern void             InndHisLogStats(void);
extern bool		FormatLong(char *p, unsigned long value, int width);
extern bool		NeedShell(char *p, const char **av, const char **end);
extern char	    **	CommaSplit(char *text);
extern void		SetupListBuffer(int size, LISTBUFFER *list);
extern char         *	MaxLength(const char *p, const char *q);
extern pid_t		Spawn(int niceval, int fd0, int fd1, int fd2,
			      char * const av[]);
extern void		CleanupAndExit(int x, const char *why)
    __attribute__ ((__noreturn__));
extern void		JustCleanup(void);
extern void		ThrottleIOError(const char *when);
extern void		ThrottleNoMatchError(void);
extern void		ReopenLog(FILE *F);
extern void		xchown(char *p);

extern bool		ARTreadschema(void);
extern const char   *	ARTreadarticle(char *files);
extern char	    *   ARTreadheader(char *files);
extern bool		ARTpost(CHANNEL *cp);
extern void		ARTcancel(const ARTDATA *Data,
				  const char *MessageID, bool Trusted);
extern void		ARTclose(void);
extern void		ARTsetup(void);
extern void		ARTprepare(CHANNEL *cp);
extern void		ARTparse(CHANNEL *cp);
extern void             ARTlogreject(CHANNEL *cp, const char *text);
extern void		ARTreject(Reject_type, CHANNEL *);

extern bool		CHANsleeping(CHANNEL *cp);
extern CHANNEL      *	CHANcreate(int fd, enum channel_type Type,
				   enum channel_state State,
				   innd_callback_func Reader,
				   innd_callback_func WriteDone);
extern CHANNEL      *	CHANiter(int *cp, enum channel_type Type);
extern CHANNEL      *	CHANfromdescriptor(int fd);
extern char	    *   CHANname(CHANNEL *cp);
extern int		CHANreadtext(CHANNEL *cp);
extern void		CHANclose(CHANNEL *cp, const char *name);
extern void		CHANreadloop(void)
    __attribute__ ((__noreturn__));
extern void		CHANsetup(int i);
extern void		CHANshutdown(void);
extern void		CHANtracing(CHANNEL *cp, bool Flag);
extern void		CHANcount_active(CHANNEL *cp);

extern void		RCHANadd(CHANNEL *cp);
extern void		RCHANremove(CHANNEL *cp);

extern void		SCHANadd(CHANNEL *cp, time_t Waketime, void *Event,
				 innd_callback_func Waker, void *Argument);
extern void		SCHANremove(CHANNEL *cp);
extern void		SCHANwakeup(void *Event);

extern bool		WCHANflush(CHANNEL *cp);
extern void		WCHANadd(CHANNEL *cp);
extern void		WCHANremove(CHANNEL *cp);
extern void		WCHANsetfrombuffer(CHANNEL *cp, struct buffer *bp);

extern void		CCcopyargv(char *av[]);
extern const char   *	CCaddhist(char *av[]);
extern const char   *	CCblock(OPERATINGMODE NewMode, char *reason);
extern const char   *	CCcancel(char *av[]);
extern const char   *	CCcheckfile(char *av[]);

extern bool		ICDnewgroup(char *Name, char *Rest);
extern char	    *   ICDreadactive(char **endp);
extern bool		ICDchangegroup(NEWSGROUP *ngp, char *Rest);
extern void		ICDclose(void);
extern bool		ICDrenumberactive(void);
extern bool		ICDrmgroup(NEWSGROUP *ngp);
extern void		ICDsetup(bool StartSites);
extern void		ICDwrite(void);
extern void		ICDwriteactive(void);

extern void		CCclose(void);
extern void		CCsetup(void);

extern void             KEYgenerate(HDRCONTENT *, const char *body, size_t bodylen);

extern void		LCclose(void);
extern void		LCsetup(void);

extern int		NGsplit(char *p, int size, LISTBUFFER *List);
extern NEWSGROUP    *	NGfind(const char *Name);
extern void		NGclose(void);
extern CHANNEL	    *	NCcreate(int fd, bool MustAuthorize, bool IsLocal);
extern void		NGparsefile(void);
extern bool		NGrenumber(NEWSGROUP *ngp);
extern bool		NGlowmark(NEWSGROUP *ngp, long lomark);

extern void		NCclearwip(CHANNEL *cp);
extern void		NCclose(void);
extern void		NCsetup(void);
extern void		NCwritereply(CHANNEL *cp, const char *text);
extern void		NCwriteshutdown(CHANNEL *cp, const char *text);

/* perl.c */
extern char	    *	PLartfilter(const ARTDATA *Data, char *artBody, long artLen, int lines);
extern char	    *   PLmidfilter(char *messageID);
extern void		PLmode(OPERATINGMODE mode, OPERATINGMODE NewMode,
			       char *reason);
extern char         *   PLstats(void);
extern void		PLxsinit(void);

extern int		PROCwatch(pid_t pid, int site);
extern void		PROCunwatch(int process);
/* extern void		PROCclose(bool Quickly); */
extern void		PROCscan(void);
extern void		PROCsetup(int i);

extern int		RClimit(CHANNEL *cp);
extern bool		RCnolimit(CHANNEL *cp);
extern bool		RCauthorized(CHANNEL *cp, char *pass);
extern int		RCcanpost(CHANNEL *cp, char *group);
extern char	    *	RChostname(const CHANNEL *cp);
extern char	    *	RClabelname(CHANNEL *cp);
extern void		RCclose(void);
extern void		RChandoff(int fd, HANDOFF h);
extern void		RCreadlist(void);
extern void		RCsetup(void);

extern bool		SITEfunnelpatch(void);
extern bool		SITEsetup(SITE *sp);
extern bool		SITEwantsgroup(SITE *sp, char *name);
extern bool		SITEpoisongroup(SITE *sp, char *name);
extern char	    **	SITEreadfile(const bool ReadOnly);
extern SITE	    *	SITEfind(const char *p);
extern SITE	    *	SITEfindnext(const char *p, SITE *sp);
extern const char   *	SITEparseone(char *Entry, SITE *sp,
				     char *subbed, char *poison);
extern void		SITEchanclose(CHANNEL *cp);
extern void		SITEdrop(SITE *sp);
extern void		SITEflush(SITE *sp, const bool Restart);
extern void		SITEflushall(const bool Restart);
extern void		SITEforward(SITE *sp, const char *text);
extern void		SITEfree(SITE *sp);
extern void		SITEinfo(struct buffer *bp, SITE *sp, bool Verbose);
extern void		SITEparsefile(bool StartSite);
extern void		SITEprocdied(SITE *sp, int process, PROCESS *pp);
extern void		SITEsend(SITE *sp, ARTDATA *Data);
extern void		SITEwrite(SITE *sp, const char *text);

extern void		STATUSinit(void);
extern void		STATUSmainloophook(void);

extern void		WIPsetup(void);
extern WIP	    *	WIPnew(const char *messageid, CHANNEL *cp);
extern void		WIPprecomfree(CHANNEL *cp);
extern void		WIPfree(WIP *wp);
extern bool		WIPinprogress(const char *msgid, CHANNEL *cp,
				      bool Add);
extern WIP	    *	WIPbyid(const char *mesageid);
extern WIP	    *	WIPbyhash(const HASH hash);

/*
**  Python globals and functions
*/
#if DO_PYTHON
extern bool		PythonFilterActive;

void			PYfilter(bool value);
extern const char   *	PYcontrol(char **av);
extern int		PYreadfilter(void);
extern char	    *	PYartfilter(const ARTDATA *Data, char *artBody, long artLen, int lines);
extern char	    *	PYmidfilter(char *messageID, int msglen);
extern void		PYmode(OPERATINGMODE mode, OPERATINGMODE newmode,
			       char *reason);
extern void		PYsetup(void);
extern void		PYclose(void);
#endif /* DO_PYTHON */

END_DECLS

#endif /* INND_H */
