/
Crimson2/alias/
Crimson2/area.tmp/
Crimson2/area.tmp/AnomalySpaceDock/
Crimson2/area.tmp/AnomalyStation/
Crimson2/area.tmp/AntHill/
Crimson2/area.tmp/ArcticTerrarium/
Crimson2/area.tmp/BuilderCity/
Crimson2/area.tmp/Dungeon/
Crimson2/area.tmp/MiningDock/
Crimson2/area.tmp/PipeSystem/
Crimson2/area.tmp/RattArea/
Crimson2/area.tmp/RobotFactory/
Crimson2/area.tmp/SilverDale/
Crimson2/area.tmp/StarshipFearless/
Crimson2/area.tmp/StationConduits/
Crimson2/area.tmp/TerrariumAlpha/
Crimson2/area.tmp/TerrariumBeta/
Crimson2/area.tmp/TestArea/
Crimson2/area.tmp/Void/
Crimson2/area/
Crimson2/area/AnomalySpaceDock/
Crimson2/area/AnomalyStation/
Crimson2/area/MiningDock/
Crimson2/area/PipeSystem/
Crimson2/area/SilverDale/
Crimson2/area/StationConduits/
Crimson2/area/Void/
Crimson2/board/
Crimson2/clone/
Crimson2/lib/
Crimson2/mole/
Crimson2/mole/mole_src/HELP/
Crimson2/player/
Crimson2/util/
Crimson2/wldedit/
Crimson2/wldedit/res/
/* part of Crimson2 */
/* Written by B. Cameron Lesiuk */
/* Written for use with Crimson2 MUD (written/copyright Ryan Haksi 1995).
 * This source is proprietary. Use of this code without permission from 
 * Ryan Haksi or Cam Lesiuk is strictly prohibited. 
 * 
 * (clesiuk@engr.uvic.ca)
 */

/* MOLE related buffer/socket management tools */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#ifndef WIN32
  #include <unistd.h>
#endif

#include "crimson2.h"
#include "macro.h"
#include "log.h"
#include "str.h"
#include "queue.h"
#include "send.h"
#include "ini.h"
#include "extra.h"
#include "property.h"
#include "file.h"
#include "thing.h"
#include "index.h"
#include "edit.h"
#include "history.h"
#include "mem.h"
#include "socket.h"
#include "site.h"
#include "exit.h"
#include "world.h"
#include "base.h"
#include "object.h"
#include "char.h"
#include "affect.h"
#include "fight.h"
#include "mobile.h"
#include "skill.h"
#include "player.h"
#include "parse.h"
#include "area.h"
#include "moledefs.h"
#include "mole.h"

LWORD MOLEParse(SOCK *sock, BYTE *cmd, ULWORD *moleCmd) {
  LWORD       i;
  LWORD       j;
  ULWORD      checkSum;
  BYTE       *p;
  BYTE        buf[2*(MOLE_PKT_MAX+1)];
  BYTE        data;

  if ((!cmd)||(!sock)||(!moleCmd)) return -1;
  /* First, check the header */
  i=0;

  /* Zip past any garbage at the start */
  while((cmd[i])&&(cmd[i]!=MOLE_DELIM_CHAR))
    i++;
  /* Check integrity of MOLE header */
  p=MOLE_HDR;
  for (j=0;(cmd[i+j])&&(j<MOLE_HDR_SIZE);j++)
    if (p[j]!=cmd[i+j]) 
      break;
  if (j!=MOLE_HDR_SIZE) return -1;

  if (cmd[i+j])
    i+=j+1; /* increment past header and mandatory space */
  else 
    return -1;

  *moleCmd=0;
  for (j=0;(j<4)&&(cmd[i+j]);j++) {
    (*moleCmd)<<=8;
    (*moleCmd)|=cmd[i+j];
  }
  if (j<4) return -1;

  /* we've just read in our cmd. */
  if (cmd[i+j])
    i+=j+1; /* increment past command word */
  else 
    return -1;

  /* now we just need to read in our buffer */
  j=0;
  checkSum=0;
  while((cmd[i+(j<<1)])&&(cmd[i+(j<<1)+1])) {
    if ((cmd[i+(j<<1)]==MOLE_DELIM_CHAR)&&(cmd[i+(j<<1)+1]==MOLE_DELIM_CHAR)) {
      if (checkSum) return -1; /* checksum should be 0 */
      if (j) j--;              /* whack off trailing byte (checksum) */
      buf[(j<<1)]=0; /* terminate string */
      if (j) QAppend(sock->sMole,buf,Q_DONTCHECKSTR); 
      return j;
    } else {
      if (j==(MOLE_PKT_MAX+1))
        return -1;              /* packet too large - error */
 
      /* decode data - check for data integrity */
      if ((cmd[i+(j<<1)]>='0')&&(cmd[i+(j<<1)]<='9'))
        data=(cmd[i+(j<<1)]-'0')<<4;
      else if ((cmd[i+(j<<1)]>='A')&&(cmd[i+(j<<1)]<='F'))
        data=(cmd[i+(j<<1)]-'A'+10)<<4;
      else return -1; /* error in format - only 1-9, A-F allowed */

      if ((cmd[i+(j<<1)+1]>='0')&&(cmd[i+(j<<1)+1]<='9'))
        data+=(cmd[i+(j<<1)+1]-'0');
      else if ((cmd[i+(j<<1)+1]>='A')&&(cmd[i+(j<<1)+1]<='F'))
        data+=(cmd[i+(j<<1)+1]-'A'+10);
      else return -1; /* error in format - only 1-9, A-F allowed */

      /* now save data */
      buf[(j<<1)]=cmd[i+(j<<1)];
      buf[(j<<1)+1]=cmd[i+(j<<1)+1];
      checkSum^=data;

      j++;
    } /* if .. else */
  } /* while */
  return -1;
}

void MOLEFlushQ(SOCK *sock) {
  if (sock) {
    QFlush(sock->sMole);
  }
}

LWORD MOLEGetQSize(SOCK *sock) {
  if (sock) return sock->sMole->qLen;
  return -1;
}

LWORD MOLEGetQData(SOCK *sock, BYTE *buf, ULWORD *bufLen,FLAG flag) {
  BYTE   tmpBuf[4];
  ULWORD i;
  BYTE   data;

  if ((!sock)||(!buf)||(!bufLen)) return -1;
  i=0;
  if (flag & GQD_STRING)
    (*bufLen)--;
  while ((MOLEGetQSize(sock)>=2)&&(i<*bufLen)) {
    /* read in 2 characters */
    QReadByte(sock->sMole,tmpBuf,4,Q_COLOR_IGNORE,2);

    if (tmpBuf[0] && tmpBuf[1]) tmpBuf[2]=0;

    /* process 2-byte string into a number */
    if ((tmpBuf[0]>='0')&&(tmpBuf[0]<='9'))
      data=(tmpBuf[0]-'0')<<4;
    else if ((tmpBuf[0]>='A')&&(tmpBuf[0]<='F'))
      data=(tmpBuf[0]-'A'+10)<<4;
    else return -1; /* error in format - only 1-9, A-F allowed */

    if ((tmpBuf[1]>='0')&&(tmpBuf[1]<='9'))
      data+=(tmpBuf[1]-'0');
    else if ((tmpBuf[1]>='A')&&(tmpBuf[1]<='F'))
      data+=(tmpBuf[1]-'A'+10);
    else return -1;
  
    buf[i]=data;
    if ((data==0x00)&&(flag & GQD_STRING))
      break;
    i++;
  }
  *bufLen=i;
  if (flag&GQD_STRING)
    buf[i+1]=0x00; /* terminate if we've filled a string buffer fully */
  return i;
}

/* reads the first 4 bytes as a packet Cmd - ie straight out of the
 * data stream. This may be different from MOLEGetQULWORD. */
LWORD MOLEGetQDataCmd(SOCK *sock, ULWORD *pktCmd) {
  ULWORD bufLen;

  if ((!sock)||(!pktCmd))
    return -1;
  bufLen=4;
  MOLEGetQData(sock,(BYTE*)pktCmd,&bufLen,GQD_BINARY);
  if (bufLen!=4)
    return -1;
  return 0;
}

/* reads the first 4 bytes from the queue and stuffs them in *data.
 * If there's not 4 bytes for the full ULWORD, the bytes are still 
 * read, and -1 is returned (error). */
LWORD MOLEGetQULWORD(SOCK *sock, ULWORD *data) {
  BYTE   buf[6];
  ULWORD bufLen;

  *data=0L;
  if ((!sock)||(!data))
    return -1;
  bufLen=4;
  MOLEGetQData(sock,buf,&bufLen,GQD_BINARY);
  if (bufLen!=4) 
    return -1;
  *data=(((ULWORD)(buf[0])&0x0FFL))|(((ULWORD)(buf[1])&0x0FFL)<<8)|
        (((ULWORD)(buf[2])&0x0FFL)<<16)|(((ULWORD)(buf[3]))<<24);
  return 0;
}

LWORD MOLEGetQStr(SOCK *sock, STR **data) {
  static BYTE  *buf=NULL;
  static LWORD  bufLen=1024;
         LWORD  rc;
         STR   *str;
         LWORD  size;

  if ((!sock)||(!data))
    return -1;

  /* Resize our buffer if it's too small. This part just assumes
   * the string we are about to read is the size of the remaining
   * mole buffer - an incorrect assumption, but a safe one! */
  /* Note that this should alloc us a buffer when buf==NULL */
  while(((MOLEGetQSize(sock)/2+1)>=bufLen)||(!buf))
    REALLOC("WARNING! MOLE string buffer overflow... resizing\n",
      buf,BYTE,(MOLEGetQSize(sock)/2+1),bufLen);

  /* go get our string */
  size=bufLen;
  rc=MOLEGetQData(sock,buf,&size,GQD_STRING);
  str=NULL;
  if (rc>=0) {
    /* now create a STR to return */
    str=StrCreate(buf,SLEN_UNKNOWN,HASH);
  }
  if (data)
    *data=str;
  if (str)
    return 0;
  return -1;
}

/* This proc inserts srcBuf into dstBuf, sending MORE packets if req'd. */
/* NOTE This proc assumes dstBuf is at LEAST MOLE_PKT_MAX bytes long.   */
LWORD MOLEWriteULWORD(SOCK *sock, ULWORD ulWord, BYTE *dstBuf,ULWORD *bufPos) {
  if ((!sock)||(!dstBuf)||(!bufPos)) return -1;
  if ((*bufPos)>=(MOLE_PKT_MAX-4)) {
    MOLESend(sock,dstBuf,*bufPos,MOLE_CMD_MORE);
    (*bufPos)=0;
    }
  dstBuf[*bufPos]=(BYTE)((ulWord & 0x000000FFL));
  (*bufPos)++;
  dstBuf[*bufPos]=(BYTE)((ulWord & 0x0000FF00L)>>8);
  (*bufPos)++;
  dstBuf[*bufPos]=(BYTE)((ulWord & 0x00FF0000L)>>16);
  (*bufPos)++;
  dstBuf[*bufPos]=(BYTE)((ulWord & 0xFF000000L)>>24);
  (*bufPos)++;
  return 0;
}

/* This proc inserts srcBuf into dstBuf, sending MORE packets if req'd. */
/* NOTE This proc assumes dstBuf is at LEAST MOLE_PKT_MAX bytes long.   */
LWORD MOLEWriteBuf(SOCK *sock,BYTE *srcBuf,BYTE *dstBuf,ULWORD *bufPos) {
  if ((!sock)||(!srcBuf)||(!dstBuf)||(!bufPos)) return -1;
  /* copy file name into buffer */
  srcBuf--; /* we do this so that we INCLUDE the trailing 0x00 */
  do {
    srcBuf++;
    dstBuf[*bufPos]=*srcBuf;
    (*bufPos)++;
    if ((*bufPos)>= MOLE_PKT_MAX) {
      MOLESend(sock,dstBuf,*bufPos,MOLE_CMD_MORE);
      (*bufPos)=0;
    }
  } while (*srcBuf);
  return 0;
}

/* This proc calls MOLEWriteBuf to insert flag and type lists into
 * the MOLE packet */
LWORD MOLEWriteList(SOCK *sock,ULWORD list,LWORD listSize,BYTE *dstBuf,ULWORD *bufPos) {
  LWORD i;


  i=-1; /* this is so we get & send our last NULL string */
  do {
    i++;
    MOLEWriteBuf(sock,*((BYTE**)(list+i*listSize)),dstBuf,bufPos);
  } while (**((BYTE**)(list+i*listSize))!='\0');
  return 0;
}

/* This proc sends a MOLE-formatted packet to sock. No buffer length */
/* checking is done - it's the caller's responsibility to enseure    */
/* cmdLen doesn't exceed MOLE_PKT_MAX                                */
void MOLESend(SOCK *sock, BYTE* cmd, LWORD cmdLen, ULWORD moleCmd) {
  ULWORD     i;
  ULWORD     counter;
  BYTE       buf[MOLE_HDR_SIZE+(MOLE_PKT_MAX*2)+14];
  UWORD      checkSum;

  if ((!sock)||(!cmd)) return;

  i=0; /* this is our buffer position marker. */

  /**** MOLE Package format is defined here! ****/
  /* start with a start-of-packet character */
  buf[i]=MOLE_PKT_START;
  i++;

  /* append our header */ 
  strcpy(&(buf[i]),MOLE_HDR);
  i+=MOLE_HDR_SIZE;
 
  /* <space><command><space> */ 
  buf[i]=' ';
  i++;
  buf[i+0]=(moleCmd>>24)&0xFF;
  buf[i+1]=(moleCmd>>16)&0xFF;
  buf[i+2]=(moleCmd>>8)&0xFF;
  buf[i+3]=(moleCmd)&0xFF;
  i+=4;
  buf[i]=' ';
  i++;

  /* <data><data><data><...><data><checksum> */
  checkSum=0;
  for (counter=0;counter<cmdLen;counter++) {
    sprintf(&(buf[i]),"%02X",(UWORD)cmd[counter]);
    checkSum^=cmd[counter];
    i+=2;
  }
  sprintf(&buf[i],"%02X",checkSum);
  i+=2;

  /* Ending delimiter */
  buf[i]=MOLE_DELIM_CHAR;
  i++;
  buf[i]=MOLE_DELIM_CHAR;
  i++;
 
  /* end-of-packet character */ 
  buf[i]=MOLE_PKT_STOP;
  i++;

  /* oh! Don't forget to send a '\n'! */
  buf[i]='\n';
  i++;

  /* and terminate our string */
  buf[i]=0;
/*
  buf[0]=MOLE_PKT_START;
  buf[1]=0;
  SEND(buf,sock);
  SEND(MOLE_HDR,sock);
  SEND(" ",sock); 
  buf[0]=(moleCmd>>24)&0xFF;
  buf[1]=(moleCmd>>16)&0xFF;
  buf[2]=(moleCmd>>8)&0xFF;
  buf[3]=(moleCmd)&0xFF;
  buf[4]=0;
  SEND(buf,sock);
  SEND(" ",sock);
  checkSum=0;
  for (counter=0;counter<cmdLen;counter++) {
    sprintf(buf,"%02X",(UWORD)cmd[counter]);
    SEND(buf,sock);
    checkSum^=cmd[counter];
  }
  sprintf(buf,"%02X",checkSum);
  SEND(buf,sock);
  SEND(MOLE_DELIM,sock);
  buf[0]=MOLE_PKT_STOP;
  buf[1]=0;
  SEND(buf,sock);
  buf[0]='\n';
  buf[1]=0;
  */
  SEND(buf,sock);
}

LWORD MOLECommandCheck(SOCK *sock, BYTE *cmd, LWORD virtual) {
  BYTE  fullCmd[256];

  if (virtual<0)
    return ParseCommandCheck(TYPEFIND(cmd,commandList),sock,cmd);
  
  sprintf(fullCmd,"%s %li",cmd,virtual);
  return ParseCommandCheck(TYPEFIND(cmd,commandList),sock,fullCmd);
}