/*     
      SCOL SYSTEM . Magma 1.0 . 1996 . Sylvain HUET

         scolsys.h : routines de gestion de package de scol
*/
//
// Modification history:
//
//$ ER(09/07/2001): Add testDureeLicense function to compare current date to utilisation period
//				    turn SERVERM calls to SERVER && MUTUALISE in SCsendCapacity and SCchecksign functions
//$ FA(06/08/2001): Add the SPGetModifDate() function that returns the date (as a tuple) when a file 
//                  was last modified
//
//$ LB (30/05/2002) : defined an empty SCsendCapacity for the ClubHouse server
//


#include "include/vscol.h"
#ifdef VERSION_WIN
#include <windows.h>
#endif
#include <stdio.h>
#include <string.h>
#ifdef VERSION_WIN
#include <io.h>
#include <direct.h>
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>
#endif


#include "mmemory.h"
//#include "mbytec.h"
#include "mbytec2.h"     // refers to MBdeftab()
//#include "analyzer.h"
#include "listlab.h"
#include "loadpak.h"     // refers to PKloader() and PKaddpak() 
#include "scol.h"
#include "scolsign.h"
#include "scolpack.h"
#include "fifo.h"        // refers to SCsendpile()

/* activation du cache */
int SCcacheActivate(mmachine m)
{
  MMechostr(MSKDEBUG,"Cache Activation\n");
  Firstpack=Cachepack;
  return MMpush(m,0);
}

/* ajout d'un chemin à la partition en cours */
int SPrefinePartition(mmachine m)
{
  int p,k;
  p=MMget(m,0)>>1;
  if ((p==NIL)||(Cachepack==Firstpack)) return 0;
  k=SPrefinePack(Firstpack,MMstartstr(m,p));
  return 0;
}

/* ajout d'un chemin à la n-ieme partition */
int SPrefineNthPartition(mmachine m)
{
  int p,k,n;
  packdir f;

  n=MMpull(m)>>1;
  p=MMget(m,0)>>1;
  if ((n<0)||(p==NIL)) return 0;
  f=Firstpack;
  while((f)&&(n))
  {
	  f=f->next;
	  n--;
  }
  k=SPrefinePack(f,MMstartstr(m,p));
  return 0;
}

/* verification de la presence d'un package
  en 0 : nom complet
 -> en 0 : 1 si present, 0 si absent */
int SPcheckpack(mmachine m)
{
  int p,k;
  char name[SIZESIGN];
  char buf[SIZESIGN];

  p=MMget(m,0)>>1;
  if (p==NIL) return 0;
  k=SPgettypsign(MMstartstr(m,p));
  if ((k==TYPESNONE)&&((ScolRights&R_RIGHTS)==0))
  {
      MMset(m,0,NIL);
      return 0;
  }
  else if (k==TYPESENV)
  {
      SPgetname(MMstartstr(m,p),name);
	  p=MMfetch(m,MMgetglobal(m,OFFSCCUR)>>1,OFFCHANENV);
      if (MMpush(m,p)) return MERRMEM;
      if (k=SCsignenv(m)) return k;
      sprintf(name,"%s$%s",name,MMstartstr(m,MMpull(m)>>1));
	  p=MMget(m,0)>>1;
	  if (strcmp(name,MMstartstr(m,p)))
	  {
		  MMset(m,0,NIL);
		  return 0;
	  }
  }
  else if (k==TYPESMACH)
  {
      SPgetname(MMstartstr(m,p),name);
	  if (k=SCsignmachine(m)) return k;
      sprintf(name,"%s&%s",name,MMstartstr(m,MMpull(m)>>1));
	  p=MMget(m,0)>>1;
	  if (strcmp(name,MMstartstr(m,p)))
	  {
		  MMset(m,0,NIL);
		  return 0;
	  }
  }
  else if (k==TYPESCOOKIES)
  {
      SPgetname(MMstartstr(m,p),name);
      sprintf(buf,"%s;%s",name,cookies);
	  MMechostr(MSKDEBUG,"cookies test : %s - %s\n",buf,MMstartstr(m,p));
	  if (strcmp(buf,MMstartstr(m,p)))
	  {
		  MMset(m,0,NIL);
		  return 0;
	  }
  }
  if (SPfindfile(Firstpack,MMstartstr(m,p),NULL,name)==-1)
    {
      MMset(m,0,NIL);
      return 0;
    }
  MMpull(m);
  return Mpushstrbloc(m,name);
}

/* definition du suffixe cookies
  en 0 : nom cookies 
  -> inchange */
int SPsetCookies(mmachine m)
{
  int p;
  char *c;

  if (cookies[0]) return 0;
  p=MMget(m,0)>>1;
  if (p==NIL) return 0;
  c=MMstartstr(m,p);
  if ((*c)&&(strlen(c)<63)) strcpy(cookies,c);
  return 0;
}

/* stockage d'un package depuis la bande memoire
  en 0 : nom complet   1 : string package
 -> 0 : 0 si succes, -1 sinon */
int SPstorepack(mmachine m)
{
  int p,typs,n,k;
  char name[SIZESIGN],sign[SIZESIGN],sign2[SIZESIGN];
  FILE *g;

  p=MMpull(m)>>1;
  if (p==NIL)
    {
      MMset(m,0,-1*2);
      return 0;
    }
  strcpy(sign,MMstartstr(m,p));
  SPgetname(sign,name);
  typs=SPgettypsign(sign);
  if ((typs==TYPESNONE)&&((ScolRights&W_RIGHTS)==0))
  {
      MMset(m,0,-1*2);
      return 0;
  }
  if ((typs==TYPESLOGIC)&&((ScolRights&K_RIGHTS)==0))
  {
      MMset(m,0,-1*2);
      return 0;
  }
  
  p=MMget(m,0)>>1;
  if ((p==NIL)||(typs<0))
    {
      MMset(m,0,-1*2);
      return 0;
    }

  /* verification de la signature */
  n=MMsizestr(m,p);
  SCsign(m,MMstartstr(m,p),n,name,typs,sign2);
  if (strcmp(sign,sign2))
    {
      MMset(m,0,-1*2);
      return 0;
    }
  p=MMget(m,0)>>1;

  k=SPaddfile(Firstpack,sign2,n,name);
  if ((k)||((g=fopen(name,"wb"))==NULL))
    {
      MMset(m,0,-1*2);
      if ((k!=-1)&&(Firstpack==Cachepack))
	  {
		  MMechostr(MSKRUNTIME,"file : %s\n",name);
		  return MERRFILE;
	  }
	  return 0;
    }
  fwrite(MMstartstr(m,p),1,n,g);
  fclose(g);

  MMset(m,0,0);
  return 0;
}

/* préparation d'un fichier modifiable
 en 0 : nom complet
 -> 0 : type W si succes, NIL sinon */
int SPgetmodifypack(mmachine m)
{
  int p,typs,k;
  char name[SIZESIGN],sign[SIZESIGN],sign2[SIZESIGN];

  p=MMget(m,0)>>1;
  if (p==NIL) return 0;
  strcpy(sign,MMstartstr(m,p));
  SPgetname(sign,name);
  typs=SPgettypsign(sign);
  if ((typs==TYPESNONE)&&((ScolRights&W_RIGHTS)==0))
  {
      MMset(m,0,NIL);
      return 0;
  }
  if (typs!=TYPESLOGIC)
  {
	  /* verification de la signature */
	SCsign(m,NULL,0,name,typs,sign2);
	if (strcmp(sign,sign2))
	{
      MMset(m,0,NIL);
      return 0;
    }
  }
  k=SPaddfile(Firstpack,sign,0,name);
  MMpull(m);
  if (k<-1)
  {
	  MMechostr(MSKRUNTIME,"file : %s\n",name);
	  return MERRFILE;
  }
  if (k) return MMpush(m,NIL);
  return Mpushstrbloc(m,name);
}

/* creation d'un package
  en 0 : nom W   1 : string package
 -> 0 : 0 si succes, -1 sinon */
int SPcreatepack(mmachine m)
{
  int p,n;
  char *name;
  FILE *g;

  p=MMpull(m)>>1;
  if (p==NIL)
  {
	  MMset(m,0,-1*2);
	  return 0;
  }
  name=MMstartstr(m,p);
  
  p=MMget(m,0)>>1;
  if (p==NIL)
    {
      MMset(m,0,-1*2);
      return 0;
    }
  n=MMsizestr(m,p);
  if ((g=fopen(name,"wb"))==NULL)
    {
      MMset(m,0,-1*2);
      if (Firstpack==Cachepack)
	  {
		  MMechostr(MSKRUNTIME,"file : %s\n",name);
		  return MERRFILE;
	  }
	  return 0;
    }
  fwrite(MMstartstr(m,p),1,n,g);
  fclose(g);

  MMset(m,0,0);
  return 0;
}

/* append d'un package
  en 0 : nom W   1 : string package
 -> 0 : 0 si succes, -1 sinon */
int SPappendpack(mmachine m)
{
  int p,n;
  char *name;
  FILE *g;

  p=MMpull(m)>>1;
  if (p==NIL)
  {
	  MMset(m,0,-1*2);
	  return 0;
  }
  name=MMstartstr(m,p);
  
  p=MMget(m,0)>>1;
  if (p==NIL)
    {
      MMset(m,0,-1*2);
      return 0;
    }
  n=MMsizestr(m,p);
  if ((g=fopen(name,"a+b"))==NULL)
    {
      MMset(m,0,-1*2);
      if (Firstpack==Cachepack)
	  {
		  MMechostr(MSKRUNTIME,"file : %s\n",name);
		  return MERRFILE;
	  }
	  return 0;
    }
  fwrite(MMstartstr(m,p),1,n,g);
  fclose(g);

  MMset(m,0,0);
  return 0;
}

/* conversion W -> P */
int SPWtoP(mmachine m)
{
	return 0;
}

/* chargement d'un package en memoire (sans traitement particulier)
  en 0 : chemin complet
 -> en 0 : chaine contenant le package (nil si absent) */
#ifdef VERSION_WIN
int SPgetpack(mmachine m)
{
  int p,l,s,size;
  HANDLE g;
  char *ch;
  int res;

  p=MMget(m,0)>>1;
  if ((p==NIL)||((g=CreateFile(MMstartstr(m,p),GENERIC_READ,FILE_SHARE_READ,NULL,
	  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL))==INVALID_HANDLE_VALUE))
    {
      MMset(m,0,NIL);
      return 0;
    }
  size=GetFileSize(g,NULL);

  l=(size+4)>>2;
  s=MMmalloc(m,l+1,TYPEBUF); if (s==NIL) return MERRMEM;
  MMsetsizestr(m,s,size);
  ch=MMstartstr(m,s);
  ReadFile(g,ch,size,&res,NULL);
  CloseHandle(g);
  ch[size]=0;

  MMset(m,0,s+s+1);
  return 0;
}
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
int SPgetpack(mmachine m)
{
  int p,k,l,s,size;
  char buf[1024];
  FILE *g;
  char *ch;

  p=MMget(m,0)>>1;
  if ((p==NIL)||((g=fopen(MMstartstr(m,p),"rb"))==NULL))
    {
      MMset(m,0,NIL);
      return 0;
    }
  size=0;
  do
    {
      k=fread(buf,1,1024,g);
      size+=k;
    }
  while(k==1024);
  fseek(g,0,SEEK_SET);

  l=(size+4)>>2;
  s=MMmalloc(m,l+1,TYPEBUF); if (s==NIL) return MERRMEM;
  MMsetsizestr(m,s,size);
  ch=MMstartstr(m,s);
  fread(ch,1,size,g);
  fclose(g);
  ch[size]=0;

  MMset(m,0,s+s+1);
  return 0;
}
#endif

#ifdef VERSION_MAC
  int SPgetpack(mmachine m) TODO
#endif

/* destruction d'un fichier */
int SPdeletepack(mmachine m)
{
  char buf1[SIZESIGN];
  char buf2[SIZESIGN];
  int q;
  packdir p;

  q=MMget(m,0)>>1;
  if ((q==NIL)||(Firstpack==Cachepack)||(MMsizestr(m,q)>=SIZESIGN)) return 0;
  strcpy(buf1,MMstartstr(m,q));
  SPslashtoback(buf1);
  SPkillmaj(buf1);

  p=Firstpack; /* cherche le fichier dans les partitions en ecriture */
  while(p)
    {
      if ((p->quota!=-1)&&(p->path))
        {
		  strcpy(buf2,p->path);
		  SPslashtoback(buf2);
		  SPkillmaj(buf2);
//		  MMechostr(1,"compare %s\n        %s\n",buf1,buf2);
		  if (!strncmp(buf1,buf2,strlen(buf2)))
		  {
#ifdef VERSION_WIN
			  DeleteFile(MMstartstr(m,q));
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
			  unlink(MMstartstr(m,q));
#endif
#ifdef VERSION_MAC
			  TODO
#endif
			  MMset(m,0,NIL);
			  return 0;
		  }
        }
      p=p->next;
    }
  return 0;
}

/* chargement (et compilation) d'un package sur le canal courant 
 le nom du package est dans la pile */
int SPloadpakbis(mmachine m)
{
  int k,t;
  char path[SIZESIGN];

  t=MMgetglobal(m,OFFSCCUR);  /* empiler l'environnement courant */
  if (t==NIL) return MERRTYP;
  t=MMfetch(m,t>>1,OFFCHANENV);
  if (MMpush(m,t)) return MERRMEM;

  t=MMget(m,1);
  if (t==NIL) return 0;

  if (SPfindfile(Firstpack,MMstartstr(m,t>>1),NULL,path))
    {
      MMechostr(0,"%s : not found\n",MMstartstr(m,t>>1));
      return MERRNF;
    }
  if (k=PKloader(m,path,MMstartstr(m,t>>1))) return k;  /* package magma */

  t=MMgetglobal(m,OFFSCCUR);  /* stocker le nouvel environnement */
  MMstore(m,t>>1,OFFCHANENV,MMget(m,0));
  return 0;
}

int SPloadpak(mmachine m)
{
  int pp,k;

  pp=MMgetPP(m);
  k=SPloadpakbis(m);
  MMsetPP(m,pp);
  MMset(m,0,k*2);
  return k;
}

/* calcul du nom complet d'un fichier present en bande memoire
  en 0: string type (caractere separateur), 1:nom clair 2:string package
 -> 0 : nom complet si succes, nil sinon */
int SPgetlongname(mmachine m)
{
  int p,typs;
  char name[SIZESIGN],sign[SIZESIGN];

  p=MMpull(m)>>1;
  if (p==NIL)
    {
      MMpull(m);
      MMset(m,0,NIL);
      return 0;
    }
  typs=SPgettypsign(MMstartstr(m,p));
  p=MMpull(m)>>1;
  if (p==NIL)
    {
      MMset(m,0,NIL);
      return 0;
    }
  strcpy(name,MMstartstr(m,p));

  p=MMget(m,0)>>1;
  if (p==NIL)
    {
      MMset(m,0,NIL);
      return 0;
    }

  /* verification de la signature */
  if (SCsign(m,MMstartstr(m,p),MMsizestr(m,p),name,typs,sign)==-1)
    {
      MMset(m,0,NIL);
      return 0;
    }
  MMpull(m);
  return Mpushstrbloc(m,sign);
}

/* calcul de la signature d'un fichier, sans passer par la memoire scol */
int SPfileSign(mmachine m)
{
  int q,i;
  char bufs[1024];
  char sign[SIZESIGN];
  FILE *fd;

  q=MMpull(m)>>1;
  if (q==NIL) return MMpush(m,NIL);

  if (fd=fopen(MMstartstr(m,q),"rb"))
  {
	  SCincSignInit();
	  do
	  {
		  i=fread(bufs,1,1024,fd);
		  SCincSign(bufs,i,NULL);
	  }
	  while(i==1024);
	  strcpy(sign,"#");
	  SCincSign(NULL,0,&sign[1]);
	  fclose(fd);
	  return Mpushstrbloc(m,sign);
  }
  return MMpush(m,NIL);
}

/* calcul de la taille d'un fichier, sans passer par la memoire scol */
#ifdef VERSION_WIN
int SPfileSize(mmachine m)
{
	HANDLE f;
	int res,q;
	
	q=MMpull(m)>>1;
	if (q==NIL) return MMpush(m,NIL);
	f=CreateFile(MMstartstr(m,q),GENERIC_READ,FILE_SHARE_READ,NULL,
		OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (f==INVALID_HANDLE_VALUE) return MMpush(m,NIL);
    SetFilePointer(f,0,NULL,FILE_END);
	res=SetFilePointer(f,0,NULL,FILE_CURRENT);
	CloseHandle(f);
	return MMpush(m,res*2);
}
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
int SPfileSize(mmachine m)
{
	FILE *f;
	int res,q;
	
	q=MMpull(m)>>1;
	if (q==NIL) return MMpush(m,NIL);
	f=fopen(MMstartstr(m,q),"rb");
	if (f==NULL) return MMpush(m,NIL);
	fseek(f,0,SEEK_END);
	res=ftell(f);
	fclose(f);
	return MMpush(m,res*2);
}
#endif
#ifdef VERSION_MAC
  int SPfileSize(mmachine m) TODO
#endif

/* chargement d'un package hard sur le canal courant 
 le nom du package est dans la pile */
int SCloadhardbis(mmachine m)
{
  int k,t;
  char *name;

  t=MMgetglobal(m,OFFSCCUR);  /* empiler l'environnement courant */
  if (t==NIL) return 0;
  t=MMfetch(m,t>>1,OFFCHANENV);
  if (k=MMpush(m,t)) return k;

  t=MMget(m,1);
  if (t==NIL) return 0;
  name=MMstartstr(m,t>>1);
  
  t=Msearchpak(m,MMgetglobal(m,OFFSCSYS),name);
  if (t==NIL) return MERRNF;

  if (k=MMpush(m,t+t+1)) return k;  /* package systeme */
  if (k=PKaddpak(m)) return k;

  t=MMgetglobal(m,OFFSCCUR);  /* stocker le nouvel environnement */
  MMstore(m,t>>1,OFFCHANENV,MMget(m,0));
  return 0;
}


#ifdef VERSION_WIN
int SPGetModifDate(mmachine m)
//$ FA(06/08/2001): Returns the date (as a tuple) when the file was last modified
// [0] file path
// (Windows version)
{
  SEWORD     path = SEPOP(m);
  HANDLE     hFile;
  FILETIME   ft;
  SYSTEMTIME st;

  // Returns nil if argument path is nil
  if (path == NIL) {
    SECHECK(SEPUSH(m, NIL));
    return MERROK;
  }
  if ((hFile = CreateFile(SESTR(m, SEW2P(path)), GENERIC_READ, FILE_SHARE_READ, 
      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
    SECHECK(SEPUSH(m, NIL));
    return MERROK;
  }
  if (!GetFileTime(hFile, NULL, NULL, &ft)) {
    SECHECK(SEPUSH(m, NIL));
    return MERROK;
  }
  if (!FileTimeToSystemTime(&ft, &st)) {
    SECHECK(SEPUSH(m, NIL));
    return MERROK;
  }
  CloseHandle(hFile);
  SECHECK(SEPUSH(m, SEI2W(st.wYear)));
  SECHECK(SEPUSH(m, SEI2W(st.wMonth)));
  SECHECK(SEPUSH(m, SEI2W(st.wDay)));
  SECHECK(SEPUSH(m, SEI2W(st.wDayOfWeek)));
  SECHECK(SEPUSH(m, SEI2W(st.wHour)));
  SECHECK(SEPUSH(m, SEI2W(st.wMinute)));
  SECHECK(SEPUSH(m, SEI2W(st.wSecond)));
  SECHECK(SEPUSH(m, SEI2W(st.wMilliseconds)));
  SECHECK(SEPUSH(m, SEI2W(8)));
  SECHECK(SENEWTUPLE(m));
  return MERROK;
}
#else
int SPGetModifDate(mmachine m)
//$ FA(06/08/2001): Returns the date (as a tuple) when the file was last modified
// [0] file path
// (ANSI-based version)
{
  SEWORD      path = SEPOP(m);
  struct stat st;
  struct tm*  tm;

  // Returns nil if argument path is nil
  if (path == NIL) {
    SECHECK(SEPUSH(m, NIL));
    return MERROK;
  }
  if (stat(SESTR(m, SEW2P(path)), &st)) {
    SECHECK(SEPUSH(m, NIL));
    return MERROK;
  }
  tm = localtime(&st.st_mtime);
  SECHECK(SEPUSH(m, SEI2W(tm->tm_year+1900)));
  SECHECK(SEPUSH(m, SEI2W(tm->tm_mon+1)));
  SECHECK(SEPUSH(m, SEI2W(tm->tm_mday)));
  SECHECK(SEPUSH(m, SEI2W(tm->tm_wday+1)));
  SECHECK(SEPUSH(m, SEI2W(tm->tm_hour)));
  SECHECK(SEPUSH(m, SEI2W(tm->tm_min)));
  SECHECK(SEPUSH(m, SEI2W(tm->tm_sec)));
  SECHECK(SEPUSH(m, SEI2W(0)));
  SECHECK(SEPUSH(m, SEI2W(8)));
  SECHECK(SENEWTUPLE(m));
  return MERROK;
}
#endif


int SCloadhard(mmachine m)
{
  int pp,k;

  pp=MMgetPP(m);
  k=SCloadhardbis(m);
  MMsetPP(m,pp);
  MMset(m,0,k*2);
  return k;
}


char *SCGetName(char *name)
{
    int i,k;

    i=k=0;
    while(name[i])
    {
        if ((name[i]=='\\')||(name[i]=='/')) k=i+1;
        i++;
    }
	return &name[k];
}

/* signature d'un environnement */
int SCsignenv(mmachine m)
{
  int p;
  char *s;
  char sign[32];

  SCincSignInit();
  p=MMpull(m);
  while((p!=NIL)&&(p!=MMgetglobal(m,OFFSCBASE)))
    {
      s=SCGetName((char*)MMstart(m,MMfetch(m,MMfetch(m,p>>1,OFFLVAL)>>1,OFFPKNAME)>>1));
      SCincSign(s,strlen(s)+1,NULL);
	  p=MMfetch(m,p>>1,OFFLNEXT);
    }
  SCincSign(NULL,0,sign);
  return Mpushstrbloc(m,sign);
}

/* signature de la machine */
int SCsignmachine(mmachine m)
{
  int p,q;
  char *s;
  char sign[32];

  SCincSignInit();
  q=MMgetglobal(m,OFFSCCHAN);
  while(q!=NIL)
    {
      p=MMfetch(m,MMfetch(m,q>>1,OFFLVAL)>>1,OFFCHANENV);
      while((p!=NIL)&&(p!=MMgetglobal(m,OFFSCBASE)))
        {
          s=SCGetName((char*)MMstart(m,MMfetch(m,MMfetch(m,p>>1,OFFLVAL)>>1,OFFPKNAME)>>1));
          SCincSign(s,strlen(s)+1,NULL);
	      p=MMfetch(m,p>>1,OFFLNEXT);
        }
      q=MMfetch(m,q>>1,OFFLNEXT);
    }
  SCincSign(NULL,0,sign);
  return Mpushstrbloc(m,sign);
}

int SCgetress(mmachine m);

/* routine interceptant un message "__checksign" */
int SCchecksign(mmachine m)
{
  int p,k;
  char buf[256];
  char *c;

  if (Mpushstrbloc(m,"License")) return MERRMEM;
  if (k=SCgetress(m)) return k;
  p=MMpull(m);
  if ((p==NIL)||(MMsizestr(m,p>>1)<10)) c="No_license";
  else c=MMstartstr(m,p>>1)+8;

  sprintf(buf,"__version \"%s\" %x %x \"%s\"",VERSION_NAME,MAXSOCKS,maxsock,c);

  if (Mpushstring(m,buf)) return MERRMEM;
  c=(char*)MMstart(m,MMget(m,0)>>1);
  p=strlen(c)+1;
  c[0]=(p-2)&255;
  c[1]=((p-2)>>8)&255;
  return SCsendpile(m);
}



#ifdef SERVER
extern int socklife;


//$ LB (30/05/2002) : defined an empty SCsendCapacity for the ClubHouse server
#ifdef CLUBHOUSE_SERVER
/* routine envoyant la capacité courante au Superviseur */
int SCsendCapacity(mmachine m)
{return 0;}
#else


/* routine envoyant la capacité courante au Superviseur */
int SCsendCapacity(mmachine m)
{
  int p,k;
  char buf[128];
  char *c;


//$ ER(09/07/01) SCsendCapacity was previously defined on two versions, upon the SERVERM or SERVERS constant
//				 Here I merged the two version in one and manage the running with the MUTUALISE variable
	if (MUTUALISE)
	{
		sprintf(buf,"__@c%d",maxsock-1);

		if (MMpush(m,MMgetglobal(m,OFFSCCUR))) return MERRMEM;
		k=0;
		if (!SCselectcanal(m,socklife))
		{
			if (Mpushstring(m,buf)) return MERRMEM;
			c=(char*)MMstart(m,MMget(m,0)>>1);
			p=strlen(c)+1;
			c[0]=(p-2)&255;
			c[1]=((p-2)>>8)&255;
			k=SCsendpile(m);
		}
	} else
	{
		sprintf(buf,"__@c%d",SCgetnbsocket(m));
		if (MMpush(m,MMgetglobal(m,OFFSCCUR))) return MERRMEM;
		k=0;
		if (!SCselectcanal(m,socklife))
		{
			if (Mpushstring(m,buf)) return MERRMEM;
			c=(char*)MMstart(m,MMget(m,0)>>1);
			p=strlen(c)+1;
			c[0]=(p-2)&255;
			c[1]=((p-2)>>8)&255;
			k=SCsendpile(m);
		}
	}

	MMsetglobal(m,OFFSCCUR,MMpull(m));       /* repositionne environnement */
	return k;
}  
#endif
#endif


#ifdef VERSION_WIN

/* retourne la liste des fichiers d'un répertoire */
int SClistoffiles(mmachine m)
{
	int res,p,n,k,i;
	long h;
	struct _finddata_t fileinfo;
	char buf[1024],shortbuf[1024];
	packdir pk;

	p=MMpull(m)>>1;
	if (p==NIL) return MMpush(m,NIL);
	if (MMsizestr(m,p)>512) return MMpush(m,NIL);
	strcpy(shortbuf,MMstartstr(m,p));
	if ((Firstpack==Cachepack)&&(strncmp(shortbuf,"public/",7))&&(strcmp(shortbuf,"public"))) return MMpush(m,NIL);
	p=strlen(shortbuf);

	if (shortbuf[0]=='/') return MMpush(m,NIL);
	if ((p)&&(!SPisname(shortbuf[0],0))) return MMpush(m,NIL);
	for(i=1;i<p;i++) if (!SPisname(shortbuf[i],shortbuf[i-1])) return MMpush(m,NIL);

	if ((p)&&(shortbuf[p-1]=='/')) shortbuf[p-1]=0;

	p=strlen(shortbuf);
	n=0;
	pk=Firstpack;

	while(pk)
	{
		shortbuf[p]=0;
		if (p) sprintf(buf,"%s%s/*.*",pk->path,shortbuf);
		else sprintf(buf,"%s*.*",pk->path);
		h=_findfirst(buf,&fileinfo );
		res=h;
		while(res!=-1)
		{
			if (p) sprintf(shortbuf+p,"/%s",fileinfo.name);
			else sprintf(shortbuf+p,"%s",fileinfo.name);
			if (!(fileinfo.attrib&16))
			{
				SPkillmaj(shortbuf);
				if (k=Mpushstrbloc(m,shortbuf)) return k;
				n++;
			}
			res=_findnext(h,&fileinfo );
		}
		if (h!=-1) _findclose(h);
		pk=pk->next;
	}
	if (MMpush(m,NIL)) return MERRMEM;
	for(i=0;i<n;i++)
	{
		if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	return 0;
}


/* retourne la liste des sous-répertoires d'un répertoire */
int SClistofsubdir(mmachine m)
{
	int res,p,n,k,i;
	long h;
	struct _finddata_t fileinfo;
	char buf[1024],shortbuf[1024];
	packdir pk;
	
	p=MMpull(m)>>1;
	if (p==NIL) return MMpush(m,NIL);
	if (MMsizestr(m,p)>512) return MMpush(m,NIL);
	strcpy(shortbuf,MMstartstr(m,p));
	if ((Firstpack==Cachepack)&&(strncmp(shortbuf,"public/",7))&&(strcmp(shortbuf,"public"))) return MMpush(m,NIL);
	p=strlen(shortbuf);
	
	if (shortbuf[0]=='/') return MMpush(m,NIL);
	if ((p)&&(!SPisname(shortbuf[0],0))) return MMpush(m,NIL);
	for(i=1;i<p;i++) if (!SPisname(shortbuf[i],shortbuf[i-1])) return MMpush(m,NIL);
	
	if ((p)&&(shortbuf[p-1]=='/')) shortbuf[p-1]=0;
	
	p=strlen(shortbuf);
	n=0;
	pk=Firstpack;
	
	while(pk)
	{
		shortbuf[p]=0;
		if (p) sprintf(buf,"%s%s/*.*",pk->path,shortbuf);
		else sprintf(buf,"%s*.*",pk->path);
		h=_findfirst(buf,&fileinfo );
		res=h;
		while(res!=-1)
		{
			if (p) sprintf(shortbuf+p,"/%s",fileinfo.name);
			else sprintf(shortbuf+p,"%s",fileinfo.name);
			if (fileinfo.attrib&16)
			{
				if (strcmp(fileinfo.name,".")&&strcmp(fileinfo.name,".."))
				{
					SPkillmaj(shortbuf);
					if (k=Mpushstrbloc(m,shortbuf)) return k;
					n++;
				}
			}
			res=_findnext(h,&fileinfo );
		}
		if (h!=-1) _findclose(h);
		pk=pk->next;
	}
	if (MMpush(m,NIL)) return MERRMEM;
	for(i=0;i<n;i++)
	{
		if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
	}
	return 0;
}
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
int SClistoffiles(mmachine m)
{
	int p,q,n,k,i;
	long h;
	DIR *d;
	struct dirent *dp;
	struct stat typ;
	char buf[1024],shortbuf[1024];
	packdir pk;
	
	p=MMpull(m)>>1;
	if (p==NIL) return MMpush(m,NIL);
	if (MMsizestr(m,p)>512) return MMpush(m,NIL);
	strcpy(shortbuf,MMstartstr(m,p));
	if ((Firstpack==Cachepack)&&(strncmp(shortbuf,"public/",7))&&(strcmp(shortbuf,"public"))) return MMpush(m,NIL);
	p=strlen(shortbuf);
	
	if ((p)&&(!SPisname(shortbuf[0],0))) return MMpush(m,NIL);
	for(i=1;i<p;i++) if (!SPisname(shortbuf[i],shortbuf[i-1])) return MMpush(m,NIL);
	
	if ((p)&&(shortbuf[p-1]=='/')) shortbuf[p-1]=0;
	
	SPkillmaj(shortbuf);
	p=strlen(shortbuf);
	n=0;
	pk=Firstpack;
	
	while(pk)
    {
		shortbuf[p]=0;
		if (p) sprintf(buf,"%s%s",pk->path,shortbuf);
		else sprintf(buf,"%s",pk->path);
		d=opendir(buf);
		q=strlen(buf);
		if (d)  while(dp=readdir(d))
		{
			if (p) sprintf(shortbuf+p,"/%s",dp->d_name);
			else sprintf(shortbuf+p,"%s",dp->d_name);
			sprintf(buf+q,"/%s",dp->d_name);
			stat(buf,&typ);
			if ((typ.st_mode&S_IFMT)!=S_IFDIR)
			{
				SPkillmaj(shortbuf);
				if (k=Mpushstrbloc(m,shortbuf)) return k;
				n++;
			}
		}
		if (d) closedir(d);
		pk=pk->next;
    }
	if (MMpush(m,NIL)) return MERRMEM;
	for(i=0;i<n;i++)
    {
		if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
    }
	return 0;
}

int SClistofsubdir(mmachine m)
{
	int p,q,n,k,i;
	long h;
	DIR *d;
	struct dirent *dp;
	struct stat typ;
	char buf[1024],shortbuf[1024];
	packdir pk;
	
	p=MMpull(m)>>1;
	if (p==NIL) return MMpush(m,NIL);
	if (MMsizestr(m,p)>512) return MMpush(m,NIL);
	strcpy(shortbuf,MMstartstr(m,p));
	if ((Firstpack==Cachepack)&&(strncmp(shortbuf,"public/",7))&&(strcmp(shortbuf,"public"))) return MMpush(m,NIL);
	p=strlen(shortbuf);
	
	if ((p)&&(!SPisname(shortbuf[0],0))) return MMpush(m,NIL);
	for(i=1;i<p;i++) if (!SPisname(shortbuf[i],shortbuf[i-1])) return MMpush(m,NIL);
	
	if ((p)&&(shortbuf[p-1]=='/')) shortbuf[p-1]=0;
	
	SPkillmaj(shortbuf);
	p=strlen(shortbuf);
	n=0;
	pk=Firstpack;
	
	while(pk)
    {
		shortbuf[p]=0;
		if (p) sprintf(buf,"%s%s",pk->path,shortbuf);
		else sprintf(buf,"%s",pk->path);
		d=opendir(buf);
		q=strlen(buf);
		if (d)  while(dp=readdir(d))
		{
			if (p) sprintf(shortbuf+p,"/%s",dp->d_name);
			else sprintf(shortbuf+p,"%s",dp->d_name);
			sprintf(buf+q,"/%s",dp->d_name);
			stat(buf,&typ);
			if ((typ.st_mode&S_IFMT)==S_IFDIR)
				if (strcmp(dp->d_name,".")&&strcmp(dp->d_name,".."))
				{
					SPkillmaj(shortbuf);
					if (k=Mpushstrbloc(m,shortbuf)) return k;
					n++;
				}
		}
		if (d) closedir(d);
		pk=pk->next;
    }
	
	if (MMpush(m,NIL)) return MERRMEM;
	for(i=0;i<n;i++)
    {
		if (MMpush(m,2*2)) return MERRMEM;
		if (k=MBdeftab(m)) return k;
    }
	return 0;
}

#endif

#ifdef VERSION_MAC
  int SClistoffiles(mmachine m) TODO
  int SClistofsubdir(mmachine m) TODO
#endif


/* nom de l'utilisateur */
int SCusername(mmachine m)
{
	char buf[128];

	buf[0]=0;
	/*	GetUserName(buf,127);
	 */
	return Mpushstrbloc(m,buf);
}

/* nom de l'ordinateur */
int SCcomputername(mmachine m)
{
	char buf[128];

	buf[0]=0;
	/*GetComputerName(buf,127);
	 */
	return Mpushstrbloc(m,buf);
}

#ifdef VERSION_WIN
/* deplace les fichiers du cache dans un sous-repertoire */
int SCmovecache(mmachine m)
{
	int res,p,n,i;
	long h;
	struct _finddata_t fileinfo;
	char bufdir[1024],shortbuf[1024];
	char bufsrc[1024],bufdst[1024];
	packdir pk;

	p=MMget(m,0)>>1;
	if (p==NIL) return 0;
	if (MMsizestr(m,p)>512) return 0;
	strncpy(shortbuf,MMstartstr(m,p),16);
	shortbuf[16]=0;
	p=strlen(shortbuf);
	if ((p==0)||(shortbuf[0]=='/')) return 0;
	if ((p)&&(!SPisname(shortbuf[0],0))) return 0;
	for(i=1;i<p;i++) if (!SPisname(shortbuf[i],shortbuf[i-1])) return 0;
	if ((p)&&(shortbuf[p-1]=='/')) shortbuf[p-1]=0;

	n=0;
	pk=Cachepack;

	sprintf(bufdst,"%s%s",pk->path,shortbuf);
	_mkdir(bufdst);

	sprintf(bufdir,"%s*.*",pk->path);
	h=_findfirst(bufdir,&fileinfo );
	res=h;
	while(res!=-1)
	{
		if ((strcmp(fileinfo.name,shortbuf))&&(strcmp(fileinfo.name,"."))&&(strcmp(fileinfo.name,"..")))
		{
			sprintf(bufsrc,"%s%s",pk->path,fileinfo.name);
			sprintf(bufdst,"%s%s/%s",pk->path,shortbuf,fileinfo.name);
			MoveFile(bufsrc,bufdst);
		}
		res=_findnext(h,&fileinfo );
	}
	if (h!=-1) _findclose(h);
	return 0;
}
#endif
#if defined(VERSION_X11) || defined(VERSION_NOX)
/* deplace les fichiers du cache dans un sous-repertoire */
int SCmovecache(mmachine m)
{
	return 0;
}
#endif

#ifdef VERSION_MAC
  int SCmovecache(mmachine m) TODO
#endif



/* -----------------------------------------

  TRAITEMENT DE LA TRACE

---------------------------------------- */

#include "bignum.h"

/* decryptage d'une clef de fichier de clef
- s_code est une chaîne hexadécimale contenant la clef
- s_primal_key est une chaîne hexadécimale codant un grand nombre premier
- pi_datedebut pointe vers un entier dans lequel on retourne la datedebut (nombre de jours depuis le 1er jan 1970)
- pi_periode pointe vers un entier dans lequel on retourne la periode de validité en jours (0 si illimitée)
retourne :
- 0 si Ok
- -1 si mauvaise clef

détail :
 on effectue le calcul suivant : Inv code mod primal_key
 le résultat doit être compris entre 2^32 et 2^33, sinon on retourne -1
 on retourne les 32 premiers bits
*/
int getFromKey(char *s_code, char *s_primal_key, int *pi_datedebut, int *pi_periode)
{
	short key[SIZEV];
	short primal[SIZEV];
	short res[SIZEV];
	int i;
	
	CRfromAsc(s_code,key);
	CRfromAsc(s_primal_key,primal);
	
	CRinv(key,primal,res);

	for(i=3;i<SIZEV;i++) if (res[i]) return -1;
	if (res[2]!=1) return -1;

	*pi_datedebut=(res[1]&0xffff);
	*pi_periode=(res[0]&0xffff);
	return 0;
}

/*
lit la trace T : recherche la première trace compatible
- s_tracename est une chaîne contenant le nom de la clef
- s_tracekey est une chaîne hexadécimale codant un grand nombre premier
- s_buf est une chaîne d'au moins 32 octets, dans laquelle la trace va être retournée

la fonction retourne :
- 0 si OK, et dans ce cas, la trace est dans le s_buf
- -1 sinon : trace non présente

*/
int readT(char *s_tracename, char *s_tracekey,  int *pi_datedebut, int *pi_periode)
{
#if defined(VERSION_WIN)
	FILE *f;
	char trace[32];
	char filename[1024];
    char keyname[1024];
	char s_buf[1024];
    int msize;
	int res;
	int i;

	if (strlen(s_tracename)>16) return -2;	// nom trop long
	strcpy(trace,s_tracename);
	for(i=0;i<strlen(trace);i++) if ((trace[i]<48)||(trace[i]>57)) return -2;	// nom composé d'autre chose que de chiffres

	// première trace
    res = GetWindowsDirectory ( filename , 1024 );
    if ((res>0)&&(res<1024))
	{
		sprintf(filename+strlen(filename),"\\%s.ini",trace);
        /* lit le fichier */ 
        if ((f=fopen( filename,"rb"))!=NULL)
		{
			s_buf[0]=0;
			fgets(s_buf,32,f);
			fclose(f);
			if (getFromKey(s_buf,s_tracekey,pi_datedebut,pi_periode)==0) return 0;
		}
	}

	// seconde trace
	for(i=0;i<strlen(trace);i++) trace[i]+=49;	// on passe de '0' à 'a', et donc de '9' à 'j'

    res = GetSystemDirectory ( filename , 1024 );
    if ((res>0)&&(res<1024))
	{
		sprintf(filename+strlen(filename),"\\%s.dll",trace);
        /* lit le fichier */ 
        if ((f=fopen( filename,"rb"))!=NULL)
		{
			s_buf[0]=0;
			fgets(s_buf,32,f);
			fclose(f);
			if (getFromKey(s_buf,s_tracekey,pi_datedebut,pi_periode)==0) return 0;
		}
	}

	// troisième trace
	for(i=0;i<strlen(trace);i++) trace[i]+=10;	// on passe de 'a' à 'k', et donc de 'j' à 't'

	sprintf(keyname,"SOFTWARE\\CryoNetworks\\%s",trace);
	msize=32;
    if (RegQueryValue(HKEY_LOCAL_MACHINE,keyname,s_buf,&msize)==ERROR_SUCCESS)
	{
		if (getFromKey(s_buf,s_tracekey,pi_datedebut,pi_periode)==0) return 0;
	}
#endif	
	return -1;
}

/* lit une trace cachée dans la machine */
int SCreadTrace(mmachine m)
{
	int p,q;
	int debut,periode;

	p=MMpull(m)>>1;	// prime number
	q=MMpull(m)>>1;	// name

	if ((p==NIL)||(q==NIL)) return MMpush(m,NIL);

	if (readT(MMstartstr(m,q),MMstartstr(m,p),&debut,&periode)) return MMpush(m,NIL);

	if (MMpush(m,debut<<1)) return MERRMEM;
	if (MMpush(m,periode<<1)) return MERRMEM;
	if (MMpush(m,2<<1)) return MERRMEM;
	return MBdeftab(m);
}
