/* $Id: innd.h 6907 2004-05-27 18:55:23Z rra $
**
** Many of the data types used here have abbreviations, such as CT
** for CHANNELTYPE. 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/time.h"
#include "portable/socket.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <syslog.h>
#include <sys/stat.h>
#include "inn/buffer.h"
#include "inn/history.h"
#include "inn/messages.h"
#include "inn/timer.h"
#include "libinn.h"
#include "nntp.h"
#include "paths.h"
#include "storage.h"
/* TCL defines EXTERN, so undef it after inclusion since we use it. */
#if DO_TCL
# include <tcl.h>
# undef EXTERN
#endif
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.
*/
typedef enum _OPERATINGMODE {
OMrunning,
OMpaused,
OMthrottled
} 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 */
} HDRCONTENT;
/*
** A way to index into the header table.
*/
#define HDR_FOUND(_x) (hc[(_x)].Length > 0)
#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] = '\r'
#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 MAX_ARTHEADER 39
/*
** Miscellaneous data we want to keep on an article. All the fields
** are not always valid.
*/
typedef struct _ARTDATA {
int Body; /* where body begins in article
it indicates offset from bp->Data */
char * Poster; /* Sender otherwise From in article */
char * Replyto; /* Reply-To otherwise From in article */
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 */
long BytesValue; /* size of stored article, "\r\n" is
counted as 1 byte */
char Bytes[16]; /* 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' */
long CurHeader; /* where current header starts.
this is used for folded header
it indicates offset from bp->Data */
bool NullHeader; /* contains NULL in current header */
long LastTerminator; /* where last '.' exists. only set if
it exists at the begining of line
it indicates offset from bp->Data */
long LastCR; /* where last CR exists
it indicates offset from bp->Data */
long LastCRLF; /* where last CRLF exists.
indicates where last LF exists
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 */
} ARTDATA;
/*
** Set of channel types.
*/
typedef enum _CHANNELTYPE {
CTany,
CTfree,
CTremconn,
CTreject,
CTnntp,
CTlocalconn,
CTcontrol,
CTfile,
CTexploder,
CTprocess
} CHANNELTYPE;
/*
** The state a channel is in. Interpretation of this depends on the
** channel's type. Used mostly by CTnntp channels.
*/
typedef enum _CHANNELSTATE {
CSerror,
CSwaiting,
CSgetcmd,
CSgetauth,
CSwritegoodbye,
CSwriting,
CSpaused,
CSgetheader,
CSgetbody,
CSgotarticle,
CSgotlargearticle,
CSnoarticle,
CSeatarticle,
CSeatcommand,
CSgetxbatch,
CScancel
} CHANNELSTATE;
#define SAVE_AMT 10 /* used for eating article/command */
/*
** 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.
*/
#define PRECOMMITCACHESIZE 128
struct _CHANNEL;
typedef void (*innd_callback_t)(struct _CHANNEL *);
typedef struct _CHANNEL {
CHANNELTYPE Type;
CHANNELSTATE State;
int fd;
bool Skip;
bool Streaming;
bool NoResendId;
bool privileged;
bool Nolist;
unsigned long Duplicate;
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 DuplicateSize;
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;
int Reported;
long Received;
long Refused;
long Rejected;
int BadWrites;
int BadReads;
int BlockedWrites;
int BadCommands;
time_t LastActive;
time_t NextLog;
struct sockaddr_storage Address;
innd_callback_t Reader;
innd_callback_t WriteDone;
time_t Waketime;
time_t Started;
innd_callback_t 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;
long Start; /* where current cmd/article starts
it indicates offset from bp->Data */
long Next; /* next pointer to read
it indicates offset from bp->Data */
char Error[SMBUF]; /* error buffer */
ARTDATA Data; /* used for processing article */
struct _CHANNEL *nextcp; /* linked list for each incoming site */
} CHANNEL;
#define DEFAULTNGBOXSIZE 64
/*
** 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;
/*
** 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;
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;
long Flushpoint;
struct buffer Buffer;
bool Buffered;
char ** Originator;
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 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 int 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 TIMEINFO 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);
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);
extern void FileGlue(char *p, const char *n1, char c, const char *n2);
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 ARTidok(const char *MessageID);
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 bool CHANsleeping(CHANNEL *cp);
extern CHANNEL * CHANcreate(int fd, CHANNELTYPE Type,
CHANNELSTATE State,
innd_callback_t Reader,
innd_callback_t WriteDone);
extern CHANNEL * CHANiter(int *cp, CHANNELTYPE Type);
extern CHANNEL * CHANfromdescriptor(int fd);
extern char * CHANname(const CHANNEL *cp);
extern int CHANreadtext(CHANNEL *cp);
extern void CHANclose(CHANNEL *cp, const char *name);
extern void CHANreadloop(void);
extern void CHANsetup(int i);
extern void CHANshutdown(void);
extern void CHANtracing(CHANNEL *cp, bool Flag);
extern void CHANsetActiveCnx(CHANNEL *cp);
extern void RCHANadd(CHANNEL *cp);
extern void RCHANremove(CHANNEL *cp);
extern void SCHANadd(CHANNEL *cp, time_t Waketime, void *Event,
innd_callback_t 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,
const char *orig, size_t length);
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(int i);
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);
/*
** TCL globals and functions
*/
#if DO_TCL
extern Tcl_Interp * TCLInterpreter;
extern bool TCLFilterActive;
extern struct buffer * TCLCurrArticle;
extern ARTDATA * TCLCurrData;
extern void TCLfilter(bool value);
extern void TCLreadfilter(void);
extern void TCLsetup(void);
extern void TCLclose(void);
#endif /* DO_TCL */
/*
** 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 */
syntax highlighted by Code2HTML, v. 0.9.1