/* Copyright (C) 1995 NetWin World, New Zealand, All rights reserved. */
#include <fdldef.h>
#include <unixio.h>
#include <file.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <descrip.h>
#include <dvidef.h>
#include <jpidef.h>
#include <ssdef.h>
#include <iodef.h>
#include <ttdef.h>
#include <opcdef.h>
#include <lnmdef.h>
#include <syidef.h>
#include <hlpdef.h>
#include <rmsdef.h>
#include <maildef.h>

#include "emsg.h"
#include "lib.h"
#define false 0
#define true (!false)



typedef struct 
	{unsigned short len; unsigned char type, class; char *ptr;} Str;
#define DEFSTR(NAME,BUFF,LEN) Str NAME = {LEN, DSC$K_DTYPE_T, DSC$K_CLASS_S, BUFF}
#define DEFSTR1(NAME,XX,YY) Str NAME
#define DEFSTR2(NAME,BUFF,LEN) NAME.len = LEN, NAME.type = DSC$K_DTYPE_T,NAME.class = DSC$K_CLASS_S, NAME.ptr = BUFF
#define DEFSTRV(NAME,BUFF,LEN) Str NAME = {LEN, DSC$K_DTYPE_T, DSC$K_CLASS_VS, BUFF}

char *lib_logical(char *logical_name);
void lib_nowrap(void);
void lib_spawn(char *s);
void vmessage(int r);

char *lib_message(int r);
int lib_keypad(void);
void lib_createdir(char *s)
{
	char bf[BFSZ];
	int r;
	DEFSTR1(v,bf,0);
	DEFSTR2(v,bf,0);

	ncpy(bf,s,BFSZ-1);
	s = strchr(bf,']');
	if (s != NULL) *(s+1) = 0;
	else {
		s = strchr(bf,':');
		if (s != NULL) *(s+1) = 0;
	}
	v.len = strlen(bf);
		
	r = LIB$CREATE_DIR(&v);
	if (r != 1) dmsg("createdir,{%s} %s\n",bf,lib_message(r));
	dmsg("createdir,{%s} %s\n",bf,lib_message(r));
}

void lib_symbol_set(char *name, char *value)
{
	int r;
	DEFSTR1(namstr,name,strlen(name));
	DEFSTR1(valuestr,value,strlen(value));

	DEFSTR2(namstr,name,strlen(name));
	DEFSTR2(valuestr,value,strlen(value));
	r = lib$set_symbol(&namstr,&valuestr,&2);
	if (r!=1) lib$signal(r);
}
char *get_symbol(char *sym);
void lib_symbol_get(char *name, char *result)
{
	strcpy(result,get_symbol(name));
}
char *get_symbol(char *sym)
{
	static char mystr[200],*s;
	int r;
	short teklen=80;
	int stype=1;

	DEFSTR1(symname,sym,strlen(sym));
	DEFSTR1(tekval,mystr,80);

	DEFSTR2(symname,sym,strlen(sym));
	DEFSTR2(tekval,mystr,80);
	mystr[0] = 0;
/*	symname.dsc$w_length = strlen(sym);
	tekval.dsc$w_length = 80;
*/
	r = lib$get_symbol(&symname,&tekval,&teklen,&stype);
	if (r!=1) {
		/* (r!=1409892) lib$signal(r);  */
		teklen = 0;
	}

	mystr[teklen] = 0;
	return mystr;
}


 /*

  The translog function attempts to find a translation for a logical
  name in a specific name_table.


  The syntax of the translog function is as follows:

        char * translog(char *table, char *logical_name)

  Additional information

  The translog function returns a char * to the translation if
  it is successfully completed otherwise it returns a char * 
  pointing to a null byte.

 */

/*
#include stdio
#include ssdef
#include descrip
#include lnmdef
#include syidef
*/
typedef struct {                                /* Item_list_3      */
  unsigned short int        Size;               /* Item Buffer Size */
  unsigned short int        Type;               /* Item Type (below)*/
  char                      *Buffer;            /* Buffer Pointer   */
  int                       *Resultant_Size;    /* Final Size Ptr   */
} item_list;

char *sys_logical(char *table,char *logical_name);
char *lib_logical(char *logical_name)
{
 	static char bf[255],*s;
	DEFSTR1(logical,logical_name,strlen(logical_name));
	DEFSTR1(result,bf,254);

	DEFSTR2(logical,logical_name,strlen(logical_name));
	DEFSTR2(result,bf,254);

	memset(bf,0,250);
	lib$sys_trnlog(&logical,0,&result);
	bf[result.len] = 0;
	s = strstr(bf,"    ");
	if (s!=NULL) *s = 0;
	return bf;
}
char *sys_logical(char *table,char *logical_name)
{

  item_list                item;
                                         /* descriptors to interface   */
                                         /* C nullterminated strings   */
                                         /* to VMS string-format       */
  struct dsc$descriptor log_nam_des,     /* descriptor for logical_name*/
                        table_des;       /* descriptor for table       */
  int                   ret,             /* return value of sys$trnlnm */
                        len = 0,         /* Resulting length of translation */
                        attr = 0;        /* Attributes for sys$trnlnm  */
  char                  translation[256],
                        null_str = '\0',
                        msg[256];

  item.Size = 255;              /* Maximum length of a logical name */
  item.Type = LNM$_STRING;      /* The item list describes a string */
  item.Buffer = translation;    /* Ptr to the result string         */
  item.Resultant_Size = &len;   /* Ptr to the resulting length      */

  log_nam_des.dsc$w_length = strlen(logical_name);
  log_nam_des.dsc$b_dtype = DSC$K_DTYPE_Z;
  log_nam_des.dsc$b_class = DSC$K_CLASS_S;
  log_nam_des.dsc$a_pointer = logical_name;

  table_des.dsc$w_length = strlen(table);
  table_des.dsc$b_dtype = DSC$K_DTYPE_Z;
  table_des.dsc$b_class = DSC$K_CLASS_S;
  table_des.dsc$a_pointer = table;


  /* system call that makes the translation */
  ret = sys$trnlnm(&attr,&table_des,&log_nam_des,0,&item);

  if(ret != SS$_NORMAL) {
    return(&null_str);
  } else {
    translation[len] = '\0';
    return(translation);
  }
}

char *lib_username(int *pid)
{
	int r;
	int rvalue,rlen=0;
	char *s;
	static char bf[40];
	DEFSTR1(rstr,bf,39);
	DEFSTR2(rstr,bf,39);
	
	r = lib$getjpi(&JPI$_USERNAME,pid,NULL,&rvalue,&rstr,&rlen);
	if (r != 1) lib$signal(r) ;
	bf[rlen] = 0;
	s = strstr(bf," ");
	if (s!=NULL) *s = 0;
	return bf;
}
/* s = time in 100/s of seconds */
void lib_xsleep(int s)
{
	int mask,r;
	int btime[2];
	char bf[10];
	static int efn;
	DEFSTR1(bfstr,bf,9);
	DEFSTR2(bfstr,bf,9);
	sprintf(bf,"0 ::00.%02d",s); 	

	r = sys$bintim(&bfstr, &btime);
	if (r != 1) lib$signal(r);

	if (efn==0) r = lib$get_ef(&efn);
	if (r != 1) lib$signal(r);
	r = sys$clref(efn);
	if ((r&1) != 1) lib$signal(r);
	r = sys$setimr(efn,&btime,NULL,NULL);
	if (r != 1) lib$signal(r);
 	mask = efn;
	if (mask>31) mask -= 32;
	mask = 1 << mask;
	s = sys$wflor(efn,mask);
	if (r != 1) lib$signal(r);
}
char *lib_message(int r)
{
	char bf[200];
	int bflen=0;
	DEFSTR1(bfstr,bf,199);
	DEFSTR2(bfstr,bf,199);

	SYS$GETMSG(r,&bflen,&bfstr,15,0);
	bf[bflen] = 0;
	return bf;
}	
extern int lib$put_output();
extern int lib$get_input();
static int do_keypad = false;
/*
	    s1% = sys$getmsg(s% by value,msglen%,msg$,15% by value,)

*/

static int tt_chan;
static short tt_iosb[4];
void tt_open(void)
{
	int st;
	static $DESCRIPTOR(tt_desc,"tt");
	st = SYS$ASSIGN(&tt_desc,&tt_chan,0,0);
	lib_nowrap();
}	
void lib_puts(char *s)
{
	int write_mask,st;

	if (tt_chan==0) tt_open();
	write_mask = IO$_WRITELBLK | IO$M_NOFILTR;
	st = SYS$QIOW(0,tt_chan,write_mask
		,tt_iosb,0,0
		,s,strlen(s),0,0,0,0);
	if ((st & 1) != 1) lib$signal(st);
	st = tt_iosb[0];
	if ((st & 1) != 1) lib$signal(st);
}
typedef struct {char class, type; short bsize; long code;} TTCHAR; 
TTCHAR tt_save_char;
void lib_nowrap(void)
{
	int write_mask,st;
	TTCHAR buff;


	if (tt_chan==0) tt_open();
	st = SYS$QIOW(0,tt_chan,IO$_SENSEMODE
		,tt_iosb,0,0
		,&buff,8,0,0,0,0);
	if ((st & 1) != 1) lib$signal(st);
	tt_save_char = buff;
	buff.code = buff.code &  ~TT$M_WRAP;
	
	st = SYS$QIOW(0,tt_chan,IO$_SETMODE
		,tt_iosb,0,0
		,&buff,8,0,0,0,0);
	if ((st & 1) != 1) lib$signal(st);
	
}
void lib_ttrestore(void)
{
	int st;

	if (tt_chan==0) return;
	st = SYS$QIOW(0,tt_chan,IO$_SETMODE
		,tt_iosb,0,0
		,&tt_save_char,8,0,0,0,0);
	if ((st & 1) != 1) lib$signal(st);
	
}
int lib_cputime(void)
{
	int r;
	int pid=0;
	int rvalue,rlen=0;
	char *s;
	static char bf[40];
	DEFSTR1(rstr,bf,39);
	DEFSTR2(rstr,bf,39);
	
	r = lib$getjpi(&JPI$_CPUTIM,&pid,NULL,&rvalue,&rstr,&rlen);
	if (r != 1) lib$signal(r) ;
	return rvalue;
}
char *lib_procname(void)
{
 	int r;
 	int rvalue,rlen=0;
 	char *s;
 	static char bf[40];
 	DEFSTR1(rstr,bf,39);
	DEFSTR2(rstr,bf,39);

 	r = lib$getjpi(&JPI$_PRCNAM,NULL,NULL,&rvalue,&rstr,&rlen);
 	if (r != 1) lib$signal(r) ;
 	bf[rlen] = 0;
 	return bf;
 }
struct {long forward; void (*fn)(void); int narg; 
		int *pstatus; int fill2[4];  } exit_block;


/* this routine doesn't work, used atexit instead */
void lib_atexit(void (*exit_fn)(void) )
{
	int r;
	static int status;
	exit_block.narg = 1;	
	exit_block.fn = exit_fn;
	exit_block.pstatus = &status;
	r = sys$dclexh(&exit_block);
	if (r != 1) lib$signal(r) ;
}


void fdl_create(char *fname, char *fdl)
{
	int st;
	int sts=0,stv=0;
	int flags=FDL$M_FDL_STRING;
	DEFSTR1(fdlstr,fdl,strlen(fdl));
	DEFSTR1(filestr,fname,strlen(fname));
	DEFSTR2(fdlstr,fdl,strlen(fdl));
	DEFSTR2(filestr,fname,strlen(fname));
	st = fdl$create(&fdlstr,&filestr,NULL,NULL,NULL,&flags,NULL,NULL,&sts,&stv);
	if ((st&1)!=1) {
		dmsg("sts, %s",lib_message(sts));
		dmsg("stv, %s",lib_message(stv));
		lib$signal(st);
	}
}
void lib_delete(char *s)
{
	int r;
	DEFSTR1(wildstr,s,strlen(s));
	DEFSTR2(wildstr,s,strlen(s));

	r = lib$delete_file(&wildstr);
	/* if ((r&1)!=1) if (r!=RMS$_FNF) lib$signal(r); */
}
	
void lib_opermsg(char *s)
{
	struct {char type; char target[3]; int id; char text[200];} msgbuf;
	DEFSTR1(msgstr,(char *) &msgbuf,8+strlen(s));
	DEFSTR2(msgstr,(char *) &msgbuf,8+strlen(s));

	strcpy(msgbuf.text,s);
	msgbuf.type = OPC$_RQ_RQST;
	msgbuf.target[0] = OPC$M_NM_CENTRL | OPC$M_NM_NTWORK;
	msgbuf.target[1] = 0;
	msgbuf.target[2] = 0;
	msgbuf.id = 123;
	sys$sndopr(&msgstr,NULL);
}
/*----------------------------------------------------------------------*/
char *lib_findfile(char *s)
{
	static char wild[200],buff[201];
	static DEFSTR1(wild_str,wild,0);
	DEFSTR1(buff_str,buff,200);
	static int r,context;
	int i;
	int flags=1;

	if (s!=NULL) strcpy(wild,s);
	DEFSTR2(wild_str,wild,strlen(wild));
	DEFSTR2(buff_str,buff,200);
	
	strcpy(buff,"");
	r = lib$find_file(&wild_str, &buff_str, &context);
	if ((r&1)!=1) {
		r = lib$find_file_end(&context);
		if (r&1 != 1) wmsg("lib: %s\n",lib_message(r));
		return NULL;
	}
	s = strchr(buff,' ');
	if (s!=NULL) *s = 0;
	return buff;
}
/* Mail a file using the vms callable mail interface */
typedef struct itmlst
{
	short len;
	short code;
	char *buff;
	int *rlen;
} Itmlst; 
Itmlst nulllist[] = { {0,0,0,0} };

void mail_setrec(Itmlst *x,int code, char *bf, int *rlen);
void mail_setrec(Itmlst *x,int code, char *bf, int *rlen)
{
	x->len = strlen(bf);
	x->buff = bf;
	x->code = code;
	x->rlen = rlen;
}
int mail_good(void)
{
	emsg("Mail good \n");
	return TRUE;
}
int mail_bad(void)
{
	emsg("Mail bad \n");
	return TRUE;
}
int lib_mail_filex(char *to, char *subj, char *fname)
{
	int r;
	int context;
	char realto[200];
	int to_len,fname_len,subj_len;
	Itmlst address_list[3];
	Itmlst body_list[3];
	Itmlst attrib_list[3];
	Itmlst send_list[3];


	imsg("vms_lib_mail_file(%s,%s,%s)\n",to,subj,fname);

	if (strchr(to,'@')!=NULL) {
		sprintf(realto,"%s%%\"%s\"",config_get(C_MAIL),to);
	} else strcpy(realto,to);
	
	dmsg("lib: mail address changed to {%s} \n",realto);

	mail_setrec(&address_list[0],MAIL$_SEND_USERNAME,realto,&to_len);
	mail_setrec(&address_list[1],0,"",0);
	mail_setrec(&body_list[0],MAIL$_SEND_FILENAME,fname,&fname_len);
	mail_setrec(&body_list[1],0,"",0);
	mail_setrec(&attrib_list[0],MAIL$_SEND_TO_LINE,realto,&to_len);
	mail_setrec(&attrib_list[1],MAIL$_SEND_SUBJECT,subj,&subj_len);
	mail_setrec(&attrib_list[2],0,"",0);

	/* Just for debugging, msut add send_list to send call */
	mail_setrec(&send_list[0],0,"    ",0);
	mail_setrec(&send_list[1],0,"    ",0);
	mail_setrec(&send_list[2],0,"    ",0);
	send_list[0].code = MAIL$_SEND_ERROR_ENTRY;
	send_list[0].buff = (char *) mail_bad;
	send_list[1].code = MAIL$_SEND_SUCCESS_ENTRY;
	send_list[1].buff = (char *) mail_good;

	r = mail$send_begin(&context, nulllist, nulllist);
	if (r != SS$_NORMAL) { emsg("mail: %s\n",lib_message(r)); return FALSE;}

	r = mail$send_add_address(&context,address_list,nulllist);
	if (r != SS$_NORMAL) { emsg("mail: %s\n",lib_message(r)); return FALSE;}

	r = mail$send_add_attribute(&context,attrib_list,nulllist);
	if (r != SS$_NORMAL) { emsg("mail: %s\n",lib_message(r)); return FALSE;}
		
	r = mail$send_add_bodypart(&context,body_list,nulllist);
	if (r != SS$_NORMAL) { emsg("mail: %s\n",lib_message(r)); return FALSE;}

	r = mail$send_message(&context,nulllist,nulllist);	
	if (r != SS$_NORMAL) { emsg("mail: %s\n",lib_message(r)); return FALSE;}
	
	r = mail$send_end(&context,nulllist,nulllist);	
	if (r != SS$_NORMAL) { emsg("mail: %s\n",lib_message(r)); return FALSE;}

	imsg("vms_lib_mail_file_finished\n");
	return TRUE;
}
/* Return result as number of free 1K blocks (not vms blocks) */
int lib_freespace(char *s)
{
	int rslt;
	int code = DVI$_FREEBLOCKS;
	DEFSTR1(devstr,s,strlen(s));
	DEFSTR2(devstr,s,strlen(s));

	rslt = 0;
	lib$getdvi(&code,NULL,&devstr,&rslt,NULL,NULL);
	return rslt/2;
}
int usleep(int x)
{
	return 0;
}
void filter_idle(void)
{
	
}
int lib_spawn_cmd(char *cmd)
{
	return 1;
}
int rad_lookup(char *user, char *pass, char *host, char *seckey, int ecode, char *extra)
{
	return 0;
}
int spawn_isalive(int x)
{
	return 0;
}
int spawn_kill(int x)
{
	return 0;
}
int spawn_release(int x)
{
	return 0;
}
