/*     
      SCOL SYSTEM . Magma 1.0 . 1996 . Sylvain HUET

         scolsys.cpp : routines systeme de scol
*/
// Modification history:
//$ FA(28/05/2001): Replaced call to SCexeccomm0() by SCexeccomm(), which is 
//                  completely equivalent
//$ FA(28/05/2001): Promoted to C++ implementation file
//$ FA(28/05/2001): Rewrite SCscript() and SCscriptc() to use Script class methods
//$ FA(01/06/2001): Comment MMpull() after call to SCexeccomm()
//$ FA(06/06/2001): Includes baselib.h 
//$ FA(18/06/2001): Debugger integration. Add channel id and channel user name support.
//$ FA(19/06/2001): Debugger integration. Close debugger's channel in SCclosemachine().
//                  Send notification when a package is removed
//
//$ LB(20/06/2001): add SCdefinesocksVersion and SCdefinesocksAuthentication function bodys,
//                  to make scol able to specifiy socks protocol parameters 
//                  (protocol version and the need of authentication)
//
//$ ER(09/07/2001): Rewrite testLicense to decrypt the parameters from the license number
//					Turn #ifdef SERVERM in the test of MUTUALISE in setserver
//$ FA(16/07/2001): Use h2i() function as a replacement for Mgethx()
//$ FA(23/07/2001): Comment out SCsetsocket(m, c, -1)
//$ FA(27/08/2001): Print a message into the log indicating the max number of sockets
//                  the license allows
//$ FA(12/11/2001): Replace SCOL_DEBUGGER_AWARE by INCLUDE_DEBUGGER
//$ FA(17/01/2002): Revise and rewrite SCdestroychannel(). Extra notify parameter is used
//                  in order to know if '_closed' callback needs to be called. Modify all
//                  invocations to take into account of the extra parameter, in particular
//                  SCchanneldown() which should set the notify parameter to 1.
//$ FA(30/01/2002): SCremovepkg() modified to return nil when the user reaches the base environment
//$ FA(08/04/2002): Correct SCfreememory(), so that it returns a positive value
//
//$ LB (30/05/2002) : testlicence function : make the ClubHouse Server accept an unlimited number of connections
//

#include "scolPrerequisites.h"

//$BLG - v5.2.06: Add
#if SCOL_PLATFORM == SCOL_PLATFORM_WINDOWS
#include <windows.h>
#include <tchar.h>
#include <psapi.h>
#endif


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


extern "C" {
#include "common/vscol.h"

//$BB
extern ScolWindowID ActiveXhwnd;
extern ScolWindowID hscol;
#define WM_SCOLAXMESS (WM_USER+11)
#define WM_SCOLSETWPTR (WM_USER+12)

struct tagAXdata
{
   char mess[1024];
};
typedef struct tagAXdata * AXDATA;

}
#if SCOL_PLATFORM == SCOL_PLATFORM_LINUX
#include <sys/time.h>
#include <unistd.h>
#endif

extern "C" {
#include "scolMMemory.h"
#include "vm/mbytec.h"
#include "listlab.h"
#include "loadpak.h"
#include "mainscol.h"
#include "scol.h"
#include "scolpack.h"
#include "scolsign.h"
#include "fifo.h"
#include "common/socket.h"
//$LB : use socks protocol interface
#include "common/socks.h"
//
#include "common/common.h"
#include "scolobj.h"
}
#include "baselib.h"
//$ FA(08/11/2000): Use debugger interface
#include "debug.h"
//
#include "scolMacros.h"
#include "scolSystem.h"
//$ FA(28/05/2001): Use Script class interface
#include "script.h"
//
//$ ER(09/07/01): Use rsa library
#include "rsa.h"
#include "compiler/lexer.h"

static int unplugged_sock=FirstUnplugged;
extern "C" {
int (*LocalMessage)(char *buf);
int activeChannel=0;
char forcedIP[64];
int flagLicense;
int SClocalIPnumber;

//$ ER(09/07/01) : c'est utile ?
extern char execpath[MAX_PATH];
/*
extern int MAXSOCKS;
extern int MAXSOCKSE;
extern int maxsock;*/

int LoadUsmIni(char* cmdline);
int SCdefinesocks2(char *socks,char *mask);
}

#ifdef SERVER
#define KEY2 "11b3e"
#define KEY4 "d243f"
#endif


#if SCOL_PLATFORM == SCOL_PLATFORM_WINDOWS
	typedef UINT (WINAPI *ENUMPROCESSES)(LPDWORD, DWORD, LPDWORD);
	typedef UINT (WINAPI *ENUMPROCESSMODULES)(HANDLE, HMODULE *, DWORD, LPDWORD);
	typedef UINT (WINAPI *GETMODULEBASENAME)(HANDLE, HMODULE, LPTSTR, DWORD);
#endif


//$ FA(28/05/2001): Rewritten. Use new Script class.
int SCscript(mmachine m)
// Executes a script on the current channel
// [0]: string containing the script text
{
  int res = MERROK;
  if (MMget(m, 0) != NIL) {
    Script script(m, MMstartstr(m, MMget(m, 0)>>1));
    res = script.execute();
  }
  MMset(m, 0, 0);
  return res;
}


//$ FA(28/05/2001): Rewritten. Use new Script class.
int SCscriptc(mmachine m)
// Executes a script on a specified channel
// [1]: channel where script should execute
// [0]: string containing the script text
{
	//$BLG - v5.22: Add
	int res;

  if (MMget(m, 0) == NIL || MMget(m, 1) == NIL) 
  {
    MMpull(m);
    MMset(m, 0, 0);
    return MERROK;
  }

  // Switch to new channel
  int chn = MMget(m, 1);
  MMset(m, 1, MMgetglobal(m, OFFSCCUR));  // save current channel on the stack
  MMsetglobal(m, OFFSCCUR, chn);

  // Execute script
  //$BLG - v5.22: Modif
  //Do not execute script if it's empty, if it comes from an empty (too big) defcom for example
  //Script script(m, MMstartstr(m, MMpull(m)>>1));
  //int res = script.execute();
  res = 0;
  if (strcmp(MMstartstr(m, MMget(m, 0)>>1), "__"))
  {
	  //MMechostr(0, "script ok\n");
	  Script script(m, MMstartstr(m, MMpull(m)>>1));
	  //$BLG - v5.22: Modif
	  //int res = script.execute();
	  res = script.execute();
	}
	/*
	else
		MMechostr(0, "script __\n");
	*/

  // Restore previous channel
  MMsetglobal(m, OFFSCCUR, MMget(m, 0));
  MMset(m, 0, 0);
  return res;
}


/* creation d'un canal
 en 2 : corresp 
 en 1 : script
 en 0 : env */
int SCopenchannelbis(mmachine m)
{
  int k,base,s,ip,port,proxy;
  char buf[128];

  base=MMgetPP(m);
  if (MMgetbase(m,base,1)==NIL) return MERRTYP;

  if (k=SCmakefifo(m)) return k;                  /* bloc.fifo */
  if (MMpush(m,MMgetbase(m,base,1))) return MERRMEM;  /* env.canal */
//$ FA(08/11/2000)
  SECHECK(SEPUSH(m, NIL));              // user channel name (unspecified)
//$ FA(23/11/2000)
  SECHECK(SEPUSH(m, SEI2W(chnID++)));   // assign channed id
//
  //$BLG - v5.21: Modif (*2 to <<1)
  if (MMpush(m,SIZECHAN<<1)) return MERRMEM;
  if (k=MBdeftab(m)) return k;

  MMsetglobal(m,OFFSCCUR,MMget(m,0));
  if (MMgetbase(m,base,3)==NIL)
  {
    //$BLG - v5.21: Del
    //MMechostr(MSKDEBUG,"\nunplugged channel %d\n",unplugged_sock);  
    SCsetsocket(m,MMgetglobal(m,OFFSCCUR),unplugged_sock--);
    if (k=Mpushstrbloc(m,"unplugged")) return k;
    SCsetsockname(m,MMgetglobal(m,OFFSCCUR)); /* reglage du nom */
    MMechostr(MSKDEBUG,"unplugged\n");
  }
  else
  {
    /* lancer la connexion socket */
    s=SCKconnect(MMstartstr(m,MMgetbase(m,base,3)>>1),&ip,&port,&proxy);
    if (s<0)
		{
		  if (MMpush(m,NIL)) return MERRMEM;
		  return 0;
		}
    if (proxy) SCsetproxy(m,MMgetglobal(m,OFFSCCUR));
    SCsetsocket(m,MMgetglobal(m,OFFSCCUR),s);
    if (k=Mpushstrbloc(m,SCKgetstringbyip(buf,ip,port))) return k;
    SCsetsockname(m,MMgetglobal(m,OFFSCCUR)); /* reglage du nom */
    MMechostr(MSKDEBUG,"ChannelIP: %s\n", MMstartstr(m,MMgetbase(m,base,3)>>1));
  }

  if (k=SCaddcanal(m)) return k;

  MMset(m,0,MMgetbase(m,base,2));
  if (k=SCscript(m)) return k;
  if (MMpull(m)) return MERRTYP;

  return MMpush(m,MMgetglobal(m,OFFSCCUR));
}

int SCopenchannel3(mmachine m)
{
  int k,base;

  if (MMpush(m,MMgetglobal(m,OFFSCCUR))) return MERRMEM;
  base=MMgetPP(m);
  k=SCopenchannelbis(m);
  MMsetglobal(m,OFFSCCUR,MMgetbase(m,base,0));
  if (k)
    MMsetbase(m,base,3,NIL);
  else
    MMsetbase(m,base,3,MMget(m,0));
  MMsetPP(m,base+3);
  return k;
}

int SCopenchannel(mmachine m)
{
  char *p;
    
  //$BLG - v5.21: Add
  int ret;
  
  
  if (MMget(m, 2) != NIL)
  {
    p = MMstartstr(m, MMget(m, 2)>>1);
    if (((ScolRights&C_RIGHTS) == 0) || (((ScolRights&D_RIGHTS) == 0) && (*p != ':')))
		{
			MMpull(m);
		  MMpull(m);
	    MMset(m, 0, NIL);
	    return 0;
		}
  }
  else if (SCgetnbsocketu(m) >= MAXSOCKSU)
  {
	  MMpull(m);
    MMpull(m);
    MMset(m, 0, NIL);
    return 0;
  }

  if (MMget(m, 0) == NIL) 
  	MMset(m, 0, MMgetglobal(m, OFFSCBASE));

	//$BLG - v5.11: Modif
  //MMechostr(MSKDEBUG,"ouverture d'un canal\n");
  MMechostr(MSKDEBUG,"Opening Channel ...\n");
  
  //$BLG - v5.11: Modif
  //return SCopenchannel3(m);
  ret = SCopenchannel3(m);
  MMechostr(MSKDEBUG, "\n");
  return ret;
}

/* Destruction de la structure canal */
int SCdestroychannel(mmachine m, int chn, int notify)
// FA  17/01/2002  Revised and rewritten
{
  int res;
  // Do nothing if channel is null
  if (chn == NIL) 
    return MERROK;
  // The order of the following steps needed to close a channel is significant
  // (1) Remove the channel from the list
  SCdelcanal(m, chn);
  // (2) Close socket and mark socket field as closed
  SCKclose(SCgetsocket(m, chn));
  SCsetsocket(m, chn, -1);
  // (3) If requested, call the '_closed' callback
  MMpush(m, chn);
  if (notify && (res = SCexeccomm(m, "_closed"))) 
    return res;
  // (4) Unlink channel environment
  chn = MMpull(m);
  MMstore(m, chn>>1, OFFCHANENV, NIL);
  // (5) Remove all channel objects and return to caller
  return OBJdelChn(m, chn);
}


/* Fermeture du canal courant */
int SCclosechannel(mmachine m)
{
  int chn = MMgetglobal(m, OFFSCCUR);  /* lire l'environnement courant */
  if (chn == NIL) 
    return MERRTYP;
//$ FA(17/01/2002): Call to SCdestroychannel() with extra 'notify' argument = 0
  SCdestroychannel(m, chn, 0);
//
  return MMpush(m, 0);
}

/* Fermeture de la machine */
int SCclosemachine(mmachine m)
{
	int c;

//  MMechostr(1,"_closemachine\n");
//$ FA(19/06/2001): Close debugger's channel
#if defined(INCLUDE_DEBUGGER)
  DBGCloseChannel(m);
#endif
//
  while(MMgetglobal(m,OFFSCCHAN)!=NIL)
  {
	  c=MMfetch(m,MMgetglobal(m,OFFSCCHAN)>>1,0);
//$ FA(17/01/2002): Call to SCdestroychannel() with extra 'notify' argument = 0
	  SCdestroychannel(m, c, 0);
//
  }
  MMechostr(MSKDEBUG,"delete servers\n");
  while(MMgetglobal(m,OFFSCSERVER)!=NIL)
  {
	  c=MMfetch(m,MMgetglobal(m,OFFSCSERVER)>>1,0);
	  MMechostr(MSKDEBUG,"close one server\n");
      SCKcloseserver(SCgetsrvsocket(m,c));
	  SCdelserver(m,c);
  }
  m->err=MERRCLOSE;
  return MMpush(m,0);
}

/* gestion de fermeture accidentelle du canal courant */
int SCchanneldown(mmachine m)
{
  int chn;
//$ FA(17/01/2002): Destroy current channel and execute _closed callback
  if ((chn = MMgetglobal(m, OFFSCCUR)) == NIL) 
    return MERRTYP;
  SCdestroychannel(m, chn, 1);
//
  return 0;
}

/* fermeture d'un canal de l'appli */
int SCkillchannel(mmachine m)
{
//$ FA(17/01/2002): Call to SCdestroychannel() with extra 'notify' argument = 0
  SCdestroychannel(m, MMget(m, 0), 0);
//
  MMset(m, 0, 0);
  return MERROK;
}

/* lit le nom du canal */
int SCchannelname(mmachine m)
{
  if (MMget(m,0)==NIL) return 0;
  return SCgetsockname(m,MMpull(m));
}

/* lit l'adresse IP du canal */
int SCchannelIP(mmachine m)
{
  char buf[256];
  int i,l,k;

  if (MMget(m,0)==NIL) return 0;
  if (k=SCgetsockname(m,MMpull(m))) return MERRMEM;
  if (MMget(m,0)==NIL) return 0;
  strcpy(buf,MMstartstr(m,MMpull(m)>>1));
  l=strlen(buf);
  for(i=0;i<l;i++) if (buf[i]==':') buf[i]=0;
  if (k=Mpushstrbloc(m,buf)) return k;
  return 0;
}

/* lit le numero de port du canal */
int SCchannelport(mmachine m)
{
  char *p;
  int k;

  if (MMget(m,0)==NIL) return 0;
  if (k=SCgetsockname(m,MMpull(m))) return MERRMEM;
  if (MMget(m,0)==NIL) return 0;
  p=MMstartstr(m,MMpull(m)>>1);
  while(*p)
    {
      //$BLG - v5.21: Modif (*2 to <<1)
      if ((*p)==':') return MMpush(m,atoi(p+1)<<1);
      p++;
    }
  return MMpush(m,-1*2);
}

/* retourne le nom de l'hote */
int SChostname(mmachine m)
{
  char buf[1204];

  return Mpushstrbloc(m,SCKhostname(buf));
}

/* retourne l'adresse IP de l'hote */
int SChostIP(mmachine m)
{
  char buf[1204];
  int i;

  if (forcedIP[0]) return Mpushstrbloc(m,forcedIP);
  i=SClocalIPnumber;
  if ((i<0)||(i>=SCKgetnbIP()))i=0;
  SCKgetnthIP(buf,i);
  return Mpushstrbloc(m,buf);
}

/* definit l'index d'IP locale */
int SCsetLocalIPnumber(mmachine m)
{

	int i;
	i=MMget(m,0)>>1;
	if ((i<0)||(i>=SCKgetnbIP())) i=0;
	SClocalIPnumber=i;
	return 0;
}


/* retourne toutes les adresses IP de l'hote */
int SChostIPall(mmachine m)
{
	char buf[64];
	int i,n,k;
	
	n=SCKgetnbIP();
	for(i=0;i<n;i++)
	{
		SCKgetnthIP(buf,i);
		if ((k=Mpushstrbloc(m,buf))) return k;
	}
	if (MMpush(m,NIL)) return MERRMEM;
	for(i=0;i<n;i++)
    {
		//$BLG - v5.21: Modif (*2 to <<1)
		if (MMpush(m,2<<1)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
    }
	return 0;
}


/* DNS synchrone */
int SCgethostbyname(mmachine m)
{
  char buf[1204];
  int k;

  if (MMget(m,0)==NIL) return 0;
  if (SCKgethostbyname(buf,MMstartstr(m,MMpull(m)>>1))==NULL)
    return MMpush(m,NIL);
  if (k=Mpushstrbloc(m,buf)) return k;
  return 0;
}

/* DNS synchrone name -> IP */
int SCgetnamebyIP(mmachine m)
{
  char buf[1204];
  int k;

  if (MMget(m,0)==NIL) return 0;
  if (SCKgetnamebyIP(buf,MMstartstr(m,MMpull(m)>>1))==NULL)
    return MMpush(m,NIL);
  if (k=Mpushstrbloc(m,buf)) return k;
  return 0;
}

/* canal courant */
int SCchannel(mmachine m)
{
  //MMechostr(0, "> OFFSCCUR (2 nxt lines):\n");
  return MMpush(m,MMgetglobal(m,OFFSCCUR));
}

/* changement de canal courant */
int SCsetchannel(mmachine m)
{
  int p;

  p=MMget(m,0);
  if (p!=NIL) MMsetglobal(m,OFFSCCUR,p);
  return 0;
}

/* nom du premiet package d'un environnement */
int SCenvfirstname(mmachine m)
{
  int p;
  char path[SIZESIGN];

  p=MMget(m,0);
  if (p==NIL) return 0;
  strcpy(path,(char*)MMstart(m,MMfetch(m,MMfetch(m,p>>1,OFFLVAL)>>1,OFFPKNAME)>>1));
  MMpull(m);
  return Mpushstrbloc(m,path);
}

/* lecture de l'environnement lie a un canal */
int SCenvchannel(mmachine m)
{
  int t;

  t=MMget(m,0);  /* canal argument */
  if (t==NIL) return 0;
  MMset(m,0,MMfetch(m,t>>1,OFFCHANENV));
  return 0;
}

/* retirer un package d'un environnement */
int SCremovepkg(mmachine m)
{
//$ FA(19/06/2001): Notify debugger that a package has been removed!
#if defined(INCLUDE_DEBUGGER)
  int res;
  SECHECK(SEPUSH(m, SEHEAD(m, SEW2P(SEGETTOP(m, 0)))));
  if (res = DBGNotifyPackageRemoved(m))
    return res;
#endif
//$ FA(30/01/2002): We stop when we find the beginning of the base environment
  if (SEGETROOT(m, OFFSCBASE) == SETAIL(m, SEW2P(SEGETTOP(m, 0)))) {
    SESETTOP(m, 0, NIL);
    return MERROK;
  }
//
  return MBtl(m);
}

/* creation d'une appli a partir du canal courant */
int SCsetenv(mmachine m)
{
  int e,t;

  e=MMpull(m);
  if (e==NIL) e=MMgetglobal(m,OFFSCBASE);
  t=MMget(m,0);  /* canal argument */
  if (t==NIL) return 0;
  MMstore(m,t>>1,OFFCHANENV,e);
  MMset(m,0,0);
  return 0;
}

/* definition du serveur
 en 2 : env
 en 1 : numero de port
 en 0 : script */
//$ ER(09/07/01) turn #ifdef SERVERM to test of MUTUALISE
int SCsetserver(mmachine m)
{
  int s,port,k;
  time_t ts;

#ifdef SERVER
  if ((!ScolSuper)&&(!flagLicense))
    {
      MMechostr(MSKRUNTIME,"cannot start server : no licence\n");
      return MERRTYP;
    }
#endif
  if ((ScolRights&S_RIGHTS)==0)
    {
      MMpull(m);
      MMpull(m);
      MMset(m,0,NIL);
      return 0;
    }
  
  if (MMget(m,2)==NIL) MMset(m,2,MMgetglobal(m,OFFSCBASE));

  /* ouvrir une socket d'ecoute sur le port donne' en parametre */
  port=MMget(m,1)>>1;
  if ((s=SCKstartserver(port))<0)
    {
      MMpull(m);
      MMpull(m);
      MMset(m,0,NIL);
      return 0;
    }
  //$BLG - v5.21: Modif (*2 to <<1)
  if (MMpush(m,s<<1)) return MERRMEM;
  time(&ts);
  if (MMpush(m,MMget(m,3))) return MERRMEM;
  //$BLG - v5.21: Modif (*2 to <<1)
  if (MMpush(m,port<<1)) return MERRMEM;
  if (MMpush(m,ts<<1)) return MERRMEM;
  if (MMpush(m,SIZESRV<<1)) return MERRMEM;
  
  if (k=MBdeftab(m)) return k;
  MMset(m,2,MMget(m,0));
  MMset(m,1,MMget(m,0));
  MMpull(m);
  if (k=SCaddserver(m)) return k;

#ifdef SERVER
  if ((!ScolSuper) && (MUTUALISE))
	  SCsendCapacity(m);
#endif
 
  return 0;
}

/* fermeture du serveur */
int SCcloseserver(mmachine m)
{
  int s,t;

  t=MMget(m,0);
  if (t==NIL) return 0;

  /* fermer la socket d'ecoute */
  s=SCgetsrvsocket(m,t);
  SCKcloseserver(s);
  SCdelserver(m,t);
  MMset(m,0,0);
  return 0;
}


/* definition d'un serveur udp
 en 2 : env
 en 1 : numero de port
 en 0 : script */
int SCsetUDPserverbis(mmachine m)
{
  int k,base,s,p;

  base=MMgetPP(m);
  if (MMgetbase(m,base,3)==NIL) return MERRTYP;

  if (k=SCmakefifo(m)) return k;                  /* bloc.fifo */
  if (MMpush(m,MMgetbase(m,base,3))) return MERRMEM;  /* env.canal */
//$ FA(08/11/2000)
  SECHECK(SEPUSH(m, NIL));              // user channel name (unspecified)
//$ FA(23/11/2000)
  SECHECK(SEPUSH(m, SEI2W(chnID++)));   // assign channed id
//
  //$BLG - v5.21: Modif (*2 to <<1)
  if (MMpush(m,SIZECHAN<<1)) return MERRMEM;
  if (k=MBdeftab(m)) return k;

  MMsetglobal(m,OFFSCCUR,MMget(m,0));

  /* lancer la connexion socket */
  p=MMgetbase(m,base,2)>>1;

  if (p>=0) s=SCKstartudpserver(p);
  if ((p<0)||(s<0))
    {
      if (MMpush(m,NIL)) return MERRMEM;
	  return 0;
	}
  SCsetudp(m,MMgetglobal(m,OFFSCCUR));
  SCsetsocket(m,MMgetglobal(m,OFFSCCUR),s);

  if (k=SCaddcanal(m)) return k;

  MMset(m,0,MMgetbase(m,base,1));
  if (k=SCscript(m)) return k;
  if (MMpull(m)) return MERRTYP;

  return MMpush(m,MMgetglobal(m,OFFSCCUR));
}

int SCsetUDPserver(mmachine m)
{
  int k,base;

  if (MMpush(m,MMgetglobal(m,OFFSCCUR))) return MERRMEM;
  base=MMgetPP(m);
  k=SCsetUDPserverbis(m);
  MMsetglobal(m,OFFSCCUR,MMgetbase(m,base,0));
  if (k)
    MMsetbase(m,base,3,NIL);
  else
    MMsetbase(m,base,3,MMget(m,0));
  MMsetPP(m,base+3);
  return k;
}

/* emission d'un message udp */
int SCsendudp(mmachine m)
{
  int l;
  char *p;

  if ((MMget(m,0)==NIL)||(MMget(m,1)==NIL))
    {
      MMpull(m);
      MMset(m,0,0);
      return 0;
    }
  p=(char*)MMstart(m,MMget(m,0)>>1);
  l=(p[0]&255)+((p[1]&255)<<8)+2;
  
  SCKsendudp(MMstartstr(m,MMget(m,1)>>1),p,l);
  MMpull(m);
  MMset(m,0,0);
  return 0;
}

/* emission d'un message udp en spécifiant la socket */
int SCsendudpchn(mmachine m)
{
  int l;
  char *p;

  if ((MMget(m,0)==NIL)||(MMget(m,1)==NIL)||(MMget(m,2)==NIL))
    {
      MMpull(m);
      MMpull(m);
      MMset(m,0,0);
      return 0;
    }
  p=(char*)MMstart(m,MMget(m,0)>>1);
  l=(p[0]&255)+((p[1]&255)<<8)+2;

  SCKsendudpchn(SCgetsocket(m,MMget(m,2)),MMstartstr(m,MMget(m,1)>>1),p,l);
  MMpull(m);
  MMpull(m);
  MMset(m,0,0);
  return 0;
}

/* recuperation de la duree d'un canal */
int SCchanneltime(mmachine m)
{
  int c;
  
  if ((c=MMget(m,0))==NIL) return 0;
  MMset(m,0,SCgetchanneltime(m,c)*2);
  return 0;
}

/* recuperation de la duree d'un canal */
int SCservertime(mmachine m)
{
  int c;
  
  if ((c=MMget(m,0))==NIL) return 0;
  MMset(m,0,SCgetservertime(m,c)*2);
  return 0;
}


/* emission d'un message */
int SCon(mmachine m)
{
  int k, z;

//MMechostr(0, "SCon\n");

  if ((MMget(m, 0) == NIL) || (MMget(m, 1) == NIL))
  {
    MMpull(m);
    MMset(m, 0, 0);
    return 0;
  }

  z = MMget(m, 1);         /* echange environnement */
  MMset(m, 1, MMgetglobal(m, OFFSCCUR));
  MMsetglobal(m, OFFSCCUR, z);
  k = SCsendpile(m);
  if (k) return k;
  MMsetglobal(m, OFFSCCUR, MMget(m, 0));      /* echange environnement */

  MMset(m, 0, 0);
  return 0;
}

#if SCOL_PLATFORM == SCOL_PLATFORM_WINDOWS
	/* emission d'un message vers activeX */
	int SConX(mmachine m)
	{
	  char cmess[1024];  
	  sprintf(cmess, "%s", (MMstartstr(m,MMget(m,0)>>1)-2));
		if ((LocalMessage)&&(MMget(m,0)!=NIL))
		{
			MMechostr(MSKTRACE,">>onX : %s\n",cmess);
			(*LocalMessage)(cmess);
		}
	  
	  //$BB ax comm
	  if ((MMget(m,0)!=NIL) && (ActiveXhwnd))
	  {
		MMechostr(MSKTRACE,">>onX ActiveXhwnd : %s\n", cmess);
		COPYDATASTRUCT cpd;
		cpd.dwData = WM_SCOLAXMESS;
		cpd.cbData = (strlen(cmess) + 1);
		cpd.lpData = (PVOID)cmess;
		
		MMechostr(MSKTRACE,">>onX ActiveXhwnd : COPYDATASTRUCT setted\n");
		SendMessage(ActiveXhwnd,WM_COPYDATA,(WPARAM)hscol,(LPARAM)(LPVOID)&cpd);
	  }
		return 0;
	}

	/* definition du canal ActiveX */
	int SCsetX(mmachine m)
	{
		if (MMget(m,0)==NIL) return 0;
		activeChannel=SCgetsocket(m,MMget(m,0));
		return 0;
	}
#else
	// ActiveX is windows only technology!
#endif

/* comptage des messages en attente dans la fifo d'un canal */
int SCwaitingfifo(mmachine m)
{
  int c,n;
  
  if ((c=MMget(m,0))==NIL) return 0;
  c>>=1;
  n=0;
  if ((c=MMfetch(m,c,OFFCHANFIFO))!=NIL)
    {
      c>>=1;
      c=MMfetch(m,c,FIFOOUT)>>1;
      while(c!=NIL)
	{
          n++;
          c=MMfetch(m,c,OFFLNEXT)>>1;
	}
    }   
  MMset(m,0,n*2);
  return 0;
}

/* taille des messages en attente dans la fifo d'un canal */
int SCsizewaitingfifo(mmachine m)
{
  int c,n,v;
  char *p;
  
  if ((c=MMget(m,0))==NIL) return 0;
  c>>=1;
  n=0;
  if ((c=MMfetch(m,c,OFFCHANFIFO))!=NIL)
    {
      c>>=1;
      c=MMfetch(m,c,FIFOOUT)>>1;
      while(c!=NIL)
	{
          v=MMfetch(m,c,OFFLVAL)>>1;
          p=(char*)MMstart(m,v);
          n+=(p[0]&255)+((p[1]&255)<<8);
          c=MMfetch(m,c,OFFLNEXT)>>1;
	}
    }   
  MMset(m,0,n*2);
  return 0;
}

/* reglage de la limite d'une la fifo */
int SCsetsizefifo(mmachine m)
{
  int c,n;
  
  n=MMpull(m);
  if ((c=MMget(m,0)>>1)==NIL) return 0;
  if ((c=MMfetch(m,c,OFFCHANFIFO)>>1)==NIL) return 0;
  if (n!=NIL) n=((n>>3)<<1);
  MMstore(m,c,FIFOMAX,n);
  return 0;
}

/* lecture des droits de la machine */
int SCgetrights(mmachine m)
{
  //$BLG - v5.21: Modif (*2 to <<1)
  return MMpush(m,ScolRights<<1);
}

/* restriction des droits de la machine */
int SCsetrights(mmachine m)
{
  int k;
    
  k=MMpull(m);
  if (k==NIL) return MMpush(m,NIL);
  ScolRights&=(k>>1);
  //$BLG - v5.21: Modif (*2 to <<1)
  return MMpush(m,ScolRights<<1);
}
    
/* lecture de la taille de la memoire */
int SCsizememory(mmachine m)
{
  //$BLG - v5.21: Modif (*2 to <<1)
  return MMpush(m,m->sizetape<<1);
}

/* lecture de la taille disponible en memoire */
int SCfreememory(mmachine m)
{
	MMgc(m);
  //$BLG - v5.21: Modif (*2 to <<1)
  return MMpush(m,(m->sizetape-m->topheap+m->pp)<<1); //$ FA(08/04/2002)
}

#if SCOL_PLATFORM == SCOL_PLATFORM_WINDOWS
	/* Windows Memory Trimming */
	int SCtrimmemory(mmachine m)
	{
	  OSVERSIONINFO stOSVI ;
	  DWORD vID, minV, majV;


	  memset(&stOSVI ,0 , sizeof(OSVERSIONINFO));
	  stOSVI.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	  if (!GetVersionEx(&stOSVI))
		  return MMpush(m, NIL);
	  
	  vID  = stOSVI.dwPlatformId;
	  minV = stOSVI.dwMinorVersion;
	  majV = stOSVI.dwMajorVersion;

	  if (vID == VER_PLATFORM_WIN32_NT)
		{
			//WinNT, Win2000 or WinXP
			if (((majV == 4) && (minV == 0)) || ((majV == 5) && (minV == 0)) || ((majV == 5) && (minV == 1)))
			{
				if (SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1))
					return MMpush(m, 0);
				else
					return MMpush(m, NIL);
			}
		}

		return MMpush(m,0);
	}
#endif


/* Scol CPU usage */
int SCgetcpuusage(mmachine m)
{
	return MMpush(m, 0);
}


#if SCOL_PLATFORM == SCOL_PLATFORM_WINDOWS
	/* Number of current scol.exe running processes */
	int IsItScolProcess(DWORD processID)
	{
	  TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
	  HANDLE hProcess;
	  HMODULE hMod;
	  DWORD ret_bytes;
	  char scolname[512];

	  HMODULE hPSAPI = GetModuleHandle("psapi");
		ENUMPROCESSMODULES EnumProcessModules;
		EnumProcessModules = (ENUMPROCESSMODULES)GetProcAddress(hPSAPI, "EnumProcessModules");
		GETMODULEBASENAME GetModuleBaseName;
		GetModuleBaseName = (GETMODULEBASENAME)GetProcAddress(hPSAPI, "GetModuleBaseNameA");
	  
	  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);

	  if (NULL != hProcess )
	  {
		if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &ret_bytes))
		{
		  if (!GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR)))
		  	szProcessName[0] = 0;
		}
	  }
	  
	  CloseHandle( hProcess );
	  
	  //$BB get the current scol.exe name

	  int i = strlen(execname);
	  while (i && (execname[i]!='\\') && (execname[i]!='/')) i--;
	  sprintf (scolname,"%s", execname + (i + 1));

	  if (!strcmpi(szProcessName, scolname))
	  	return 1;
		else
			return 0;
	}

	int SCgetScolProcesses(mmachine m)
	{
	  DWORD processes[1024], ret_bytes, running_p;
	  unsigned int i;
	  int ret;

		HINSTANCE hInstance = LoadLibrary("psapi");
		ENUMPROCESSES EnumProcesses;
		EnumProcesses = (ENUMPROCESSES)GetProcAddress(hInstance, "EnumProcesses");

	  if (!EnumProcesses(processes, sizeof(processes), &ret_bytes))
	  {
		FreeLibrary(hInstance);
		return MMpush(m, NIL);
	  }

	  running_p = ret_bytes / sizeof(DWORD);
		ret = 0;
	  for (i = 0; i < running_p; i++)
	  {
		if (processes[i] != 0)
		  ret += IsItScolProcess(processes[i]);
	  }
	  
	  FreeLibrary(hInstance);
		        
		return MMpush(m, ret<<1);
	}

	//$BB count process != thisinst
	int countOtherScolProcesses()
	{
	  DWORD processes[1024], ret_bytes, running_p;
	  DWORD thisprocid;
	  unsigned int i;
	  int ret;
	  
	  thisprocid = GetCurrentProcessId();
		HINSTANCE hInstance = LoadLibrary("psapi");
		ENUMPROCESSES EnumProcesses;
		EnumProcesses = (ENUMPROCESSES)GetProcAddress(hInstance, "EnumProcesses");

	  if (!EnumProcesses(processes, sizeof(processes), &ret_bytes))
	  {
		FreeLibrary(hInstance);
	  }

	  running_p = ret_bytes / sizeof(DWORD);
		ret = 0;
	  for (i = 0; i < running_p; i++)
	  {
		if ((processes[i] != 0) && (processes[i] != thisprocid))
		  ret += IsItScolProcess(processes[i]);
	  }
	  
	  FreeLibrary(hInstance);
	  return ret;
	}
#else
	// TODO_LINUX TODO_MAC equivalent functions...
#endif

//$LB (22/04/2002) : avoid negative value of tickcount
#if SCOL_PLATFORM == SCOL_PLATFORM_LINUX
int _globalTickcount = 0;
#endif


/* lecture du nombre de millisecondes ecoulees */
int SCtickcount(mmachine m)
{
#if SCOL_PLATFORM == SCOL_PLATFORM_WINDOWS
  //$BLG - v5.21: Modif (*2 to <<1)
  return MMpush(m,GetTickCount()<<1);
#elif SCOL_PLATFORM == SCOL_PLATFORM_LINUX
  struct timeval tm;
  int t;

  gettimeofday(&tm,NULL);
  t=(tm.tv_sec*1000)+(tm.tv_usec/1000);
  //$LB (22/04/2002)
  return MMpush(m, SEI2W(t - _globalTickcount));;
#elif SCOL_PLATFORM == SCOL_PLATFORM_APPLE
  TODO
#endif
}

/* lancement d'une machine SCOL */
int SCnewmachine(mmachine m)
{
  int size,rights,k;
  char buf[1024],srights[16],sizestr[16];
  char *p;
  char *q;
    
  size=MMpull(m);
  rights=MMpull(m);
  if ((MMget(m,1)==NIL)||(MMget(m,0)==NIL))
    {
      MMpull(m);
      MMset(m,0,NIL);
      return 0;
    }
  if (k=MBstrtoweb(m)) return k;
  if (size==NIL) size=m->sizetape;
  else size>>=1;
  if (rights==NIL) rights=ScolRights;
  else rights=(rights>>1)&ScolRights;
  if (Firstpack==Cachepack) rights&=~M_RIGHTS;
  SCendcodeRights(srights,rights);
    
  p=MMstartstr(m,MMpull(m)>>1);
  q=MMstartstr(m,MMget(m,0)>>1);
  sprintf(sizestr,"%d",size);
  sprintf(buf,"$%s$%s",q,p);
  k=StartUSM(buf,srights,sizestr);
  MMset(m,0,k*2);
  return 0;
}

int SCnewmachineS(mmachine m)
{
  int size,rights,k;
  char buf[1024],srights[16],sizestr[16];
  char *q;

  size=MMpull(m);
  rights=MMpull(m);
  if (MMget(m,0)==NIL)
  {
	  k=StartUSM(NULL,NULL,NULL);
	  MMset(m,0,k*2);
	  return 0;
  }
  if (size==NIL) size=m->sizetape;
  else size>>=1;
  if (rights==NIL) rights=ScolRights;
  else rights=(rights>>1)&ScolRights;
  if (Firstpack==Cachepack) rights&=~M_RIGHTS;
  SCendcodeRights(srights,rights);
    
  q=MMstartstr(m,MMget(m,0)>>1);
  sprintf(sizestr,"%d",size);
  sprintf(buf,"\"%s\"",q);
  k=StartUSM(buf,srights,sizestr);
  MMset(m,0,k*2);
  return 0;
}

/* definition de la socket life */
int SCsetsocklife(mmachine m)
{
  int c;

  if (socklife!=-1) return 0;
  if ((c=MMget(m,0))==NIL) return 0;
  socklife=SCgetsocket(m,c);
  return 0;
}

/* affichage de la console */
int SCshowconsole(mmachine m)
{
  ScolShowConsole();
  return MMpush(m,0);
}

/* effacement de la console */
int SChideconsole(mmachine m)
{
  ScolHideConsole();
  return MMpush(m,0);
}

/* lancement d'un browser http */
int SCopenbrowserhttp(mmachine m)
{
  if (MMget(m,0)==NIL) return 0;
  StartHTTP(MMstartstr(m,MMget(m,0)>>1),1);
  return 0;
}

/* lancement d'un browser http a partir d'un fichier local */
int SCopenbrowserhttpP(mmachine m)
{
  int ask=1;
  if (MMget(m,0)==NIL) return 0;
  if (ScolSuper) ask=0;
  StartHTTP(MMstartstr(m,MMget(m,0)>>1),ask);
  return 0;
}

 

//$LBDEBUG (11/10/2003)
int SCopenbrowserhttpM(mmachine m)
{
  if (MMget(m,0)==NIL) return 0;
  StartHTTP(MMstartstr(m,MMget(m,0)>>1),0);
  return 0;
}


/* numero de version de la machine scol */
int SCversion(mmachine m)
{
  //$BLG - v5.21: Modif (*2 to <<1)
  return MMpush(m,VERSION_N<<1);
}

/* nom de version de la machine scol */
int SCversionname(mmachine m)
{
  return Mpushstrbloc(m,VERSION_NAME);
}


//$BLG: v4.6a7 - Add
//Last compilation's date for the VM
int SCversiondate(mmachine m)
{
  //$BLG - v5.21: Modif (*2 to <<1)
  return MMpush(m,VERSION_D<<1);
}


int SCsizeress(mmachine m)
{
  int p,n;
  n=0;
  p=MMgetglobal(m,OFFSCRESS);
  while(p!=NIL)
    {
      p>>=1;
      n++;
      p=MMfetch(m,p,OFFLNEXT);
    }
  return n;
}

/* lecture d'une variable ressource */
int SCfindress(mmachine m,char *name,int *prev)
{
  int p,q;

  *prev=NIL;
  p=MMgetglobal(m,OFFSCRESS);
  while(p!=NIL)
    {
      p>>=1;
      q=MMfetch(m,p,OFFLVAL)>>1;
      if ((q!=NIL)&&
	  (!strcmp(name,MMstartstr(m,MMfetch(m,q,0)>>1) )) )
	return p;
      *prev=p;
      p=MMfetch(m,p,OFFLNEXT);
    }
  return NIL;
}

/* lecture d'une variable ressource */
int SCgetress(mmachine m)
{
  int p,q;
  char *name;

  if (MMget(m,0)==NIL) return 0;
  name=MMstartstr(m,MMget(m,0)>>1);
  p=SCfindress(m,name,&q);
  if (p==NIL)
    {
      MMset(m,0,NIL);
      return 0;
    }
  q=MMfetch(m,p,OFFLVAL)>>1;
  MMset(m,0,MMfetch(m,q,1));
  return 0;
}

//$ ER(09/07/01) : rewrite of testLicense to decrypt the parameters from the license number
//				   Initialisation of maxsock, MAXSOCKS, MAXSOCKSE, Debut, Period, MUTUALISE
int testLicense(mmachine m)
{
#ifdef SERVER

//$ LB (30/05/2002) : make the ClubHouse Server accept an unlimited number of connections
// $ LB (31/01/2005) : SCOL_FREE
#if defined (CLUBHOUSE_SERVER) || defined (SCOL_FREE)
	//$BLG - Note: Number of connected clients
	MAXSOCKS = 1000001;
	maxsock = MAXSOCKS;
	//$BLG - v4.6a5: Modified (Number of concurrent running sites on server)
	//MAXSOCKSE=50;
	MAXSOCKSE=1000;
  MMechostr(MSKTRACE, " Scol Server allows for a maximum of %d sockets.\n", maxsock);
#else


	char buf[16];
	char MyBuf[21];
	char *p;
	int i,x,s,o, Param, Id;
	short MyShort[16];
	char PublicKey[21];

	p=MMstartstr(m,MMget(m,0)>>1);
	if (MMsizestr(m,MMget(m,0)>>1)!=20) return -1;
	s=0; o=0;
	for(i=0;i<4;i++)
	{
		strncpy(buf,p+4*i,4);
		buf[4]=0;
    if (!h2i(buf, &x))  //$ FA(16/07/2001)
      return -1;
		s+=x;
		o|=x;
	}
	strncpy(buf,p+16,4);
	strcpy(MyBuf,p);
	MyBuf[20]=0;
    buf[4]=0;
  if (!h2i(buf, &x))    //$ FA(16/07/2001)
    return -1;
	s&=0xffff;

	sprintf( PublicKey, "%s%s%s%s", KEY1, KEY2, KEY3, KEY4 );
	convertKeycod(MyBuf, PublicKey, MyShort );
	Periode=getPeriodeFromKeycode( MyBuf, PublicKey );
	Debut=getDateFromKeycode(MyBuf, PublicKey );
	Param=getParamFromKeycode(MyBuf, PublicKey );
	Id=getIdFromKeycode(MyBuf, PublicKey );
	if (Id < 0) return -1;

/*	convertKeycod(MyBuf, "6360f 859a8 0e836 0cfe9", MyShort );
	Periode=getPeriodeFromKeycode( MyBuf, "6360f859a80e8360cfe9" );
	Debut=getDateFromKeycode(MyBuf, "6360f859a80e8360cfe9" );
	Param=getParamFromKeycode(MyBuf, "6360f859a80e8360cfe9" );*/

	MAXSOCKS=Param>>1;
	maxsock=Param>>1;
	//$BLG - v4.6a5: Modified
	//MAXSOCKSE=50;
	MAXSOCKSE=1000;
	MUTUALISE=(Param&1);
    MMechostr(MSKTRACE, "Your license number allows for a maximum of %d sockets.\n", maxsock);
#endif
#else

//$BLG - v4.6a5: Removed
/*
#ifdef SE_P10
	MAXSOCKS=11;
	MAXSOCKSE=20;
#endif

#ifdef SE_D10
	MAXSOCKS=11;
	MAXSOCKSE=50;
#endif
*/

	maxsock=MAXSOCKS;
#endif
	 return 0;
}

/* ecriture d'une variable ressource */
int SCsetress(mmachine m)
{
  int q,prev,k;
  char buf[32];

	//$BLG - v5.11: Modif
  //MMechostr(MSKRUNTIME,"Debut multiress\n");
  MMechostr(MSKRUNTIME,"_setress ");
  if (MMget(m,1)==NIL)
  {
    MMpull(m);
    return 0;
  }
  //$BLG - v5.21: Add
  MMechostr(MSKRUNTIME, "%s\n", MMstartstr(m,MMget(m,1)>>1));
  

  if (MMget(m,0)==NIL)
  {
    if (!strcmp(MMstartstr(m,MMget(m,1)>>1),"License")) flagLicense=1;
    q=SCfindress(m,MMstartstr(m,MMget(m,1)>>1),&prev);
    if (q!=NIL)
		{
		  if (prev==NIL) MMsetglobal(m,OFFSCRESS,MMfetch(m,q,OFFLNEXT));
		  else MMstore(m,prev,OFFLNEXT,MMfetch(m,q,OFFLNEXT));
		}
    MMpull(m);
    MMset(m,0,NIL);
    return 0;
  }
  if (!strcmp(MMstartstr(m,MMget(m,1)>>1),"License"))
  {
    if (testLicense(m))
		{
		  MMechostr(MSKRUNTIME,">>>bad license number<<<\n");
		  return MERRTYP;
		}
    if ((!ScolSuper)&&(!flagLicense))
		{
		  strncpy(buf,MMstartstr(m,MMget(m,0)>>1),16);
		  buf[16]=0;
		  SPrefinePack(Cachepack,buf);
		  MMechostr(1," new cache : %s\n",Cachepack->path);
		}
    flagLicense=1;
  }
  q=SCfindress(m,MMstartstr(m,MMget(m,1)>>1),&prev);
  if (q!=NIL) MMstore(m,MMfetch(m,q,OFFLVAL)>>1,1,MMget(m,0));
  else
  {
    if (MMpush(m,MMget(m,1))) return MERRMEM;
    if (MMpush(m,MMget(m,1))) return MERRMEM;
    //$BLG - v5.21: Modif (*2 to <<1)
    if (MMpush(m,2<<1)) return MERRMEM;
    if (k=MBdeftab(m)) return k;
    if (MMpush(m,MMgetglobal(m,OFFSCRESS))) return MERRMEM;
    //$BLG - v5.21: Modif (*2 to <<1)
    if (MMpush(m,2<<1)) return MERRMEM;
    if (k=MBdeftab(m)) return k;
    MMsetglobal(m,OFFSCRESS,MMpull(m));
  }
  MMset(m,1,MMget(m,0));
  MMpull(m);
  MMechostr(MSKRUNTIME,"_setress complete\n");
  return 0;
}


// File reading
// Used to read .ini config files. Now reading files from Common App Data directory/ScolRoot/. if not in stand alone mode
int NSCloadfile(mmachine m, char *name)
{
	FILE *f;
	char buf[1025];
	int i, n, k, p;

	//$BLG - v5.2.06: Modif
	//strcpy(buf, cappdatapath2);
  //$BB add stand alone mode
  strcpy(buf, bStandAlone ? execpath2 : mydcmtspath2);
	strcat(buf, name);

	f = fopen(buf, "rb");
	if (f == NULL) 
		return MMpush(m, NIL);

	p = 0;
	do
	{
		n = fread(buf, 1, 1024, f);
		buf[n] = 0;
		if (k = Mpushstrbloc(m, buf)) 
			return k;
		p++;
	} while (n == 1024);

	for (i = 1; i < p; i++) if (k = MBstrcat(m)) return k;
	
	fclose(f);
	
	return 0;
}


// File saving
// Used to save .ini config files. Now storing files under Common App Data directory/ScolRoot/. if not in stand alone mode
int NSCsavefile(mmachine m, char *name)
{
	FILE *f;
	int p;
	char buf[1024];

	if (!ScolSuper) 
		return 0;
	
	p = MMget(m, 0)>>1;
	if (p == NIL) 
		return 0;

	//$BLG - v5.2.06: Modif
	//strcpy(buf, cappdatapath2);
  //$BB add stand alone mode
  strcpy(buf, bStandAlone ? execpath2 : mydcmtspath2);
	//strcpy(buf, mydcmtspath2);
	strcat(buf, name);
	f = fopen(buf, "wb");
	if (f == NULL) 
		return 0;
	
	fwrite(MMstartstr(m, p), 1, MMsizestr(m, p), f);
	fclose(f);
	
	return 0;
}


/* donne a un canal tous les objets d'un autre */
int SCchangeChn(mmachine m)
{
	int newchn,oldchn;

	newchn=MMpull(m);
	oldchn=MMget(m,0);
	MMset(m,0,newchn);
	if (newchn==NIL) return 0;
	return OBJchgchannel(m,oldchn,newchn);
}


//$BLG - v5.2.06: Add
int SCcheckressini(void)
{
	FILE *f;
	char buf[MAX_PATH];
	char dflt[] = "Origin Scol_\nDefaultLanguage french\nlocalIPindex 0\nAutodetectProxy Yes\nSocksVer 5\nSocks5Authentication no\nvideocapture 0";
	
	strcpy(buf, mydcmtspath2);
	strcat(buf, "usmress.ini");
	
	//MessageBox(NULL,buf,"SCcheckressini",MB_OK);
	f = fopen(buf, "rb");
	if (f == NULL) 
	{
		//MessageBox(NULL,"not found","SCcheckressini",MB_OK);
		f = fopen(buf, "wb");
		//if (f == NULL)
			//MessageBox(NULL,"not created","SCcheckressini",MB_OK);
		if (f == NULL)
			return 0;
		
		fwrite (dflt, 1, strlen(dflt), f);
		fclose(f);
		//MessageBox(NULL,"created","SCcheckressini",MB_OK);
	}
	else
	{
		//MessageBox(NULL,"found","SCcheckressini",MB_OK);
		fclose(f);
	}
	
	return 1;
}

/* lecture du fichier d'initialisation des ressources */
int SCloadressini(mmachine m)
{
	//$BLG - v5.2.06: Add
	int ret;
	//MessageBox(NULL,"in","SCloadressini",MB_OK);
	ret = SCcheckressini();
	if (!ret)
		MMechostr(0, "Error: UsmRess.ini file not found and not initialiazed\n");
	//if (!ret)
		//MessageBox(NULL,"err","SCloadressini",MB_OK);	
	//MessageBox(NULL,"out","SCloadressini",MB_OK);	
	
	return NSCloadfile(m,"usmress.ini");
}

/* sauvegarde du fichier d'initialisation des ressources */
int SCsaveressini(mmachine m)
{
	return NSCsavefile(m,"usmress.ini");
}


//$BLG - v5.2.06: Add
int SCcheckuserini(void)
{
	FILE *f;
	char buf[MAX_PATH];
	char dflt[] = "# Scol Configuration: User settings\n\n# DO NOT MODIFY !!!!!!!!!\n\nport 1200\n#porthttp 80\nmemorymax 512\n\nlog no\necho 0\n#logwin yes\n#supervisor debug\n#runtime-checks on\n\n#forcedIP 1.2.3.4\n#refreshIP no\n\n3dhardware OpenGL OpenGL\n";
	
	strcpy(buf, mydcmtspath2);
	strcat(buf, "usmuser.ini");
	
	//MessageBox(NULL,buf,"SCcheckuserini",MB_OK);	
	f = fopen(buf, "rb");
	if (f == NULL) 
	{
		//MessageBox(NULL,"not found","SCcheckuserini",MB_OK);	
		f = fopen(buf, "wb");
		//if (f == NULL)
			//MessageBox(NULL,"not created","SCcheckuserini",MB_OK);	
		if (f == NULL)
			return 0;
		
		fwrite (dflt, 1, strlen(dflt), f);
		fclose(f);
		//MessageBox(NULL,"created","SCcheckuserini",MB_OK);	
	}
	else
	{
		//MessageBox(NULL,"found","SCcheckuserini",MB_OK);	
		fclose(f);
	}
	
	return 1;
}


/* lecture du fichier usm.ini */
int SCloadusmini(mmachine m)
{
	int q,s;
	char sign[32];
	
  //$BB add stand alone mode
  if (!bStandAlone)
  {
	  //$BLG - v5.2.06: Add
	  int ret;
	  //MessageBox(NULL,"in","SCloadusmini",MB_OK);	
	  ret = SCcheckuserini();
	  if (!ret)
		  MMechostr(0, "Error: UsmUser.ini file not found and not initialiazed\n");
	  //if (!ret)
		  //MessageBox(NULL,"err","SCloadusmini",MB_OK);	
	  //MessageBox(NULL,"out","SCloadusmini",MB_OK);	

	  //$BLG - v5.2.06: Modif
	  //NSCloadfile(m,"usm.ini");
	  NSCloadfile(m,"usmuser.ini");
  }
  else
  {
    NSCloadfile(m,"usm.ini");
  }

	q=MMpull(m);
	s=MMget(m,0);
	MMset(m,0,q);
	if ((q==NIL)||(ScolSuper)) return 0;
	
	strcpy(sign,"#");
	SCincSignInit();
	SCincSign(MMstartstr(m,q>>1),MMsizestr(m,q>>1),sign+1);

	if ((s==NIL)||(strcmp(MMstartstr(m,s>>1),sign))) MMset(m,0,NIL);
	return 0;
}


/* sauvegarde du fichier usm.ini */
int SCsaveusmini(mmachine m)
{ 
  //$BB add stand alone mode
  if (int k=NSCsavefile(m, bStandAlone ? ((char*)"usm.ini") : ((char*)"usmuser.ini")))
    return k;

  SPdesallocpackdir();
  LoadUsmIni("");
  SPinitpack();
  return 0;
}

/* transfer d'un fichier */
int SCcopyFile(mmachine m)
{
	int p,q,n;
	FILE *r,*w;
	char buf[1024];
	char *c;

	p=MMpull(m)>>1;
	q=MMpull(m)>>1;
	if ((p==NIL)||(q==NIL)||(!ScolSuper)) return MMpush(m,NIL);
	c=MMstartstr(m,p);
	if ((c[0]=='/')||(c[0]=='\\')||(c[0]=='.')||(c[0]=='/')||(c[1]==':'))
		return MMpush(m,NIL);
	r=fopen(MMstartstr(m,q),"rb");
	if (r==NULL) return MMpush(m,NIL);
	w=fopen(c,"wb");
	if (w)
	{
		do
		{
			n=fread(buf,1,1024,r);
			if (n>0) fwrite(buf, 1, n, w);
		}
		while (n==1024);
		fclose(w);
	}
	else
	{
		fclose(r);
		return MMpush(m,NIL);
	}

	fclose(r);
	return MMpush(m,0);
}

/* definition du proxy */
int SCdefineproxy(mmachine m)
{
	MMpull(m);
	MMpull(m);
	MMpull(m);
	return MMpush(m,0);
}

int SCdefinesocks2(char *socks, char *mask)
{
	char *port;

	if (mask==NULL) mask="255.255.255.0";
	if ((socks==NULL)||(!stricmp(socks,"no"))) SCKsetproxy(NULL,"1080",mask);
	else
	{
		if (port=strstr(socks,":"))
		{
			*port=0;
			SCKsetproxy(socks,port+1,mask);
			*port=':';
		}
		else SCKsetproxy(socks,"1080",mask);
	}
	return 0;
}



/* definition du proxy socks*/
int SCdefinesocks(mmachine m)
{
	int msk,p;

	msk=MMpull(m)>>1;
	p=MMpull(m)>>1;
	SCdefinesocks2(p==NIL?NULL:MMstartstr(m,p),msk==NIL?NULL:MMstartstr(m,msk));
	return MMpush(m,0);
}




/************************************************/
/* $ LB : scol v 4                              */
/*                                              */
/* int SCdefinesocksVersion (mmachine m)        */
/*                                              */
/* precise the protocol version of socks        */
/************************************************/
int SCdefinesocksVersion (mmachine m)
{
int verPtr, ver;
char* verStr;

	// get string pointer
	verPtr = MMpull(m)>>1;
	if (verPtr == NIL)
		ver = 4;
	else
	{
		// get soscks version parameter
		verStr = MMstartstr (m,verPtr);
		if (!strcmp (verStr, "5"))
			ver = 5;
		else ver = 4;
	}

	// update the version value
	SOCKSsetVersion (ver);
	return MMpush (m,0);
}



/*************************************************/
/* $ LB : scol v 4                               */
/*                                               */
/* int SCdefinesocksAuthentication (mmachine m)  */
/*                                               */
/* precise if socks need authentication protocol */
/*************************************************/
int SCdefinesocksAuthentication (mmachine m)
{
int authPtr, auth;
char* authStr;

	// get string pointer
	authPtr = MMpull(m)>>1;
	if (authPtr == NIL)
		auth = 0;
	else
	{
		// get socks Authentication parameter
		authStr = MMstartstr (m, authPtr);
		if (!strnicmp (authStr, "yes", 3))
			auth = 1;
		else auth = 0;
	}

	// update the authentication value
	SOCKSsetAuthentication (auth);
	return MMpush (m,0);
}




/* proxy par defaut */
int SCdefaultproxy(mmachine m)
{
	int k;

	if (k=Mpushstrbloc(m,autoHTTPproxy)) return k;
	if (k=Mpushstrbloc(m,autoSOCKSproxy)) return k;
	if (k=Mpushstrbloc(m,"255.255.255.0")) return k;
	//$BLG - v5.21: Modif (*2 to <<1)
	if (MMpush(m,3<<1)) return MERRMEM;
	return MBdeftab(m);
}


/* ajout d'un chemin à la partition en cours */
int SCreduceCapacity(mmachine m)
{
  int p;

  p=MMget(m,0)>>1;
  if ((p<0)||(p>maxsock))
  {
	  MMset(m,0,NIL);
	  return 0;
  }
  maxsock=p;
  return 0;
}

/* ----------------------- */
/* gestion des executables */
/* ----------------------- */
sysexe SysExeHdList=NULL;
sysexe SysExeTlList=NULL;

/* initialise la liste des exe */
int SCexeInit()
{
	SysExeHdList=NULL;
	SysExeTlList=NULL;
	return 0;
}

/* libère la liste des exe */
int SCexeEnd()
{
	sysexe p;
	while(SysExeHdList)
	{
		p=SysExeHdList->next;
		free(SysExeHdList);
		SysExeHdList=p;
	}
	SysExeTlList=NULL;
	return 0;
}

/* recherche du path d'un exe en fonction d'une catégorie et d'un alias */
sysexe SCexeSearch(char *categ, char *name)
{
	sysexe p;
	p=SysExeHdList;
	while(p)
	{
		if ((categ==NULL || !strcmp(p->categ,categ)) && !strcmp(p->name,name)) return p;
		p=p->next;
	}
	return NULL;
}

/* ajout d'un exe dans la liste (pos=0 en tete, pos=1 en queue) */
int SCexeAdd(int pos, char *categ, char *name, char *path)
{
	sysexe p;
	if (strlen(categ)>=128) return -1;
	if (strlen(name)>=128) return -1;
	if (strlen(path)>=1024) return -1;
	if (SCexeSearch(categ,name)!=NULL) return 0;
	p=(sysexe)malloc(sizeof(struct SysExe));
	if (p==NULL) return -1;
	strcpy(p->categ,categ);
	strcpy(p->name,name);
	strcpy(p->path,path);
	if (pos==0) {
		if (SysExeTlList==NULL)
			SysExeTlList=p;
		p->prev=NULL;
		p->next=SysExeHdList;
		SysExeHdList=p;
	}
	else {
		if (SysExeHdList==NULL)
			SysExeHdList=p;
		p->prev=SysExeTlList;
		p->next=NULL;
		if (SysExeTlList==NULL)
			SysExeTlList=p;
		else {
			SysExeTlList->next=p;
			SysExeTlList=p;
		}
	}
//	MMechostr(MSKDEBUG,"pos=%d categ=<%s> name=<%s> path=<%s>\n",pos,categ,name,path);
	return 0;
}

/* suppression d'un exe dans la liste */
int SCexeDel(char *categ, char *name)
{
	sysexe p;
	if (strlen(categ)>=128) return -1;
	if (strlen(name)>=128) return -1;
	if ((p=SCexeSearch(categ,name))==NULL) return 0;
	if (p->prev)
		p->prev->next=p->next;
	else
		SysExeHdList=p->next;
	if (p->next)
		p->next->prev=p->prev;
	else
		SysExeTlList=p->prev;
	free(p);
//	MMechostr(MSKDEBUG,"categ=<%s> name=<%s>\n",categ,name);
	return 0;
}

/* lancement d'un exe : paramètres <categorie> <alias> <arguments> */
int SCstartExe(mmachine m)
{
	int p,q,r;
	sysexe e;
	char *categ,*path,*param;

	r=MMpull(m)>>1;
	q=MMpull(m)>>1;
	p=MMget(m,0)>>1;
	if ((q==NIL)||(Firstpack==Cachepack)) return 0;
	param=NULL;
	categ=NULL;
	if (r!=NIL) param=MMstartstr(m,r);
	if (p!=NIL) categ=MMstartstr(m,p);
	e=SCexeSearch(categ,MMstartstr(m,q));
	if (e) {
		path=e->path;
		if (path) StartExe(path,param);
	}
	return 0;
}

/* reconstruction de la liste des exe */
int SCrefreshExe(mmachine m)
{
	if (Firstpack==Cachepack) return MMpush(m,0);
	SCexeEnd();
	SCexeInit();
	RefreshExe();

	return MMpush(m,0);
}

/* liste des alias [S r1] d'une catégorie */
int SCgetExe(mmachine m)
{
	int p;
	char categ[128];
	sysexe e;
	int n,i,k,lg,l,s;

	p=MMpull(m)>>1;
	if (Firstpack==Cachepack) return MMpush(m,NIL);
	categ[0]=0;
	if (p!=NIL)
	{
		if (strlen(MMstartstr(m,p))>=sizeof(categ)) return MMpush(m,NIL);
		strcpy(categ,MMstartstr(m,p));
	}

	n=0;
	e=SysExeHdList;
	while(e)
	{
		if (categ==NULL || !strcmp(e->categ,categ))
		{
			lg=strlen(e->name);
			if (lg<32) lg=32;
			l=(lg+4)>>2;
			s=MMmallocCLR(m,l+1,TYPEBUF); if (s==NIL) return MERRMEM;
			strcpy(MMstartstr(m,s),e->name);
			MMsetsizestr(m,s,strlen(e->name));
			//$BLG - v5.21: Modif (*2 to <<1)
			//if (MMpush(m,s+s+1)) return MERRMEM;
			if (MMpush(m,(s<<1)+1)) return MERRMEM;
			n++;
		}
		e=e->next;
	}

	if (MMpush(m,NIL)) return MERRMEM;
	for (i=0;i<n;i++) {
		//$BLG - v5.21: Modif (*2 to <<1)
		if (MMpush(m,2<<1)) return MERRMEM;
		if ((k=MBdeftab(m))) return k;
	}
	return 0;
}

/* ajout d'un exe : paramètres <categorie> <fichier (type P)> */
int SCaddExe(mmachine m)
{
	int p,q;

	p=MMpull(m)>>1;
	q=MMpull(m)>>1;
	if (Firstpack==Cachepack) return MMpush(m,NIL);
	if (p==NIL || q==NIL) return MMpush(m,NIL);
	if (AddExe(MMstartstr(m,q),MMstartstr(m,p)))
		return MMpush(m,NIL);
	return MMpush(m,0);
}

/* suppression d'un exe : paramètres <categorie> <alias> */
int SCdelExe(mmachine m)
{
	int p,q;

	p=MMpull(m)>>1;
	q=MMpull(m)>>1;
	if (Firstpack==Cachepack) return MMpush(m,NIL);
	if (p==NIL || q==NIL) return MMpush(m,NIL);
	if (DelExe(MMstartstr(m,q),MMstartstr(m,p)))
		return MMpush(m,NIL);
	return MMpush(m,0);
}

/* mixage 8 bits :
en entree : [[I S] r1] I : liste [volume echantillon] + volume principal,
les volumes sont par rapport à 256 (256 : aucune amplification)
en retour : [S I] : echantillon mixé, nombre d'échantillons saturés */
int SCmix8(mmachine m)
{
	int vol,p,q,r,v,i,k,len,s;
	int *buf;
	char *src;

	vol=MMpull(m)>>1;
	if (vol<0) vol=0;

	p=MMpull(m)>>1;
	if (p==NIL) return MMpush(m,NIL);
	q=MMfetch(m,p,0)>>1;
	if (q==NIL) return MMpush(m,NIL);
	r=MMfetch(m,q,1)>>1;
	if (r==NIL) return MMpush(m,NIL);
	len=MMsizestr(m,r);
	if (len==0) return MMpush(m,NIL);
	buf=(int*)malloc(len*sizeof(int));
	if (buf==NULL) return MMpush(m,NIL);
	for(i=0;i<len;i++) buf[i]=0;
	do
	{
		q=MMfetch(m,p,0)>>1;
		if (q!=NIL)
		{
			v=MMfetch(m,q,0)>>1;
			if (v<0) v=0;
			r=MMfetch(m,q,1)>>1;
			if ((r!=NIL)&&(MMsizestr(m,r)==len))
			{
				src=MMstartstr(m,r);
				for(i=0;i<len;i++)
				{
					k=((*(src++))&255)-128;
					buf[i]+=(k*v)>>8;
				}
			}
		}
		p=MMfetch(m,p,1)>>1;
	} while(p!=NIL);
	s=MMmalloc(m,((len+4)>>2)+1,TYPEBUF); if (s==NIL) return MERRMEM;
	MMsetsizestr(m,s,len);
	src=MMstartstr(m,s);
	src[len]=0;
	p=0;
	for(i=0;i<len;i++)
	{
		k=((buf[i]*vol)>>8)+128;
		if (k>255) {k=255; p++;}
		if (k<0) {k=0; p++;}
		*(src++)=k;
	}
	free(buf);
	//$BLG - v5.21: Modif (*2 to <<1)
	if (MMpush(m,(s<<1)+1)) return MERRMEM;
	if (MMpush(m,p<<1)) return MERRMEM;
	if (MMpush(m,2<<1)) return MERRMEM;
	
	return MBdeftab(m);
}

/* mixage 16 bits :
en entree : [[I S] r1] I : liste [volume echantillon] + volume principal,
les volumes sont par rapport à 256 (256 : aucune amplification)
en retour : [S I] : echantillon mixé, nombre d'échantillons saturés */
int SCmix16(mmachine m)
{
	int vol,p,q,r,v,i,k,len,s;
	int *buf;
	short *src;

	vol=MMpull(m)>>1;
	if (vol<0) vol=0;

	p=MMpull(m)>>1;
	if (p==NIL) return MMpush(m,NIL);
	q=MMfetch(m,p,0)>>1;
	if (q==NIL) return MMpush(m,NIL);
	r=MMfetch(m,q,1)>>1;
	if (r==NIL) return MMpush(m,NIL);
	len=MMsizestr(m,r)>>1;
	if (len==0) return MMpush(m,NIL);
	buf=(int*)malloc(len*sizeof(int));
	if (buf==NULL) return MMpush(m,NIL);
	for(i=0;i<len;i++) buf[i]=0;
	do
	{
		q=MMfetch(m,p,0)>>1;
		if (q!=NIL)
		{
			v=MMfetch(m,q,0)>>1;
			if (v<0) v=0;
			r=MMfetch(m,q,1)>>1;
			if ((r!=NIL)&&(MMsizestr(m,r)==(len*2)))
			{
				src=(short*)MMstartstr(m,r);
				for(i=0;i<len;i++)
				{
#if VERSION_MAC
					k=((*((char*)src))&255)+((*(((char*)src)+1))<<8);
#else
					k=*(src++);
#endif
					buf[i]+=(k*v)>>8;
				}
			}
		}
		p=MMfetch(m,p,1)>>1;
	} while(p!=NIL);
	s=MMmalloc(m,((len*2+4)>>2)+1,TYPEBUF); if (s==NIL) return MERRMEM;
	MMsetsizestr(m,s,len*2);
	src=(short*)MMstartstr(m,s);
	src[len*2]=0;
	p=0;
	for(i=0;i<len;i++)
	{
		k=(buf[i]*vol)>>8;
		if (k>32767) {k=32767; p++;}
		if (k<-32768) {k=-32768; p++;}
		*(src++)=k;
	}
	free(buf);
	//$BLG - v5.21: Modif (*2 to <<1)
	if (MMpush(m,(s<<1)+1)) return MERRMEM;
	if (MMpush(m,p<<1)) return MERRMEM;
	if (MMpush(m,2<<1)) return MERRMEM;
	
	return MBdeftab(m);
}
