lpmoo-1.2/etc/
lpmoo-1.2/mudlib/
lpmoo-1.2/mudlib/etc/
lpmoo-1.2/mudlib/include/
lpmoo-1.2/mudlib/include/moo/
lpmoo-1.2/mudlib/lpc/
lpmoo-1.2/mudlib/std/auto/
lpmoo-1.2/mudlib/std/bfuns/
/*
 * NAME:	binary.c
 * DESCRIPTION:	connection object specialized for binary connections
 */

inherit "/std/connection";

# include <moo/errors.h>

private string	inbuf;		/* incoming data buffer */
private	string	outbuf;		/* outgoing data buffer */
private	int	co_flush;	/* flush() call_out handle */
private int	flags;		/* special binary flags */

# define F_CURRENT	0x01	/* execution started with this object */
# define F_CLOSING	0x02	/* connection is trying to close */

# define BUFTHRESH	2048	/* buffer limit before flushing */

/*
 * NAME:	create()
 * DESCRIPTION:	initialize data
 */
static
void create(void)
{
  inbuf = outbuf = "";
  ::create();
}

/*
 * NAME:	flush()
 * DESCRIPTION:	try to send the output buffer to the connection
 */
void flush(void)
{
  int len;

  if (co_flush)
    {
      remove_call_out(co_flush);
      co_flush = 0;
    }

  if (! strlen(outbuf))
    return;

  len = send_message(outbuf);
  if (len >= 0)
    {
      if (strlen(outbuf = outbuf[len ..]))
	co_flush = call_out("flush", 1);
    }
  else
    outbuf = "";  /* not connected? */
}

/*
 * NAME:	finish()
 * DESCRIPTION:	called to finish processing; flush the output buffer
 */
void finish(void)
{
  ::finish();
  flush();

  flags &= ~F_CURRENT;
}

/*
 * NAME:	send()
 * DESCRIPTION:	called to send a partial line to the user (raw data)
 */
void send(string msg)
{
  outbuf += msg;

  if (! (flags & F_CURRENT) || strlen(outbuf) > BUFTHRESH)
    flush();
}

/*
 * NAME:	notify()
 * DESCRIPTION:	send a line of text
 */
void notify(string msg)
{
  send(msg + "\r\n");
}

/*
 * NAME:	get_line()
 * DESCRIPTION:	return a line of pending input, if available
 */
string get_line(void)
{
  string line;

  return (sscanf(inbuf, "%s\r\n%s", line, inbuf) == 2 ||
	  sscanf(inbuf, "%s\n%s",   line, inbuf) == 2) ? line : 0;
}

/*
 * NAME:	get_data()
 * DESCRIPTION:	return any pending input as raw data
 */
string get_data(void)
{
  string data;

  if (strlen(inbuf))
    {
      data  = inbuf;
      inbuf = "";
    }
  else
    data = 0;

  return data;
}

/*
 * NAME:	receive_message()
 * DESCRIPTION:	called by DGD when binary data arrives
 */
static
void receive_message(string data)
{
  string line;

  if (flags & F_CLOSING)  /* ignore further input */
    return;

  inbuf += data;

  if (! strlen(inbuf))
    return;

  flags |= F_CURRENT;

  if (want_binary())
    {
      data  = inbuf;
      inbuf = "";

      process_data(data);
    }
  else if (line = get_line())
    {
      if (strlen(inbuf))
	call_out("receive_message", 0, "");

      process_line(line);
    }

  finish();
}

/*
 * NAME:	destruct()
 * DESCRIPTION:	attempt to flush the output buffer before destructing
 */
static
void destruct(void)
{
  flags |= F_CLOSING;

  if (co_flush)
    {
      call_out("destruct", 1);
      return;
    }

  ::destruct();
}