/* Copyright (C) 1995 NetWin World, New Zealand, All rights reserved. */
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#ifdef WIN32
#include <io.h>
#endif
#include <errno.h>


#ifdef VMS
#include <unixio.h>
#endif
#ifndef WIN32
#ifndef Mac
#ifndef NOUNISTD
#include <unistd.h>
#endif
#endif
#endif        

#ifdef OS2
#include <io.h>
#endif
#ifndef NO_FCNTL
#include <fcntl.h>
#else
/*RHP not for mac*/
#ifndef Mac
#include <file.h>
#endif
#endif


#define IS_EMSG TRUE
#include "dnews.h"
#include "lib.h"
#include "emsg.h"
#ifdef DOTHREADS
#include "mutex.h"
#endif
#undef mymalloc
#undef myfree
#define mymalloc(x) mymalloc2(x,M_EMSG)
#define myfree(x) myfree2(x,M_EMSG)


void post_seterr(char *s);
void emsg_do(int lvl,char *in);
void emsg_rotate_debug(void);
void emsg_close(void);
void emsg_open(int clear);
void emsg_elog(char *s);
#ifdef NEED_STRERROR
char *strerror(int x);
#endif

enum {L_LOG,L_IN,L_OUT};
#define OUTSIZE 12000
static char output[OUTSIZE];
void log_flush_lvl2(int lvl);
void emsg_rotate_one(int lvl);
void log_system(int lvl, char *in);
void chan_sendlog(char *s);

#define NTRACE 200
void rej_flush(void);

void emsg_openx(int clear, int line);
static char *trace_fname[NTRACE];
static int trace_line[NTRACE];
void keeplog_do(char *in);
static int trace_id[NTRACE];
static int trace_upto,trace_disable;
void trace_add(char *fname, int line)
{	
#ifdef DOTHREADS
	mutex_wait(M_TRACE);
#endif
	trace_fname[trace_upto] = fname;
	trace_line[trace_upto] = line;
#ifdef DOTHREADS
	trace_id[trace_upto] = th_id();
#endif
	trace_upto++;
	if (trace_upto>=NTRACE) trace_upto = 0;
#ifdef DOTHREADS
	mutex_release(M_TRACE);
#endif
}
char *trace_xfname(int i)
{
	static char bf[BFSZ];
	char *s;
	strcpy(bf,trace_fname[i]);


	for (s=bf;*s!=0;s++) {
		if (*s=='\r') *s = 0;
		if (*s=='\n') *s = 0;	
	}
	return bf;
}
void trace_show(void)
{
	int i;
	char bf[BFSZ];

#ifdef isunix
	int f;

	f = open(file_log("crash.log"),O_WRONLY | O_CREAT | O_APPEND);
	if (f>0) {
	  strcpy(bf,"------------- Crash Trace Starts ----------\n");
          write(f,bf,strlen(bf));
	  for (i=trace_upto;i<NTRACE; i++) {
		if (trace_fname[i]==NULL) continue;
		lprintf(bf,BFSZ-1,"[%d] %s:%d\n",trace_id[i],trace_xfname(i),trace_line[i]);
		write(f,bf,strlen(bf));
	 }
	 for (i=0;i<trace_upto; i++) {
		if (trace_fname[i]==NULL) continue;
		lprintf(bf,BFSZ-1,"[%d] %s:%d\n",trace_id[i],trace_xfname(i),trace_line[i]);
		write(f,bf,strlen(bf));
	 }
	 close(f);
	}
#endif
	trace_disable = TRUE;
	emsg_do(D_ERROR,"------------- Crash Trace Starts ----------\n");
	for (i=trace_upto;i<NTRACE; i++) {
		if (trace_fname[i]==NULL) continue;
		lprintf(bf,BFSZ-1,"[%d] %s:%d\n",trace_id[i],trace_xfname(i),trace_line[i]);
		emsg_do(D_ERROR,bf);
	}
	for (i=0;i<trace_upto; i++) {
		if (trace_fname[i]==NULL) continue;
		lprintf(bf,BFSZ-1,"[%d] %s:%d\n",trace_id[i],trace_xfname(i),trace_line[i]);
		emsg_do(D_ERROR,bf);
	}

}
void trace_addmsg(char *msg)
{
	static char *lines[NTRACE];
	static int upto=0;

	if (trace_disable) return;
#ifdef DOTHREADS
	mutex_wait(M_TRACE);
#endif
	if (lines[upto]==NULL) lines[upto] = mymalloc(100);
	ncpy(lines[upto],msg,90);
	trace_add(lines[upto],0);
	upto++;
	if (upto>=NTRACE) upto = 0;
#ifdef DOTHREADS
	mutex_release(M_TRACE);
#endif
}


void inmsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;

        if (debug_lvl<D_INFO) return;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, INMSG ERROR TOO LONG\n");
        emsg_do(D_IN,output);
}
#define FILE_REJ file_log("dnews.rej")
#define FILE_REJ2 file_log("dnews2.rej")
#define FILE_REJ3 file_log("dnews3.rej")
#define FILE_REJ4 file_log("dnews4.rej")
static FILE *rejfile;
        
void sucklog_do(char *in);
void sucklog(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;

	
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        sucklog_do(output);
}
void keeplog(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;

	
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        keeplog_do(output);
}
void outmsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;

        if (debug_lvl<D_WARN) return;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, OUTMSG ERROR TOO LONG\n");
        emsg_do(D_OUT,output);
}
int emsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        static int busy;
        if (busy) {printf("EMSG not rentrant %s\n",arg_list); return 0;}
        busy = TRUE;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, EMSG ERROR TOO LONG\n");
        emsg_do(D_ERROR,output);
        log_flush_lvl2(L_LOG);
        busy = FALSE;
	return 0;
}
int wmsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;

        if (debug_lvl<D_WARN) return 0;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, WMSG ERROR TOO LONG\n");

        emsg_do(D_WARN,output);
	return 0;
}
int wmsgf(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
	static int busy;
	if (busy) return 0;
	busy = TRUE;

        if (debug_lvl<D_WARN) return 0;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;

        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, WMSG ERROR TOO LONG\n");

        emsg_do(D_WARN,output);
        log_flush_lvl2(L_LOG);
	busy = FALSE;
	return 0;
}
int imsg(const char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        static int busy;
        if (debug_lvl<D_INFO) return 0;
        if (busy) { return 0;}
        busy = TRUE;

        va_start(arg_ptr, arg_list);
        format = (char *) arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;

        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, IMSG ERROR TOO LONG\n");

        emsg_do(D_INFO,output);
        busy = FALSE;
	return 0;
}
static char *recent[5];
void status_recent(char * arg_list, ...)
{
	int i;
        va_list arg_ptr;
        char *format;
        int len;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output, BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
	if (recent[2]!=NULL) if (strcmp(recent[2],output)==0) return;
	if (recent[0]!=NULL) mystrfree(recent[0],SD_STATUS);
	for (i=0; i<2; i++) {
		recent[i] = recent[i+1];
	}
	recent[2] = mystrdup(output,SD_STATUS);
}
char *get_recent(void)
{
	static char bf[2000];
	char tmp[BFSZ];
	int i;

	if (recent[2]==NULL) return "";
	lprintf(bf,2000-1,"Recent Connections Rejected\n");
	for (i=0; i<3; i++) if (recent[i]!=NULL) {
		lprintf(tmp,BFSZ-1,"  %s\n",recent[i]);
		strcat(bf,tmp);
	}
	return bf;
}
int  imsgf(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        static int busy;
        if (debug_lvl<D_INFO) return 0;
        if (busy) {printf("EMSG not rentrant %s\n",arg_list); return 0;}
        busy = TRUE;

        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output, BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, IMSG ERROR TOO LONG\n");

        emsg_do(D_INFO,output);
        log_flush_lvl2(L_LOG);
        busy = FALSE;
	return TRUE;
}
/*
#ifdef NETWARE 
#define strerror nostrerror
char *nostrerror(int x)
{
        static char bf[80];
        lprintf(bf,80-1,"ErrorCode=%d",x);
        return bf;       
}
#endif
*/
int filemsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        char bf[BFSZ];

	if (errno<0) lprintf(bf,BFSZ-1,"errno = %d ",errno);
	else if (strerror(errno)==NULL) strcpy(bf,"Strerror = NULL");
        else ncpy(bf,strerror(errno),BFSZ-1);

        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, fileMSG ERROR TOO LONG\n");

        emsg_do(D_ERROR,output);
        emsg("file: %s \n",bf);
	return 0;
}
void fimsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        char bf[BFSZ];
	char output[OUTSIZE];

        ncpy(bf,strerror(errno),BFSZ-1);

        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, fiMSG ERROR TOO LONG\n");
        imsg("(%s) %s",bf,output);
}
int is_debug(void)
{
	if (debug_lvl>=D_DEBUG) return TRUE;
	return FALSE;
}
int debug_trace = TRUE;
int dmsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;  /* Shouldn't be necessary */
        int len;
        char *s,bf[20];
        
        if (debug_lvl<D_DEBUG) return 0; 
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output, BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, OUTMSG ERROR TOO LONG\n");

        if (strlen(output)>1000) emsg("FATAL: Debug output too long %d \n",strlen(output));

        ncpy(bf,output,15); 
        s = strchr(bf,':');
        if (s==NULL) return 0;
        s++; *s = 0;

        if (strstr(debug_str,bf)!=NULL) {
                emsg_do(D_DEBUG,output);
        }
	return 0;
}

/* debug_str = "nntp:err:warn:fatal:item:group" */
static FILE *flog[15];
static char *fnames[15];
void emsg_rotate(void);
static int echan;
void echan_set(int e)
{
	echan = e;
}
int echan_get(void)
{
	return echan;
}
#ifdef EMSG_USEC
#include <sys/time.h>
#include <unistd.h>
#endif

void emsg_do(int lvl, char *in)
{
        time_t t;
        static int doneinit;
	char tmpstr[BFSZ];
	int i;
	static char *ignore[200];
	struct tm atm;
	static int nignore;
	char *ccc;
	char *s;
	static int busy;
        char tstr[30],bf[1000];
        struct tm *tt; 
        static int last_wday= -10;      
	char tmsec[100];
	static int done_init,done2;
#ifdef EMSG_USEC
	struct timeval tsec;
	struct timezone xtzone;
#endif
	char errname[BFSZ];
#ifdef unix
	if (!done_init) {
#ifndef Mac
		tzset();
#endif
		done_init = TRUE;
	}
#endif

	if (busy) return;
	busy = TRUE;

	if (strlen(in)>200) {
		in[199] = '\n';
		in[200] = 0; /*Truncate long error messages*/
	}
	if (!done2) {
		done2 = TRUE;
		strcpy(bf,config_get(C_LOG_IGNORE));
		s = strtok(bf,",");
		for (;s!=NULL;) {
			ignore[nignore++] = mystrdup(s,SD_IGNORE);
/*printf("Compare (%s)\n",ignore[nignore-1]);*/
			s = strtok(NULL,",");
		}
	}
	for (i=0; i<nignore; i++) {
		busy = FALSE;
		if (strstr(in,ignore[i])!=NULL) {
			return;
		}
	}
	if (config_true(C_LOG_SYSTEM)) {
		log_system(lvl,in);
	}
	if (!config_true(C_LOG_FILES)) {
		busy = FALSE;
		return;	
	}
	t = time(NULL);
        tt = safe_localtime(&t,&atm);

	ccc = safe_ctime(&t,tmpstr);
	if (ccc==NULL) ccc = "badtimebadtimebadtime";
        strcpy(tstr,ccc);
        tstr[19] = 0;

        if (!doneinit) emsg_init();
        doneinit = TRUE;

        /*if (last_wday>=0) if (tt->tm_wday != last_wday) emsg_rotate();
        last_wday = tt->tm_wday;
	*/

	strcpy(tmsec,"");
#ifdef EMSG_USEC
	gettimeofday(&tsec,&xtzone);
	lprintf(tmsec,100-1,".%03d",tsec.tv_usec/1000);
#endif
	strcpy(errname,debug_names[lvl]);

	if (config_true(C_LOG_ONEFILE)) {
			lprintf(bf,1000-1,"%s s%d %d:%s: %s",tstr+8,slave_n(),echan,errname,in);
	 if (echan<0)	lprintf(bf,1000-1,"%s s%d :%s: %s",tstr+8,slave_n(),errname,in);
	} else {  
			lprintf(bf,1000-1,"%s%s %d:%s: %s",tstr+8,tmsec,echan,errname,in);
	 if (echan<0)	lprintf(bf,1000-1,"%s%s  :%s: %s",tstr+8,tmsec,errname,in);
	}
#ifdef NETWARE
        if (lvl<=D_WARN) printf("%s",bf);
        else if (debug_lvl>D_DEBUG) printf("%s",bf);
      
/*
 {
           static FILE *h;
           static char hname[BFSZ];
                    h = fopen("sys:\\dnews\\test.log","a");
                if (h==NULL) {perror("sys:\\dnews\\test.log"); gets(bf); return;}
                fprintf(h,"%s",bf);
                fclose(h);
                h = NULL; 
       }
       return;         
*/      


#endif  
	chan_sendlog(bf);

	trace_addmsg(bf);
	if (lvl==D_IN) {
		if (!config_true(C_LOG_INLINE)) goto skip_inline;	
	}     
	if (lvl==D_OUT) {
		if (config_true(C_LOG_OUT_ONLY)) goto skip_inline;	
	}     
        log_str(L_LOG,bf);
skip_inline:;
	busy = FALSE;
        if (lvl==D_IN) {
		if (config_true(C_LOG_NO_IN)) return;
		log_str(L_IN,bf);
	} else if (lvl==D_OUT) {
		if (config_true(C_LOG_NO_OUT)) return;
		log_str(L_OUT,bf);
	}


}


char *emsg_time(void)
{
        time_t t;
	char *ccc;
	struct tm atm;
        static char tstr[30],bf[1000];
	char tmpstr[BFSZ];
        struct tm *tt; 
	t = time(NULL);
        tt = safe_localtime(&t,&atm);

	ccc = safe_ctime(&t,tmpstr);
	if (ccc==NULL) ccc = "badtimebadtimebadtime";
        strcpy(tstr,ccc);
        tstr[19] = 0;
	return tstr;
}







void sucklog_do(char *in)
{
        time_t t;
	static time_t lastt;
	static FILE *f;
	struct tm atm;
        char tstr[30];
	char *ccc;
        struct tm *tt; 
	char tmpstr[BFSZ];
	static int nsent;
	static int max;
	if (max==0) max = atoi(config_get(C_SUCK_MAXLOG));
	if (max==0) max = 1000000;
	if (nsent==0) {
		nsent = lib_length_file(file_log("suck.log"));
	}
	if (strlen(in)>200) {
		in[199] = '\n';
		in[200] = 0; /*Truncate long error messages*/
	}
	t = time(NULL);
        tt = safe_localtime(&t,&atm);

	ccc = safe_ctime(&t,tmpstr);
	if (ccc==NULL) ccc = "badtimebadtimebadtime";
        strcpy(tstr,ccc);
        tstr[19] = 0;

	if (f==NULL) f = fopen(file_log("suck.log"),"a");
	if (f==NULL) return;
	fprintf(f,"%s %s",tstr+8,in);
	if (t!=lastt) fflush(f);
	lastt = t;
	nsent += strlen(in)+10;
	if (nsent>max) {
		nsent = 0;
		fclose(f);
		f = NULL;
		remove(file_log("suck.log"));
	}
}
void keeplog_do(char *in)
{
        time_t t;
	char *cmd="";
	static time_t lastt;
	static FILE *f;
        char tstr[30];
	char *ccc;
        struct tm *tt; 
	struct tm atm;
	static int nsent;
	char tmpstr[BFSZ];
	static int max;
	if (max==0) max = 5000000;
	if (nsent==0) {
		nsent = lib_length_file(file_log("keep.log"));
	}
	if (strlen(in)>200) {
		in[199] = '\n';
		in[200] = 0; /*Truncate long error messages*/
	}
	t = time(NULL);
        tt = safe_localtime(&t,&atm);

	ccc = safe_ctime(&t,tmpstr);
	if (ccc==NULL) ccc = "badtimebadtimebadtime";
        strcpy(tstr,ccc);
        tstr[19] = 0;

	if (f==NULL) f = fopen(file_log("keep.log"),"a");
	if (f==NULL) return;
	cmd = "";
#ifdef WIN32
	//cmd = GetCommandLine();
#endif
	fprintf(f,"%s %s %s",tstr+8,cmd,in);
	if (t!=lastt) fflush(f);
	lastt = t;
	nsent += strlen(in)+10;
	if (nsent>max) {
		char bf[BFSZ];
		nsent = 0;
		fclose(f);
		f = NULL;
		remove(file_log("keep2.log"));
		ncpy(bf,file_log("keep2.log"),BFSZ-1);
		rename(file_log("keep.log"),bf);
	}
}

#ifdef WIN32
#include <windows.h>
#endif
int lib_msec(void) /* Return time in msec if possible */
{
	static int base;
	if (base==0) base = time(NULL)-(24*60*60);
#ifdef WIN32
	{
		SYSTEMTIME systime;
		GetSystemTime(&systime);
		return ((time(NULL)-base)*1000)+(systime.wMilliseconds);
	}
#else
#ifdef EMSG_USEC
	{
		struct timeval tsec;
		struct timezone xtzone;
		gettimeofday(&tsec,&xtzone);
		return ((tsec.tv_sec-base)*1000)+(tsec.tv_usec/1000);
	}
#else
	return (time(NULL)-base)*1000;
#endif
#endif
}

void emsg_flush(void)
{
	rej_flush();
        emsg_close();
}

#define NBUF 100
static int nlogs[15];
void emsg_rotate_debug(void)
{
        emsg_init();
        emsg_close();
        emsg_rotate_file(fnames[L_LOG]);
        emsg_openx(FALSE,__LINE__);
}
#ifdef NETWARE
#define SHORT_NAMES TRUE
#endif

#ifdef WIN32
#define SHORT_NAMES TRUE
#endif

void log_panic(char * arg_list, ...);
static char later_old[BFSZ];
static char later_new[BFSZ];
static int rename_later;
void do_rename(void)
{
	log_panic("Rename try again (%s) (%s)\n",later_old,later_new);
	if (rename(later_old,later_new)!=0) {
		log_panic("Rename failed again  (%s)\n",strerror(errno));
		return;
	}
	rename_later = FALSE;
}
void log_panic(char * arg_list, ...)
{
#ifdef disabled_NOW       
        va_list arg_ptr;
        char *format;  /* Shouldn't be necessary */
	char output[9000];
	FILE *f;
	time_t t;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        vsnprintf(output, BFSZ-1,format, arg_ptr);
	output[BFSZ-1] = 0;

#ifdef WIN32
	f = fopen("\\dpanic.log","a");
	if (f==NULL) return;
	time(&t);

	fprintf(f,"%.19s: s%d %s",ctime(&t),slave_n(),output);
	fclose(f);
#endif
#endif
}

void lib_sleep(int x);
void emsg_rotate_file(char *fname)
{
        char *s;
	int x;
        char oname[400],cname[400];
        char tmp[400];
        int i;
	char *rest = ".log";
	int nrot=atoi(config_get(C_LOG_COUNT));
	if (nrot==0) nrot = 4;

	if (config_true(C_LOG_ONEFILE)) {
		if (slave_n()>0) return;
	}
/* d2.ews.in   (..../dnews.in_4) */

        for (i=nrot; i>1; i--) {
                strcpy(tmp,fname);
		if (strlen(tmp)>4) {
			s = tmp + strlen(tmp);
			if (s[-2]=='_') s = s - 2;
			s = s - 4;
			if (*s != '.') s++;
			*s = 0;	     
			rest = s+1;
			
			if (*rest == '.') rest++;
		}
		
                lprintf(oname,400-1,"%s%d.%s",tmp,i,rest);
                lprintf(cname,400-1,"%s%d.%s",tmp,i-1,rest);
                if (i==2) ncpy(cname,fname,199);
                if (i==nrot) remove(oname);
		/*log_panic("Rename (%s) to (%s)\n",cname,oname);*/
                if (rename(cname,oname)!=0) {
			log_panic("Rename failed %s\n",strerror(errno));
			if (i==2) {
				for (x=0; x<6; x++) {
			                if (rename(cname,oname)==0) goto doneit;
					lib_sleep(1);
				}
				rename_later = TRUE;
				strcpy(later_old,cname);
				strcpy(later_new,oname);
			}
		} /* perror(oname); */
doneit:;
        }
/*	f = fopen(fname,"w");
	if (f!=NULL) fclose(f);
	*/
}
void emsg_rotate(void)
{
        int i;
        emsg_init();
	imsg("emsg_rotate called\n");
        emsg_close(); 
        for (i=0; i<3; i++) emsg_rotate_file(fnames[i]);  /*loop*/
        emsg_openx(FALSE,__LINE__);
}
static int ndebug[8];

void emsg_rotate_one(int lvl)
{
	/*log_panic("emsg_rotate_one(%d)\n",lvl);*/
        emsg_init();
        emsg_close(); 
        emsg_rotate_file(fnames[lvl]);  /*loop*/
        emsg_openx(FALSE,__LINE__);
	ndebug[lvl]=0;
}
void emsg_init(void)
{
        static int doneinit;
        int i;

        if (doneinit) return;
	        
        doneinit = TRUE;
	
        for (i=0; i<13; i++) fnames[i] = mymalloc(200);
        if (get_expire_mode())
            lprintf(fnames[L_LOG],BFSZ-1,"%s%s.log",config_getu(C_LOGDIR),"expire");
        else
            lprintf(fnames[L_LOG],BFSZ-1,"%s%s.log",config_getu(C_LOGDIR),dnews_name);
        lprintf(fnames[L_IN],BFSZ-1,"%s%s.in",config_getu(C_LOGDIR),dnews_name);
        lprintf(fnames[L_OUT],BFSZ-1,"%s%s.out",config_getu(C_LOGDIR),dnews_name);

	if (!config_true(C_LOG_ONEFILE)) {
	if (is_slave()) {
	   lprintf(fnames[L_LOG],BFSZ-1,"%s%s.log_%d",config_getu(C_LOGDIR),dnews_name,slave_n());
	   lprintf(fnames[L_IN],BFSZ-1,"%s%s.in_%d",config_getu(C_LOGDIR),dnews_name,slave_n());
	   lprintf(fnames[L_OUT],BFSZ-1,"%s%s.out_%d",config_getu(C_LOGDIR),dnews_name,slave_n());
	}
	}
        /* Empty the files */
	if (!config_true(C_LOG_ROTATE_NOSTART)) {
		for (i=0; i<3; i++) emsg_rotate_file(fnames[i]);
	}
        emsg_openx(FALSE,__LINE__);
}
void emsg_open(int clear)
{
	emsg_openx(clear,__LINE__);
}
void emsg_openx(int clear, int line)
{
        int i;
        for (i=0; i<3; i++) {
                if (flog[i]==NULL) {
#ifdef xxVMS
                  flog[i] = fopen(fnames[i],"a","ctx=rec","shr=get");
#else
                  flog[i] = myfopen(fnames[i],"a");
#endif
		/*log_panic("Opened log %d, from line %d\n",i,line);*/

                  if (flog[i]==NULL) {
                        printf("Unable to open log file {%s} \n",fnames[i]);
                        perror("Logfile:");
                  } else {
                       /*  printf("Opened log file [%d]{%s} \n",i,fnames[i]);*/
                         /* fprintf(flog[i],"Opened log file\n"); */
                 }
                }
        }

}
void emsg_close(void)
{
        int i;
	log_panic("emsg_close called \n");
        for (i=0; i<3; i++) {
                if (flog[i]!=NULL) {
			fclose(flog[i]);
			log_panic("Closing log %d\n",i);
		}
                flog[i] = NULL;
        }
	if (rename_later) do_rename();
}
static int is_local;
int inmsg_setpost(int t)
{
	is_local = t;	
	return TRUE;
}

void log_flush_lvlx(int lvl);
static char *logbf[100];
static int loglen[100];
#define FILE_LCL file_log("dnews_post.log")
void log_str(int lvl, char *s)
{
        int r=0;
	static FILE *fagain;
	FILE *f;
	static int busy;
	busy++;
	if (busy>=2) {
		if (busy==2) printf("log_str called inside itself\n");
		busy--;
//abort();
		return;
	}
        emsg_init();

        ndebug[lvl]++;

	/*log_panic("log_str[%d] (%s)\n",lvl,s);*/

	if (lvl==L_LOG) {	
		r = atoi(config_get(C_DEBUG_ROTATE));
		if (r==0) r = 5000;
	}
	if (lvl==L_IN) {	
		r = atoi(config_get(C_DEBUG_ROTATE_IN));
		if (r==0) r = 1000;
	}
	if (lvl==L_OUT) {
		r = atoi(config_get(C_DEBUG_ROTATE_OUT));
		if (r==0) r = 1000;
	}
        if (r==0) r = 20000;
        if (r>0) if (ndebug[lvl]>r) {
		ndebug[lvl]=0;
		/*imsg("Rotating [%d] ndebug=%d\n",lvl,ndebug[lvl]);*/
		emsg_rotate_one(lvl); 
	}

        if (flog[lvl]==NULL) emsg_openx(FALSE,__LINE__);
        nlogs[lvl]++;
#define LBF 10000
#ifdef xVMS
	if (strlen(s)+loglen[lvl] > LBF) log_flush_lvl2(lvl);
	if (logbf[lvl]==NULL) logbf[lvl] = mymalloc(LBF);
	strcpy(logbf[lvl] + loglen[lvl],s);
	loglen[lvl] += strlen(s);
#else
        if (flog[lvl]!=NULL) fprintf(flog[lvl],"%s",s);
#endif
        if ((nlogs[lvl]>2000)) 
                log_flush_lvl2(lvl);
        if ((debug_lvl==D_FLUSH)) 
                log_flush_lvl(lvl);	
	if (config_true(C_LOG_AGAIN)) {
	 	if (fagain==NULL) fagain = myfopen(file_log("again.log"),"a");
		fprintf(fagain,"%s",s);
		fflush(fagain);
	}
	if (is_local) if (lvl==L_IN) {	
		f = fopen(FILE_LCL,"a");
		if (f!=NULL) {
			fprintf(f,"%s",s);
			fclose(f);
		}
		if (lib_filesize(FILE_LCL)>50000000) {
			remove(FILE_LCL);
		}
	}
	busy--;

}
void logbf_flush(int lvl);
void logbf_flush(int lvl)
{
        if (flog[lvl]==NULL) return;
	if (loglen[lvl]<=0) return;
	if (logbf[lvl]==NULL) return;
	fwrite(logbf[lvl],1,loglen[lvl],flog[lvl]);	
	loglen[lvl] = 0;
}
void log_flush_lvl(int lvl)
{
        if (nlogs[lvl]==0) return;
#ifdef xVMS
	logbf_flush(lvl);
#endif
        if (flog[lvl]!=NULL) {
                /* fprintf(flog[lvl],"%d closed\n",lvl); */
                fclose(flog[lvl]); /* DON'T use fflush, it doesnt work*/
		flog[lvl] = NULL;
                flog[lvl] = myfopen(fnames[lvl],"a");
                if (flog[lvl]==NULL) {
                        printf("Unable to open log file {%s} \n",fnames[lvl]);
                }
#ifdef Mac
		lib_doevents();
#endif
        }
        nlogs[lvl] = 0;
}               
void log_flush_lvl2(int lvl)
{
#ifdef xVMS
	logbf_flush(lvl);
#endif
        if (nlogs[lvl]==0) return;
        if (flog[lvl]!=NULL) {
		fflush(flog[lvl]);
        }
        nlogs[lvl] = 0;
}               





static char m_ipname[200],m_mid[200],m_group[200];
static int m_len;
void msg_from(char *ipname)
{
        ncpy(m_ipname,ipname,100);
        strcpy(m_mid,"");
        strcpy(m_group,"");
}
void msg_setlen(int len)
{
	m_len = len;
}
void msg_id(char *mid)
{
        ncpy(m_mid,mid,100);
}
void msg_group(char *group)
{
        ncpy(m_group,group,100);
}
static char cur_reason[BFSZ];
void msg_show(char *s)
{
        ncpy(cur_reason,s,BFSZ-1);
}
char *msg_reason(void)
{
        return cur_reason;
}
void msg_reject(char * arg_list, ...)
{
        va_list arg_ptr;
        char *s;
        char *format,output[2000];
        int len;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output, BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>1900) emsg("fatal: msg_reject message too long\n"); 
        for (s=output; *s!=0; s++) {
                if (*s=='\015') *s = ' ';
                if (*s=='\012') *s = ' ';
        }
        post_seterr(output);
        inmsg("reject: %s: %s: %s: %s\n",output,m_ipname,m_group,m_mid);
	if (config_true(C_LOG_REJ)) {
		if (rejfile==NULL) {
			rejfile = fopen(FILE_REJ,"a");
			if (rejfile==NULL) { filemsg("Could not append to %s\n",FILE_REJ); return;}
		}		
		fprintf(rejfile,"%s reject: %s: %s: %s: %s %d\n",emsg_time(),output,m_ipname,m_group,m_mid,m_len);
	}
}
void rej_flush(void)
{
	if (rejfile!=NULL) fclose(rejfile); rejfile = NULL;
}
void rej_rotate(void)
{
	char bf[BFSZ];
	if (rejfile!=NULL) fclose(rejfile); rejfile = NULL;
	remove(FILE_REJ4);
	strcpy(bf,FILE_REJ3);
	rename(bf,FILE_REJ4);

	strcpy(bf,FILE_REJ2);
	rename(bf,FILE_REJ3);

	strcpy(bf,FILE_REJ);
	rename(bf,FILE_REJ2);
}
void msg_ok(char * arg_list, ...)
{
        char *s;
        va_list arg_ptr;
        char *format, output[2000];
        int len;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;
        if (len>1000) emsg("Fatal: msg_ok is too long \n");
        for (s=output; *s!=0; s++) {
                if (*s=='\015') *s = ' ';
                if (*s=='\012') *s = ' ';
        }
        inmsg("ok: %s: %s: %s: %s %d\n",output,m_ipname,m_group,m_mid,m_len);
}

#ifdef NEED_STRERROR
extern int sys_nerr;
extern char *sys_errlist[];
char *strerror(int x)
{
      if ((x<sys_nerr) && (x>=0)) return sys_errlist[x];
      return "No error";
}
#endif

/* If logging doesn't work, define LOG_DUMMY */


#define LOG_UNIX TRUE
#ifdef LOG_DUMMY
#undef LOG_UNIX
#endif

#ifdef NETWARE
#undef LOG_UNIX
#endif
#ifdef OS2
#undef LOG_UNIX
#endif
#ifdef VMS
#undef LOG_UNIX
#endif
#ifdef Mac
#undef LOG_UNIX
#endif

#ifdef WIN32
#undef LOG_UNIX
#define LOG_SYSTEM_DONE
void log_system(int lvl, char *in)
{
}
#endif

#ifdef LOG_UNIX
#define LOG_SYSTEM_DONE TRUE
#include <syslog.h>
#ifndef LOG_NEWS
#define LOG_NEWS LOG_DAEMON
#endif
void log_system(int lvl, char *in)
{
	static int inited;
	if (!inited) {
		inited = TRUE;
		openlog("dnews",0,LOG_NEWS);
	}
	switch (lvl) {
	case D_IN:
		syslog(LOG_INFO, "%s", in);
		break;
	case D_OUT:
		syslog(LOG_INFO, "%s", in);
		break;
	case D_INFO:
		syslog(LOG_NOTICE, "%s", in);
		break;
	case D_WARN:
		syslog(LOG_WARNING, "%s", in);
		break;
	case D_ERROR:
		syslog(LOG_ERR, "%s", in);
		break;
	case D_DEBUG:
		syslog(LOG_DEBUG, "%s", in);
		break;
	}
}
#endif


#ifndef LOG_SYSTEM_DONE
void log_system(int lvl, char *in)
{
}
#endif



int log_spawn(const char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
	char output[BFSZ];
	FILE *f;
        va_start(arg_ptr, arg_list);
        format = (char *) arg_list;
        vsnprintf(output,BFSZ-1, format, arg_ptr);
	output[BFSZ-1] = 0;

	f = fopen(file_log("spawn.log"),"a");
	if (f==NULL) return FALSE;
	fprintf(f,"%s %s",emsg_time(),output);
	fclose(f);
	return TRUE;
}
