/* Copyright (C) 1995 NetWin World, New Zealand, All rights reserved. */
#define ISLIB 1
#ifdef VMS
#include <unixio.h>
#else

/*RHP stuff for mac*/
#ifdef __MWERKS__
#include "Mac.h"
#endif
#ifndef WIN32
#ifndef Mac /*RHP not for mac thanks*/
#ifndef NOUNISTD
#include <unistd.h>
#endif
#endif
#endif

#endif


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

#ifdef OS2
#include <direct.h>
#include <io.h>
#define MKDIR1 TRUE
#endif

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>


#ifdef WIN32
#define MKDIR1 TRUE
#include <direct.h>
#include <io.h>
#endif

#include "emsg.h"
#include "lib.h"
#include "key.h"
#include "dnews.h"
#include "group.h"
#include "sary.h"
#include "str.h"
#include "nntp.h"
/* #include "chan_dmy.h"  don't know why this was here */
#include "chan.h"

extern int debug_lvl;
char *mystrdup(char *s)
{
  int xlen = strlen(s)+1;
  char *n;
  n = mymalloc(xlen);
  strcpy(n,s);
  return n;
}
char *mystrkeep(char *s)
{
  int xlen = strlen(s)+1;
  char *n;
  mem_log(M_STRKEEP,xlen);
  n = mykeep(xlen);
  strcpy(n,s);
  return n;
}
int wild_total;
int lib_wild_total(void)
{
	return wild_total;
}
int lib_localtime(void)
{               /* On VMS should correct to make it a GMT time.  */
        time_t t;
        time(&t);
        return (int) t;
}
char *lib_trim(char *s)
{
        char *ss = s;
        for (;*s!=0; s++) if (*s!=' ') break;
        for (;*s!=0; s++) if (*s==' ') *s = 0;
        return ss;
}
char *lib_trim_msg(char *s)
{
        static char bf[500];
        s = strchr(s,'<');
        if (s==NULL) return "";
        ncpy(bf,s,498);
        s = strchr(bf+1,'>');
        if (s==NULL) return "";
        *(s+1) = 0;
        return bf;
}
char *lib_safe(char *s)
{
        static char bf[100];
        ncpy(bf,s,90);
        return bf;
}
char *str_trimspace(char *s)
{
        char *ss = s;
        for (;*s!=0; s++) if (*s==' ') *s = 0;
        return ss;
}
struct tm *lib_split_time(int *t)
{
        unsigned long x = *t;
#ifdef VMS
        return localtime(&x);
#else
        return gmtime(&x); 
#endif

}
static int vms_timezone;
#ifdef WIN32
#define timezone _timezone
#endif

#ifdef VMS

#else

#ifndef USEGMTOFF
#ifndef NETWARE
#ifndef TZ_GOT
extern time_t timezone;
#endif
#endif
#endif

#endif
int lib_gmt_to_local(int x)
{
        lib_tzinit();
        return x-vms_timezone;  
}
int lib_local_to_gmt(int x)
{
        lib_tzinit();
        return x+vms_timezone;  
}
#ifdef GMTVARS
static time_t tts;
static struct tm *ttm;
#endif
void lib_tzinit(void)
{
        static int done_init=FALSE;
#ifdef VMS
        char *s;
        if (!done_init) {
                done_init = TRUE;
                s = config_get(C_TIMEZONE);
                strlwr(s);
                vms_timezone = get_zone(s);
                imsg("lib: Timezone %s = %d \n",s,vms_timezone);
                if (vms_timezone==0) emsg("lib: Timezone not found {%s} \n",s);
        }
#else
        if (!done_init) {
                done_init = TRUE;
#ifndef Mac
                tzset();
#endif
        }               
        vms_timezone = 0; /* don't know timezone on a mac I think, shouldn't matter*/
#ifndef Mac
#ifdef USEGMTOFF
                tts = time(NULL);
                ttm = localtime(&tts);
                vms_timezone = (int) (ttm->tm_gmtoff);
#else
                vms_timezone = (int) timezone;
		imsg("Timezone Offset %d\n",vms_timezone);
#endif

#endif
#endif
}
int lib_fixtime(time_t t)
{
#ifdef Mac
        static time_t base;
        struct tm ts;
        static int doneinit;

        if (!doneinit) {  /* Use 1 Jan 1970 as base time so int works  */
                memset(&ts,0,sizeof( struct tm));
                ts.tm_year = 70;
                base = mktime(&ts);
                doneinit = TRUE;
        }
        t -= base;
#endif  
        return (int) t;
}
void iffree(void *x)
{
        if (x!=NULL) myfree(x);
}
int strcmpnc(char *s1, char *s2)
{
   
        for (;TRUE;s1++,s2++) {
                if ((*s1 == 0) && (*s2==0)) return 0;
                if (tolower(*s1)<tolower(*s2)) return -1;
                if (tolower(*s1)>tolower(*s2)) return 1;
                if (*s1 == 0) return -1;
                if (*s2 == 0) return 1;
        }
        return 0;
}

int strncmpnc(const char *s1, const char *s2, int len)
{
        int i;
/*      char tmp1[200],tmp2[200];
        ncpy(tmp1,s1,len);
        ncpy(tmp2,s2,len);
        dmsg("Compare nocase {%s} {%s} %d \n",tmp1,tmp2,len);
*/
        for (i=0;i<len;i++,s1++,s2++) {
                if (tolower(*s1)<tolower(*s2)) return -1;
                if (tolower(*s1)>tolower(*s2)) return 1;
                if (*s1 == 0) return -1;
                if (*s2 == 0) return 1;
        }
        return 0;
}
#ifdef Mac
#define NOUPPER TRUE
#endif

#ifdef NOUPPER
#define _tolower(_c)    ( (_c)-'A'+'a' )
#define _toupper(_c)    ( (_c)-'a'+'A' )
#endif

char *strupr(char *s)
{
        char *ss=s;
        for (;*s!=0;s++) if (islower(*s)) *s = _toupper(*s);
        return ss;
}
char *strlwr(char *s)
{
        char *ss=s;
        for (;*s!=0;s++) if (isupper(*s)) if (*s>0) *s = _tolower(*s);
        return ss;
}
#ifdef VMS
#define NEED_STRDUP
#endif
/*RHP Mac also needs strdup*/
#ifdef Mac
#define NEED_STRDUP
#endif



#ifdef NEED_STRDUP
char *strdup(char *s)
{
        char *t;
        t = mymalloc(strlen(s)+1);
        strcpy(t,s);
        return t;
}
#endif
/*
dumb idiotic strncpy command pads, so 20K strings get coppied around for 3 char
strings.  

char *ncpy(char *dst, char *src, int len)
{
        strncpy(dst,src,len);
        dst[len] = 0;
        return dst;
}
*/
/*char *ncpy(char *dst, char *src, int len)
{
        char *xdst = dst;
        int xlen = len;
        for (;(*src !=0) && (len>0); ) {*dst++  = *src++; len--;}
        *dst++ = 0;
        xdst[xlen] = 0;
        return xdst;
}
*/
void cvt_numfile(int x, int *fg, int *fi) 
{

        *fg = x/100;
        *fi = x % 100;
}
void cvt_numfile2(int x, int *fg, int *fi) 
{

        *fg = (x/100)*100;
        *fi = x % 100;
}
#define xisspace(x) ((x==' ') || (x=='\t'))
char *get_word(char *s,int n) /*comp.os.vms 001 000 m*/
{
        static char tmp[600];
        int i;
        char *ss=s;

        for (;(*ss!=0) && xisspace(*ss);) ss++; 
        for (i=0; i<n && *ss!=0; i++) {
                ss++;
                if (*ss==0) return "";
                for (;(*ss!=0) && !xisspace(*ss);) ss++; 
                for (;(*ss!=0) && xisspace(*ss);) ss++; 
                if (*ss==0) return "";
                ss--; 
                if (ss==NULL) return "";
        }
        if (*ss==0) return "";
        if (xisspace(*ss)) ss++;
        ncpy(tmp,ss,499);
        ss = tmp;
        for (;(*ss!=0) && (!xisspace(*ss));) ss++; 
        if (ss==NULL) ss = tmp + strlen(tmp);
        *ss = 0;
        return tmp; 
}
char *str_decodelf(char *s)
{
	static char bf[BFSZ];
	char *out;
	for (out=bf;*s!=0;s++,out++) {
		if (*s=='\\') {
			s++;
			if (*s=='n') *out = '\n';
			if (*s=='\\') *out = '\\';
			if (*s=='r') *out = '\r';
		} else *out = *s;
	}
	*out++ = 0;
	return bf;
}
char *get_wordq(char *s,int n) /*comp.os.vms "001 000" m*/
{
        static char tmp[600];
        int i;
        char *ss=s;

        for (;(*ss!=0) && xisspace(*ss);) ss++; 
        for (i=0; i<n && *ss!=0; i++) {
                ss++;
                if (*ss==0) return "";
                for (;(*ss!=0) && !xisspace(*ss);) ss++; 
                for (;(*ss!=0) && xisspace(*ss);) ss++; 
                if (*ss==0) return "";
                ss--; 
                if (ss==NULL) return "";
        }
        if (*ss==0) return "";
        if (xisspace(*ss)) ss++;
        ncpy(tmp,ss,499);
        ss = tmp;
	if (*ss == '"') ss = strchr(ss+1,'"');
	if (ss==NULL) {
		s = tmp;
	        for (;(*ss!=0) && (!xisspace(*ss));) ss++; 
	}
	if (ss==NULL) ss = tmp + strlen(tmp);
        *ss = 0;
	if (tmp[0]=='"') return tmp+1;
        return tmp; 
}
char *get_wordv(char *s,int n) /*comp.os.vms 001 000 m*/
{
        static char tmp[16000];
        int i;
        char *ss=s;

        for (;(*ss!=0) && xisspace(*ss);) ss++; 
        for (i=0; i<n && *ss!=0; i++) {
                ss++;
                if (*ss==0) return "";
                for (;(*ss!=0) && !xisspace(*ss);) ss++; 
                for (;(*ss!=0) && xisspace(*ss);) ss++; 
                if (*ss==0) return "";
                ss--; 
                if (ss==NULL) return "";
        }
        if (*ss==0) return "";
        if (xisspace(*ss)) ss++;
        ncpy(tmp,ss,14990);
        ss = tmp;
        for (;(*ss!=0) && (!xisspace(*ss));) ss++; 
        if (ss==NULL) ss = tmp + strlen(tmp);
        *ss = 0;
        return tmp; 
}
char *get_rest(char *s,int n) /*comp.os.vms 001 000 m*/
{
        static char tmp[600];
        int i;
        char *ss=s;
        for (i=0; i<n && *ss!=0; i++) {
                ss++;
                for (;(*ss!=0) && !xisspace(*ss);) ss++; 
                for (;(*ss!=0) && xisspace(*ss);) ss++; 
                if (*ss==0) return "";
                ss--; 
                if (ss==NULL) return "";
        }
        if (*ss==0) return "";
        if (xisspace(*ss)) ss++;
        strncpy(tmp,ss,399);
        return tmp; 
}


/* Routines which are specific to a certain computer system */

/* should convert g++ to g_p_p  */
#ifdef VMS
char *lib_tovms(char *s);
char *lib_tovms(char *s)
{
        static char bf[500];
        char *o=bf;
        for (;*s!=0;s++) {
                if (*s=='+') {*o++ = '$'; *o++ = 'p';}
                else if (*s=='&') {*o++ = '$'; *o++ = 'd';}
                else if (*s=='\'') {*o++ = '$'; *o++ = 'a';}
                else *o++ = *s;
        }
        *o++ = 0;
        return bf;

}


char *sys_gdir(int g)
{
        static char bf[200];
        if (config_true(C_DIRFAST)) {
          sprintf(bf,"%s[%d]",config_get(C_SPOOL),group_getgroupid(g));
        } else {
          sprintf(bf,"%s[%s]",config_get(C_SPOOL),lib_tovms(group_namelc(g)));
        }
        return bf;
}
char *fast_vms(char *bf, int g, int item, char *name)
{
        int fg,fi;
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s[%d]%d%s",config_get(C_SPOOL),group_getgroupid(g),fg);
        return bf;
}
char *sys_gname(int g, int item)
{
        static char bf[200];
        static char lastbf[200];
        int fg,fi;
        char *s = group_namelc(g);

        if (config_true(C_DIRFAST)) return fast_vms(bf,g,item,"00.itm"); 
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s[%s]%d00.itm",config_get(C_SPOOL),lib_tovms(s),fg);
        return bf;
}
char *sys_nname(int g, int item)
{
        static char bf[200];
        int fg,fi;
        char *s = group_namelc(g);

        if (config_true(C_DIRFAST)) return fast_vms(bf,g,item,"00.new"); 
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s[%s]%d00.new",config_get(C_SPOOL),lib_tovms(s),fg);
        return bf;
}
char *sys_iname(int g, int item) /*VMS */
{
        static char bf[200];
        char *s = group_namelc(g);
        int fg,fi;

        if (config_true(C_DIRFAST)) return fast_vms(bf,g,item,"00.idx"); 
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s[%s]%d00.idx",config_get(C_SPOOL),lib_tovms(s),fg);
        return bf;
}
char *sys_xname(int g, int item)
{
        static char bf[200];
        char *s = group_namelc(g);
        int fg,fi;

        if (config_true(C_DIRFAST)) return fast_vms(bf,g,item,"00.xov"); 
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s[%s]%d00.xov",config_get(C_SPOOL),lib_tovms(s),fg);
        return bf;
}


#endif
#ifdef unix
char *lib_tounix(char *s);

#ifdef WIN32
char *lib_tounix(char *s)
{
        static char bf[BFSZ];
        static char bf2[BFSZ];
        char *ss=s;
        char *s2;
        char *out=bf2;
        int gotdot = TRUE;

        ncpy(bf,s,BFSZ-1);
        for (;gotdot;) {
                gotdot = FALSE;
                s2 = strchr(s,'.');
                if (s2!=NULL) {
                        *s2 = 0;
                        gotdot = TRUE;
                }
                if (strcmp(s,"aux")==0) {
                        strcpy(out,"a_x");
                } else if (strcmp(s,"nul")==0) {
                        strcpy(out,"n_l");
                } else strcpy(out,s);
                out += strlen(s);
                if (gotdot) {strcpy(out,"/"); out++;}
                s = s2+1;
        }       
        strcpy(ss,bf2);
                
        for (s = ss;*s!=0;s++) {
                if (*s=='\'')   *s = '#';
                if (*s=='&')   *s = '#';
        }
        return ss;
}
#else
char *lib_tounix(char *s)
{
        char *ss=s;
        for (;*s!=0;s++) {
                if (*s=='.')   *s = '/';
                if (*s=='&')   *s = '#';
                if (*s=='\'')   *s = '#';
        }
        return ss;
}
#endif


#ifdef NETWARE
#define SHORT_NAMES TRUE
char *dirfix(char *s)
{
        char *ss = s;
        for (;*s!=0;s++) if (*s=='/') *s = '\\';
        s = strstr(ss,".conf");
        if (s!=NULL) *(s+4) = 0;
        return ss;
}
#endif
#ifndef NETWARE
/*RHP Mac version of dirfix -  replace / by :*/
#ifdef Mac
char *dirfix(char *s)
{
        char *ss = s;
        for (;*s!=0;s++) if (*s=='/') *s = ':';
        return ss;
}
#else

#ifdef OS2
char *dirfix(char *s)
{
        char *ss = s;
        for (;*s!=0;s++) {
        	if (*s=='/') *s = '\\';
	}
        return ss;
}
#else
#define dirfix(x) (x)
#endif

#endif
#endif




#ifdef SHORT_NAMES
char *sys_gdir(int g)
{
        static char bf[200],bf2[200];
        sprintf(bf,"%s/%d",config_get(C_SPOOL),group_getgroupid(g));
        return dirfix(bf);
}
char *sys_gname(int g, int item)
{
        static char bf[200];
        int fg,fi;
        char bf2[300];
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s/%d/%d.itm",config_get(C_SPOOL),group_getgroupid(g),fg);
        return dirfix(bf);
}
char *sys_iname(int g, int item) /*NETWARE*/
{
        static char bf[200];
        int fg,fi;
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s/%d/%d.idx",config_get(C_SPOOL),group_getgroupid(g),fg);
        return dirfix(bf);
}
char *sys_xname(int g, int item)
{
        static char bf[200];
        int fg,fi;
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s/%d/%d.xov",config_get(C_SPOOL),group_getgroupid(g),fg);
        return dirfix(bf);
}
char *sys_nname(int g, int item)
{
        static char bf[200];
        int fg,fi;
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s/%d/%d.new",config_get(C_SPOOL),group_getgroupid(g),fg);
        return dirfix(bf);
}
#else

char *sys_gdir(int g)
{
        static char bf[200],bf2[200];
        char *s = group_namelc(g);
        strcpy(bf2,s); s = bf2;
        
        lib_tounix(s);
        sprintf(bf,"%s/%s",config_get(C_SPOOL),bf2);
        return dirfix(bf);
}

char *fast_unix(char *bf, int g, int item, char *name)
{
        int fg,fi;
        cvt_numfile(item,&fg,&fi);
        sprintf(bf,"%s/%d_%d%s",config_get(C_SPOOL),group_getgroupid(g),fg,name);
	imsg("fast unix {%s} \n",bf);
        return dirfix(bf);
}

char *sys_gname(int g, int item)
{
        static char bf[200];
        int fg,fi;
        char bf2[300];
        static char lastbf[200];
        static int lastg= -1,lastitem;
        char *s;

        if (g==lastg && item==lastitem) {
                strcpy(bf,lastbf);
                return bf;
        }
        lastg = g; lastitem = item;
        s = group_namelc(g);


        if (config_true(C_DIRFAST)) {
        	fast_unix(bf,g,item,"00.itm"); 
	        strcpy(lastbf,bf);
		return bf;
	}

        cvt_numfile(item,&fg,&fi);
        strcpy(bf2,s); s = bf2;
        lib_tounix(s);
        sprintf(bf,"%s/%s/%d00.itm",config_get(C_SPOOL),bf2,fg);
        s = dirfix(bf);
        strcpy(lastbf,bf);
        return s;
}
char *sys_iname(int g, int item) /*UNIX and NT*/ 
{
        static char bf[200];
        int fg,fi;
        char *s = group_namelc(g);
        char bf2[300];


        if (config_true(C_DIRFAST)) return fast_unix(bf,g,item,"00.idx"); 
        cvt_numfile(item,&fg,&fi);
        strcpy(bf2,s); s = bf2;
        lib_tounix(s);
        sprintf(bf,"%s/%s/%d00.idx",config_get(C_SPOOL),bf2,fg);
        return dirfix(bf);
}
char *sys_xname(int g, int item)
{
        static char bf[200];
        int fg,fi;
        char *s = group_namelc(g);
        char bf2[300];


        if (config_true(C_DIRFAST)) return fast_unix(bf,g,item,"00.xov"); 
        cvt_numfile(item,&fg,&fi);
        strcpy(bf2,s); s = bf2;
        lib_tounix(s);
        sprintf(bf,"%s/%s/%d00.xov",config_get(C_SPOOL),bf2,fg);
        return dirfix(bf);
}
char *sys_nname(int g, int item)
{
        static char bf[200];
        int fg,fi;
        char *s = group_namelc(g);
        char bf2[300];

        if (config_true(C_DIRFAST)) return fast_unix(bf,g,item,"00.new"); 
        cvt_numfile(item,&fg,&fi);
        strcpy(bf2,s); s = bf2;
        lib_tounix(s);
        sprintf(bf,"%s/%s/%d00.new",config_get(C_SPOOL),bf2,fg);
        return dirfix(bf);
}
#endif
#endif

#ifdef VMS
#include <stat.h>
#else
#ifdef WIN32
#include <sys/types.h>
#endif
/*RHP no sys/ for mac thanks*/
#ifdef Mac
#include <stat.h>
#else
#include <sys/stat.h>
#endif
#endif

int file_length(int f)
{
#ifdef WIN32
        int r;
        r = filelength(f);
        if (r<0) {
                filemsg("FATAL Could not get file length\n");
                return 0;
        }
        return r;
#else
/*RHP need fstat replacement for mac - luckily f number returned by codewarrior unix lib
open call is really a mac file refnum so we can use that to find file and thenn size */
#ifdef Mac
                CInfoPBRec cpb;
                FCBPBRec pb;
                int err;
                char fname[63];
                HFileInfo       *hpb = (HFileInfo *)&cpb;
        
            if (f<0){filemsg("FATAL Could not get file length f=%d\n",f);return 0;}
                pb.ioCompletion = nil;
                pb.ioFCBIndx = 0;
                pb.ioRefNum = f;
                pb.ioNamePtr = (unsigned char *)fname;
                err = PBGetFCBInfoSync(&pb);
                if (err){filemsg("FATAL Could not get file length of %s err=%d\n",PtoCstr((unsigned char *)fname),err);return 0;}
                return pb.ioFCBEOF;
/*              hpb->ioCompletion = nil;
                hpb->ioVRefNum = pb.ioVRefNum;
                hpb->ioFDirIndex = 0;
                hpb->ioNamePtr = (unsigned char *)fname;
                hpb->ioDirID = 0L;
                err = PBGetCatInfoSync(&cpb);
                if (err){filemsg("FATAL Could not get file length b err=%d\n",err);return 0;}
                {filemsg("Good got file length %ld\n",hpb->ioFlLgLen);return 0;}
                return hpb->ioFlLgLen;*/
#else
        struct stat bf;
        if (fstat(f,&bf)!=0) {filemsg("FATAL Could not get file length\n"); return 0;}
        return bf.st_size;
#endif
#endif
}
void die(char *s)
{
        emsg("Dieing {%s} \n",s);
        exit(1);
}

int lib_filesize(char *s)
{
 	FILE *f;
	int len;
	f = fopen(s,"r");
	if (f==NULL) {
		dmsg("lib: Can't open {%s} \n",s);
		return -1;
	}
	len = file_length(fileno(f));
	fclose(f);
	return len;
}

int str_hash(char *s, int max)
{
        int total=0;
	int r;
        int i;
        for (i=0;*s!=0;s++,i++) {
                total += ((*s) * 8)*i;    
        }
	r = total % max;
	if (r<0) return -r;
	return r;
}
char *lib_hostname(void)
{
        static char hname[201];
        if (strlen(hname)==0) ncpy(hname,config_get(C_MYNAME),200);
        return hname;
}
char *lib_hostnamex(void)
{
        static char hname[201];
        if (strlen(hname)==0) ncpy(hname,config_get(C_MYNAME),200);
	if (strlen(config_get(C_STAMP_PATH))>0) ncpy(hname,config_get(C_STAMP_PATH),200);
        return hname;
}
char *lib_messageid(void)
{
        static char idbuff[300];
        static time_t now,last;
	char *s;
	static int x;
	char bf[BFSZ];
        time(&now);
        if (last==now) {x++;}
        else x=0;
	strcpy(bf,lib_hostnamex());
	s = strchr(bf,'|');
	if (s==NULL) s = strchr(bf,'!');
	if (s!=NULL) *s = 0;
        sprintf(idbuff,"<%lx.%d@%s>",now,x,bf);
        last = now;
        return idbuff;
}
static char *months[]={
        "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};
char *lib_strdate(void)
{
        static char bf[70];
        time_t now;
        struct tm *t;

        time(&now);
        t = gmtime(&now);
        if (t==NULL) t = localtime(&now);
        sprintf(bf,"%d %s %d %02d:%02d:%02d GMT",
                t->tm_mday,months[t->tm_mon],t->tm_year,
                t->tm_hour,t->tm_min,t->tm_sec);
        return bf;
}
static char *weekday[]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", };
char *lib_email_date(void)
{
        static char bf[70];
        time_t now;
        struct tm *t;

        time(&now);
        t = gmtime(&now);
        if (t==NULL) t = localtime(&now);
        sprintf(bf,"%s, %d %s %d %02d:%02d:%02d GMT",
        	weekday[t->tm_wday],
                t->tm_mday,months[t->tm_mon],t->tm_year,
                t->tm_hour,t->tm_min,t->tm_sec);
        return bf;
}
char *lib_hour(void)
{
        static char bf[70];
        time_t now;
        struct tm *t;

        time(&now);
        t = localtime(&now);
        sprintf(bf,"%02d:%02d",t->tm_hour,t->tm_min);
        return bf;
}
char *lib_strdate2(int offset)
{
        static char bf[70];
        time_t now;
        struct tm *t;

        time(&now);
        now += offset;
        t = gmtime(&now);
        if (t==NULL) t = localtime(&now);
        sprintf(bf,"%d %s %d %02d:%02d:%02d GMT",
                t->tm_mday,months[t->tm_mon],t->tm_year,
                t->tm_hour,t->tm_min,t->tm_sec);
        return bf;
}
#ifndef VMS
#ifdef WIN32
#include <errno.h>
#endif
/*RHP Mac version of create directory*/
#ifdef Mac
void lib_createdir(char *s)
{
        char bf[BFSZ];
        OSErr           iErr;
        FSSpec          spec;
        long            nDirID;
        
   ncpy(bf,s,BFSZ-1);
   if (strlen(s)<2) return;
   s = bf+2;
   for (;*s!=0; s++)  {
      if (*s==':')  {
         *s = 0;
                iErr = FSMakeFSSpec(0,0,CtoPstr(bf),&spec);
                PtoCstr((unsigned char *)bf);
                if (iErr==fnfErr){
                        iErr = FSpDirCreate(&spec, smSystemScript, &nDirID);
                }else
                dmsg("lib: Create directory failed %d %s\n",iErr,bf);
         *s = ':';
      }
   }
}
#else
void lib_createdir(char *s)
{
   int r;
   char bf[BFSZ];
   
   ncpy(bf,s,BFSZ-1);
   if (strlen(s)<2) return;
   s = bf+2;
   for (;*s!=0; s++)  {
      if ((*s=='/') || (*s == '\\'))  {
         *s = 0;
#ifdef MKDIR1
         r = mkdir(bf);
         if (r!=0) {
                dmsg("lib: Create failed (if file exists then its OK) %d %s\n",errno,strerror(errno));
         }
#else
         r = mkdir(bf,0770);
#endif
         *s = '/';
      }
   }
}
#endif
#endif

        
int token_split(char *s, char *p[], char *sep, int tmax)
{
        int n=0;

        for (;*s!=0;) {
                s += strspn(s,sep);  /* Skip spaces */
                if (*s==0) break;
                p[n++] = s;
                s += strcspn(s,sep);  /* Find end of word */
                if (*s==0) break;               
                *s = 0; s++;
                if ((n+5)>=tmax) {
                        emsg("Too many tokens in this header line\n");
                        break;
                }
        }
        p[n] = NULL;
        return n;
}
/* with this one, two separators next to each other = another field.*/
int token_split2(char *s, char *p[], char *sep, int tmax)
{
        int n=0;

        for (;*s!=0;) {
                p[n++] = s;
                s = strchr(s,*sep); 
                if (s==NULL) break;
                *s = 0;
                s++;            
                if ((n+5)>=tmax) {
                        emsg("Too many tokens in this header line\n");
                        break;
                }

        }
        p[n] = NULL;
        return n;
}
int lib_exists(char *s)
{
        FILE *f;
        int r;
        f = fopen_log(s,"r");
        if (f==NULL) r = FALSE;
        else r = TRUE;
        if (f!=NULL) xfclose(f);
        return r;
}
char *lib_getlicense(void)
{
        return "D500";  
} 
#define FLUSH(x) (fflush(f)==EOF || ferror(f))
#ifdef unix
#ifndef WIN32
#ifndef NETWARE
#ifndef OS2
/*RHP Mac needs own version too*/
#ifndef Mac
int lib_freespace(char *disk)
{
   char cmd[400];
   char bf[1002],tmp[1001];
   char *s;
   FILE *f;
	int r;
	int kavail=atoi(config_get(C_DF_COLUMN))-1;

	if (kavail<0) kavail = 3;

   if (config_true(C_NOSPACECHECK)) return 1000000; 

   
   strcpy(cmd,config_get(C_DF));
   strcat(cmd," "); strcat(cmd,disk);
   if ((f = popen(cmd,"r"))==NULL)  {
        filemsg("lib: popen failed for cmd {%s} \n",cmd);
        return 1000000;   
   }
   strcpy(bf,"");
   for (;!feof(f);) {
      if (fgets(tmp,1000,f)==NULL) if (!feof(f)) filemsg("Problem reading pipe\n");
      if (strlen(tmp) + strlen(bf)>1000) {emsg("lib: du too much output \n"); break;}
      strcat(bf,tmp);
   }            
        
   if (pclose(f)!=0) {filemsg("lib: du, pclose failed \n"); return 1000000;}
        
   s = strchr(bf,'/');
   if (s==NULL) {emsg("lib: du, couldn't find / in output %s\n",bf); return 1000000;}
   r = atoi(get_word(s,kavail));
   s[80] = 0;
   dmsg("lib: {%s} {%s} {%s} \n",disk,get_word(s,kavail),s);   
   if (r==0) imsg("df failed {%s} {%s} {%s} \n",get_word(s,kavail),s,disk);
   return r;
}
/*RHP mac version of lib_mail_file and lib_freespace and s_wild*/
#else
void s_wild(Sary *ls, char *path, char *wild){
        Str255          filename; 
        char            s[255];
        OSErr           iErr;
        FSSpec          spec;
        short           dirID;
        long            vRefNum;
        int                     len;
        CInfoPBRec      cipbr;                                                  /* local pb */
        HFileInfo       *fpb = (HFileInfo *)&cipbr;             /* pointers to it  of two types for diff structs*/
        DirInfo         *dpb = (DirInfo *)  &cipbr;
        short           rc, idx;
        
	wild_total = 0;
        strcpy (s,path);
        len = strlen(s);
        if (s[len-1] != ':') 
                strcat(s,": ");
        else
                strcat(s," ");
        vRefNum = 0;    dirID = 0;
        iErr = FSMakeFSSpec(vRefNum,dirID,CtoPstr(s),&spec);
        PtoCstr((unsigned char *)s);
        if ((iErr==noErr | iErr==fnfErr)){
                fpb->ioVRefNum = spec.vRefNum;                  /* default volume */
                fpb->ioNamePtr = filename;      /* buffer to receive name */
        
                for( idx=1; TRUE; idx++) {      /* indexing loop */
                        fpb->ioDirID = dirID;           /* must set on each loop */
                        fpb->ioFDirIndex = idx;
        
                        rc = PBGetCatInfo( &cipbr, FALSE );
                        if (rc) break;  /* exit when no more entries */
        
                        PtoCstr( filename );            /* make ASCIIZ for printf() */
                        if (fpb->ioFlAttrib & 16) {
                                //printf( ("Directory = %s:%s", dirFullName,filename );
                        }
                        else if(fpb->ioFlFndrInfo.fdFlags==fInvisible){
                                //printf( "Invisible File = %s\n", fpb->ioNamePtr );    
                        }
                        else{
                                //printf( "%s\n", filename );    
                    if (match_wild(wild,(char *)filename))
                        s_add(ls,(char *)filename);
                        }
                }
        }else{
                /*RHP invalid path what should we do?? */
                return;
        }
}

int lib_freespace(char *ps){
/* RHP I presume we are passed a disk name or path name*/
        HVolumeParam    volPB;
        OSErr                   error;
        int                     len;
        char                    s[256];
        
        strcpy(s,ps);
        len = strlen(s);
        if (s[len-1] != ':') 
                strcat(s,": ");
        else
                strcat(s," ");
        volPB.ioNamePtr = CtoPstr(s);   // make sure it returns the name 
        volPB.ioVRefNum = 0;    //RHP2 was 2 instead of 0    0 means use ioVolIndex 
        volPB.ioVolIndex = -1;  // use name 
        error = PBHGetVInfo((HParmBlkPtr)&volPB,false); 
        if(error == noErr)
        return volPB.ioVFrBlk*volPB.ioVAlBlkSiz/1000; //RHP2 I  presume we return a number of k
        else{
        imsg("GetDiskFreeSpace call failed, {%s} errcode=%d \n",PtoCstr((unsigned char *)s),error);
                return 2000000;
        }
}



#endif /*RHP Mac*/
#endif
#endif
#endif
#endif

/*      Same as lib_mail_file, but this one writes a new header on top
        to make sure that the subject and to lines are obeyed */
#define TEMP_FILE file_work("report.tmp")
int lib_mail_msg(char *to, char *subj, char *fname)
{
        String *xnew,*rest;
        char bf[BFSZ];
        int r;

        if (strlen(to)>200) {emsg("lib_mail To too long \n"); return FALSE;}
        if (strlen(subj)>200) {emsg("lib_mail subj too long \n"); return FALSE;}
        if (strlen(fname)>200) {emsg("lib_mail fname too long \n"); return FALSE;}
        xnew = str_new();
        rest = str_new();
        if (!str_read(rest,fname)) { r = FALSE; goto do_return;}

        sprintf(bf,"From: %s@%s\015\012",DNEWS_NAME,config_get(C_MYNAME)); str_copysn(xnew,bf);
        sprintf(bf,"Subject: %s\015\012",subj); str_addsn(xnew,bf);
        sprintf(bf,"To: %s\015\012",to); str_addsn(xnew,bf);
        sprintf(bf,"Message-ID: %s\015\012",lib_messageid()); str_addsn(xnew,bf);

        str_addsn(xnew,"\015\012");
        str_add(xnew,rest);
        
        remove(TEMP_FILE);
        if (!str_write(xnew,TEMP_FILE)) filemsg("Error writing %s \n",TEMP_FILE); 
        if (!lib_mail_file(to,subj,TEMP_FILE)) {
                emsg("dnews: Failed to email msg to manager\n");
        }
        r = TRUE;
do_return:
        str_free(xnew);
        str_free(rest);
        return r;
}


static int nxopen,nxfopen;
int open_log(char *fname, int access, int aa)
{
        int r;
        r = xopen(fname,access,aa);
        return r;
}
FILE *fopen_log(char *fname, char *mde)
{
        FILE *r;
        r = xfopen(fname,mde);
        return r;
}

/*int my_lib_gmtime(char *file, int line)
{
	imsg("lib_gmtime %s:%d\n",file,line);
 	return xlib_gmtime();
}

  */
extern int xtime_now;
int db_total_space(void);
int lib_pused(void)
{
        int all = db_total_space();
        if (all==0) all = 30; /* Default value, 30 Megabytes, very small*/
        return diskuse_get() / (all*100);
}
char *lib_now(void)
{
        time_t t;
        static char bf[100];
        t = time(NULL);
        strcpy(bf,ctime(&t));
        bf[24] = 0;
        return bf;
}
int xfclose(FILE *f)
{       
        int r;
        dmsg("lib: file: xfclose %d \n",fileno(f));
        nxfopen--;
        r = fclose(f);
        if (r!=0) {
                filemsg("lib: xfclose failed\n");
        }
        return r;
}
int xopen(char *fname, int access, int mde)
{
        int r;
/*RHP different open for mac - we just ignore mde setting*/
#ifdef Mac
        r = open(fname,access);
        if (r<0) errno = ENOENT;//RHP2 Mac does not set erno so have to assume this is problem
#else
        r = open(fname,access,mde);
#endif
        if (r>=0) nxopen++;
        dmsg("lib: file: xopen %d {%s} acces=%d Totals (%d:%d)\n",r,fname,access,nxopen,nxfopen);
        return r;
}
int xclose(int x)
{
   int r;
   dmsg("lib: file: xclose %d \n",x);
   nxopen--;
   r = close(x);
   if (r!=0) filemsg("XClose error \n");
   return r;
    
}
FILE *xfopen(char *fname, char *mode)
{
        FILE *f;
        f = fopen(fname,mode);
        if (f!=NULL) nxfopen++;
        if (f!=NULL) dmsg("lib: file: xfopen %d {%s} Totals (%d:%d)\n",fileno(f),fname,nxopen,nxfopen);
        return f;
}
#ifdef VMS
void s_wild(Sary *ls, char *path, char *wild)
{
        char *r,*r2,*s;
        char bf[400];
        s_clear(ls);
	s_grow(ls,500);
        if ((strlen(path)>200) || (strlen(wild)>200)) return;
	wild_total = 0;
        sprintf(bf,"%s%s;",path,wild);
        s = lib_findfile(bf);
        for (;s!=NULL;) {
                r2 = NULL;
                r = strchr(s,']');
                if (r!=NULL) r2 = strchr(r+1,']');
                if (r2!=NULL) r = r2;
                if (r!=NULL) s_add(ls,r+1);
                s = lib_findfile(NULL);
        }
}
#else

#ifdef NETWARE
#define NODIRENT
#endif

/*
#ifdef OS2
#define NODIRENT
#endif
*/

#ifdef WIN32
#else

#ifndef NODIRENT
#ifdef NeXT
#include <sys/dirent.h>
#include <sys/dir.h>
#else
#include <dirent.h>
#endif
void s_wild(Sary *ls, char *path, char *wild)
{
        DIR *dirp; 
        struct dirent *direntp; 

	wild_total = 0;
        dirp = opendir(path); 
        s_clear(ls);
        if (dirp==NULL) {filemsg("Could not read %s \n",path); return;}

        while ((direntp=readdir(dirp))!=NULL) {
                if (match_wild(wild,direntp->d_name)) {
             		if (strcmp(direntp->d_name,".")==0) continue;
             		if (strcmp(direntp->d_name,"..")==0) continue;
                        s_add(ls,direntp->d_name);
		}
        }
        closedir(dirp);
}
#endif
#endif
#endif



#ifdef WIN32
#include <windows.h>
void s_wild(Sary *ls, char *path, char *wild)
{
        char *s;
        char bf[BFSZ],tmp[BFSZ];
        char *s2;
        int status;
        struct _finddata_t info;
        long handle;

        s_clear(ls);
	s_grow(ls,500);
	wild_total = 0;
        if ((strlen(path)>200) || (strlen(wild)>200)) return;
        sprintf(bf,"%s/%s",path,wild);

        handle = _findfirst(bf,&info);
        status = handle;
        while (status!= -1) {
                ncpy(tmp,info.name,BFSZ-1);
		wild_total += info.size / 100;
                dmsg("Found file %s \n",tmp);
                s = tmp;
                s2 = strchr(s,'\\');
                for (;s2!=NULL;) {
                        if (s2!=NULL)  s = s2 + 1;
                        s2 = strchr(s,'\\');
                }               
                s_add(ls,s);
                status = _findnext(handle,&info);
        }
        if (handle!= -1) _findclose(handle);
}
int lib_freespace(char *s)
{
#ifdef OS2
        return 1000000;
#else
        char bf[BFSZ];
        int sc,bs,fc,c;
	   if (config_true(C_NOSPACECHECK)) return 1000000; 

        strcpy(bf,s);
        s = strchr(bf,':');
        if (s!=NULL) {s+=2; *s = 0; s = bf;} else strcpy(s,"c:"); 
        if (!GetDiskFreeSpace(s,&sc,&bs,&fc,&c)) {
                imsg("GetDiskFreeSpace call failed, {%s} errcode=%d \n",s,GetLastError());
                return 1000000;
        }
	dmsg("lib: Disk space for {%s} %d %d %d\n",s,sc,bs,fc);
        return sc*(bs/512)*(fc/2);  /* Avoid an overflow */
#endif
}
#endif

char *str_trimtabs(char *s)
{
        char *ss=s;
        char *end;
        char bf[BFSZ];
        
        for (;(*s==' ') || (*s=='\t');) s++;
        ncpy(bf,s,BFSZ-1);
        end = bf;
        for (s=bf;*s!=0; s++) {
                if (!xisspace(*s)) end = s;
        }
        end++;
        *end = 0; 
        strcpy(ss,bf);
        return ss;
}
int lib_append(char *src, char *dst)
{
        FILE *fsrc,*fdst;
        char bf[BFSZ];

        fsrc = xfopen(src,"r");
        if (fsrc==NULL) return FALSE;
        fdst = xfopen(dst,"a");
        if (fdst==NULL) { 
                xfclose(fsrc);
                filemsg("Can't open output file (%s)\n",dst); 
                return FALSE;
        }
                
        for (;!feof(fsrc) ;) {
                if (fgets(bf,BFSZ-10,fsrc)==NULL) break;
                fprintf(fdst,"%s",bf);
        }
        xfclose(fdst); xfclose(fsrc);
        return TRUE;
}
char *feed_fname(char *xname, char *xext)
{
        static char bf[400],ext[100],name[400];
        char *out;
        char *s;
	ncpy(ext,xext,20);
	ncpy(name,xname,200);
#ifdef SHORT_NAMES
	xext[3] = 0;
	name[8] = 0;		
#endif        
        strcpy(bf,file_work(""));
        for (s=name,out=bf+strlen(bf);*s!=0;s++,out++) {
                if (*s=='.') *out = '_';
                else *out = *s;
                if (*out==':') *out = '_'; /* So address:port works */  
        }        
        *out = 0;
        strcat(out,ext);
        return bf;
}
int memdebug_total;
int mem_total(void)
{
        return memdebug_total;
}
int lib_remove(char *s)
{
#ifdef WIN32
        if (!DeleteFile(s)) {
                emsg("Delete failed {%s} err=%d\n",s,GetLastError());
                return 0;
        } 
        return -1;
#else
        return remove(s);
#endif
}
int lib_test_files(void)
{
        int f[9000];
        char bf[BFSZ];
        int i,r;
        for (i=0; i<3000; i++) {
                sprintf(bf,"test%d.tmp",i);
#ifdef Mac
                f[i] = open(bf,O_WRONLY | O_CREAT | O_BINARY);
#else
                f[i] = open(bf,O_WRONLY | O_CREAT | O_BINARY,U_RW);
#endif
                if (f[i]<0) {
			filemsg("lib_test_files %d \n",i);
			break;
		}
        }
        r = i;
        for (i=0; i<r; i++) {
                if (f[i]>=0) {
                        close(f[i]);
                        sprintf(bf,"test%d.tmp",i);
                        remove(bf);
                }
        }
        return r;
}


static char *time_names[100];
static int ntime,time_n[100];
static double time_cpu[100];
void time_start(char *s)
{
        int i;
        for (i=0; i<ntime; i++) if (strcmp(s,time_names[i])==0) goto gotit;
        if (ntime>50) {emsg("stat problem %s \n",s); return;}
        time_names[ntime++] = mystrdup(s);
        i = ntime-1;
gotit:
        time_cpu[i]  -= clock();
}
void time_end(char *s)
{
        int i;
        for (i=0; i<ntime; i++) if (strcmp(s,time_names[i])==0) break;
        time_cpu[i] += clock();
        time_n[i]++;
}
void time_show(void)
{
        int i;
        int cps=CLOCKS_PER_SEC;

        for (i=0; i<ntime; i++) {
		if (cps==0) break;
		if (time_n[i]==0) break;
                imsg("Time %14s %7.2f %7.2f %d\n",time_names[i]
                        ,time_cpu[i]/cps,time_cpu[i]/cps/time_n[i],time_n[i]); 
        }
}

#ifdef NEED_MEMMOVE
void *memmove(char *dst, char *src, int len)
{
        bcopy(src,dst,len);
        return (void *) dst;
}
#endif



#ifdef NETWARE
/* Some dummy routines that need to be properly ported */
int lib_freespace(char *disk) {return 1000000;}
void s_wild(Sary *ls, char *path, char *wild)
{
	wild_total = 0;
        s_clear(ls);
}
#endif


#ifdef WIN32
#define LOCK_FILE file_work("dlock.dat")
#include <errno.h>
#include <share.h>
int lib_locked(void)
{
        static int f;
        if (f!=0) {printf("oops, liblock \n"); return TRUE;} /* Should never happen */
        f = sopen(LOCK_FILE,_O_CREAT | _O_RDWR,_SH_DENYRW,S_IREAD | S_IWRITE);
        if (f<0) {
                if (errno==EACCES) return TRUE;
                printf("Lock errno %d, probably you have not created the SPOOL directory \n",errno);
		emsg("The SPOOL directory MUST be created for dnews to work\n");
        } 
        /* Intentionally leave file handle open*/ 
        return FALSE;
}
#endif



int key_expired;
#define DNEWS_KEYFILE file_kfile()
static char cur_key[200],cur_other[200];
static char key_msg[BFSZ];
char *key_reason(void)
{
	return key_msg;
}
int nt_setkey(char *s)
{
        FILE *f;
        char ex[200];
        time_t now;
        struct tm *t; 
        int users,flags;
        
        now = time(NULL);
        t = localtime(&now);
        /* Month is 0-11 */
        
        if (!new_test(s,host_details(),&users,&flags,ex)) {
                emsg("Key registration failed {%s} {%s} \n",s,ex);
		strcpy(key_msg,ex);
                return FALSE;
        }       
/*        if (flags<2) {
                emsg("Sorry, key generated by old software, contact NetWin@world.std.com\n");
                return FALSE;
        }
  */
        emsg("Key registration ok {%s} \n",ex);
        key_expired = FALSE;

        f = fopen(DNEWS_KEYFILE,"w");
        if (f==NULL) {
		filemsg("Can't write? %s\n",DNEWS_KEYFILE); 
		sprintf(key_msg,"Please remove (%s) and check file prot and ownership",DNEWS_KEYFILE);
		return FALSE;
	}
        fprintf(f,"%s\n",s);                            
        fclose(f);

        strcpy(cur_key,s);
        strcpy(cur_other,s);

        f = fopen(nt_other(),"w");
        if (f==NULL) {
        	filemsg("FATAL: You must delete this file before entering your key (%s)\n",nt_other()); 
		sprintf(key_msg,"Please remove (%s) and check file prot and ownership",nt_other());
                return FALSE;
        } else {
        	fprintf(f,"%s\n",s);                            
        	fclose(f);
	} 

        return TRUE;
}
int glob_ok;
int nt_getkey(char *ex, int nchan)
{
        FILE *f;
        char bf[BFSZ];
        time_t now;
        struct tm *t; 
        int users,flags;
        int nloop;
	nloop = 0;
#ifdef NOKREG
                strcpy(cur_key,"");
                return TRUE;
#endif


        now = time(NULL);
        t = localtime(&now);

        if (strlen(cur_key)==0) {
                f = fopen(DNEWS_KEYFILE,"r"); 
                if (f!=NULL) {
                        fgets(cur_key,BFSZ-1,f);
                        fclose(f);
                }
  		strcpy(cur_other,cur_key);
                f = fopen(nt_other(),"r"); 
                if (f!=NULL) {
                        fgets(cur_other,BFSZ-1,f);
                        fclose(f);
                }
                if (strlen(cur_key)==0) if (strlen(cur_other)!=0) {
                        strcpy(cur_key,cur_other);
		       	f = fopen(DNEWS_KEYFILE,"w");
		        if (f!=NULL) {
			        fprintf(f,"%s\n",cur_key);                            
			        fclose(f);
			}
	        }
                if (strlen(cur_key)==0) {
                        t->tm_mon ++;
                        if (t->tm_mon==12) {t->tm_year++; t->tm_mon = 0;}
#ifdef AUTOREG
                        strcpy(bf,new_make(0,2,1,"*"));
#else
                        strcpy(bf,new_make(2,0,1,"*"));
#endif
                        emsg("PC name is {%s} \n",host_details());
                        nt_setkey(bf);
                }
		if (key_test(cur_key,t->tm_mon,t->tm_year,&users,&flags,nt_pcname(),ex)) {
			if ((flags>=2) && (strlen(ex)==0)) {
			 	/* Create Permanent key */
	                        strcpy(bf,new_make(0,users,1,host_details()));
	                        nt_setkey(bf);
			} else {
				/* Create Temporary key */
	                        strcpy(bf,new_make(2,users,1,"*"));
	                        nt_setkey(bf);
			} 
		}
        }       

        if (strcmp(cur_key,cur_other)!=0) {
                sprintf(ex,"Keys don't match (%s) (%s) check ownership of log dir",cur_key,cur_other);
                goto fail;
        }
again:
	nloop++;
	if (nloop>100) goto fail;
        if (!new_test(cur_key,host_details(),&users,&flags,ex)) {
		if (strcmp(ex,"Key for wrong computer")==0) {
		        if (users!=2) users = 0;
			if (new_test(cur_key,nntp_hostip(),&users,&flags,ex)) if (strlen(ex)==0) {
		 		emsg("V4 key change in progress - Request a new key from netwin@netwinsite.com if necessary \n");
				/* Create Temporary key */
	                        strcpy(bf,new_make(2,users,1,host_details()));
	                        nt_setkey(bf);
				strcpy(cur_key,bf);
				goto again;						
			}
			emsg("Computer rename in progress - Request a new key from netwin@netwinsite.com (send new register.txt)\n");
	                strcpy(bf,new_make(2,users,1,"*"));
	                nt_setkey(bf);
			strcpy(cur_key,bf);
			goto again;				
		}
                emsg("Key no good {%s} {%s} \n",cur_key,ex);
                goto fail;
        }       
	glob_ok = TRUE;

        if ((chan_nusers()>users) && (users>2)) {
                strcpy(ex,"Sorry, your license does not permit this many connections");
                return FALSE;
        }
        return TRUE;
fail:
        key_expired = TRUE;
        return TRUE;

}
char *strip_spaces(char *bf)
{
	char *s=bf;
	char *out=bf;
	for (;*s!=0;s++) {
		if (isspace(*s)) continue;
		*out++ = *s;
	}
	*out++ = 0;
	return bf;
}
char *host_details(void)
{
 	static char bf[BFSZ];
	sprintf(bf,"%s:%s",nt_pcname(),nntp_hostip());
	return strip_spaces(bf);
}

#ifdef NETWARE
char *nt_pcname(void)
{
        char *s = config_get(C_NWSERVER);
        if (strlen(s)==0) return "noname";
        return s;
}


char *nt_other(void)
{
        static char bf[BFSZ];
        sprintf(bf,"sys:system\\dxyntky.exe");
        return bf;
}
#endif
#ifndef WIN32
#ifndef NETWARE
char *nt_pcname(void)
{
        char *s=nntp_hostname();
        if (strlen(s)==0) return "noname";
        return s;
}


char *nt_other(void)
{
        static char bf[BFSZ];
        strcpy(bf,file_log("dnews.lock"));
        return bf;
}


#endif
#endif

#ifdef WIN32
#define REALKEY TRUE
#endif

#ifdef NETWARE
#define REALKEY TRUE
#endif
#define REALKEY TRUE
#ifndef REALKEY

char *nt_pcname(void)
{
        return "UNIX";
}
char *nt_other(void)
{
        return "/etc/dxyntky.exe";
}
char *key_make(int month, int year, int users, int flags, char *host)
{
        return "";
} 
int key_test(char *k, int month, int year, int *users, int *flags, char *host, char *expires)
{
        return TRUE;
}

#endif

char *mystats(void);
String *hist_status(void);
static int m_total[60];
static int m_max[60];
String *lib_showmem(void)
{
        static String *stat;
        char *s;
        char bf[BFSZ];
        int i;
        if (stat==NULL) stat = str_new();
        str_copysn(stat,"");
        for (i=0; m_names[i]!=NULL; i++) {
                sprintf(bf,"Memory use %8dk for {%s} Max %dk\n",m_total[i]/1000,m_names[i],m_max[i]/1000);
                str_addsn(stat,bf);
        }
        for (i=0; i<1000; i++) {
                s = p_show_blockn(i);
                if (strlen(s)==0) break;
                str_addsn(stat,s);
        }
        str_add(stat,hist_status());
        str_addsn(stat,group_status());
/*      str_addsn(stat,mystats());*/

        return stat;
}
char *hist_status_s(void);
void lib_logmem(void)
{
        char *s;
        int i;
	imsgf("Memory allocation tables at time of exit\n");
        for (i=0; m_names[i]!=NULL; i++) {
                imsgf("mem: Memory use %8dk for {%s} Max %dk\n",m_total[i]/1000,m_names[i],m_max[i]/1000);
        }
        for (i=0; i<1000; i++) {
                s = p_show_blockn(i);
                if (strlen(s)==0) break;
		imsgf("mem: %s",s);
        }
        imsgf("mem: %s",hist_status_s());
        imsgf("mem: %s",group_status());
}
void mem_log(int type, int amnt)
{

        m_total[type] += amnt;
	if (m_max[type] < m_total[type]) m_max[type] = m_total[type];
}

char *mystrstrnc(const char *s, const char *w)
{
        const char *ww = w;
        int len = strlen(w);

        for (;*s!=0;) {
                s = mystrchrnc(s,*w);
                if (s==NULL) return NULL;
                if (strncmpnc(s,w,len)==0) return (char *) s;
                s++;
        }
        return NULL;
}
char *mystrchrnc(const char *s,int c)
{
	c = tolower(c);
 	for (;*s!=0;s++) if (tolower(*s)==c) return (char *) s;
	return NULL;
}
char *mystrchr(const char *s, int c)
{
 	for (;*s!=0;s++) if (*s==c) return (char *) s;
	return NULL;
}
char *ncpy(char *dst, char *src, int len)
{
        char *xdst = dst;
        int xlen = len;
/*	int z;
	z = strlen(src);
	if (z<len) return strcpy(dst,src);*/
		
	for (;(*src !=0) && (len>0); ) {*dst++  = *src++; len--;}
        *dst++ = 0;
        xdst[xlen] = 0;
        return xdst;
}



#ifdef OS2xxx
void s_wild(Sary *ls, char *path, char *wild)
{
	char bf[BFSZ];
	char *s;
	FILE *f;

	remove(file_work("dir.tmp"));
	sprintf(bf,"dir /b %s\\%s >%s",path,wild,file_work("dir.tmp"));
	if (system(bf)== -1) {imsg("System command failed\n"); return;}
        s_clear(ls);
	f = fopen(file_work("dir.tmp"),"r");
	if (f==NULL) {emsg("s_wild failed {%s} \n",file_work("dir.tmp")); return; }
	for (;!feof(f);) {
	 	fgets(bf,BFSZ-10,f);
		s = strtok(bf," \n\t");
		if (s!=NULL) {
			s_add(ls,s);
		}
	}
	fclose(f);
}
#endif        
/*
        char *s;
        char bf[BFSZ],tmp[BFSZ];
        char *s2;
        int status;
        struct _finddata_t info;
        long handle;

        s_clear(ls);
        if ((strlen(path)>200) || (strlen(wild)>200)) return;
        sprintf(bf,"%s/%s",path,wild);

        handle = _findfirst(bf,&info);
        status = handle;
        while (status!=-1) {
                ncpy(tmp,info.name,BFSZ-1);
                dmsg("Found file %s \n",tmp);
                s = tmp;
                s2 = strchr(s,'\\');
                for (;s2!=NULL;) {
                        if (s2!=NULL)  s = s2 + 1;
                        s2 = strchr(s,'\\');
                }               
                s_add(ls,s);
                status = _findnext(handle,&info);
        }
        if (handle!=-1) _findclose(handle);
*/
#ifdef OS2
int lib_freespace(char *s)
{
#ifdef OS2
        return 1000000;
#else
        char bf[BFSZ];
        int sc,bs,fc,c;
        strcpy(bf,s);
        s = strchr(bf,':');
        if (s!=NULL) {s+=2; *s = 0; s = bf;} else strcpy(s,"c:"); 
        if (!GetDiskFreeSpace(s,&sc,&bs,&fc,&c)) {
                imsg("GetDiskFreeSpace call failed, {%s} errcode=%d \n",s,GetLastError());
                return 1000000;
        }
        return sc*bs*(fc/1000); 
#endif
}
#endif
#ifdef OS2
#endif

void lib_doevents(void) /* Call this during any time consuming activity */
{
#ifdef Mac
        EventRecord theEvent;
        WaitNextEvent(0, &theEvent, 1, nil);
#endif
#ifdef NETWARE
        delay(1); 
#endif
}




#ifdef USE_RLIMIT
#include <sys/time.h>
#include <sys/resource.h>
void lib_grow_memory(void)
{
        static long min;
        struct rlimit lim;
        static long max;
        if (min>0) return;

        getrlimit(RLIMIT_DATA,&lim);  
        max = lim.rlim_max;
        if (lim.rlim_cur==RLIM_INFINITY) {imsg("No memory limit defined\n"); return;}
        imsg("Current memory limit is %ld\n",lim.rlim_cur);
	if (max==0) max = 900000000;
        lim.rlim_cur = max;
        if (setrlimit(RLIMIT_DATA,&lim)!=0) filemsg("Set rlimit failed\n");
        imsg("Current memory limit is now set to %ld\n",lim.rlim_max);


        getrlimit(RLIMIT_NOFILE,&lim);  
        max = lim.rlim_max;
        if (lim.rlim_cur==RLIM_INFINITY) {imsg("No FILE OPEN limit defined\n"); return;}
        imsg("Current file open limit is %d\n",lim.rlim_cur);
        lim.rlim_cur = max;
        if (setrlimit(RLIMIT_NOFILE,&lim)!=0) filemsg("Set rlimit failed\n");
        imsg("Current RLIMIT_NOFILE is now set to %d\n",lim.rlim_max);
}
#else
void lib_grow_memory(void)
{
         
}
#endif

char *lib_unescape(char *s)  /*  ~ = ' ' */
{
	static char bf[BFSZ];
	char *out;
	if (s==NULL) return "";
	for (out=bf; *s != 0; s++) {
	 	if (*s=='+') *out++ = ' ';
		else if (*s=='\\') { s++; *out++ = *s; } 
		else *out++ = *s;
	}
	*out++ = 0;
	return bf;
}
char *lib_escape(char *s)  /*  ~ = ' ' */
{
	static char bf[1000];
	char *out=bf;
	if (s==NULL) return "";
	for (;*s!=0; s++) {
	 	if (*s==' ') {strcpy(out,"+"); out += strlen(out);}
	 	else if (*s=='+') {strcpy(out,"\\+"); out += strlen(out);}
	 	else if (*s=='\\') {strcpy(out,"\\\\"); out += strlen(out);}
		else *out++ = *s;
	}
	*out++ = 0;
	return bf;
}

char *xstrdup(char *s)
{
  int xlen = strlen(s)+1;
  char *n;
  n = r_malloc(xlen);
  strcpy(n,s);
  return n;
}
void xstrfree(char *s)
{
	r_free(s);
}

static int stack_max;
void dnews_stacksize(void)
{
}
int dnews_stackused(void)
{
        return stack_max;
}

/*-----------------------------------------------------------*/
/* Routines to deal with incoming messages that grow too big */
/*-----------------------------------------------------------*/
static String *big_str[MAX_CHAN];
static FILE *big_file[MAX_CHAN];
static int big_mode[MAX_CHAN];
static int lasth;
static int big_xlen[MAX_CHAN];
enum {B_NULL,B_STR,B_FILE,B_FAILED};
#define MAX_BIG 50000
int big_maxsz(void)
{
	int r = atoi(config_get(C_BIG_SIZE));
	int b;
	if (r==0) r = MAX_BIG;
	b = atoi(config_get(C_BODY_CHUNK));
	if (b>r) r = b;
	return r;	
}
void show_outbf(char *s, int len)
{
	char *x;
	char bf[500];
	int total;

	for (total=0;total<len;) {
		ncpy(bf,s,400);
		x = strchr(bf,'\015');
		if (x==NULL) {
			bf[100] = 0;
			imsg("No end of line in this string {%s} \n",bf);
			return;
		}
		*x = 0;
		imsg("String {%s}\n",bf);
		total += x-bf+2;
		s += x-bf+2;
	}	 	
}
char *big_name(int h)
{
	char bf[BFSZ];
	sprintf(bf,"big_%d.tmp",h);
	return file_work(bf);
}
int big_add(int h, char *s, int sz)
{
	if ((h<0) || (h>=MAX_CHAN)) {
	 	emsg("FATAL, big_add() failed, channel %d \n",h);
		return FALSE;
	}
	if (big_mode[h]==B_NULL) {
		emsg("Cannot add string to null big buffer %d\n",h);
		return FALSE;
	}
	if (big_mode[h]==B_FAILED) {
		imsg("Discarding incoming data due to big error above %d\n",h);
		return FALSE;
	}
	if (big_mode[h]==B_STR) {
		big_xlen[h] += sz;
		str_adds(big_str[h],s,sz);
		if (str_len(big_str[h])>big_maxsz()) {
			if (big_file[h]!=NULL) big_close(h);
		 	big_file[h] = fopen(big_name(h),"wb");
			if (big_file[h]==NULL) {
			 	filemsg("Cannot write temporary file %s\n",big_name(h));
				big_fail(h); /* Delete anything we have stored */
				return FALSE;
			}
		 	fwrite(str_s(big_str[h]),1,str_len(big_str[h]),big_file[h]);
			str_free(big_str[h]);
			big_str[h] = NULL;
			big_mode[h] = B_FILE;
			lasth = h;
		}
		return TRUE;
	}
	if (big_mode[h]==B_FILE) {
		big_xlen[h] += sz;
		if (lasth!=h) big_close(lasth);
		if (big_file[h]==NULL) {
			big_file[h] = fopen(big_name(h),"ab");
			if (big_file[h]==NULL) {
				filemsg("Cannot append to temporary file %s\n",big_name(h));
				big_fail(h); /* Delete anything we have stored */
				return FALSE;
			}	 	
			lasth = h;
		}
		if (fwrite(s,1,sz,big_file[h])!=(size_t) sz) {
			filemsg("Failed appending to temporary file %s\n",big_name(h));
			big_fail(h);
			return FALSE;
		}
		return TRUE;
	}
	return TRUE;
}
void big_close(int h)
{
	if (h<0) return;
	if (big_file[h]!=NULL) fclose(big_file[h]);
	big_file[h] = NULL;
	if (lasth==h) lasth = -1;
}
int big_free(int h)
{
	big_xlen[h] = 0;
 	if (big_str[h]!=NULL) {
	 	str_free(big_str[h]);
		big_str[h] = NULL;
	}
	if (big_mode[h]==B_FILE) {
		big_close(h);
	 	remove(big_name(h));
	}
	big_mode[h] = B_NULL;
	return TRUE;
} 
void big_fail(int h) /* We are still writing, but an error occured so stop accepting info*/
{
	big_free(h);
	big_mode[h] = B_FAILED;
}
void big_init(int h)
{
	big_free(h);
	big_xlen[h] = 0;
	big_str[h] = str_new();
	big_mode[h] = B_STR;
	str_expand(big_str[h],4000);
}
int big_len(int h)
{
	return big_xlen[h];
}	
String *big_get(int h)
{
	FILE *f;
	char *s;
	size_t chunk,got,wanted;
	big_close(h);
	if (big_mode[h]==B_NULL) {
		emsg("big_get[%d]: state = B_NULL\n",h);
		return NULL;
	}
	if (big_mode[h]==B_FAILED) {
		emsg("Returning null because of error during store [%d]\n",h);
		return NULL;
	}
	if (big_mode[h]==B_STR) {
		return big_str[h];				
	}
	if (big_mode[h]==B_FILE) {
		f = fopen(big_name(h),"rb");
		if (f==NULL) {
			filemsg("Cannot read temporary file %s\n",big_name(h));
			big_fail(h); /* Delete anything we have stored */
			return NULL;
		}	 	
		if (big_str[h]==NULL) big_str[h] = str_new();
		wanted = big_xlen[h];
	       	if (wanted>(size_t) MAX_STRLEN) {
			fclose(f);
			imsg("big_get: item too big %d bytes\n",wanted);
			big_fail(h);
			return NULL;
		}
		str_setsize(big_str[h],wanted+10);
		str_setlen(big_str[h],0);
		s = str_s(big_str[h]);
		got = 0;
		for (;!feof(f) && got<wanted;) {
			chunk = 50000;
			if ((got+chunk) > wanted) chunk = wanted-got;
			if (fread(s+got,1,chunk,f)!=chunk) break;
			got += chunk;
		}
		fclose(f);
		if (got<wanted) {
			filemsg("Failed to read entire item from temp file %s\n",big_name(h));
			big_fail(h);
			return NULL;
		}
		str_setlen(big_str[h],wanted);			 
		return big_str[h];
 	}
	return NULL;
}
int lib_str_start(void)
{
 	int r = atoi(config_get(C_STR_START));
	if (r==0) r = (int) (atoi(config_get(C_ITEM_MAX))*2.5);
	if (r<900000) r = 900000;
	return r;
}
char *big_get_chunk(int h, int from, int len, int *rlen)
{
	String *aa = big_get(h);
	static char *bf;
	if (bf==NULL) bf = mymalloc(big_maxsz()+20000);								
    	if (len>big_maxsz()) {
		emsg("Big get chunk, size %d > %d\n",len,big_maxsz());
	}
    	if (len>big_maxsz()+10000) {
		emsg("Big get chunk, size %d > %d\n",len,big_maxsz());
		return NULL;
	}

	if (aa==NULL) return NULL;
	if (from+len>str_len(aa)) {
	 	len = str_len(aa) - from;
		if (len<0) len = 0;
		*rlen = len;
		if (len==0) return NULL;
	}
	*rlen = len;
	strncpy(bf,str_s(aa)+from,len);
	bf[len] = 0;
	return bf;
}

void *mykeep(int sz)
{		       
	static int left;
	static char *next,*cur;
	
	sz +=3;
        sz = sz & 0x5ffffffc; 

	if (left<sz) {
		mem_log(M_XKEEP,60000);
		next = (char *) mymalloc(60000);
		left = 60000;
	}
	cur = next;
	next += sz;
	left -= sz;
	return (void *) cur;
}
void lib_dir_split(char *orig, char *dir, char *wild)
{
 	char *s;
	char *last=NULL;
	char src[BFSZ];

	strcpy(wild,"");
	ncpy(src,orig,BFSZ-1);
	for (s=src;*s!=0;s++) {
	 	if (*s=='/') last = s;
	 	if (*s==':') last = s;
	 	if (*s=='\\') last = s;
	 	if (*s==']') last = s;
	}
	if (last==NULL) {emsg("Split directory failed {%s} \n",src); return;}
	if (*last=='/') *last = 0;
	if (*last=='\\') *last = 0;
	if (*last==']') {
		ncpy(wild,last+1,100);
		*(last+1) = 0;
		ncpy(dir,src,100);
		return; 
	}
	ncpy(dir,src,100);
	ncpy(wild,last+1,100);
}
char *str_trunc(char *s, int len)
{
	static char bf[399];
	if (len>300) len = 300;
	ncpy(bf,s,len);
	return bf;
}
#ifdef WIN32
#define SLOW_TIMExxx
#endif
static int xtimex;
int lib_gmtime(void)
{               /* On VMS correct to make it a GMT time.  */
    static time_t t;
#ifdef SLOW_TIME
	static int ns;
	if (ns<20) {
		ns++;
        return (int) lib_fixtime(t); /* Convert to STD base date of 1970 */
	}
	ns = 0;
#endif
        time(&t);
#ifdef VMS
        lib_tzinit();
        t += vms_timezone;
#endif
        xtimex = (int) lib_fixtime(t); /* Convert to STD base date of 1970 */
        return xtimex;
}
int lib_gmtimex(void)
{
	return xtimex;
}
int lib_rmdir(char *s)
{
#ifdef WIN32
	return (RemoveDirectory(s));
#else
	if (remove(s)==0) return TRUE;
	return FALSE;
#endif	
}

#ifdef OS2
#define MAIL_FEED TRUE
#endif

#ifdef WIN32
#define MAIL_FEED TRUE
#endif

#ifdef VMS
#define MAIL_FEED TRUE
#endif

#ifdef NETWARE
#define MAIL_FEED TRUE
#endif

#ifdef Mac
#define MAIL_FEED TRUE
#endif

#ifdef MAIL_FEED
int lib_mail_file2(char *to, char *subj, char *fname)
{
	return lib_mail_file(NULL,subj,fname);
}
int lib_mail_file(char *to, char *subj, char *fname)
{
        String *xitem;
        xitem = str_new();
        if (!str_read(xitem,fname)) return FALSE;
        post_local(xitem,to,TRUE);
        str_free(xitem);
        return TRUE;
}
#else
int lib_mail_file2(char *to, char *subj, char *fname)
{
	return lib_mail_file(to,subj,fname);
}
int lib_mail_file(char *to, char *subj, char *fname)
{
   char cmd[400];
   int inhead;
   char bf[BFSZ];
   char *s;
   int i;
   FILE *fin;
   FILE *f;
   
   /* Path should include %s for 'to' */
   sprintf(cmd,config_get(C_SENDMAIL),to);
   if ((f = popen(cmd,"w"))==NULL)  {return FALSE;   }
   fprintf(f,"To: %s\n",to);
   if (FLUSH(f)) {pclose(f); return FALSE;    }

   /* Write the headers, a blank line, then the article. */
 
   
   
   inhead = TRUE;
   fin = fopen(fname,"r");
   if (fin==NULL) {filemsg("Couldn't find (%s)\n",fname); pclose(f); return FALSE;}

   for (i=0; !feof(fin); i++)  {
        if (fgets(bf,BFSZ-10,fin)==NULL) break;
	s = strchr(bf,'\r'); if (s!=NULL) *s = 0;
	s = strchr(bf,'\n'); if (s!=NULL) *s = 0;
	if (strncmp(bf,"To:",3)==0) continue;
	fprintf(f,"%s\n",bf);
	if (strlen(bf)==0) inhead = FALSE;
	if (FLUSH(f)) {pclose(f); fclose(fin); return FALSE;    }
   }
   fclose(fin);
   if (pclose(f)!=0) return FALSE;
   return TRUE;
}
#endif


#ifdef WIN32
#include <process.h>
int myspawn(char *cmd)
{
	char *args[20];
	int n=0;
	char xcmd[BFSZ];
	char *s;
	int h;	
	int i;
	s = strtok(cmd," ");
	for (;s!=NULL;) {
		args[n++] = mystrdup(s);
		if (n==1) strcpy(xcmd,s);
		s = strtok(NULL," ");
	}
	args[n++] = NULL;
	h = _spawnv(_P_WAIT,xcmd,args);
	if (h<0) filemsg(xcmd);
	for (i=0; i<n; i++) {
		if (args[i]!=NULL) myfree(args[i]);
	}
	return TRUE;
}

#endif

static int strstrok=1;
void strstr_test(void)
{
	clock_t t1,t2;
	int i;
	char bf[2000];
	char *s;
	
	strstrok = 0;
	t1 = clock();
	strcpy(bf,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazd");
	for (i=0; i<100; i++) strcat(bf,"bbbbbbbbb"); 
	for (i=0; i<10000; i++) {
		s = strstr(bf,"zd");
	}
	t1 = clock() - t1;
	t2 = clock();
	for (i=0; i<10000; i++) {
		s = mystrstr(bf,"zd");
	}
	t2 = clock() - t2;
	strstrok = 0;
	if (t1<t2) strstrok = 1;
	if (strstrok) imsg("lib: String strstr(%d) mystrstr(%d), using system strstr\n",t1,t2);
	else imsg("lib: String strstr(%d) mystrstr(%d), using dnews strstr\n",t1,t2);
}

#ifdef strstr
#undef strstr
#endif

char *mystrstr(const char *s, const char *w)
{
        const char *ww = w;
        int len; 
/*	if (strstrok) return strstr(s,w);*/

	len = strlen(w);
        for (;*s!=0;) {
                s = mystrchr(s,*w);
                if (s==NULL) return NULL;
                if (strncmp(s,w,len)==0) return (char *) s;
                s++;
        }
        return NULL;
}
void lib_sleep(int x)
{
#ifdef WIN32
	Sleep(x*1000);	
#else
	sleep(x);	
#endif
}

