/*     
      SCOL ENVIRONMENT . Magma 1.0 . 1996 . Sylvain HUET

         fifo.c : gestion des fifo de l'environnement SCOL
*/
// Modification history:
//$ FA(01/06/2001): Comment MMpull() after call to SCexeccomm()
//$ ER(01/07/2001): Update of the SERVERM and SERVERS calls to the SERVER and MUTUALISE variable. SERVERS and SERVERM constants no longer exist
//
//$ LB(18/07/2001) : add the process of two internal defcom in SCreadchar, in order to  : 
//							- allow a scol machine to ask the main machine the informations for http proxy authentication
//							- make the main machine communicate back those informations to the client machine
//
//$ LB(25/01/2002) : in function SCreadchar : have moved the http proxy messages check after the "#ifdef SERVER"
//
//$LB (25/01/2002) : in function SCreadchar : reload scol pointer in orderto be aware of the f.... gc.
//

#include "scolPrerequisites.h"

#include <stdio.h>
#include <string.h>
#include <time.h>

#include "scolMMemory.h"
#include "vm/mbytec.h"
#include "mbytec2.h"
#include "listlab.h"
#include "loadpak.h"
#include "scol.h"
#include "scolSystem.h"
#include "fifo.h"
#include "common/vscol.h"
#include "common/socket.h"
//$ LB(18/07/2001) : for SCreadchar
#include "common/proxyhttp.h"


// Output states
/* etats en sortie */
#define SC_NOTCON  0
#define SC_BUSY    1
#define SC_READY   2
#define SC_PROXY   3
#define SC_UDP     4

// Input states
/* etats en entree */
#define SC_SIZE0   0
#define SC_SIZE1   1
#define SC_DATA    2

//$BB
extern ScolWindowHandle ActiveXhwnd;
extern ScolWindowHandle hscol;
#define WM_SCOLAXMESS (WM_USER+12)


//Creation and initialization of a FIFO structure
/* creation d'un bloc fifo vide */
int SCmakefifo(mmachine m)
{
  int k;
  time_t t;

  time(&t);
  if (MMpush(m, NIL)) return MERRMEM;            /* sock= NIL */
  if (MMpush(m, NIL)) return MERRMEM;            /* name= NIL */
  if (MMpush(m, NIL)) return MERRMEM;            /* fifout= NIL */
  if (MMpush(m, 0)) return MERRMEM;              /* cptout= NIL */
  //$BLG - v5.22: Modif
  //if (MMpush(m, SC_NOTCON*2)) return MERRMEM;    /* stout= NIL */
  if (MMpush(m, SC_NOTCON<<1)) return MERRMEM;   /* stout= NIL */
  if (MMpush(m, NIL)) return MERRMEM;            /* messin= NIL */
  if (MMpush(m, 0)) return MERRMEM;              /* cptin= NIL */
  if (MMpush(m, 0)) return MERRMEM;              /* sizin= NIL */
  //$BLG - v5.22: Modif
  //if (MMpush(m, SC_SIZE0*2)) return MERRMEM;     /* stin= NIL */
  if (MMpush(m, SC_SIZE0<<1)) return MERRMEM;    /* stin= NIL */
  //$BLG - v5.22: Modif
  //if (MMpush(m, t*2)) return MERRMEM;            /* time */
  if (MMpush(m, t<<1)) return MERRMEM;           /* time */
  if (MMpush(m, NIL)) return MERRMEM;            /* max fifo=NIL : inactif */
  if (MMpush(m, 0)) return MERRMEM;              /* capacite fifo= 0 */
  //$BLG - v5.22: Modif
  //if (MMpush(m, SIZE_FIFO*2)) return MERRMEM;
  if (MMpush(m, SIZE_FIFO<<1)) return MERRMEM;
  if (k = MBdeftab(m)) return k;
  return 0;
}


/* initialisation d'une socket proxy associee a un canal
   (channel est un pointeur vers le canal, avec bit 0 a 1) */
int SCsetproxy(mmachine m, int channel)
{
  int r;
  
  r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
  if (r == NIL) return 0;
  //$BLG - v5.22: Modif
  //m->tape[r+SizeHeader+FIFOSTOUT] = SC_PROXY*2;     /* ecriture handler socket */
  m->tape[r+SizeHeader+FIFOSTOUT] = SC_PROXY<<1;     /* ecriture handler socket */
  return 0;
}


/* initialisation d'une socket udp
   (channel est un pointeur vers le canal, avec bit 0 a 1) */
int SCsetudp(mmachine m, int channel)
{
    int r;
    
    r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
    if (r == NIL) return 0;
    //$BLG - v5.22: Modif
    //m->tape[r+SizeHeader+FIFOSTOUT]=SC_UDP*2;     /* ecriture handler socket */
    m->tape[r+SizeHeader+FIFOSTOUT] = SC_UDP<<1;     /* ecriture handler socket */
    return 0;
}


/* retourne 1 si le canal est une socket udp
   (channel est un pointeur vers le canal, avec bit 0 a 1) */
int SCtestudp(mmachine m, int channel)
{
    int r;
    
    r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
    if (r == NIL) return 0;
    //$BLG - v5.22: Modif
    //if (m->tape[r+SizeHeader+FIFOSTOUT]==SC_UDP*2) return 1;
    if (m->tape[r+SizeHeader+FIFOSTOUT] == SC_UDP<<1) return 1;
    return 0;
}


/* lecture du numero de socket associe a un serveur
   (server est un pointeur vers le serveur, avec bit 0 a 1) */
int SCgetsrvsocket(mmachine m, int server)
{
  return m->tape[(server>>1)+SizeHeader+OFFSRVSOCK]>>1;
}


/* lecture du numero de socket associe a un canal
   (channel est un pointeur vers le canal, avec bit 0 a 1) */
int SCgetsocket(mmachine m, int channel)
{
    int r, s;
    
    r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
    if (r == NIL) return -1;
    s = m->tape[r+SizeHeader+FIFOSOCK]>>1;     /* lecture handler socket */
    return s;
}


/* reglage du numero de socket associe a un canal
   (channel est un pointeur vers le canal, avec bit 0 a 1) */
int SCsetsocket(mmachine m, int channel, int socket)
{
    int r;
    r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
    if (r == NIL) return 0;
    //$BLG - v5.22: Modif
    //m->tape[r+SizeHeader+FIFOSOCK] = socket*2;     /* ecriture handler socket */
    m->tape[r+SizeHeader+FIFOSOCK] = socket<<1;     /* ecriture handler socket */
    return 0;
}


/* lecture du nom de socket d'un canal,
   le nom est mis dans la pile */
int SCgetsockname(mmachine m, int channel)
{
    int r;
    
    r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
    if (r == NIL) return MMpush(m, NIL);
    return MMpush(m, m->tape[r+SizeHeader+FIFONAME]);
}


/* reglagle du nom de socket d'un canal,
   le nom est dans la pile */
int SCsetsockname(mmachine m, int channel)
{
    int r;
    
    r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
    if (r == NIL) return 0;
    m->tape[r+SizeHeader+FIFONAME] = MMpull(m);
    return 0;
}


/* lecture du temps de vie en secondes d'un canal
   (channel est un pointeur vers le canal, avec bit 0 a 1) */
int SCgetchanneltime(mmachine m, int channel)
{
    int r, s;
    time_t t;

    time(&t);
    r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
    if (r == NIL) return -1;
    s = t-(m->tape[r+SizeHeader+FIFOTIME]>>1);
    return s;
}


/* lecture du temps de vie en secondes d'un serveur
   (channel est un pointeur vers le canal, avec bit 0 a 1) */
int SCgetservertime(mmachine m, int srv)
{
    int s;
    time_t t;

    time(&t);
    s = t-(m->tape[(srv>>1)+SizeHeader+OFFSRVTIME]>>1);
    return s;
}


#ifdef SERVER
/* lecture de la capacité associee a un canal
   (channel est un pointeur vers le canal, avec bit 0 a 1) */
int SCgetcapa(mmachine m, int channel)
{
    int r;
    
    r = m->tape[(channel>>1)+SizeHeader+OFFCHANFIFO]>>1;
    if (r == NIL) return 0;
    return m->tape[r+SizeHeader+FIFOCAPA]>>1;     /* lecture handler socket */
}

extern int maxsock;

/* teste la somme des capacités */
int SCchecksum(mmachine m)
{
  int p, k;
  char *c;

  k = 0;
  p = MMgetglobal(m, OFFSCCHAN);
  while (p != NIL)
  {
    p >>= 1;
    k += SCgetcapa(m, MMfetch(m, p, OFFLVAL));
    p = MMfetch(m, p, OFFLNEXT);
  }

  if (k > maxsock)
  {
	  MMechostr(MSKDEBUG,"capacity reached %d/%d\n",k,maxsock-1);
//$ ER(09/07/01) : turn of #ifdef SERVERM by the following test
	  if (MUTUALISE)
	  {
			SCchanneldown(m);
			return 1;
	  } 
	  else
	  {
			MMechostr(MSKDEBUG, "send killLast\n");
			if (Mpushstring(m, "__@k")) 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);
	  }
  }
  return 0;
}

int testlocal(char *s)
{
	char buf[128];

	if (forcedIP[0]) strcpy(buf, forcedIP);
	else strcpy(buf, "127.0.0.1");
	//	MMechostr(MSKDEBUG,"testlocal %s %s\n",s,buf);
	if (!strcmp(s, buf)) return 1;
	return 0;
}
#endif


//$ ER(09/07/01) : turn #ifdef SERVERS in #ifdef SERVER. SERVERS exists no longer and we cant test MUTUALISE during the compiling
//					since it isnot a CONSTANT. The 2 following functions are added in the binary code even when we are not a
//					mutualised server;
#ifdef SERVER
/* retourne le dernier canal non unplugged */
int SCgetlast(mmachine m)
{
  int p, s;

  p = MMgetglobal(m, OFFSCCHAN);
  while(p != NIL)
  {
    p >>= 1;
    s = SCgetsocket(m, MMfetch(m, p, OFFLVAL));
    if ((s >= 0) && (s != socklife) && (!SCtestudp(m, MMfetch(m, p, OFFLVAL)))) return s;
    p = MMfetch(m, p, OFFLNEXT);
  }
  return -1;
}

int SCkilllast(mmachine m)
{
	int s;

	s = SCgetlast(m);
	if (s < 0) return 0;
	if (MMpush(m, MMgetglobal(m, OFFSCCUR))) return MERRMEM;
	if (!SCselectcanal(m, s))
	{
		MMechostr(MSKTRACE, "Full machine, destroy %d\n", s);
		SCchanneldown(m);
	}
	MMsetglobal(m, OFFSCCUR, MMpull(m));       /* repositionne environnement */
	return 0;
}
#endif


//$BLG - v5.22: Add (cf below)
int dbg;


//checker le msg OK qd return 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


// Management of a Read message
// (We suppose the current channel has been parametered)
// (Received msg is in the buffer with given size)
// (Doesn't return anything in the stack)
// Returns 1 if channel was closed.
/* traitement d'un message Readable
  (on suppose que le canal courant a ete regle) 
  (le message recu est dans le buffer avec la taille indiquee)
  ne retourne rien dans la pile */
int SCreadchar(mmachine m, int c)
{
  int x, t, s, l, k;
  char *p;

  t = m->top[m->pp]>>1;
  x = m->tape[t+SizeHeader+FIFOSTIN]>>1;

  if (x == SC_SIZE0)
  {
    //MMechostr(0,"SC_SIZE0: %d\n", c);
    
    //$BLG - v5.22: Modif
    //m->tape[t+SizeHeader+FIFOSZIN] = c*2;
    //m->tape[t+SizeHeader+FIFOSTIN] = SC_SIZE1*2;
    m->tape[t+SizeHeader+FIFOSZIN] = c<<1;
    m->tape[t+SizeHeader+FIFOSTIN] = SC_SIZE1<<1;
    
    return 0;
  }
  
  if (x == SC_SIZE1)
  {
    //MMechostr(0,"SC_SIZE1: %d\n", c);
    
    if ((c == 0) && (m->tape[t+SizeHeader+FIFOSZIN] == 0))		MMechostr(0,"Bzong %d\n", dbg);
    
    //$BLG - v5.22: Modif
    //m->tape[t+SizeHeader+FIFOSZIN] += (c<<8)*2 + 2*2;
    m->tape[t+SizeHeader+FIFOSZIN] += ((c<<8) + 2)<<1;
    
    //MMechostr(0,"%d\n", m->tape[t+SizeHeader+FIFOSZIN]);
    
    s = m->tape[t+SizeHeader+FIFOSZIN];
    //$BLG - v5.22: Modif
    //if ((s >= MAXCOM*2) || (s <= 2*2))
    if ((s >= MAXCOM<<1) || (s <= 2<<1))
		{
		  MMechostr(MSKFOO, "#HACK : bad size %x\n", s);
		  SCchanneldown(m);
		  //$BLG - v5.22: Modif
		  //return 1;
		  return MERRCHNLDWN;
		}
    l = ((m->tape[t+SizeHeader+FIFOSZIN]>>1)+3)>>2;   /* prepare le buffer */
    s = MMmalloc(m, l, TYPEBUF); 
    if (s == NIL) return MERRMEM;
    
    t = m->top[m->pp]>>1;
    p = (char*)&m->tape[s+SizeHeader];
    p[0] = p[1] = '_';
    m->tape[t+SizeHeader+FIFOIN] = s+s+1;
    //$BLG - v5.22: Modif
    //m->tape[t+SizeHeader+FIFOCIN] = 2*2;
    //m->tape[t+SizeHeader+FIFOSTIN] = SC_DATA*2;
    m->tape[t+SizeHeader+FIFOCIN] = 2<<1;
    m->tape[t+SizeHeader+FIFOSTIN] = SC_DATA<<1;
    
    return 0;
  }
  
  //MMechostr(0,"ELSE\n");
  
  p = (char*)&m->tape[(m->tape[t+SizeHeader+FIFOIN]>>1)+SizeHeader];
  p[m->tape[t+SizeHeader+FIFOCIN]>>1] = c;
  //$BLG - v5.22: Modif
  //m->tape[t+SizeHeader+FIFOCIN] += 1*2;
  m->tape[t+SizeHeader+FIFOCIN] += 1<<1;
  
  if (m->tape[t+SizeHeader+FIFOCIN] != m->tape[t+SizeHeader+FIFOSZIN]) return 0;

  if (!strncmp(p, "__@", 3))
  {
//  MMechostr(MSKDEBUG,"received %s\n",p);
	  if (!strcmp(p, "__@check"))	  
	  {
		  if (k = SCchecksign(m)) return k;
	  }
//$ ER
#ifdef SERVER
	  else if ((ScolSuper) && (!strncmp(p, "__@c", 4)) && (testlocal(MMstartstr(m, m->tape[t+SizeHeader+FIFONAME]>>1))))
	  {
		  m->tape[t+SizeHeader+FIFOCAPA] = atoi(&p[4])<<1;
		  if (k = SCchecksum(m)) return k;
	  }
//$ ER(09/07/01) turn of #ifdef SERVERM to (!MUTUALISE)&& 
	  else if ((!MUTUALISE) && (!ScolSuper) && (!strcmp(p,"__@k")) && ((m->tape[t+SizeHeader+FIFOSOCK]>>1) == socklife))
	  {
		  if (k = SCkilllast(m)) return k;
	  }
#endif

	  //$LB (25/01/2002) : be aware of the f.... gc.
	  t = m->top[m->pp]>>1;
    p = (char*)&m->tape[(m->tape[t+SizeHeader+FIFOIN]>>1)+SizeHeader];

	  //$ LB(18/07/2001)
	  // a client scol machine ask the main machine the informations to authenticate the user by the http proxy
	  if (ScolSuper && (!strncmp (p, PROXYHTTP_DEFCOM_AUTHENTICATION_REQUEST, strlen(PROXYHTTP_DEFCOM_AUTHENTICATION_REQUEST))))
		PROXYHTTP_GetAuthInfos(m, p);

	  //$LB (25/01/2002) : be aware of the f.... gc.
	  t = m->top[m->pp]>>1;
    p = (char*)&m->tape[(m->tape[t+SizeHeader+FIFOIN]>>1)+SizeHeader];
	  
	  //$ LB(18/07/2001)
	  // receiving http proxy authentication informations from the main machine
	  if (!strncmp (p, PROXYHTTP_DEFCOM_AUTHENTICATION, strlen(PROXYHTTP_DEFCOM_AUTHENTICATION)))
		PROXYHTTP_SetAuthInfos(m, p);

	  t = m->top[m->pp]>>1;
	  m->tape[t+SizeHeader+FIFOIN] = NIL;
	  //$BLG - v5.22: Modif
	  //m->tape[t+SizeHeader+FIFOSTIN] = SC_SIZE0*2;
	  m->tape[t+SizeHeader+FIFOSTIN] = SC_SIZE0<<1;
	  
	  return 0;
  }

  if (k = SCexeccomm(m, p)) return k;
//  MMpull(m);
  t = m->top[m->pp]>>1;
  m->tape[t+SizeHeader+FIFOIN] = NIL;
  //$BLG - v5.22: Modif
  //m->tape[t+SizeHeader+FIFOSTIN] = SC_SIZE0*2;
  m->tape[t+SizeHeader+FIFOSTIN] = SC_SIZE0<<1;
  
  return 0;
}

int SCreadbis(mmachine m,char *buf,int size,int ip,int port)
{
  int i, i0, k, t, l;
  char bufn[128];

//MMechostr(MSKTRACE, "=> SCreadbis(): len = %d\n", size); 

  t = m->top[m->maxpp+OFFSCCUR];  /* lire l'environnement courant */
  if (t == NIL)
  {
    MMechostr(MSKRUNTIME, "Nil environment\n");
    return MERRTYP;
  }
  t >>= 1;
  
  t = m->tape[t+SizeHeader+OFFCHANFIFO]; /* pas de fifo : pas de reception */
  if (t == NIL) return 0;

  if (m->tape[(t>>1)+SizeHeader+FIFOSTOUT] == SC_UDP*2)
  {
//MMechostr(MSKTRACE, "=> SC_UDP\n"); 
    if (k = Mpushstrbloc(m, SCKgetstringbyip(bufn, ip, port))) return k;
    SCsetsockname(m, MMgetglobal(m, OFFSCCUR));

	  l = (buf[0]&255) + ((buf[1]&255)<<8) + 2;
	  if (l != size) return 0;
	  
	  buf[0] = '_';
	  buf[1] = '_';
	  buf[size] = 0;
    MMechostr(MSKDEBUG, "buffer : %s\n", buf); 
    if (k = SCexeccomm(m, buf)) return k;
		//MMpull(m);
	  return 0;
  }

  if (m->tape[(t>>1)+SizeHeader+FIFOSTOUT] == SC_NOTCON*2)
  {
//MMechostr(MSKTRACE, "=> SC_NOTCON\n"); 
    if (k = SCexeccomm(m, "_connected")) return k;
		//MMpull(m);
    t = m->top[m->maxpp+OFFSCCUR]>>1;
    t = m->tape[t+SizeHeader+OFFCHANFIFO];
	  if (m->tape[(t>>1)+SizeHeader+FIFOSOCK] == -2) return 0;
    m->tape[(t>>1)+SizeHeader+FIFOSTOUT] = SC_READY*2;
  }
  
  if (MMpush(m, t)) return MERRMEM; /* empilement du bloc fifo */
  t = MMget(m, 0);
  i0 = 0;
  if (m->tape[(t>>1)+SizeHeader+FIFOSTOUT] == SC_PROXY*2)
  {
//MMechostr(MSKTRACE, "=> SC_PROXY\n"); 
	  m->tape[(t>>1)+SizeHeader+FIFOSTOUT] = SC_NOTCON*2;
	  if ((size >= 8)&&(buf[1] == 90)) SCwrite(m);
	  i0 = 8;
  }
  
  //$BLG - v5.22: Add (DBG)
  /*
  MMechostr(0,"> Sz: %d\n", size);
  for(i = i0; i < size; i++)
  {
  	if ((buf[i]&255) == '\0')	MMechostr(0, "> 0: %d\n", i);
  }
  */
  
  for(i = i0; i < size; i++)
  {
	  dbg = i;
	  
	  k = SCreadchar(m, buf[i]&255);
	  if (k)
	  {
		  //MMechostr(0,"< SCreadchar: %d\n", k);
		  if (k < 0) return k;
		  return 0;
	  }
  }
  //MMechostr(0,"<\n");
	  
  MMpull(m);
  return 0;
}

int SCread(mmachine m, char *buf, int size, int ip, int port)
{
  int pp, k;

  pp = m->pp;
  //MMechostr(0, "> SCreadbis\n");
  k = SCreadbis(m, buf, size, ip, port);
  //MMechostr(0, "< SCreadbis: %d\n", k);
  m->err = k;
  m->pp = pp;
  return k;
}


// Socket problem management : Close msg posting
/* gestion d'un probleme de socket : postage d'un message close */
int SCproblemSock(mmachine m, int t)
{
  int s;

  s = m->tape[t+SizeHeader+FIFOSOCK]>>1;
  MMechostr(MSKFOO, "problemSock %d\n", s);
  //$BLG Note: Next call doesn't do anything - check in src/win/net/socket.c
  SCKpostclose(s);
//  m->tape[t+SizeHeader+FIFOSOCK]=(-s-1)*2;
  return 0;
}


// Management of a Write message
// (We suppose the current channel has been parametered)
// (Doesn't return anything in the stack)
// Returns 1 if channel was closed.
/* traitement d'un message Writable
  (on suppose que le canal courant a ete regle)
  (ne retourne rien dans la pile)
   retourne 1 si le canal est rompu */
int SCwritebis(mmachine m)
{
  int c, k , t, u, n;
  char *p;
 
  // Retrieving current Env
  t = m->top[m->maxpp+OFFSCCUR]>>1;  /* lire l'environnement courant */
  if (t == NIL)
  {
    MMechostr(MSKRUNTIME, "Nil environment\n");
    return MERRTYP;
  }
  
  // No FIFO, no sending
  t = m->tape[t+SizeHeader+OFFCHANFIFO]>>1; /* pas de fifo : pas d'emission */
  if (t == NIL) return 0;
  
  if (m->tape[t+SizeHeader+FIFOSOCK] < 0) return 0;
  //$BLG - v5.22: Modif
  //if (m->tape[t+SizeHeader+FIFOSTOUT] == SC_PROXY*2) return 0;
  //if (m->tape[t+SizeHeader+FIFOSTOUT] == SC_UDP*2) return 0;
  if (m->tape[t+SizeHeader+FIFOSTOUT] == SC_PROXY<<1) return 0;
  if (m->tape[t+SizeHeader+FIFOSTOUT] == SC_UDP<<1) return 0;

  //$BLG - v5.22: Modif
  //if (m->tape[t+SizeHeader+FIFOSTOUT] == SC_NOTCON*2)
  if (m->tape[t+SizeHeader+FIFOSTOUT] == SC_NOTCON<<1)
  {
    if (k = SCexeccomm(m, "_connected")) return k;
		//MMpull(m);
    t = m->top[m->maxpp+OFFSCCUR]>>1;
    t = m->tape[t+SizeHeader+OFFCHANFIFO]>>1;
  	if (m->tape[t+SizeHeader+FIFOSOCK] == -2) return 0;
  }
  //$BLG - v5.22: Modif
  //m->tape[t+SizeHeader+FIFOSTOUT] = SC_READY*2;
  m->tape[t+SizeHeader+FIFOSTOUT] = SC_READY<<1;
  //$BLG Note: Following call doesn't do anything - check src/win/net/socket.c - only for UNIX compatibility
  SCKclrwrite(m->tape[t+SizeHeader+FIFOSOCK]>>1);

  do
  {
    u = m->tape[t+SizeHeader+FIFOOUT];
    if (u == NIL) return 0;
    
    u >>= 1;
    p = (char*)&m->tape[(m->tape[u+SizeHeader+OFFLVAL]>>1)+SizeHeader];
    n = (p[0]&255)+((p[1]&255)<<8)+2;

    c = m->tape[t+SizeHeader+FIFOCOUT]>>1;
  //MMechostr(0, "BEFORE SCKsend: %d %d %d\n%s\n", (p[0]&255)+((p[1]&255)<<8), n, c, &p[c]);
    k = SCKsend(m->tape[t+SizeHeader+FIFOSOCK]>>1, &p[c], n-c);
   /* Gerer la deconnexion lors de l'ecriture */
    if (k < 0) return SCproblemSock(m, t);
    if ((c+k) == n)
    {
      m->tape[t+SizeHeader+FIFOCOUT] = 0;
      m->tape[t+SizeHeader+FIFOOUT] = m->tape[u+SizeHeader+OFFLNEXT];
    }
    else
      //$BLG - v5.22: Modif
      //m->tape[t+SizeHeader+FIFOCOUT] += k*2;
      m->tape[t+SizeHeader+FIFOCOUT] += k<<1;
  } while(k);

  MMechostr(MSKWARNING, "UNCOMPLETED WRITE\n");
  //$BLG - v5.22: Modif
  //m->tape[t+SizeHeader+FIFOSTOUT]=SC_BUSY*2;
  m->tape[t+SizeHeader+FIFOSTOUT] = SC_BUSY<<1;
  //$BLG Note: Following call doesn't do anything - check src/win/net/socket.c - only for UNIX compatibility
  SCKsetwrite(m->tape[t+SizeHeader+FIFOSOCK]>>1);
  return 0;
}

int SCwrite(mmachine m)
{
  int pp, k;

  pp = m->pp;
  k = SCwritebis(m);
  m->pp = pp;
  if (k == 1) k = SCchanneldown(m);
  m->err = k;
  return k;
}


// Sending a Comm type message (already in the stack) in the FIFO.
// (We suppose the current channel has been parametered)
// Returns 1 if channel was closed.
/* envoyer un message de type Comm (present dans la pile) dans la fifo
  (on suppose que le canal courant a ete regle) 
  retourne 1 si le canal est rompu */
int SCsendpile(mmachine m)
{
  int t, k, a, b, n, max, s;
  char cmess[1024];
  cmess[0]=0;

//MMechostr(0, "SCsendpile\n");

  if (MMpush(m, NIL)) return MERRMEM;
  //$BLG - v5.22: Modif
  //if (MMpush(m, 2*2)) return MERRMEM;
  if (MMpush(m, 2<<1)) return MERRMEM;
  if (k = MBdeftab(m)) return k;

  // Retrieving current Env
  t = m->top[m->maxpp+OFFSCCUR];  /* lire l'environnement courant */ 		
  if (t == NIL)
  {
    MMechostr(MSKRUNTIME, "Nil Environment\n");
    return MERRTYP;
  }
  t >>= 1;
  
  // No FIFO, no sending
  t = m->tape[t+SizeHeader+OFFCHANFIFO]; /* pas de fifo : pas d'emission */
  if (t == NIL)
  {
    MMpull(m);
    return 0;
  }
  t >>= 1;
  
  s = m->tape[t+SizeHeader+FIFOSOCK]>>1;
  if (s < 0)
  {
		a = MMget(m, 0)>>1;
		b = MMfetch(m, a, 0)>>1;
		if ((s == FirstUnplugged) && (LocalMessage))
			(*LocalMessage)((char*)MMstartstr(m, b)-2);
    
    //strcat(cmess, (MMstartstr(m, b)-2));
    //$BB ax comm
    //if ((s == FirstUnplugged) && (ActiveXhwnd))
    //  PostMessage(ActiveXhwnd,WM_SCOLAXMESS,0,(LPARAM)cmess);

		MMpull(m);
		return 0;
  } 

  n = MMsize(m, MMget(m, 0)>>1);
  a = t + SizeHeader + FIFOOUT;
  while((b = m->tape[a]) != NIL)
  {
		n += MMsize(m, MMfetch(m, b>>1, OFFLVAL)>>1);
		a = (b>>1) + SizeHeader + OFFLNEXT;
  }
  m->tape[a] = MMpull(m);
  max = m->tape[t+SizeHeader+FIFOMAX]>>1;
  if ((max >= 0) && (n > max)) return SCproblemSock(m, t);

	//$BLG - v5.22: Modif
  //if (m->tape[t+SizeHeader+FIFOSTOUT] == SC_READY*2) return SCwrite(m);
  if (m->tape[t+SizeHeader+FIFOSTOUT] == SC_READY<<1) return SCwrite(m);
  return 0;
}
