/* 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"
#ifdef KEYLIB
#include "keylib.h"
#endif
#undef mymalloc
#undef myfree
#define mymalloc(x) mymalloc2(x,M_LIB)
#define myfree(x) myfree2(x,M_LIB)
#define iffree iffreelib

extern int debug_lvl;
int key_expired;
unsigned int my_clock(void);
static int expire_mode = FALSE;
int get_expire_mode(void)
 {return expire_mode;}
void set_expire_mode(int mode) 
{expire_mode = mode;}

/*char *d_mystrdup(char *s, char *xfile, int xline)*/
char *old_mystrdup(char *s)
{
  int xlen = strlen(s)+1;
  char *n;


  n = mymalloc(xlen);
  strcpy(n,s);
/*  if (xlen<100) 
          imsg("mystrdup %d %d (%s) %s:%d \n",n,xlen,s,xfile,xline);
  else 
          imsg("mystrdup %d %d %s:%d \n",n,xlen,xfile,xline);
*/
  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;
}
void lib_mkfile(char *s)
{
	FILE *f;
	f = fopen(s,"a");
	if (f==NULL) return;
	fclosep(f);
	return;
}
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];
	char *out;
	int max=200;
        s = strchr(s,'<');
        if (s==NULL) return "";
	for (out=bf;*s!=0;s++) {
		*out++ = *s;
		max--;
		if (max<0) return "";
		if (*s=='>') break;
	}
	*out++ = 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)
{
    static struct tm atm;
        unsigned long x = *t;
#ifdef VMS
        return localtime(&x);
#else
        return safe_gmtime(&x,&atm); 
#endif

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

#ifdef VMS

#else

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

#endif

#ifdef WIN32
#define HAS_DST TRUE
#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
static int tz_done_init=FALSE;
void lib_tz_reset(void)
{
	tz_done_init = FALSE;
}
void lib_tzinit(void)
{
	struct tm atm;
#ifdef VMS
        char *s;
        if (!tz_done_init) {
                tz_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 (!tz_done_init) {
                tz_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 = safe_localtime(&tts,&atm);
                vms_timezone = (int) (ttm->tm_gmtoff);
                vms_timezone = -vms_timezone;
#else
                vms_timezone = (int) timezone;
#ifdef HAS_DST
		{
			time_t timer;
			struct tm *t;
			static int offset = 0;
			static int done;
			struct tm atm;
			if (!done) {
				done = TRUE;
				timer = time(NULL);
				t = safe_localtime(&timer,&atm);
				if (t->tm_isdst) offset = 60*60;
			}
			vms_timezone -= offset;
	                imsg("Timezone Offset %d dst %d\n",vms_timezone,offset);
		}
#else
                imsg("Timezone Offset %d\n",vms_timezone);
#endif
#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);
}
void iffree2(void *x,int t)
{
        if (x!=NULL) myfree2(x, t);
}
/*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;
}
*/
/*
 * This array is designed for mapping upper and lower case letter
 * together for a case independent comparison.  The mappings are
 * based upon ascii character sequences.
 */
static const unsigned char charmap[] = {
        0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
        0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
        0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
        0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
        0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
        0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
        0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
        0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
        0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
        0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
        0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
        0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
        0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
        0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
        0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
        0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
        0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
        0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
        0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
        0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
        0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
        0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
        0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
        0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
        0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
        0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
        0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
        0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
        0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
        0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
        0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
        0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
};

int strcmpnc(char *s1, char *s2) {
        const unsigned char *cm = charmap,
             *us1 = (const unsigned char *)s1,
             *us2 = (const unsigned char *)s2;

        while (cm[*us1] == cm[*us2++])
                if (*us1++ == '\0')
                        return (0);
        return (cm[*us1] - cm[*--us2]);
}



int szztrncmpnc(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;
}

int strncmpnc(const char *s1, const char *s2, int n) {
        const unsigned char *cm = charmap,
             *us1 = (const unsigned char *)s1,
             *us2 = (const unsigned char *)s2;

        while (cm[*us1] == cm[*us2++]) {
		n--;
		if (*us1++ == '\0')
                        return (0);
		if (n==0) return 0;
	}
        return (cm[*us1] - cm[*--us2]);
}



#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[1600];
        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,BFSZ-1);
        ss = tmp;
        for (;(*ss!=0) && (!xisspace(*ss));) ss++; 
        if (ss==NULL) ss = tmp + strlen(tmp);
        *ss = 0;
        return tmp; 
}
char *get_word_long(char *s,int n) /*comp.os.vms 001 000 m*/
{
        static char tmp[15000];
        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,14000);
        ss = tmp;
        for (;(*ss!=0) && (!xisspace(*ss));) ss++; 
        if (ss==NULL) ss = tmp + strlen(tmp);
        *ss = 0;
        return tmp; 
}
#define xisspace2(x) ((x=='\n') ||(x=='\r') || (x==' ') || (x=='\t'))
char *get_wordnolf(char *s,int n) /*comp.os.vms 001 000 m*/
{
        static char tmp[600];
        int i;
        char *ss=s;

        for (;(*ss!=0) && xisspace2(*ss);) ss++; 
        for (i=0; i<n && *ss!=0; i++) {
                ss++;
                if (*ss==0) return "";
                for (;(*ss!=0) && !xisspace2(*ss);) ss++; 
                for (;(*ss!=0) && xisspace2(*ss);) ss++; 
                if (*ss==0) return "";
                ss--; 
                if (ss==NULL) return "";
        }
        if (*ss==0) return "";
        if (xisspace2(*ss)) ss++;
        ncpy(tmp,ss,499);
        ss = tmp;
        for (;(*ss!=0) && (!xisspace2(*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;
}
static int isnot;
int word_isnot(void)
{
        return isnot;
}
char *get_wordq(char *s,int n) /*comp.os.vms "001 000" m*/
{
        static char tmp[600];
        int i;
        char *ss=s;

        isnot = FALSE;
        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++;

        if (*ss=='!') {
                isnot = TRUE;
                ss++;
        }

        ncpy(tmp,ss,499);
        ss = tmp;
        if (*ss == '"') {
                ss = strchr(ss+1,'"');
                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);
	tmp[399] = 0;
        return tmp; 
}
char *get_rest_better(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++;  /* Skip leading spaces */
        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);
	tmp[399] = 0;
        return tmp; 
}

char *get_rest2(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); tmp[399] = 0;
        if (strlen(tmp)>0) tmp[strlen(tmp)-1] = 0;
        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)) {
          lprintf(bf,200-1,"%s[%d]",config_get(C_SPOOL),group_getgroupid(g));
        } else {
          lprintf(bf,200-1,"%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);
        lprintf(bf,500-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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];
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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);
        lprintf(bf,200-1,"%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

unsigned int lib_length_file(char *fname)
{
        FILE *f;
        unsigned int sz;
        f = fopen(fname,"r");
        if (f==NULL) return 0;
        sz = file_length(fileno(f));
        fclosep(f);
        return sz;
}
unsigned int file_length(int f)
{
#ifdef WIN32
        unsigned int r;
        r = filelength(f);
        if ((int) r == -1) {
                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
#ifdef HAS_SEEK64
        struct stat64 bf;
        if (fstat64(f,&bf)!=0) {filemsg("FATAL64 Could not get file length\n"); return 0;}
        return bf.st_size;
#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
#endif
}
void die(char *s)
{
        emsg("Dieing {%s} \n",s);
        exit(1);
}

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

int lib_cdate(char *s)
{
        FILE *f;
        struct stat st;
        f = fopen(s,"r");
        if (f==NULL) {
                dmsg("lib: Can't open {%s} \n",s);
                return -1;
        }
        fstat(fileno(f),&st);
        fclosep(f);
        return st.st_mtime;
}

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(dom_ini_get(C_STAMP_PATH))>0) ncpy(hname,dom_ini_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 sid[BFSZ];
        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;

	if (strcmp(config_get(C_MYNAME),dom_ini_get(C_MYNAME))!=0) {
		strcpy(bf,dom_ini_get(C_MYNAME));
	}
	if (strchr(bf,'.')==NULL) strcpy(bf,config_get(C_MYNAME));
	strcpy(sid,"");
	if (slave_n()>0) lprintf(sid,BFSZ-1,"_%d",slave_n());

        if (x==0) lprintf(idbuff,300-1,"<%lx%s@%s>",now,sid,bf);
        else lprintf(idbuff,300-1,"<%lx$%d%s@%s>",now,x,sid,bf);
        last = now;
        return idbuff;
}
static char *months[]={
        "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
};


static int key_isextend;
int key_setextend(void)
{
        key_isextend = TRUE;
        return TRUE;
}
int key_extend(void)
{
    struct tm atm;
        time_t now;
        struct tm *t;
        time(&now);
        t = safe_localtime(&now,&atm);
        if (t->tm_mday<7) {     
                if (key_isextend) key_expired = FALSE;
        }
        return TRUE;
}

static char *weekday[]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", };
char *lib_strdate(void)
{
        static char bf[70];
        time_t now;
	struct tm atm;
        struct tm *t;
	int poffset;
        time(&now);
	poffset = atoi(config_get(C_POST_OFFSET));
/*        t = gmtime(&now);*/
	now += poffset*60;
        t = safe_localtime(&now,&atm);
        if (t==NULL) return "LOCALTIMEnull";
	if (!config_true(C_DATE_DAY)) {
	    lprintf(bf,70-1,"%d %s %d %02d:%02d:%02d %s",
	        t->tm_mday,months[t->tm_mon],t->tm_year+1900,
                t->tm_hour,t->tm_min,t->tm_sec,lib_timezone());
	}
	else {
	    lprintf(bf,70-1,"%s, %d %s %d %02d:%02d:%02d %s",
		weekday[t->tm_wday],
	        t->tm_mday,months[t->tm_mon],t->tm_year+1900,
                t->tm_hour,t->tm_min,t->tm_sec,lib_timezone());
	}
        return bf;
}
char *lib_email_date(void)
{
        static char bf[70];
        time_t now;
	struct tm atm;
        struct tm *t;

        time(&now);
        t = safe_localtime(&now,&atm);
        if (t==NULL) t = safe_gmtime(&now,&atm);
        lprintf(bf,70-1,"%s, %d %s %d %02d:%02d:%02d %s",
                weekday[t->tm_wday],
                t->tm_mday,months[t->tm_mon],t->tm_year+1900,
                t->tm_hour,t->tm_min,t->tm_sec,lib_timezone());
        return bf;
}
char *lib_timezone(void)
{
        static char bf[BFSZ];
        int now;
        int diff;

        if (strlen(config_get(C_TIMEZONE_POST))>0) {
                strcpy(bf,config_get(C_TIMEZONE_POST));
                return bf;
        }
        now = lib_gmtime();
        diff =  lib_gmt_to_local(now) - now;

        if (diff==0) return "GMT";
        lprintf(bf,BFSZ-1,"%+04d",(diff/36));
#ifdef HAS_DST_NOW_IN_TIMEZONE /* Has daylight saving, not needed */
        {
                time_t t;
		struct tm atm;
                struct tm *xtm;
                time(&t);
                xtm = safe_localtime(&t,&atm);
                if (xtm->tm_isdst !=0 ) {
                        lprintf(bf,BFSZ-1,"%+04d",(diff/36)+100);      
                }
        }
#endif
/*imsg("lib_timezone %d (%s) \n",diff/36,bf);*/
        if (strlen(bf)==4) {
                memmove(bf+2,bf+1,4);
                bf[1] = '0';
        }
        return bf;
}
char *lib_hour(void)
{
        static char bf[70];
        time_t now;
	struct tm atm;
        struct tm *t;

        time(&now);
        t = safe_localtime(&now,&atm);
        lprintf(bf,70-1,"%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;
	struct tm t2;
	struct tm atm;

	time(&now);
        now += offset;
	t = safe_gmtime(&now,&atm);
	if (t==NULL) t = safe_localtime(&now,&atm);
	if (t==NULL) dnews_ex("localtime call failed, check system time settings");
        t2 = *t;
	lprintf(bf,70-1,"%d %s %d %02d:%02d:%02d %s",
                t2.tm_mday,months[t2.tm_mon],t2.tm_year+1900,
                t2.tm_hour,t2.tm_min,t2.tm_sec,lib_timezone());
        
	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];
   
   dmsg("lib: createdir (%s) \n",s);
   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) {/* removed imsg for threading reasons */
                        break;
                }
        }
        p[n] = NULL;
        return n;
}
int token_quote(char *s, char *p[], int tmax)
{
        int n=0;
	char *sep=" \t";
	char *sep2="= \t";

        for (;*s!=0;) {
                s += strspn(s,sep);  /* Skip spaces */
                if (*s==0) break;
		if (*s=='"') {
			s++;
	                p[n++] = s;
			for (;*s!=0;s++) {
				if (*s=='"') break;
				if (*s=='\\') if (s[1]=0) s++;
			}
			goto dorest;
		}
		if (*s=='=') {
	                p[n++] = "=";
			goto dorest;			
		}
                p[n++] = s;
                s += strcspn(s,sep2);  /* Find end of word */
		if (*s=='=') {
			p[n++] = "=";	
		}
dorest:
                if (*s==0) break;               
                *s = 0; s++;
                if ((n+5)>=tmax) {
                        imsg("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) {
                        imsg("Too many tokens in this header line\n");
                        break;
                }

        }
        p[n] = NULL;
        return n;
}
int lib_file_mod(char *s)
{
        struct stat st;
        FILE *f;
        f = fopen(s,"r");
        if (f==NULL) return 0;
        fstat(fileno(f),&st);
        fclosep(f);
        return (int) st.st_mtime;

}

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
#ifndef Mac

#define USEDF TRUE

#ifdef HAS_STATFS
#ifdef INCLUDE_MOUNT
#include <limits.h>
#include <sys/param.h>
#include <sys/mount.h>
#else
#include <sys/vfs.h>
#endif
int lib_freespace(char *disk)
{
        struct statfs info;     
        int r;
        if (config_true(C_NOSPACECHECK)) return 4000000; 
        if (statfs(disk,&info)!=0) {
                filemsg("statfs failed for %s\n",disk);
                return 2200000;
        }
        r = (info.f_bavail/20)*(info.f_bsize/50);
        dmsg("lib: Free space for %s, %d blocks of %d bytes = %dk\n",disk,info.f_bavail,info.f_bsize,r);
        return r;
}
#undef USEDF
#endif

#ifdef HAS_STATVFS
#undef USEDF
#include <sys/statvfs.h>
int lib_freespace(char *disk)
{
        struct statvfs info;    
        int r;
        if (config_true(C_NOSPACECHECK)) return 4000000; 
        if (statvfs(disk,&info)!=0) {
                filemsg("statvfs failed for %s\n",disk);
                return 3000000;
        }
        r = (info.f_bavail/20)*(info.f_frsize/50);
        dmsg("lib: Free space for %s, %d blocks of %d bytes = %dk\n",disk,info.f_bavail,info.f_bsize,r);
        return r;
}
#endif

#ifdef USEDF
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 4000000; 

   
   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 4000000;   
   }
   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: df, 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;
}
#endif


/*RHP mac version of lib_mail_file and lib_freespace and s_wild*/
#else
/* Accepts either a path or path:filename and returns list of files in that
directory that match wild */
void s_wild(Sary *ls, char *path, char *wild){
        Str255          filename;
        char            s[255];
        OSErr           iErr;
        FSSpec          spec;
        long            dirID;
        long            vRefNum;
        int                     len;
        CInfoPBRec      cipbr;
/* local pb */
        HFileInfo       *fpb = (HFileInfo *)&cipbr;             /* pointersto 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,":");
                CtoPstr(s);
                vRefNum=dirID=0;
                iErr = FSMakeFSSpec(vRefNum,dirID,(unsigned char *)s,&spec);
        fpb->ioVRefNum = 0;
        fpb->ioDirID = 0;
        fpb->ioNamePtr = (unsigned char *)s;
        fpb->ioFDirIndex = 0;
        iErr = PBGetCatInfo( &cipbr, FALSE );
        dirID = fpb->ioDirID;
        if (fpb->ioFlAttrib & 16){
             /*imsg( "***Thats a directory id=%d  \n",dirID );*/
        }else{
                dirID = fpb->ioFlParID;
        }
        if (iErr==noErr){
                        fpb->ioVRefNum = spec.vRefNum;
                fpb->ioNamePtr = filename;      /* buffer to receive name */
                for( idx=1; TRUE; idx++) {      /* indexing loop */
                        fpb->ioDirID = dirID;           /* must set on eachloop */
                        fpb->ioFDirIndex = idx;

                        rc = PBGetCatInfo( &cipbr, FALSE );
                        if (rc) break;  /* exit when no more entries */

                        PtoCstr( filename );            /* make ASCIIZ forprintf() */
                        if (fpb->ioFlAttrib & 16) {
                                /*printf( ("Directory = %s:%s",dirFullName,filename );*/
                        }
                        else if(fpb->ioFlFndrInfo.fdFlags==fInvisible){
                        }
                        else{
                        if (match_wild(wild,(char *)filename))
                        s_add(ls,(char *)filename);
                        }
                }
        }else{
                /*RHP invalid path what should we do?? */
                emsg("s_wild: Invalid path specified {%s}",path);
                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);   
        volPB.ioVRefNum = 0;    
        volPB.ioVolIndex = -1;  
        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("report2.tmp")
int lib_mail_msg(char *to, char *subj, char *fname)
{
        String *xnew,*rest;
        char bf[BFSZ];
        int r;
        char me[BFSZ];

        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;}

        lprintf(me,BFSZ-1,"%s@%s",DNEWS_NAME,config_get(C_MYNAME));    strlwr(me);
        if (strlen(config_get(C_MAIL_FROM))>0) {
          strcpy(me,config_get(C_MAIL_FROM)); 
        }
        
        lprintf(bf,BFSZ-1,"From: %s\015\012",me); str_copysn(xnew,bf);
        lprintf(bf,BFSZ-1,"Subject: %s\015\012",subj); str_addsn(xnew,bf);
        lprintf(bf,BFSZ-1,"To: %s\015\012",to); str_addsn(xnew,bf);
        lprintf(bf,BFSZ-1,"Message-ID: %s\015\012",lib_messageid()); str_addsn(xnew,bf);
        lprintf(bf,BFSZ-1,"Date: %s\015\012",lib_email_date()); 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 xaccess, int aa)
{
        int r;
        r = xopen(fname,xaccess,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);
}
char *lib_now(void)
{
    char tmpstr[BFSZ];
    time_t t;
        static char bf[100];
        t = time(NULL);
        strcpy(bf,safe_ctime(&t,tmpstr));
        bf[24] = 0;
        return bf;
}
int xfclose(FILE *f)
{       
        int r;
        dmsg("lib: file: xfclose %d \n",fileno(f));
        nxfopen--;
        r = fclosep(f);
        if (r!=0) {
                filemsg("lib: xfclose failed\n");
        }
        return r;
}
int xopen(char *fname, int xaccess, int mde)
{
        int r;
/*RHP different open for mac - we just ignore mde setting*/
#ifdef Mac
        r = open(fname,xaccess,mde);
        if (r<0) errno = ENOENT;
#else
#ifdef WIN32
	xaccess |= _O_NOINHERIT;
#endif
        r = open(fname,xaccess,mde);
#endif
	
        if (r>=0) {
		nxopen++;
		close_on_exec(r);
	}
        dmsg("lib: file: xopen %d {%s} acces=%d Totals (%d:%d)\n",r,fname,xaccess,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 = myfopen(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;
        lprintf(bf,400-1,"%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 WIN32
#else

#ifndef NODIRENT
#ifdef NeXT
#include <sys/dirent.h>
#include <sys/dir.h>
#else
#ifdef NETWARE
#include <dirent.h>
#else
#ifdef OS2
#include <direct.h>
#else
#include <dirent.h>
#endif
#endif
#endif
void s_wild(Sary *ls, char *xpath, char *wild)
{
        DIR *dirp; 
        struct dirent *direntp;
        char bf[BFSZ];
        char path[BFSZ];
        strcpy(path,xpath); 

        wild_total = 0;
#ifdef NETWARE
        if (path[strlen(path)-1] != '\\') strcat(path,"\\");
        strcat(path,wild);
        strupr(path);
#endif
        dirp = opendir(path); 
        s_clear(ls);
        if (dirp==NULL) {dmsg("lib: Could not read any files %s \n",path); return;}

        while ((direntp=readdir(dirp))!=NULL) {
                strcpy(bf,direntp->d_name);
#ifdef NETWARE
                strlwr(bf);
#endif
                if (match_wild(wild,bf)) {
                        if (strcmp(direntp->d_name,".")==0) continue;
                        if (strcmp(direntp->d_name,"..")==0) continue;
                        s_add(ls,bf);
                }
        }
        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;
        lprintf(bf,BFSZ-1,"%s/%s",path,wild);
        handle = _findfirst(bf,&info);
        status = handle;
        while (status!= -1) {
                ncpy(tmp,info.name,BFSZ-1);
                wild_total += info.size / 100;
                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 5000000; 

        strcpy(bf,s);
        s = strchr(bf,':');
        if (s!=NULL) {s+=2; *s = 0; s = bf;} else {
		/* Try and find end of filer name */
		if (strncmp(bf,"\\\\",2)==0) {
			s = strchr(bf+2,'\\');
			if (s!=NULL) s = strchr(s+1,'\\');
			if (s!=NULL) *s = 0;
			s = bf;
			dmsg("lib: this fails, Using network path (%s)\n",s);
		} else 	s = "c:\\";
	}
        if (!GetDiskFreeSpace(s,&sc,&bs,&fc,&c)) {
                imsg("GetDiskFreeSpace call failed, {%s} errcode=%d \n",s,GetLastError());
                return 5000000;
        }
        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[4000];
        char bf[BFSZ];
        int i,r;
        for (i=0; i<1000; i++) {
                lprintf(bf,BFSZ-1,"test%d.tmp",i);
#ifdef Macx
                f[i] = open(file_work(bf),O_WRONLY | O_CREAT | O_BINARY);
#else
                f[i] = open(file_work(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]);
                        lprintf(bf,BFSZ-1,"test%d.tmp",i);
                        remove(file_work(bf));
                }
        }
        return r;
}

static int key_flags;
static int limit_disk;
void lib_set_flags(int f)
{
        key_flags = f;
	dmsg("lib: Key flags (%d)\n",f);
	if (key_flags==10) sponser_enable_free();
        if (key_flags==8) {
                limit_disk = TRUE;
        } else {
                limit_disk = FALSE;
        }
}
int is_limited(void)
{
        return limit_disk;
}

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,SD_LIB);
        i = ntime-1;
gotit:
        time_cpu[i]  -= my_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] += my_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;}
#endif

#ifdef NETWARE_old
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 (%s) (%s)\n",errno,LOCK_FILE,strerror(errno));
                emsg("The SPOOL directory MUST be created for dnews to work\n");
        } 
        /* Intentionally leave file handle open*/ 
        return FALSE;
}
#endif

char *file_kfile(void)
{
        static char bf[BFSZ];
        if (is_reader()) {
                lprintf(bf,BFSZ-1,"kfile%d.dat",atoi(config_get(C_READONLY_ID)));
        } else {
                return file_work("kfile.dat");
        }
        return file_work(bf);
}

#define DNEWS_KEYFILE file_kfile()
static char cur_key[BFSZ],cur_other[BFSZ];
static char key_msg[BFSZ];
char *key_reason(void)
{
        return key_msg;
}
#ifdef KEYLIB
int nt_setkey(char *s)
{
	int r;
	int ulimit=0;
	char key[BFSZ];
	char reg[BFSZ];
	char email[BFSZ];
	
	ncpy(reg,s,BFSZ-1);
	s = strchr(reg,' ');
	strcpy(email,"");
	if (s!=NULL) {
		*s = 0;
		ncpy(email,s+1,BFSZ-1);
	}
	imsg("Trying to load key (%s)\n",s);
	if (!keylib_activate_get(SECRET_FILE,PROD_NAME,reg,email,key,key_msg)) {
		imsg("Failed to get key (%s)\n",key_msg);
		return FALSE;
	}
	imsg("Got key ok %s %s\n",key,key_msg);
	r = keylib_check_file(SECRET_FILE,PROD_NAME,&ulimit,key_msg);
/*	if (!r) printf("lib.c, keylib_check_file %s\n",key_msg);*/
	if (keylib_isflag(KF_2GIG)) {
		imsg("key: Setting 2GIG spool limit according to key \n");
		lib_set_flags(8);
	}
	if (keylib_isflag(KF_FREE)) {
		sponser_enable_free();
	}
	imsg("Key check shows %s\n",key_msg);
	return r;	
}
#else
int nt_setkey(char *s)
{
        FILE *f;
        char ex[200];
        time_t now;
        struct tm *t; 
	struct tm atm;
        int users,flags=0;
        
        now = time(NULL);
        t = safe_localtime(&now,&atm);
        /* 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;
        }       
        lib_set_flags(flags);   
/*        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); 
                lprintf(key_msg,BFSZ-1,"Please remove (%s) and check file prot and ownership",DNEWS_KEYFILE);
                return FALSE;
        }
        fprintf(f,"%s\n",s);                            
        fclosep(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()); 
                lprintf(key_msg,BFSZ-1,"Please remove (%s) and check file prot and ownership",nt_other());
                return FALSE;
        } else {
                fprintf(f,"%s\n",s);                            
                fclosep(f);
        } 

        return TRUE;
}
#endif
int key_limitgroups;
int glob_ok;

#ifdef KEYLIB
int nt_getkey(char *ex, int nchan)
{
	int r;
	int ulimit = 0;
	r = keylib_check_file(SECRET_FILE,PROD_NAME,&ulimit,ex);
	if (!r) {
		if (nchan<=1) return TRUE;
		return FALSE;
	}
	if (ulimit>0) if (chan_nusers()>=ulimit) {
		lprintf(ex,200,"User limit exceeded %d > %d",chan_nusers()+1,ulimit);
		return FALSE;
	}
	if (keylib_isflag(KF_2GIG)) {
		imsg("key: Setting 2GIG spool limit according to key \n");
		lib_set_flags(8);
	}
	if (keylib_isflag(KF_FREE)) {
		sponser_enable_free();
	}
	dmsg("key: Loaded ok flags (%d) %s %s\n",ulimit,keylib_isflag(KF_FREE) ? "Free" : "NonFree",keylib_isflag(KF_2GIG) ? "2GIG" : "NoSpoolLimit" );
	return TRUE;
}
#else
int nt_getkey(char *ex, int nchan)
{
        FILE *f;
        char bf[BFSZ];
        time_t now;
	struct tm atm;
        struct tm *t; 
        int users,flags;
        int nloop;
        nloop = 0;
#ifdef NOKREG
                strcpy(cur_key,"");
                return TRUE;
#endif


        now = time(NULL);
        t = safe_localtime(&now,&atm);

        if (strlen(cur_key)==0) {
                f = fopen(DNEWS_KEYFILE,"r"); 
                if (f!=NULL) {
                        fgets(cur_key,BFSZ-1,f);
                        fclosep(f);
                }
                strcpy(cur_other,cur_key);
                f = fopen(nt_other(),"r"); 
                if (f!=NULL) {
                        fgets(cur_other,BFSZ-1,f);
                        fclosep(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);                            
                                fclosep(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);
                        } 
                }
                lib_set_flags(flags);   
        }       
    
        if (strcmp(cur_key,cur_other)!=0) {
                lprintf(ex,200-1,"Keys dont 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) for (%s)\n",host_details());
                        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;
        lib_set_flags(flags);   

        if (users!=0) if ((chan_nusers()>users) && (chan_nusers()>2)) {
                strcpy(ex,"Sorry, your license does not permit this many connections");
                return FALSE;
        }
        if (users==11) {
                if (!key_limitgroups) {
                        wmsg("BBS 1000/10 version of dnews, limited to 1000 news groups\n");
                        key_limitgroups = TRUE;
                }
        }
        return TRUE;
fail:
        key_expired = TRUE;
        return TRUE;

}
#endif
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];
        lprintf(bf,BFSZ-1,"%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];
        lprintf(bf,BFSZ-1,"sys:system\\dxyntky.exe");
        return bf;
}
#endif
/* RHP added 7/8/97 */
#ifdef Mac

#include <MacTCP.h>
char *nt_pcname(void)
{
	if (strlen(nntp_hostname())==0) return config_get(C_MYNAME);
	return nntp_hostname();
	
/*
	
	static char s[64];
        ip_addr ipaddr;
        ipaddr = xIPAddr();
                if (AddrToStr(ipaddr, s) != noErr)
                        sprintf (s, "%d.%d.%d.%d",ipaddr>>24,
                                                                ipaddr>>16 & 0xff,
                                                                ipaddr>>8 & 0xff,
                                                                ipaddr & 0xff);
        if (strlen(s)==0) return "noname";
        return s;
*/
  }


char *nt_other(void){
/* modified this whole section so it doesnt refer to preferences file by name  for Norwegian guy
*/
        static  char bf[255];
        Str63   other;
        OSErr   iErr;
                FInfo   fndrInfo;
        short   fVRefNum=0;
        long    newDirID=0;
        FSSpec  fspec;
        
                /* set path to real lock file to return */
                iErr = FindFolder(kOnSystemDisk,kPreferencesFolderType,kDontCreateFolder,&fVRefNum,&newDirID);
                if (iErr!=noErr){ /* if cant get prefs folder just return old place */
                        emsg("nt_other: Error on findfolder err=%d",iErr);
                        return file_log("dnews.lock");
                }
                /* get full path        */      
                PathNameFromDirID(newDirID, fVRefNum, other);
                /* tack on filename */
                pstrcat(other,"\pdnews.lock");
                pstrcpy((unsigned char *)bf,other); PtoCstr((unsigned char *)bf);
                /*emsg("****Other = %s\n",bf);*/
                /* If real lock file exists hide it */
                iErr = GetFInfo(other,kOnSystemDisk,&fndrInfo);
                if (iErr==noErr){
                        /*emsg("****Other exists so hiding it\n");*/
                        fndrInfo.fdType = '????';
                        fndrInfo.fdCreator = '????';
                        fndrInfo.fdFlags |= fInvisible;
                        SetFInfo(other,kOnSystemDisk,&fndrInfo);
                }else{
                        /* doesnt exist so see if old one does if so rename it  */       
                        /*emsg("****Other dosnt exist so look for old one\n"); */
                strcpy((char *)other,file_log("dnews.lock"));
                CtoPstr((char *)other);
                        iErr = GetFInfo((const unsigned char *)other,0,&fndrInfo);
                        if (iErr==noErr){
                                /*emsg("****Found old one so will try moving it\n");*/
                                iErr = CatMove(0,0,other,newDirID,"\p");
                                if (iErr != noErr){/*try copy instead of rename*/
                        FILE *f;
                        char s[BFSZ];
                        f = fopen(DNEWS_KEYFILE,"r"); 
                        if (f!=NULL) {
                        fgets(s,BFSZ-1,f);
                        fclosep(f);
                                        f = fopen(bf,"w");
                                        if (f!=NULL){
                                                        /*emsg("****  copied instead of rename\n");*/ 
                                                fprintf(f,"%s\n",s);                            
                                                fclosep(f);
                                        }
                                }
               }
                        }
                
        }
        return bf;
}
#endif


#ifndef Mac /* matching endif further down */
#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];
        static char tmp[BFSZ];
        if (is_reader()) {
                lprintf(bf,BFSZ-1,"dnews%d.lock",atoi(config_get(C_READONLY_ID)));
        } else {
                lprintf(bf,BFSZ-1,"dnews.lock");
        }
        strcpy(tmp,file_work(bf));
        return tmp;
}


#endif
#endif
#endif /*RHP*/

#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[90];
static int m_max[90];
int check_total2(void);
int fts_mem(void);
String *lib_showmem(void)
{
        static String *stat;
        char *s;
        char bf[BFSZ];
        int i;
	int val;
	int str_total=0,nostr_total=0;
        if (stat==NULL) stat = str_new();
        str_copysn(stat,"");


        for (i=0; i<1000; i++) {
                s = p_show_blockn(i);
                if (strlen(s)==0) break;
                str_addsn(stat,s);
        }
        for (i=0; i<100; i++) {
		s = mystrdup_get(i,&val);
		if (s==NULL) continue;
		lprintf(bf,BFSZ-1,"  Strdup %dk %s\n",val/1000,s);
                str_addsn(stat,bf);
	}
        for (i=0; m_names[i]!=NULL; i++) {
                lprintf(bf,BFSZ-1,"Memory use %8dk for {%s} Max %dk\r\n",m_total[i]/1000,m_names[i],m_max[i]/1000);
				if (strstr(m_names[i]," Str")!=NULL) str_total += m_total[i];
				else nostr_total += m_total[i];				
                str_addsn(stat,bf);
        }
        lprintf(bf,BFSZ-1,"Memory use %8dk for {dbi.idx}\r\n",fx_total()/1000);    
	str_addsn(stat,bf);
/*        lprintf(bf,BFSZ-1,"FTSLIB use %8dk \r\n",fts_mem()/1000);    
	str_addsn(stat,bf);
*/
	lprintf(bf,BFSZ-1,"Total misc %dk, total malloc %dk, wasted %dk total all %dk  %dk\r\n"
		,str_total/1000,nostr_total/1000,mem_wasted()/1000,(nostr_total+mem_wasted())/1000
		,check_total2()/1000);
        str_addsn(stat,bf);

        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;
}

char *ncat(char *dst, char *src, int len)
{
    if (dst && src) {
        char *ptr = dst + strlen(dst);
        len -= ptr - dst;
        len--;
        while (len > 0 && *src) {
              *ptr++ = *src++;
              len--;
        }
        if (*src) imsg("ncat: warning truncating ncat output\n");
        *ptr = '\0';
    } else {
        emsg("ncat: warning tried to use ncat with NULL string\n");
    }
    return dst;
}


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

        remove(file_work("dir.tmp"));
        lprintf(bf,BFSZ-1,"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);
                }
        }
        fclosep(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;
        lprintf(bf,BFSZ-1,"%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
        /*RHP9 - Use our event check routine*/
        CheckEvents();
        /*EventRecord theEvent;
    static long time_for_next_WNE = 0;
    if (LMGetTicks()>time_for_next_WNE){
                WaitNextEvent(0, &theEvent, 6, nil);
                time_for_next_WNE = LMGetTicks() + 3;
        }*/
#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 *lib_secret_file(void)
{
	static char bf[BFSZ];
	int id = atoi(config_get(C_READONLY_ID));
	if (id==0) return file_work("nkfile.dat");
	lprintf(bf,BFSZ-1,"nkfile_%d.dat",id);
	return file_work(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
static int big_cursz;
int big_getcursz(void);
int big_getcursz(void)
{
        int r;
        int b;
        r = atoi(config_get(C_BIG_SIZE));
        if (r==0) r = MAX_BIG;
        b = atoi(config_get(C_BODY_CHUNK));
        if (b>r) r = b;
        big_cursz = r;
        return big_cursz;       
}
int big_maxsz(void)
{
        if (big_cursz==0) big_getcursz();
        return big_cursz;
}
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];
        big_getcursz();
#ifdef VMS
        lprintf(bf,BFSZ-1,"big_%d_%d.tmp",h,slave_n());
#else
        lprintf(bf,BFSZ-1,"big/big_%d_%d.tmp",h,slave_n());
#endif
        return file_work(bf);
}
/*
Basically let the first 'n' big_add()'s called grow to 1mb
before we switch to files.

  So to do this we:

  if !big_cangrow[], ngrow<'n' then set cangrow
  if (cangrow) then use 1mb instaeld of maxsz
  if (cangrow) expand to 200K immediately
  on big_free() set cangrow false and subtrace one from ngrow;
*/
static int ngrow;
static int big_cangrow[MAX_CHAN];
static int max_ngrow=1;
int big_setgrow(int x)
{
	if (x!=0) max_ngrow = x;
	else {
		max_ngrow = 2;
		if (atoi(config_get(C_DISKSPACE))>3000) {
			max_ngrow = 3;
		}
		if (atoi(config_get(C_DISKSPACE))>9000) {
			max_ngrow = 9;
		}
	}
	return TRUE;
}
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_STR) {
		if (!big_cangrow[h]) if (ngrow<max_ngrow) if (chan_isihave(h)) {
			dmsg("lib: Allow big [%d] to grow, %d<%d\n",h,ngrow,max_ngrow);
			big_cangrow[h] = TRUE;
			ngrow++;
			if (str_len(big_str[h])==0) {
				str_expand(big_str[h],400000);
			}
		}
                big_xlen[h] += sz;
                str_adds(big_str[h],s,sz);
                if (str_len(big_str[h])>big_maxsz())  {
			if (big_cangrow[h]) if (str_len(big_str[h])<1000000) {
				return TRUE;
			}
                        if (big_file[h]!=NULL) big_close(h);
                        big_file[h] = myfopen(big_name(h),"wb");
                        if (big_file[h]==NULL) {
				lib_createdir(big_name(h));
	                        big_file[h] = myfopen(big_name(h),"wb");
				if (big_file[h]!=NULL) goto isok;
                                filemsg("Cannot write temporary file %s\n",big_name(h));
                                big_fail(h); /* Delete anything we have stored */
                                return FALSE;
                        }
isok:                   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_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;
        }
	stat_start(X_BIG_ADD);
        if (big_mode[h]==B_FILE) {
                big_xlen[h] += sz;
                if (lasth!=h) big_close(lasth);
                if (big_file[h]==NULL) {
                        big_file[h] = myfopen(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 */
				stat_end(X_BIG_ADD);
                                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);
			stat_end(X_BIG_ADD);
                        return FALSE;
                }
		stat_end(X_BIG_ADD);
                return TRUE;
        }
	stat_end(X_BIG_ADD);
        return TRUE;
}
void big_close(int h)
{
        if (h<0) return;
        if (big_file[h]!=NULL) fclosep(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;
	if (big_cangrow[h]) {
		big_cangrow[h] = FALSE;
		ngrow--;
	}
        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];
}       
void big_save(int h)
{
        String *xitem;
        char bf[BFSZ],fname[BFSZ];

        lprintf(bf,BFSZ-1,"big%d.err",h);
        strcpy(fname,file_work(bf));
        xitem = big_get(h);
        if (xitem!=NULL) {
                emsg("Recording faulty item in file %s\n",fname);
                str_write(xitem,bf);
        }
}
String *big_get(int h)
{
        FILE *f;
        char *s;
        size_t chunk,got,wanted;
	stat_start(X_BIG_GET);

        
	big_close(h);
        if (big_mode[h]==B_NULL) {
                emsg("big_get[%d]: state = B_NULL\n",h);
		stat_end(X_BIG_GET);
                return NULL;
        }
        if (big_mode[h]==B_FAILED) {
                emsg("Returning null because of error during store [%d]\n",h);
		stat_end(X_BIG_GET);
                return NULL;
        }
        if (big_mode[h]==B_STR) {
		stat_end(X_BIG_GET);
                return big_str[h];                              
        }
        if (big_mode[h]==B_FILE) {
                f = myfopen(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 */
			stat_end(X_BIG_GET);
	                return NULL;
                }               
                if (big_str[h]==NULL) big_str[h] = str_new();
                wanted = big_xlen[h];
                if (wanted>(size_t) MAX_STRLEN) {
                        fclosep(f);
                        imsg("big_get: item too big %d bytes\n",wanted);
                        big_fail(h);
			stat_end(X_BIG_GET);
                        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;
                }
                fclosep(f);
                if (got<wanted) {
                        filemsg("Failed to read entire item from temp file %s\n",big_name(h));
                        big_fail(h);
			stat_end(X_BIG_GET);
                        return NULL;
                }
                str_setlen(big_str[h],wanted);                   
		stat_end(X_BIG_GET);
		/*db_test_nulls(str_s(big_str[h]),str_len(big_str[h]),"somegroup","1","big_get");*/
                return big_str[h];
        }
	stat_end(X_BIG_GET);
        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);                                                         
		mem_log(M_BIG,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;
        if (len>(big_maxsz()+20000-1)) dnews_ex("String Length fault in get chunk, please report to netwin");
        strncpy(bf,str_s(aa)+from,len);
        bf[len] = 0;
        return bf;
}
char *strstrnc(char *s1, char *s2)
{
	int n = strlen(s2);
	for (;*s1!=0;s1++) {
		if (strncmpnc(s1,s2,n)==0) return s1;
	}
	return NULL;
}

void *mykeep(int sz)
{                      
        static int left;
        static char *next,*cur;
        
		
#ifdef QUAD_WORDS
	sz +=7;
        sz = sz & 0x5ffffff8; 
#else
	sz +=3;
        sz = sz & 0x5ffffffc; 
#endif

        if (left<sz) {
                if (sz>60000) {
                        emsg("Cannot mykeep %d bytes\n",sz);
                        dnews_ex("mykeep failed");
                }
                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=='\\') *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 *xtrunc(char *s)
{
        static char bf[399];
        ncpy(bf,s,80);
        return bf;
}

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_TIMExx
#endif
static int xtimex;
int lib_gmtime_real(void);
int lib_gmtime_testingxxx(void)
{
	static int x;
	static int n;
	n++;
	if (n<20) return x;
	n = 0;
	x = lib_gmtime();
	return x;
}
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<120) {
                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;
	char *xto = to;
	if (xto==NULL) xto = "NULL";
        xitem = str_new();
        if (!str_read(xitem,fname)) {
		imsg("mail: cannot read file (%s)\n",fname);
		return FALSE;
	}
	imsg("mail: post local to (%s) subj (%.200s) (%s)\n",xto,subj,fname);
        post_local(xitem,to,TRUE);
        str_free(xitem);
        return TRUE;
}
#else
int f_lib_mail_file2(char *to, char *subj, char *fname)
{
        return lib_mail_file(NULL,subj,fname);
}
int f_lib_mail_file(char *to, char *subj, char *fname)
{
        String *xitem;
	char *xto = to;
	if (xto==NULL) xto = "NULL";
        xitem = str_new();
        if (!str_read(xitem,fname)) {
		imsg("mail: cannot read file (%s)\n",fname);
		return FALSE;
	}
	imsg("mail: post local to (%s) subj (%.200s) (%s)\n",xto,subj,fname);
        post_local(xitem,to,TRUE);
        str_free(xitem);
        return TRUE;
}



int lib_mail_file2(char *to, char *subj, char *fname)
{
        if (config_true(C_USE_SMTP)) { 
                return f_lib_mail_file2(to,subj,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;
   
   if (config_true(C_USE_SMTP)) { 
          return f_lib_mail_file(to,subj,fname);
   }
   /* Path should include %s for 'to' */
   lprintf(cmd,400-1,config_get(C_SENDMAIL),to);
   imsgf("popen %.100s %.100s %.100s \n",to,subj,cmd);
   if ((f = popen(cmd,"w"))==NULL)  {goto err; }
   fprintf(f,"To: %s\n",to);
   if (FLUSH(f)) {pclose(f); goto err;    }

   /* 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); goto err;}

   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); fclosep(fin); goto err;  }
   }
   fclosep(fin);
   if (pclose(f)!=0) goto err;
   imsgf("popen finished successfully\n");
   return TRUE;
err:
   imsgf("popen write failed\n");
   return FALSE;
}
#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," ");
	strcpy(xcmd,"");
        for (;s!=NULL;) {
                args[n++] = mystrdup(s,SD_LIB);
                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 = my_clock();
        strcpy(bf,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazd");
        for (i=0; i<100; i++) strcat(bf,"bbbbbbbbb"); 
        for (i=0; i<10000; i++) {
                s = strstr(bf,"zd");
        }
        t1 = my_clock() - t1;
        t2 = my_clock();
        for (i=0; i<10000; i++) {
                s = mystrstr(bf,"zd");
        }
        t2 = my_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
}
void lib_msleep(int x)
{
#ifdef OS2
	delay(x);
#else
#ifdef WIN32
        Sleep(x);       
#else
	lib_usleep(x*1000);
#endif
#endif
}

#ifdef isunix
int lib_usleep(int x)
{
#ifndef NONANO
	struct timespec rqtp;
	rqtp.tv_sec = x/1000000;
	rqtp.tv_nsec = (x%1000000)*1000;
	nanosleep(&rqtp,NULL);
#else
	usleep(x);
#endif
}
#else
#ifndef WIN32
int lib_usleep(int x)
{
	sleep(x/1000000);
}
#endif
#endif
int lib_crc2(char *xin)
{
        int total=0;
        for (;(*xin!=0);xin++) {
                total += *xin;
                total = total & 0x7fff;
        }
        return total;
}
static int indian = 1;
int lib_crc(char *xin)
{
  unsigned short dx;
  unsigned char *in = (unsigned char *) xin;
  unsigned short ax;
  unsigned char *al;
  unsigned char *ah;
  unsigned char *dl;
  unsigned char *dh;
        
        ax = 0xffff;
        al = (unsigned char *) &ax;
        ah = al+indian;
        dl = (unsigned char *) &dx;
        dh = dl+indian;
        for (;(*in!=0);in++) {
          dx = ax;
          *dl = *al ^ *in;
          *dl = *dl ^ (*dl / 16);
          *ah = *dl * 16;
          *dh = *dh ^ *ah;
          *al = *dl;
          *ah = 0;
          ax *= 32;
          ax = ax ^ dx;
        }
        return ax;

}

int lib_ncrc32(char *xin,int len)
{
    /* calculate crc value for string.  Stop at len characters */
  unsigned int dx;
  int r;
  unsigned short *in;
  unsigned int ax;
  unsigned short *al;
  unsigned short *ah;
  unsigned short *dl;
  unsigned short *dh;
  /*char buf[10000];
  strncpy(buf,xin,len);
  imsg("****** lib_ncrc32 : passed body '%s'\n",xin);
  imsg("****** lib_ncrc32 : passed truncated to '%s'\n",buf);*/
  	
	len = len >> 1;      
	if (*xin==0) return 0;
        if (((long) xin)&1 == 1) xin++;
        in = (unsigned short *) xin;

        ax = 0xffffffff;
        al = (unsigned short *) &ax;
        ah = al+indian;
        dl = (unsigned short *) &dx;
        dh = dl+indian;
        for (;(*in!=0);in++,xin+=2,--len) {
          dx = ax;
          *dl = *al ^ *in;
          *dl = *dl ^ (*dl / 256);
          *ah = *dl * 256;
          *dh = *dh ^ *ah;
          *al = *dl;
          *ah = 0;
          ax *= 1024;
          ax = ax ^ dx;
	  if (xin[1] == 0) break;
          if (xin[2] == 0) break;
          if (len<2) break;
        }
        r = (int) ax;
        if (r<0) r = -r;
	/*imsg("******************** crc checksum (%d)\n",r);*/
        return r;
}

int lib_crc32(char *xin)
{
  unsigned int dx;
  int r;
  unsigned short *in;
  unsigned int ax;
  unsigned short *al;
  unsigned short *ah;
  unsigned short *dl;
  unsigned short *dh;
        
        if (*xin==0) return 0;
        if (((long) xin)&1 == 1) xin++;
        in = (unsigned short *) xin;

        ax = 0xffffffff;
        al = (unsigned short *) &ax;
        ah = al+indian;
        dl = (unsigned short *) &dx;
        dh = dl+indian;
        for (;(*in!=0);in++,xin+=2) {
          dx = ax;
          *dl = *al ^ *in;
          *dl = *dl ^ (*dl / 256);
          *ah = *dl * 256;
          *dh = *dh ^ *ah;
          *al = *dl;
          *ah = 0;
          ax *= 1024;
          ax = ax ^ dx;
          if (xin[1] == 0) break;
          if (xin[2] == 0) break;
        }
        r = (int) ax;
        if (r<0) r = -r;
        return r;

}
char *struntab(char *s)
{       
        char *ss=s;
        for (;*s!=0;s++) {
                if (*s=='\t') *s = ' ';
        }
        return ss;
}
char *nocrlf(char *s)
{
        static char bf[BFSZ];
        ncpy(bf,s,200);
        for (s=bf;*s!=0;s++) {
                if (*s=='\r') *s = ' ';
                if (*s=='\n') *s = ' ';
        }
        return bf;
}
#ifdef Mac
void gstat_init(char *name, int (*emsg)(const char *fmt,...) )
{
}
int gstat_xadd(char *name, int value)
{
        return TRUE;
}

void gstat_send(int *at, void (*sendfn)(char *s))
{}
void gstat_xsend(void)
{}
void gstat_rewrite(void)
{}

#endif

#ifndef NEW_MACIO
#ifdef Mac
#undef remove
int mac_remove(char *s)
{
        FILE *f;
        int r = remove(s);
        if (r!=0) {
                f = fopen(s,"r");
                if (f==NULL) errno = ENOENT;
                else errno = 99;
                if (f!=NULL) fclosep(f);
        }
        return r;
}
#undef fopen
FILE * mac_fopen(char *fname, char *mode)
{
        FILE *f = fopen(fname,mode);
        if (f==NULL) {
                errno = ENOENT;
        }
        return f;
}
#endif
#endif


char *cookie_date(void)
{
        static char bf[70];
        time_t now;
        struct tm *t;
	struct tm atm;

        time(&now);
	now += 60*60*24*30;
        t = safe_localtime(&now,&atm);
        if (t==NULL) t = safe_gmtime(&now,&atm);
        lprintf(bf,70-1,"%s, %d-%s-%d %02d:%02d:%02d GMT",
                weekday[t->tm_wday],
                t->tm_mday,months[t->tm_mon],t->tm_year+1900,
                t->tm_hour,t->tm_min,t->tm_sec);
        return bf;
}
char *cookie_date_plus(int tplus)
{
        static char bf[70];
        time_t now;
        struct tm *t;
	struct tm atm;

        time(&now);
	now += tplus;
        t = safe_localtime(&now,&atm);
        if (t==NULL) t = safe_gmtime(&now,&atm);
        lprintf(bf,70-1,"%s, %d-%s-%d %02d:%02d:%02d GMT",
                weekday[t->tm_wday],
                t->tm_mday,months[t->tm_mon],t->tm_year+1900,
                t->tm_hour,t->tm_min,t->tm_sec);
        return bf;
}
#ifdef WIN32
FILE* myfopen(const char *filename, const char *mode) 
{
	int h;
	int commodeset = 0;
	int scanset    = 0;
	int whileflag, pmode;
	int flags = 0;
	const char *xmode=mode;
	switch (*mode) {
	case ('r'):
		flags = _O_RDONLY;
		break;
	case ('w'):
		flags = _O_WRONLY | _O_CREAT | _O_TRUNC;
		break;
	case ('a'):
		flags = _O_WRONLY | _O_CREAT | _O_APPEND;
		break;
	default:
		return(NULL);
		break;
	}
	
	/* There can be up to three more optional mode characters:
	(1) A single '+' character,
	(2) One of 't' and 'b' and
	(3) One of 'c' and 'n'.
	*/
	
	whileflag=1;
	
	while(*++mode && whileflag)
	switch(*mode) {
		
	case ('+'):
		if (flags & _O_RDWR)
			whileflag=0;
		else {
			flags |= _O_RDWR;
			flags &= ~(_O_RDONLY | _O_WRONLY);
		}
		break;
		
	case ('b'):
		if (flags & (_O_TEXT | _O_BINARY))
			whileflag=0;
		else
			flags |= _O_BINARY;
		break;
		
	case ('t'):
		if (flags & (_O_TEXT | _O_BINARY))
			whileflag=0;
		else
			flags |= _O_TEXT;
		break;
		
	case ('c'):
		if (commodeset)
			whileflag=0;
		else {
			commodeset = 1;
		}
		break;
		
	case ('n'):
		if (commodeset)
			whileflag=0;
		else {
			commodeset = 1;
		}
		break;
		
	case ('S'):
		if (scanset)
			whileflag=0;
		else {
		scanset = 1;
			flags |= _O_SEQUENTIAL;
		}
		break;
		
	case ('R'):
		if (scanset)
			whileflag=0;
		else {
			scanset = 1;
			flags |= _O_RANDOM;
		}
		break;
		
	case ('T'):
		if (flags & _O_SHORT_LIVED)
			whileflag=0;
		else
			flags |= _O_SHORT_LIVED;
		break;
		
	case ('D'):
		if (flags & _O_TEMPORARY)
			whileflag=0;
		else
			flags |= _O_TEMPORARY;
		break;
		
	default:
		whileflag=0;
		break;
	}

	if ( (flags & _O_CREAT) && (flags & _O_RDONLY) ) pmode = _S_IREAD;
	else pmode = _S_IREAD | _S_IWRITE;

	flags |= _O_NOINHERIT;
	h = _open(filename, flags, pmode);
	if (h<0) return NULL;
	return _fdopen(h, xmode);
}


#else
FILE* myfopen(const char *filename, const char *mode) 
{
	FILE *f;
	f = fopen(filename,mode);
	if (f==NULL) return f;
        close_on_exec(fileno(f));
	return f;
}
#endif

char *lib_samepath(char  *s, char *fname)
{
	static char bf[BFSZ];
	char *last=NULL;
	ncpy(bf,s,200);
	for (s=bf;*s!=0;s++) {
		if (*s=='/') last = s;
		if (*s=='\\') last = s;
	}
	if (last==NULL) return fname;
	strcpy(last+1,fname);
	return bf;
}

/*
If no slash in then search for another bracket/brace

804200 {khamsin} Part 1 of 2 of Your Kuni 2 Fills - ks_kankad1035.jpg *** File 0789 of 1020 *** 111184 bytes*** (1/1)

1/1/2 {khamsin} Part 1 of 2 of Your Kuni 2 Fills - ks_kash9014.jpg *** File 0818 of 1020 *** 464824 bytes***  <t7eof921s90k48@corp.supernews.com>

 ...... X, per request - 24. Johny Hit And Run Paule.mp3 (2/9) [2809K]
*/
int parts_subject(char *subject, char *subj, char *fname, int *parti, int *partmax)
{
	/* Search for ( or [ from right hand side */
	char *s;
	int i;
	int noslash = TRUE;

	strcpy(fname,"file.dat");
	for (i=strlen(subject)-1;i>=0; i--) {
		s = subject + i;
		if (noslash) {
			if (*s=='/') noslash = FALSE;
		} else {
			if (*s=='(') goto found_brace;
			if (*s=='[') goto found_brace;
		}
	}
	/*imsg("No left bracket found\n");*/
	return FALSE;
	
	/* */ 
found_brace:
	if (i>BFSZ-10) {
		/*imsg("subject too long\n");*/
		return FALSE;
	}
	ncpy(subj,subject,i);

	*parti = atoi(s+1);
	s = strchr(s,'/');
	if (s==NULL) {
		/*imsg("No slash found\n");*/
		return FALSE;
	}
	*partmax = atoi(s+1);
	if (*parti<0) {
		/*imsg("parti less than zero\n");*/
		return FALSE;
	}
	if (*parti>*partmax) {
		/*imsg("parti < than max %d %d\n",*parti,*partmax);*/
		return FALSE;
	}
	if (*partmax>1000) { /* Added to prevent loops */
		return FALSE;
	}
	if (*partmax<1) { /* Added to prevent loops */
		return FALSE;
	}
	/* File name is last word of subj */
	for (i=strlen(subj)-1;i>0;i--) if (subj[i]=='.') break;
	for (;i>=0;i--) if (subj[i]==' ') { i++; break;}
	ncpy(fname,subj+i,100);
	s = strchr(fname,' '); if (s!=NULL) *s = 0;
	return TRUE;	
}

int parts_subject_yenc(char *subject,char *xsubj,int *parti,int *partmax)
{
	char *s;
	int noslash = TRUE;

	s=strrchr(subject,'(');
	if(!s) s=strrchr(subject,'[');
	if(!s) return FALSE;
	ncpy(xsubj,subject,s-subject);

	*parti = atoi(s+1);
	s=strstr(s,"/");
	if(!s) return FALSE;
	*partmax = atoi(s+1);

	return partmax && parti;
}

int myfclosep( FILE **stream )
{
	int r;
	if (*stream==NULL) {
		emsg("Attempted to close null file handle, please send drwtsn32.log file to support@netwinsite.com\n");
		abort();
	}
	r = fclose(*stream);
	*stream = NULL;
	return r;
}

static int nthread;
static int nthread_used;
int lib_thread_add(int x)
{
	nthread += x;
	if (x>0) nthread_used++;
	imsg("Current threads %d, used %d total\n",nthread,nthread_used);
	return TRUE;
}
int lib_nthread(void)
{
	return nthread;
}
/*
#ifdef time
#undef time
#endif
time_t avoid_time(time_t *x)
{
	static int n;
	static time_t t;

	if (t==0) t = time(NULL);
	n++;
	if (n<100) {
		if (x!=NULL) *x = t;
		return t;
	}
	n = 0;
	t = time(NULL);
	if (x!=NULL) *x = t;
	return t;
}
*/

char *strlwr_warn(char *p)
{
	for (;*p!=0;p++) {
		if (isupper(*p)) {
			wmsg("WARNING: mixed case password detected, please set AUTH_CASE TRUE in dnews.conf if authentication fails\n");
			return strlwr(p);
		}
	}
	return strlwr(p);	
}


/* Move this to lib.c */
int lib_file_copy(char *src, char *dst)
{
	FILE *fsrc=NULL,*fdst=NULL;
	int r=FALSE;
	int n;
	char bf[BFSZ];

	dmsg("lib: copy (%s) to (%s) \n",src,dst);
	fsrc = fopen(src,"rb");
	fdst = fopen(dst,"wb");
	if (fsrc==NULL) {imsgf("Copy failed %s %s\n",src,dst); goto failed;}
	if (fdst==NULL) {imsgf("Copy failed %s %s\n",src,dst); goto failed;}
	for (;!feof(fsrc);) {
		n = fread(bf,1,BFSZ-1,fsrc);
		if (n<=0) break;
		fwrite(bf,1,n,fdst);
	}	
	r = TRUE;
failed:	if (fsrc!=NULL) fclose(fsrc);
	if (fdst!=NULL) fclose(fdst);
	return r;
}

int set_workingset(void)
{
#ifdef WIN32
	SetProcessWorkingSetSize(GetCurrentProcess(),(unsigned long) ~0L,(unsigned long) ~0L);
#endif
	return TRUE;
}
unsigned int my_clock(void)
{
#ifdef WIN32
	unsigned int lo,hi,tot,r;
	FILETIME crtime,extime,ktime,utime;
	if (config_true(C_USE_CLOCK)) return my_clock();

	GetThreadTimes(GetCurrentThread(),&crtime,&extime,&ktime,&utime);
	lo = ktime.dwLowDateTime >> 16;
	hi = ktime.dwHighDateTime << 16;
	tot = lo + hi;
	lo = utime.dwLowDateTime >> 16;
	hi = utime.dwHighDateTime << 16;
	tot += lo + hi;
	/*
		100 nano second intervals.
		4000000000
		10000000 per second
		CLOCKS_PER_SEC per second
	*/
	
	r = (int) ((double) tot * .0065536 * CLOCKS_PER_SEC);
	r = r & 0x07fffffff;
	return (int) r;
#else
	return clock();
#endif
}
int lib_boost_thread(void)
{
#ifdef WIN32
/*	if (SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL)) {
		imsg("Boosted priority of thread %d\n",	GetCurrentThread());
	} else {
		imsg("Boosted priority of thread %d failed %d\n",GetCurrentThread(),GetLastError());
	}
	*/
	if (SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS)) {
		imsg("Boosted priority of process %d\n",	GetCurrentProcess());
	} else {
		imsg("Boosted priority of process %d failed %d\n",GetCurrentProcess(),GetLastError());
	}
	

#endif
	return TRUE;
}
int lib_boost_thisthread(void)
{
#ifdef WIN32
	if (SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL)) {
		//tmsg("Boosted priority of thread %d\n",	GetCurrentThread());
	} else {
		//tmsg("Boosted priority of thread %d failed %d\n",GetCurrentThread(),GetLastError());
	}	
#endif
	return TRUE;
}

#ifndef WIN32
#ifndef USE_CTIME
#define USE_R 1
#endif
#endif

#ifndef DONE_INCLUDES
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#endif

#undef ctime
#undef localtime
#undef asctime
#undef readdir
#undef gmtime

char *safe_ctime(const time_t *clock, char *bf)
{
#ifdef USE_R
#ifdef SOLARISx
	return ctime_r(clock,bf,27);
#else
	return ctime_r(clock,bf);
#endif
#else
	strncpy(bf,ctime(clock),27);
	return bf;
#endif
}
char *safe_asctime(const struct tm *t, char *bf)
{
#ifdef USE_R
#ifdef SOLARISx
	return asctime_r(t,bf,27);
#else
	return asctime_r(t,bf);
#endif
#else
	strncpy(bf,asctime(t),27);
	return bf;
#endif
}
struct tm *safe_localtime(const time_t *clock,struct tm *result)
{
#ifdef USE_R
	return localtime_r(clock,result);
#else
	struct tm *t;
	t = localtime(clock);
	if (t==NULL) return NULL;
	memcpy(result,t,sizeof(struct tm));
	return result;
#endif
}
struct tm *safe_gmtime(const time_t *clock,struct tm *result)
{
#ifdef USE_R
	return gmtime_r(clock,result);
#else
	struct tm *t;
	t = gmtime(clock);
	if (t==NULL) return NULL;
	memcpy(result,t,sizeof(struct tm));
	return result;
#endif
}
#ifndef WIN32
	int safe_readdir(DIR *dirp, char *dresult, struct dirent **result)
	{
#ifdef USE_R
		*result = NULL;
#	ifdef SOLARISx
		*result = readdir_r(dirp,(struct dirent *) dresult);
		return 0;
#	else
		return readdir_r(dirp,(struct dirent *) dresult,result);
#	endif
#else
		struct dirent *r;
		*result = NULL;
		r = readdir(dirp);
		if (r==NULL) {
			return 0;
		}
		memcpy(dresult,r,sizeof(struct dirent));
		*result = (struct dirent *) dresult;
		return 0;
#endif
	}
#endif

