/*
 * sma -- Sendmail log analyser
 *
 * Copyright (c) 2000, 2001, 2002 Jarkko Turkulainen. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Date: 2003/04/03 12:43:33 $
 */
#include "conf.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>

#ifdef USE_REGEXP
#include <sys/types.h>
#if defined _WIN32
#include "regex/regex.h"
#else /* defined _WIN32 */
#include <regex.h>
#endif /* defined _WIN32 */
#endif /* defined USE_REGEXP */

#if !defined _WIN32
#include <unistd.h>
#endif

#define VERSION		"1.4"
#define FORMAT_ASCII	3
#define FORMAT_HTML	2
#define FORMAT_CLOG	5

/* pointer to program name: */
char *pname;

/* current time: */
time_t tval;
struct tm *curr;
struct tm tp;

/*
 * Command line arguments
 * xflag sets argument x on/off
 * xchar is pointer to argument string if x requires an argument
 */
int aflag;
int cflag;
int dflag;
int hflag;
int nflag;
int sflag;
int qflag;
int lflag;
int vflag;
int wflag;
unsigned int lnum;
unsigned int lrnum;
int rflag;
unsigned int rnum;
unsigned int rrnum;
int bflag;
const char *bchar;
int fflag;
const char *fchar;
int oflag;
const char *ochar;
int Lflag;
const char *Lchar;
int Oflag;
const char *Ochar;
int Dflag;
const char *Dchar;
int pflag;
int iflag;
int tflag;
int dcaddrflag;
const char *tchar;

/* Configuration file parameters: */
int Hflag;
const char *Hchar;
int Cflag;
const char *Cchar;
int Fflag;
const char *tbchar;
int pgflag;
const char *bechar;
const char *cfchar;
const char *puchar;
const char *pachar;
const char *plchar;
const char *ppchar;
const char *htchar;
const char *ftchar;
int csflag;
int lrflag;
int rrflag;
int clsflag;
unsigned int stnum;
unsigned int rsnum;
unsigned int rsrnum;
unsigned int epnum;
unsigned int rpnum;

/* Start and end times: */
char *sstring;
char *estring;
char *tstring;
time_t sstime;
time_t eetime;
int syear;
int smonth;
int sday;
int shour;
int sminute;
int ssecond;
int eyear;
int emonth;
int eday;
int ehour;
int eminute;
int esecond;

/* hash table sizes: */
int asize;
int rsize;
char *hsstring;
char *hastring;
char *hrstring;

/* sender structure: */
struct in {

	/* next struct: */
	struct in *next;

	/* name of the entry: */
	char *name;

	/* total number of msgs: */
	unsigned int num;

	/* total size: */
	long double size;
};

/* receiver structure: */
struct out {

	/* next struct: */
	struct out *next;

	/* name of the entry: */
	char *name;

	/* total number of msgs: */
	unsigned int num;

	/* total size: */
	long double size;

};

/* input relay struct: */
struct rin {

	/* next */
	struct rin *next;

	/* name: */
	char *name;

	/* total number: */
	unsigned int num;

	/* total size: */
	long double size;
};

/* output relay struct: */
struct rout {

	/* next */
	struct rout *next;

	/* name: */
	char *name;

	/* total number: */
	unsigned int num;

	/* total size: */
	long double size;
};

/* message id structure: */
struct msgid {

	/* next */
	struct msgid *next;

	/* message id */
	char *id;

	/* msgid */
	char *msgid;

	/* sender */
	char *sender;

	/* relay */
	char *relay;

	/* hour and day */
	int hh;
	int day;

	/* size of the msg */
	long double size;

	/* number of msgs  */
	int num;

	/* flags */
	int flag;
};

/*
 * Structure for out-of-order messages, that is for
 * messages without "to=" line in log (unknown local user etc.)
 */
struct omsgid {

	/* next */
	struct omsgid *next;

	/* message id */
	char *id;

	/* flags */
	int flags;
};

/* Relay structure for rulesets: */
struct rrelay {

	/* next */
	struct rrelay *next;

	/* name: */
	char *name;

	/* total number: */
	unsigned int num;

};

/* Structure for ruleset based rejections */
struct rule {

	/* next */
	struct rule *next;

	/* Relay structure for rulesets: */
	struct rrelay *rrelaytab;
	struct rrelay **srrelaytab;
	unsigned int reldif;

	/* name: */
	char *name;

	/* total number: */
	unsigned int num;

};

/* Status structure */
struct status {

	/* next */
	struct status *next;

	/* name: */
	char *name;

	/* total number: */
	unsigned int num;
};

/* Envelope pair structure */
struct envpair {

	/* next */
	struct envpair *next;

	/* pairs: */
	char *fname;
	char *tname;

	/* total number: */
	unsigned int num;

	/* total size: */
	long double size;
};

/* Relay pair structure */
struct relpair {

	/* next */
	struct relpair *next;

	/* pairs: */
	char *fname;
	char *tname;

	/* total number: */
	unsigned int num;

	/* total size: */
	long double size;
};


/* host structure: */
struct host {

	/* next struct: */
	struct host *next;

	/* name of the entry: */
	char *name;

	/* envelope pair structures: */
	struct envpair **etab;
	struct envpair **setab;

	/* pointers to in -and out addresses: */
	struct in **itab;
	struct out **otab;
	struct in **sitab;
        struct out **sotab;

	/* relay pair structures: */
	struct relpair **rtab;
	struct relpair **srtab;

	/* pointers to in -and out relays: */
	struct rin **ritab;
	struct rout **rotab;
	struct rin **rsitab;
	struct rout **rsotab;

	/* ruleset structures */
	struct rule **ruletab;
	struct rule **sruletab;

	/* status structures */
	struct status **sttab;
	struct status **ssttab;

	/* pointer to message id table: */
	struct msgid *msgidtab;

	/* pointer to out-of-order msg ids: */
	struct omsgid *omsgidtab;

	/* start and end times: */
	time_t ftime;
	time_t ltime;
	time_t cdtime;
	double dtime;
	int fday;
	int lday;
	int fhour;

	/* alias table rebuilds: */
	int alias;

	/* SYSERR: */
	int hopc;
	int lcerror;
	int oserror;

	/* daemon starts: */
	int dstart;

	/* time tables: */
	int ihh[24];
	float fihh[24];
	int idd[7];
	float fidd[7];
	int ohh[24];
	float fohh[24];
	int odd[7];
	float fodd[7];

	/* total number of msgs: */
	unsigned long inum;
	unsigned long onum;
	unsigned long rinum;
	unsigned long ronum;
	unsigned long gonum;

	/* stat-fields: Sent, queued, Host unknown, Deferred ...*/
	int sent;
	int queu;
	int hunk;
	int uunk;
	int defe;
	int rule;
	int service;
	int other;

	/* total size of msgs: */
	long double size;
	long double isize;
	long double osize;
	int lsize;
	int fhost;

	/* total number of different messages: */
	unsigned int edif; /* envelope pairs */
	unsigned int rrdif; /* relay pairs */
	unsigned int idif; /* input envelope */
	unsigned int odif; /* output envelope */
	unsigned int ridif; /* input relay */
	unsigned int rodif; /* output relay */
	unsigned int sdif; /* status messages */
	unsigned int rdif; /* rejected messages */

};

/* Filters */
char *sef;
char *ref;
char *srf;
char *rrf;
#ifdef USE_REGEXP
regex_t csef;
regex_t cref;
regex_t csrf;
regex_t crrf;
#endif

/* Output file handle: */
FILE *ofp;

/* total number of hosts: */
int hosts;

/* inital host structure: */
struct host first;

/* function definitions: */
void usage(void);
void error_memory(void);
void parse(FILE *, const char *);
time_t conv_time(int, int, int, int, int);
int conv_mon(const char *);
void copying(void);
const char * get_name(char *);
const char * get_relay_name(char *);
unsigned hash(const char *,int);
struct host *init_host(const char *);
void update_in(struct host *, const char *, int);
void remove_in(struct host *, const char *, int);
void update_out(struct host *, const char *, int);
void update_rin(struct host *, const char *, int);
void remove_rin(struct host *, const char *, int);
void update_rout(struct host *, const char *, int);
int comp_env(const void *, const void *);
int comp_in(const void *, const void *);
int comp_out(const void *, const void *);
int comp_rel(const void *, const void *);
int comp_rin(const void *, const void *);
int comp_rout(const void *, const void *);
int comp_s(const void *, const void *);
int comp_r(const void *, const void *);
int comp_rrel(const void *, const void *);
void sort(struct host *);
void average(struct host *, int *, float *, int *, float *);
void html(FILE *);
void ascii(FILE *);
void init(FILE *);
int update_msgid(struct host *, const char *, const char *, const char *,
	int, int, int, int, const char *);
int update_omsgid(struct host *, const char *, int);
void check_msgid(struct host *, const char *, int);
void remove_msgid(struct host *, const char *);
int check_omsgid(struct host *, const char *);
struct msgid *get_msgid(struct host *, const char *);
char * stripn(char *);
char * get_string(char *);
void printclog(time_t, const char *, int, const char *, const char *,
	const char *, const char *, const char *, int);
void update_status(struct host *, const char *);
void update_ruleset(struct host *, const char *, const char *);
void update_envpair(struct host *, const char *, const char *, int);
void update_relpair(struct host *, const char *, const char *, int);
void scan_time(time_t *, char *);
void dump_config(FILE *);

/* macros */
#define MIN(a,b) (a > b) ? b : a
