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/
*** dgd/src/comm.c.orig	Sat Aug 12 19:00:38 1995
--- dgd/src/comm.c	Thu Aug 31 21:32:49 1995
***************
*** 8,16 ****
  # include "comm.h"
  
  # ifndef TELOPT_LINEMODE
! # define TELOPT_LINEMODE	34	/* linemode option */
! # define LM_MODE		1
! # define MODE_EDIT		0x01
  # endif
  
  typedef struct _user_ {
--- 8,16 ----
  # include "comm.h"
  
  # ifndef TELOPT_LINEMODE
! # define TELOPT_LINEMODE       34      /* linemode option */
! # define LM_MODE               1
! # define MODE_EDIT             0x01
  # endif
  
  typedef struct _user_ {
***************
*** 20,69 ****
      } u;
      int inbufsz;		/* bytes in input buffer */
      int outbufsz;		/* bytes in output buffer */
      char flags;			/* connection flags */
      char state;			/* telnet state */
-     short newlines;		/* # of newlines in input buffer */
      connection *conn;		/* connection */
!     char inbuf[INBUF_SIZE];	/* input buffer */
!     char outbuf[OUTBUF_SIZE];	/* output buffer */
  } user;
  
  /* flags */
! # define CF_ECHO	0x01	/* client echoes input */
! # define CF_TELNET	0x02	/* telnet connection */
! # define CF_GA		0x04	/* send GA after prompt */
! # define CF_SEENCR	0x08	/* just seen a CR */
  
  /* state */
  # define TS_DATA	0
  # define TS_IAC		1
  # define TS_DO		2
  # define TS_DONT	3
! # define TS_WILL	4
! # define TS_WONT	5
! # define TS_SB		6
! # define TS_SE		7
  
  static user **users;		/* array of users */
  static int maxusers;		/* max # of users */
  static int nusers;		/* # of users */
  static int newlines;		/* # of newlines in all input buffers */
- static long binchars;		/* # characters in binary buffers */
  static object *this_user;	/* current user */
  
  /*
   * NAME:	comm->init()
   * DESCRIPTION:	initialize communications
   */
! void comm_init(nusers, telnet_port, binary_port)
! int nusers, telnet_port, binary_port;
  {
      register int i;
      register user **usr;
  
!     conn_init(nusers, telnet_port, binary_port);
!     users = ALLOC(user*, maxusers = nusers);
!     for (i = nusers, usr = users; i > 0; --i, usr++) {
  	*usr = (user *) NULL;
      }
  }
--- 20,71 ----
      } u;
      int inbufsz;		/* bytes in input buffer */
      int outbufsz;		/* bytes in output buffer */
+     int newlines;               /* # of newlines in input buffer */
      char flags;			/* connection flags */
      char state;			/* telnet state */
      connection *conn;		/* connection */
!     char *inbuf;                /* input buffer */
!     char *outbuf;               /* output buffer */
  } user;
  
  /* flags */
! # define CF_ECHO	0x01    /* client echoes input */
! # define CF_TELNET	0x02    /* telnet connection */
! # define CF_GA		0x04    /* send GA after prompt */
! # define CF_SEENCR	0x08    /* just seen a CR */
! # define CF_PORT        0x10    /* port connection */
! # define CF_DATAGRAM    0x20    /* datagram connection */
! # define CF_CONNECTING  0x40    /* connection being initiated */
  
  /* state */
  # define TS_DATA	0
  # define TS_IAC		1
  # define TS_DO		2
  # define TS_DONT	3
! # define TS_WILL        4
! # define TS_WONT        5
! # define TS_SB          6
! # define TS_SE          7
  
  static user **users;		/* array of users */
  static int maxusers;		/* max # of users */
  static int nusers;		/* # of users */
  static int newlines;		/* # of newlines in all input buffers */
  static object *this_user;	/* current user */
  
  /*
   * NAME:	comm->init()
   * DESCRIPTION:	initialize communications
   */
! void comm_init(cf_users)
! int cf_users;
  {
      register int i;
      register user **usr;
  
!     conn_init(cf_users);
!     users = ALLOC(user*, maxusers = cf_users);
!     for (i = cf_users, usr = users; i > 0; --i, usr++) {
  	*usr = (user *) NULL;
      }
  }
***************
*** 80,119 ****
  
  /*
   * NAME:	comm->new()
!  * DESCRIPTION:	accept a new connection
   */
! static void comm_new(obj, conn, telnet)
  object *obj;
  connection *conn;
! bool telnet;
  {
!     static char init[] = { IAC, WONT, TELOPT_ECHO, IAC, DO, TELOPT_LINEMODE };
      register user **usr;
  
      if (obj->flags & (O_USER | O_EDITOR)) {
! 	error("user object is already used for user or editor");
      }
      for (usr = users; *usr != (user *) NULL; usr++) ;
      mstatic();
!     *usr = ALLOC(user, 1);
      mdynamic();
      (*usr)->u.obj = obj;
      obj->flags |= O_USER;
      obj->etabi = usr - users;
      (*usr)->inbufsz = 0;
      (*usr)->outbufsz = 0;
      (*usr)->conn = conn;
!     if (telnet) {
! 	/* initialize connection */
! 	conn_write(conn, init, sizeof(init));
! 	(*usr)->flags = CF_TELNET | CF_ECHO;
  	(*usr)->state = TS_DATA;
! 	(*usr)->newlines = 0;
      } else {
! 	(*usr)->flags = 0;
      }
      nusers++;
-     this_user = obj;
  }
  
  /*
--- 82,142 ----
  
  /*
   * NAME:	comm->new()
!  * DESCRIPTION:	allocate and init a new user struct (assumes nusers < maxusers)
   */
! static void comm_new(obj, conn, flags)
  object *obj;
  connection *conn;
! int flags;
  {
!     static char give_lm[] = { IAC, DO, TELOPT_LINEMODE };
!     static char echo_on[] = { IAC, WONT, TELOPT_ECHO };
! 
      register user **usr;
+     register int size;
  
      if (obj->flags & (O_USER | O_EDITOR)) {
! 	error("User object is already used for user or editor");
!     }
! 
!     if (flags & CF_PORT) {
! 	size = sizeof(user);
!     } else if (flags & CF_TELNET) {
! 	size = sizeof(user) + INBUF_SIZE + OUTBUF_SIZE;
!     } else {
! 	size = sizeof(user) + OUTBUF_SIZE;
      }
+ 
      for (usr = users; *usr != (user *) NULL; usr++) ;
      mstatic();
!     *usr = (user *)ALLOC(char, size);
      mdynamic();
      (*usr)->u.obj = obj;
      obj->flags |= O_USER;
      obj->etabi = usr - users;
      (*usr)->inbufsz = 0;
      (*usr)->outbufsz = 0;
+     (*usr)->newlines = 0;
      (*usr)->conn = conn;
!     (*usr)->flags = flags;
!     if (flags & CF_PORT) {
! 	(*usr)->inbuf = (char *) NULL;
! 	(*usr)->outbuf = (char *) NULL;
!     } else if (flags & CF_TELNET) {
! 	(*usr)->inbuf = (char *) *usr + sizeof(user);
! 	(*usr)->outbuf = (*usr)->inbuf + INBUF_SIZE;
  	(*usr)->state = TS_DATA;
! 	if (!(flags & CF_CONNECTING)) {
! 	    if (flags & CF_ECHO) {
! 		conn_write(conn, echo_on, 3);
! 	    }
! 	    conn_write(conn, give_lm, 3);
! 	}
      } else {
! 	(*usr)->inbuf = (char *) NULL;
! 	(*usr)->outbuf = (char *) *usr + sizeof(user);
      }
      nusers++;
  }
  
  /*
***************
*** 128,135 ****
      conn_del((*usr)->conn);
      if ((*usr)->flags & CF_TELNET) {
  	newlines -= (*usr)->newlines;
-     } else {
- 	binchars -= (*usr)->inbufsz;
      }
      obj = (*usr)->u.obj;
      obj->flags &= ~O_USER;
--- 151,156 ----
***************
*** 150,155 ****
--- 171,238 ----
  }
  
  /*
+  * NAME:	comm->listen()
+  * DESCRIPTION:	have an object listen to a port
+  */
+ void comm_listen(obj, port, protocol)
+ object *obj;
+ int port, protocol;
+ {
+     register connection *conn;
+     int flags;
+ 
+     if (nusers >= maxusers)
+ 	error("Max number of connection/port objects exceeded");
+ 
+     if (protocol == PRC_TELNET) {
+ 	flags = CF_TELNET | CF_ECHO | CF_PORT;
+ 	protocol = PRC_TCP;
+     } else if (protocol == PRC_UDP) {
+ 	flags = CF_DATAGRAM | CF_PORT;
+     } else {
+ 	flags = CF_PORT;
+     }
+     conn = conn_listen(port, protocol);
+     if (conn != (connection *) NULL) {
+ 	comm_new(obj, conn, flags);
+     } else {
+         error("Could not open port");
+     }
+     if (i_call(obj, "open", TRUE, 0)) {
+         i_del_value(sp++);
+     }
+ }
+ 
+ /*
+  * NAME:	comm->connect()
+  * DESCRIPTION:	initiate a telnet or tcp connection
+  */
+ void comm_connect(obj, host, port, protocol)
+ object *obj;
+ char *host;
+ int port, protocol;
+ {
+     register connection *conn;
+     int flags;
+ 
+     if (nusers >= maxusers)
+ 	error("Max number of connection/port objects exceeded");
+ 
+     if (protocol == PRC_TELNET) {
+ 	flags = CF_TELNET | CF_CONNECTING;
+ 	protocol = PRC_TCP;
+     } else if (protocol == PRC_TCP) {
+ 	flags = CF_CONNECTING;
+     }
+     conn = conn_connect(host, port, protocol);
+     if (conn != (connection *) NULL) {
+ 	comm_new(obj, conn, flags);
+     } else {
+ 	error("Could not initiate connection");
+     }
+ }
+ 
+ /*
   * NAME:	comm->send()
   * DESCRIPTION:	send a message to a user
   */
***************
*** 162,173 ****
      register unsigned short len, size;
  
      usr = users[UCHAR(obj->etabi)];
      p = str->text;
      len = str->len;
      if (usr->flags & CF_TELNET) {
- 	/*
- 	 * telnet connection
- 	 */
  	size = usr->outbufsz;
  	q = usr->outbuf + size;
  	while (len != 0) {
--- 245,259 ----
      register unsigned short len, size;
  
      usr = users[UCHAR(obj->etabi)];
+     if (usr->flags & (CF_DATAGRAM | CF_PORT)) {
+         error("Object is not a stream connection");
+     }
+     if (usr->flags & CF_CONNECTING) {
+ 	error("Connection is not yet ready");
+     }
      p = str->text;
      len = str->len;
      if (usr->flags & CF_TELNET) {
  	size = usr->outbufsz;
  	q = usr->outbuf + size;
  	while (len != 0) {
***************
*** 218,223 ****
--- 304,329 ----
  }
  
  /*
+  * NAME:	comm->sendto()
+  * DESCRIPTION:	send a datagram
+  */
+ void comm_sendto(obj, data, host, port)
+ object *obj;
+ string *data;
+ char *host;
+ int port;
+ {
+     register user *usr;
+ 
+     usr = users[UCHAR(obj->etabi)];
+     if (usr->flags & CF_DATAGRAM == 0) {
+ 	error("Object is not a datagram object");
+     }
+     conn_sendto(usr->conn, data->text, data->len, host, port);
+ }
+ 
+ 
+ /*
   * NAME:	comm->echo()
   * DESCRIPTION:	turn on/off input echoing for a user
   */
***************
*** 229,234 ****
--- 335,342 ----
      char buf[3];
  
      usr = users[UCHAR(obj->etabi)];
+     if (usr->flags & CF_CONNECTING)
+ 	error("Connection is not yet ready");
      if ((usr->flags & CF_TELNET) && echo != (usr->flags & CF_ECHO)) {
  	buf[0] = IAC;
  	buf[1] = (echo) ? WONT : WILL;
***************
*** 276,590 ****
   * NAME:	comm->receive()
   * DESCRIPTION:	receive a message from a user
   */
! object *comm_receive(buf, size)
! char *buf;
! int *size;
  {
      static int lastuser;
      connection *conn;
      object *o;
!     register int n, i, state, flags, nls;
      register char *p, *q;
  
-     if (nusers < maxusers) {
- 	/*
- 	 * accept new telnet connection
- 	 */
- 	conn = conn_tnew();
- 	if (conn != (connection *) NULL) {
- 	    if (ec_push()) {
- 		conn_del(conn);		/* delete connection */
- 		error((char *) NULL);	/* pass on error */
- 	    }
- 	    call_driver_object("telnet_connect", 0);
- 	    ec_pop();
- 	    if (sp->type != T_OBJECT) {
- 		fatal("driver->telnet_connect() did not return an object");
- 	    }
- 	    d_export();
- 	    comm_new(o = o_object(sp->oindex, sp->u.objcnt), conn, TRUE);
- 	    sp++;
- 	    if (i_call(o, "open", TRUE, 0)) {
- 		i_del_value(sp++);
- 		d_export();
- 	    }
- 	    comm_flush(TRUE);
- 	}
-     }
- 
-     if (nusers < maxusers) {
- 	/*
- 	 * accept new binary connection
- 	 */
- 	conn = conn_bnew();
- 	if (conn != (connection *) NULL) {
- 	    if (ec_push()) {
- 		conn_del(conn);		/* delete connection */
- 		error((char *) NULL);	/* pass on error */
- 	    }
- 	    call_driver_object("binary_connect", 0);
- 	    ec_pop();
- 	    if (sp->type != T_OBJECT) {
- 		fatal("driver->binary_connect() did not return an object");
- 	    }
- 	    d_export();
- 	    comm_new(o = o_object(sp->oindex, sp->u.objcnt), conn, FALSE);
- 	    sp++;
- 	    if (i_call(o, "open", TRUE, 0)) {
- 		i_del_value(sp++);
- 		d_export();
- 	    }
- 	    comm_flush(TRUE);
- 	}
-     }
- 
-     /*
-      * read input from users
-      */
      this_user = (object *) NULL;
!     n = conn_select(newlines == 0 && binchars == 0);
!     if (n <= 0) {
! 	/*
! 	 * call_out to do, or timeout
! 	 */
! 	if (newlines == 0 && binchars == 0) {
! 	    return (object *) NULL;
! 	}
!     } else {
! 	static char intr[] =	 { '\177' };
! 	static char brk[] =	 { '\034' };
! 	static char tm[] =	 { (char) IAC, (char) WILL, (char) TELOPT_TM };
! 	static char will_sga[] = { (char) IAC, (char) WILL, (char) TELOPT_SGA };
! 	static char wont_sga[] = { (char) IAC, (char) WONT, (char) TELOPT_SGA };
! 	static char mode_edit[]= { (char) IAC, (char) SB,
! 				   (char) TELOPT_LINEMODE, (char) LM_MODE,
! 				   (char) MODE_EDIT, (char) IAC, (char) SE };
! 	register user **usr;
! 
! 	for (i = maxusers, usr = users; i > 0; --i, usr++) {
! 	    if (*usr != (user *) NULL && (*usr)->inbufsz != INBUF_SIZE) {
! 		p = (*usr)->inbuf + (*usr)->inbufsz;
! 		n = conn_read((*usr)->conn, p, INBUF_SIZE - (*usr)->inbufsz);
! 		if (n < 0) {
! 		    /*
! 		     * bad connection
! 		     */
! 		    comm_del(usr);
! 		    d_export();	/* this cannot be in comm_del() */
! 		} else if ((*usr)->flags & CF_TELNET) {
! 		    /*
! 		     * telnet mode
! 		     */
! 		    flags = (*usr)->flags;
! 		    state = (*usr)->state;
! 		    nls = (*usr)->newlines;
! 		    q = p;
! 		    while (n > 0) {
! 			switch (state) {
! 			case TS_DATA:
! 			    switch (UCHAR(*p)) {
! 			    case '\0':
! 				flags &= ~CF_SEENCR;
! 				break;
  
! 			    case IAC:
! 				state = TS_IAC;
! 				break;
  
! 			    case BS:
! 			    case 0x7f:
! 				if (q != (*usr)->inbuf && q[-1] != LF) {
! 				    --q;
! 				}
! 				flags &= ~CF_SEENCR;
! 				break;
  
! 			    case CR:
! 				nls++;
! 				newlines++;
! 				*q++ = LF;
! 				flags |= CF_SEENCR;
! 				break;
  
! 			    case LF:
! 				if ((flags & CF_SEENCR) != 0) {
  				    flags &= ~CF_SEENCR;
  				    break;
! 				}
! 				nls++;
! 				newlines++;
! 				/* fall through */
! 			    default:
! 				*q++ = *p;
! 				flags &= ~CF_SEENCR;
  				break;
- 			    }
- 			    break;
  
! 			case TS_IAC:
! 			    switch (UCHAR(*p)) {
! 			    case IAC:
! 				*q++ = *p;
! 				state = TS_DATA;
! 				break;
  
! 			    case DO:
! 				state = TS_DO;
! 				break;
  
! 			    case DONT:
! 				state = TS_DONT;
! 				break;
  
! 			    case WILL:
! 				state = TS_WILL;
! 				break;
  
! 			    case WONT:
! 				state = TS_WONT;
! 				break;
  
! 			    case SB:
! 				state = TS_SB;
  				break;
  
! 			    case IP:
! 				conn_write((*usr)->conn, intr, 1);
  				state = TS_DATA;
  				break;
  
! 			    case BREAK:
! 				conn_write((*usr)->conn, brk, 1);
  				state = TS_DATA;
  				break;
  
! 			    default:
! 				/* let's hope it wasn't important */
  				state = TS_DATA;
  				break;
- 			    }
- 			    break;
- 
- 			case TS_DO:
- 			    if (UCHAR(*p) == TELOPT_TM) {
- 				conn_write((*usr)->conn, tm, 3);
- 			    } else if (UCHAR(*p) == TELOPT_SGA) {
- 				flags &= ~CF_GA;
- 				conn_write((*usr)->conn, will_sga, 3);
- 			    }
- 			    state = TS_DATA;
- 			    break;
- 
- 			case TS_DONT:
- 			    if (UCHAR(*p) == TELOPT_SGA) {
- 				flags |= CF_GA;
- 				conn_write((*usr)->conn, wont_sga, 3);
- 			    }
- 			    state = TS_DATA;
- 			    break;
  
! 			case TS_WILL:
! 			    if (UCHAR(*p) == TELOPT_LINEMODE) {
! 				/* linemode confirmed; now request editing */
! 				conn_write((*usr)->conn, mode_edit, 7);
! 			    }
! 			    /* fall through */
! 			case TS_WONT:
! 			    state = TS_DATA;
! 			    break;
! 
! 			case TS_SB:
! 			    /* skip to the end */
! 			    if (UCHAR(*p) == IAC) {
! 				state = TS_SE;
! 			    }
! 			    break;
  
! 			case TS_SE:
! 			    if (UCHAR(*p) == SE) {
! 				/* end of subnegotiation */
! 				state = TS_DATA;
! 			    } else {
! 				state = TS_SB;
  			    }
! 			    break;
  			}
! 			p++;
! 			--n;
  		    }
! 		    (*usr)->flags = flags;
! 		    (*usr)->state = state;
! 		    (*usr)->newlines = nls;
! 		    (*usr)->inbufsz = q - (*usr)->inbuf;
! 		} else {
! 		    /*
! 		     * binary mode
! 		     */
! 		    (*usr)->inbufsz += n;
! 		    binchars += n;
! 		}
! 	    }
! 	}
!     }
! 
!     if (newlines != 0 || binchars != 0) {
! 	register user *usr;
! 
! 	n = lastuser;
! 	for (;;) {
! 	    n = (n + 1) % maxusers;
! 	    usr = users[n];
! 	    if (usr != (user *) NULL && usr->inbufsz != 0) {
! 		if (usr->flags & CF_TELNET) {
! 		    /*
! 		     * telnet connection
! 		     */
! 		    if (usr->newlines != 0) {
! 			/*
! 			 * input terminated by \n
! 			 */
  			p = (char *) memchr(usr->inbuf, LF, usr->inbufsz);
- 			usr->newlines--;
  			--newlines;
  			lastuser = n;
! 			*size = n = p - usr->inbuf;
! 			if (n != 0) {
! 			    memcpy(buf, usr->inbuf, n);
  			}
! 			p++;	/* skip \n */
  			n++;
! 			usr->inbufsz -= n;
  			if (usr->inbufsz != 0) {
  			    /* can't rely on memcpy */
  			    for (q = usr->inbuf, n = usr->inbufsz; n > 0; --n) {
  				*q++ = *p++;
  			    }
  			}
! 			return this_user = usr->u.obj;
  		    } else if (usr->inbufsz == INBUF_SIZE) {
  			/*
  			 * input buffer full
  			 */
  			lastuser = n;
! 			memcpy(buf, usr->inbuf, *size = INBUF_SIZE);
  			usr->inbufsz = 0;
! 			return this_user = usr->u.obj;
  		    }
  		} else {
  		    /*
! 		     * binary connection
  		     */
! 		    lastuser = n;
! 		    binchars -= usr->inbufsz;
! 		    memcpy(buf, usr->inbuf, *size = usr->inbufsz);
! 		    usr->inbufsz = 0;
! 		    return this_user = usr->u.obj;
  		}
  	    }
  	}
      }
- 
-     return (object *) NULL;
  }
  
  /*
--- 384,696 ----
   * NAME:	comm->receive()
   * DESCRIPTION:	receive a message from a user
   */
! void comm_receive()
  {
      static int lastuser;
      connection *conn;
      object *o;
!     register int n;
      register char *p, *q;
  
      this_user = (object *) NULL;
!     n = conn_select(newlines == 0);
!     if (n > 0 || newlines > 0) {
! 	static char intr[] =            { '\177' };
! 	static char brk[] =             { '\034' };
! 	static char tm[] =              { (char) IAC, (char) WILL,
! 					  (char) TELOPT_TM };
! 	static char will_sga[] =        { (char) IAC, (char) WILL,
! 					  (char) TELOPT_SGA };
! 	static char wont_sga[] =        { (char) IAC, (char) WONT,
! 					  (char) TELOPT_SGA };
! 	static char mode_edit[] =       { (char) IAC, (char) SB,
! 					  (char) TELOPT_LINEMODE,
! 					  (char) LM_MODE, (char) MODE_EDIT,
! 					  (char) IAC, (char) SE };
! 	register user *usr;
! 	char buf[INBUF_SIZE];
! 	Int size;
  
! 	n = lastuser;
! 	for (;;) {
! 	    n = (n + 1) % maxusers;
! 	    usr = users[n];
! 	    if (usr != (user *) NULL) {
! 		if (usr->flags & CF_CONNECTING) {
! 		    int r;
! 
! 		    r = conn_connected(usr->conn);
! 		    if (r == 1) {
! 			usr->flags &= ~CF_CONNECTING;
! 			this_user = usr->u.obj;
! 			if (i_call(this_user, "open", TRUE, 0)) {
! 			    i_del_value(sp++);
! 			}
! 			comm_flush(TRUE);
! 		    } else if (r == -1) {
! 			comm_del(&users[n]);
! 		    }
! 		} else if (usr->flags & CF_DATAGRAM) {
! 		    size = conn_recvfrom(usr->conn, buf, INBUF_SIZE);
! 		    if (size > 0) {
! 			lastuser = n;
! 			(--sp)->type = T_STRING;
! 			str_ref(sp->u.string = str_new(buf, (long) size));
! 			(--sp)->type = T_STRING;
! 			str_ref(sp->u.string = conn_ipnum(usr->conn));
! 			(--sp)->type = T_INT;
! 			sp->u.number = conn_port(usr->conn);
! 			this_user = usr->u.obj;
! 			if (i_call(this_user, "receive_datagram", TRUE, 3)) {
! 			    i_del_value(sp++);
! 			    d_export();
! 			}
! 			return;
! 		    }
! 		} else if (usr->flags & CF_PORT) {
! 		    if (nusers < maxusers) {
! 			conn = conn_accept(usr->conn);
! 			if (conn != (connection *) NULL) {
! 			    (--sp)->type = T_STRING;
! 			    str_ref(sp->u.string = conn_ipnum(conn));
! 			    (--sp)->type = T_INT;
! 			    sp->u.number = conn_port(conn);
! 			    if (ec_push()) {
! 				conn_del(conn);
! 				error((char *) NULL);   /* pass on error */
! 			    }
! 			    this_user = usr->u.obj;
! 			    if (!i_call(this_user, "connection", TRUE, 2) ||
! 				sp->type != T_OBJECT) {
! 				error("connection() did not return an object");
! 			    }
! 			    ec_pop();
! 			    comm_new(o = o_object(sp->oindex, sp->u.objcnt),
! 				     conn, usr->flags & ~CF_PORT);
! 			    sp++;
! 			    this_user = o;
! 			    if (i_call(this_user, "open", TRUE, 0)) {
! 				i_del_value(sp++);
! 			    }
! 			    comm_flush(TRUE);
! 			}
! 		    }
! 		} else if (usr->flags & CF_TELNET) {
! 		    p = usr->inbuf + usr->inbufsz;
! 		    size = conn_read(usr->conn, p, INBUF_SIZE - usr->inbufsz);
! 		    if (size < 0) {
! 			/*
! 			 * bad connection
! 			 */
! 			comm_del(&users[n]);
! 			continue;
! 		    } else if (size > 0) {
! 			register int state, flags, nls;
! 
! 			flags = usr->flags;
! 			state = usr->state;
! 			nls = usr->newlines;
! 			q = p;
! 			while (size > 0) {
! 			    switch (state) {
! 			    case TS_DATA:
! 				switch (UCHAR(*p)) {
! 				case IAC:
! 				    state = TS_IAC;
! 				    break;
  
! 				case BS:
! 			        case 0x7f:
! 				    if (q != usr->inbuf && q[-1] != LF) {
! 					--q;
! 				    }
! 				    flags &= ~CF_SEENCR;
! 				    break;
  
! 			        case CR:
! 				    nls++;
! 				    newlines++;
! 				    *q++ = LF;
! 				    flags |= CF_SEENCR;
! 				    break;
  
! 				case LF:
! 				    if ((flags & CF_SEENCR) != 0) {
! 					flags &= ~CF_SEENCR;
! 					break;
! 				    }
! 				    nls++;
! 				    newlines++;
! 				    /* fall through */
! 			        default:
! 				    *q++ = *p;
  				    flags &= ~CF_SEENCR;
  				    break;
! 			        }
  				break;
  
! 			    case TS_IAC:
! 				switch (UCHAR(*p)) {
! 				case IAC:
! 				    *q++ = *p;
! 				    state = TS_DATA;
! 				    break;
  
! 			        case DO:
! 				    state = TS_DO;
! 				    break;
  
! 			        case DONT:
! 				    state = TS_DONT;
! 				    break;
  
! 			        case WILL:
! 				    state = TS_WILL;
! 				    break;
  
! 				case WONT:
! 				    state = TS_WONT;
! 				    break;
! 
! 				case SB:
! 				    state = TS_SB;
! 				    break;
! 
! 			        case IP:
! 				    conn_write(usr->conn, intr, 1);
! 				    state = TS_DATA;
! 				    break;
! 
! 				case BREAK:
! 				    conn_write(usr->conn, brk, 1);
! 				    state = TS_DATA;
! 				    break;
  
! 			        default:
! 				    state = TS_DATA;
! 				    break;
! 				}
  				break;
  
! 			    case TS_DO:
! 				if (UCHAR(*p) == TELOPT_TM) {
! 				    conn_write(usr->conn, tm, 3);
! 				} else if (UCHAR(*p) == TELOPT_SGA) {
! 				    flags &= ~CF_GA;
! 				    conn_write(usr->conn, will_sga, 3);
! 				}
  				state = TS_DATA;
  				break;
  
! 			    case TS_DONT:
! 				if (UCHAR(*p) == TELOPT_SGA) {
! 				    flags |= CF_GA;
! 				    conn_write(usr->conn, wont_sga, 3);
! 			        }
  				state = TS_DATA;
  				break;
  
! 			    case TS_WILL:
! 				if (UCHAR(*p) == TELOPT_LINEMODE) {
! 				    conn_write(usr->conn, mode_edit, 7);
! 				}
! 				/* fall through */
! 			    case TS_WONT:
  				state = TS_DATA;
  				break;
  
! 			    case TS_SB:
! 				/* skip to the end */
! 				if (UCHAR(*p) == IAC) {
! 				    state = TS_SE;
! 				}
! 				break;
  
! 			    case TS_SE:
! 				if (UCHAR(*p) == SE) {
! 				    /* end of subnegotiation */
! 				    state = TS_DATA;
! 				} else if (UCHAR(*p) == IAC) {
! 				    /* doubled IAC counts as data */
! 				    state = TS_SB;
! 				}
! 				break;
  			    }
! 			    p++;
! 			    --size;
  			}
! 			usr->flags = flags;
! 			usr->state = state;
! 			usr->newlines = nls;
! 			usr->inbufsz = q - usr->inbuf;
  		    }
! 		    if (usr->newlines > 0) {
  			p = (char *) memchr(usr->inbuf, LF, usr->inbufsz);
  			--newlines;
+ 			--(usr->newlines);
  			lastuser = n;
! 			size = n = p - usr->inbuf;
! 			if (size != 0) {
! 			    memcpy(buf, usr->inbuf, size);
  			}
! 			p++;   /* skip \n */
  			n++;
! 			usr->inbufsz -= size + 1;
  			if (usr->inbufsz != 0) {
  			    /* can't rely on memcpy */
  			    for (q = usr->inbuf, n = usr->inbufsz; n > 0; --n) {
  				*q++ = *p++;
  			    }
  			}
! 			this_user = usr->u.obj;
! 			(--sp)->type = T_STRING;
! 			str_ref(sp->u.string = str_new(buf, (long) size));
! 			if (i_call(this_user, "receive_message", TRUE, 1)) {
! 			    i_del_value(sp++);
! 			    d_export();
! 			}
! 			return;
  		    } else if (usr->inbufsz == INBUF_SIZE) {
  			/*
  			 * input buffer full
  			 */
  			lastuser = n;
! 			(--sp)->type = T_STRING;
! 			str_ref(sp->u.string = 
! 				str_new(usr->inbuf, (long) INBUF_SIZE));
  			usr->inbufsz = 0;
! 			this_user = usr->u.obj;
! 			if (i_call(this_user, "receive_message", TRUE, 1)) {
! 			    i_del_value(sp++);
! 			    d_export();
! 			}
! 			return;
  		    }
  		} else {
  		    /*
! 		     * binary mode
  		     */
! 		    size = conn_read(usr->conn, buf, INBUF_SIZE);
! 		    if (size < 0) {
! 			comm_del(&users[n]);
! 		    } else if (size > 0) {
! 			lastuser = n;
! 			(--sp)->type = T_STRING;
! 			str_ref(sp->u.string = str_new(buf, (long) size));
! 			this_user = usr->u.obj;
! 			if (i_call(this_user, "receive_message", TRUE, 1)) {
! 			    i_del_value(sp++);
! 			    d_export();
! 			}
! 			return;
! 		    }
  		}
  	    }
+ 	    if (n == lastuser) {
+ 		return;
+ 	    }
  	}
      }
  }
  
  /*
***************
*** 594,603 ****
  string *comm_ip_number(obj)
  object *obj;
  {
!     char *ipnum;
! 
!     ipnum = conn_ipnum(users[UCHAR(obj->etabi)]->conn);
!     return str_new(ipnum, (long) strlen(ipnum));
  }
  
  /*
--- 700,706 ----
  string *comm_ip_number(obj)
  object *obj;
  {
!     return conn_ipnum(users[UCHAR(obj->etabi)]->conn);
  }
  
  /*
*** dgd/src/comm.h.orig	Tue Jun  6 18:12:12 1995
--- dgd/src/comm.h	Thu Aug 31 20:51:38 1995
***************
*** 1,24 ****
  # define INBUF_SIZE	2048
  # define OUTBUF_SIZE	1024
  
  typedef struct _connection_ connection;
  
! extern void	   conn_init	P((int, unsigned int, unsigned int));
  extern void	   conn_finish	P((void));
! extern connection *conn_tnew	P((void));
! extern connection *conn_bnew	P((void));
  extern void	   conn_del	P((connection*));
  extern int	   conn_select	P((int));
  extern int	   conn_read	P((connection*, char*, int));
  extern int	   conn_write	P((connection*, char*, int));
! extern char	  *conn_ipnum	P((connection*));
  
! extern void	comm_init	P((int, int, int));
  extern void	comm_finish	P((void));
  extern int	comm_send	P((object*, string*));
  extern void	comm_echo	P((object*, int));
  extern void	comm_flush	P((int));
! extern object  *comm_receive	P((char*, int*));
  extern string  *comm_ip_number	P((object*));
  extern void	comm_close	P((object*));
  extern object  *comm_user	P((void));
--- 1,36 ----
  # define INBUF_SIZE	2048
  # define OUTBUF_SIZE	1024
  
+ # define  PRC_TCP      1
+ # define  PRC_UDP      2
+ # define  PRC_TELNET   3
+ 
  typedef struct _connection_ connection;
  
! extern void	   conn_init	P((int));
  extern void	   conn_finish	P((void));
! extern connection *conn_listen	P((int, int));
! extern connection *conn_accept	P((connection*));
! extern connection *conn_connect	P((char*, int, int));
! extern int	   conn_connected P((connection*));
  extern void	   conn_del	P((connection*));
  extern int	   conn_select	P((int));
+ extern int	   conn_recvfrom P((connection*, char*, int));
  extern int	   conn_read	P((connection*, char*, int));
+ extern void	   conn_sendto	P((connection*, char*, int, char*, int));
  extern int	   conn_write	P((connection*, char*, int));
! extern string	  *conn_ipnum	P((connection*));
+ extern int	   conn_port	P((connection*));
  
! extern void	comm_init	P((int));
  extern void	comm_finish	P((void));
+ extern void     comm_listen     P((object*, int, int));
+ extern void     comm_connect    P((object*, char*, int, int));
  extern int	comm_send	P((object*, string*));
+ extern void     comm_sendto     P((object*, string*, char*, int));
  extern void	comm_echo	P((object*, int));
  extern void	comm_flush	P((int));
! extern void	comm_receive	P((void));
  extern string  *comm_ip_number	P((object*));
  extern void	comm_close	P((object*));
  extern object  *comm_user	P((void));
*** dgd/src/comp/comp.c.orig	Mon Jul 31 15:15:44 1995
--- dgd/src/comp/comp.c	Thu Aug 31 20:43:23 1995
***************
*** 529,536 ****
   * NAME:	comm->init()
   * DESCRIPTION:	pretend to initialize communications
   */
! void comm_init(nusers, telnet_port, binary_port)
! int nusers, telnet_port, binary_port;
  {
  }
  
--- 529,536 ----
   * NAME:	comm->init()
   * DESCRIPTION:	pretend to initialize communications
   */
! void comm_init(nusers)
! int nusers;
  {
  }
  
***************
*** 569,574 ****
--- 569,607 ----
   */
  void comm_flush(flag)
  int flag;
+ {
+ }
+ 
+ /*
+  * NAME:        comm->listen()
+  * DESCRIPTION: pretend to open a port for listening
+  */
+ void comm_listen(obj, port, protocol)
+ object *obj;
+ int port, protocol;
+ {
+ }
+ 
+ /*
+  * NAME:        comm->connect()
+  * DESCRIPTION: pretend to initiate a telnet or tcp connection
+  */
+ void comm_connect(obj, host, port, protocol)
+ object *obj;
+ char *host;
+ int port, protocol;
+ {
+ }
+ 
+ /*
+  * NAME:        comm->sendto()
+  * DESCRIPTION: pretend to send a datagram
+  */
+ void comm_sendto(obj, data, host, port)
+ object *obj;
+ string *data;
+ char *host;
+ int port;
  {
  }
  
*** dgd/src/config.c.orig	Sat Aug 12 19:00:38 1995
--- dgd/src/config.c	Thu Aug 31 20:34:04 1995
***************
*** 163,169 ****
  	fatal("failed to dump callout table");
      }
      if (!pc_dump(fd)) {
! 	fatal("failed to dump precompiled objects");
      }
  
      header[2] = conf[TYPECHECKING].u.num;
--- 163,169 ----
  	fatal("failed to dump callout table");
      }
      if (!pc_dump(fd)) {
!        fatal("failed to dump precompiled objects");
      }
  
      header[2] = conf[TYPECHECKING].u.num;
***************
*** 582,587 ****
--- 582,592 ----
      header[16] = (char *) &pdummy.p - (char *) &pdummy.fill; /* pointer align */
      header[17] = sizeof(align);				     /* struct align */
  
+     /* initialize communications */
+     mstatic();
+     comm_init((int) conf[USERS].u.num);
+     mdynamic();
+ 
      starttime = boottime = P_time();
      i_set_cost((Int) conf[MAX_COST].u.num);
      if (dumpfile == (char *) NULL) {
***************
*** 598,610 ****
  	call_driver_object("restored", 0);
      }
      i_del_value(sp++);
- 
-     /* initialize communications */
-     mstatic();
-     comm_init((int) conf[USERS].u.num,
- 	      (int) conf[TELNET_PORT].u.num,
- 	      (int) conf[BINARY_PORT].u.num);
-     mdynamic();
  }
  
  /*
--- 603,608 ----
***************
*** 635,642 ****
  }
  
  /*
!  * NAME:	config->array_size()
!  * DESCRIPTION:	return the maximum array size
   */
  int conf_array_size()
  {
--- 633,640 ----
  }
  
  /*
!  * NAME:       config->array_size()
!  * DESCRIPTION:        return the maximum array size
   */
  int conf_array_size()
  {
*** dgd/src/dgd.c.orig	Sun Aug 13 15:25:58 1995
--- dgd/src/dgd.c	Thu Aug 31 21:33:00 1995
***************
*** 88,97 ****
  int argc;
  char **argv;
  {
-     char buf[INBUF_SIZE];
-     int size;
-     object *usr;
- 
      if (argc < 2 || argc > 3) {
  	P_message("Usage: dgd config_file [dump_file]\012");	/* LF */
  	return 2;
--- 88,93 ----
***************
*** 164,179 ****
  	}
  
  	/* user input */
! 	usr = comm_receive(buf, &size);
! 	if (usr != (object *) NULL) {
! 	    (--sp)->type = T_STRING;
! 	    str_ref(sp->u.string = str_new(buf, (long) size));
! 	    if (i_call(usr, "receive_message", TRUE, 1)) {
! 		i_del_value(sp++);
! 		comm_flush(TRUE);
! 		d_export();
! 	    }
! 	}
  
  	/* callouts */
  	co_call();
--- 160,167 ----
  	}
  
  	/* user input */
! 	comm_receive();
! 	comm_flush(TRUE);
  
  	/* callouts */
  	co_call();
*** dgd/src/host/unix/connect.c.orig	Tue Jun  6 18:12:13 1995
--- dgd/src/host/unix/connect.c	Thu Aug 31 21:25:12 1995
***************
*** 13,97 ****
  
  struct _connection_ {
      int fd;				/* file descriptor */
!     struct sockaddr_in addr;		/* internet address of connection */
      struct _connection_ *next;		/* next in list */
  };
  
  static int nusers;			/* # of users */
  static connection *connections;		/* connections array */
  static connection *flist;		/* list of free connections */
- static int telnet;			/* telnet port socket descriptor */
- static int binary;			/* binary port socket descriptor */
  static fd_set fds;			/* file descriptor bitmap */
  static fd_set readfds;			/* file descriptor read bitmap */
  static int maxfd;			/* largest fd opened yet */
  
  /*
   * NAME:	conn->init()
   * DESCRIPTION:	initialize connections
   */
! void conn_init(maxusers, telnet_port, binary_port)
  int maxusers;
- unsigned int telnet_port, binary_port;
  {
-     struct sockaddr_in sin;
-     struct hostent *host;
      register int n;
      register connection *conn;
-     char buffer[256];
-     int on;
- 
-     gethostname(buffer, sizeof(buffer));
-     host = gethostbyname(buffer);
-     if (host == (struct hostent *) NULL) {
- 	perror("gethostbyname");
- 	exit(2);
-     }
- 
-     telnet = socket(host->h_addrtype, SOCK_STREAM, 0);
-     binary = socket(host->h_addrtype, SOCK_STREAM, 0);
-     if (telnet < 0 || binary < 0) {
- 	perror("socket");
- 	exit(2);
-     }
-     on = 1;
-     if (setsockopt(telnet, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
- 		   sizeof(on)) < 0) {
- 	perror("setsockopt");
- 	exit(2);
-     }
-     on = 1;
-     if (setsockopt(binary, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
- 		   sizeof(on)) < 0) {
- 	perror("setsockopt");
- 	exit(2);
-     }
- 
-     memset(&sin, '\0', sizeof(sin));
-     memcpy(&sin.sin_addr, host->h_addr, host->h_length);
-     sin.sin_port = htons(telnet_port);
-     sin.sin_family = host->h_addrtype;
-     sin.sin_addr.s_addr = INADDR_ANY;
-     if (bind(telnet, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
- 	perror("bind");
- 	exit(2);
-     }
-     sin.sin_port = htons(binary_port);
-     if (bind(binary, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
- 	perror("bind");
- 	exit(2);
-     }
- 
-     if (listen(telnet, 5) < 0 || listen(binary, 5) < 0) {
- 	perror("listen");
- 	exit(2);
-     }
- 
-     if (fcntl(telnet, F_SETFL, FNDELAY) < 0 ||
- 	fcntl(binary, F_SETFL, FNDELAY) < 0) {
- 	perror("fcntl");
- 	exit(2);
-     }
  
      connections = ALLOC(connection, nusers = maxusers);
      for (n = nusers, conn = connections; n > 0; --n, conn++) {
--- 13,43 ----
  
  struct _connection_ {
      int fd;				/* file descriptor */
!     struct sockaddr_in sin;             /* peer's address */
      struct _connection_ *next;		/* next in list */
+     char host[16];                      /* ascii ip number of peer */
+     char hostlen;                       /* length of host string */
  };
  
  static int nusers;			/* # of users */
  static connection *connections;		/* connections array */
  static connection *flist;		/* list of free connections */
  static fd_set fds;			/* file descriptor bitmap */
+ static fd_set connectfds;               /* file descriptor bitmap */
  static fd_set readfds;			/* file descriptor read bitmap */
+ static fd_set writefds;                 /* file descriptor write bitmap */
+ static fd_set failfds;                  /* file descriptor exception bitmap */
  static int maxfd;			/* largest fd opened yet */
  
  /*
   * NAME:	conn->init()
   * DESCRIPTION:	initialize connections
   */
! void conn_init(maxusers)
  int maxusers;
  {
      register int n;
      register connection *conn;
  
      connections = ALLOC(connection, nusers = maxusers);
      for (n = nusers, conn = connections; n > 0; --n, conn++) {
***************
*** 101,106 ****
--- 47,53 ----
      }
  
      FD_ZERO(&fds);
+     FD_ZERO(&connectfds);
  }
  
  /*
***************
*** 109,139 ****
   */
  void conn_finish()
  {
-     close(telnet);
-     close(binary);
  }
  
  /*
!  * NAME:	conn->tnew()
!  * DESCRIPTION:	accept a new telnet connection
   */
! connection *conn_tnew()
  {
-     int fd, len;
-     struct sockaddr_in sin;
      register connection *conn;
- 
-     len = sizeof(sin);
-     fd = accept(telnet, (struct sockaddr *) &sin, &len);
-     if (fd < 0) {
- 	return (connection *) NULL;
-     }
- 
      conn = flist;
      flist = conn->next;
      conn->fd = fd;
!     memcpy(&conn->addr, (char *) &sin, len);
!     FD_SET(fd, &fds);
      if (fd > maxfd) {
  	maxfd = fd;
      }
--- 56,78 ----
   */
  void conn_finish()
  {
  }
  
  /*
!  * NAME:	conn->new()
!  * DESCRIPTION:	initialize a new connection struct
   */
! static connection *conn_new(fd, sin)
! int fd;
! struct sockaddr_in *sin;
  {
      register connection *conn;
      conn = flist;
      flist = conn->next;
      conn->fd = fd;
!     memcpy(&conn->sin, sin, sizeof(conn->sin));
!     strcpy(conn->host, inet_ntoa(sin->sin_addr));
!     conn->hostlen = strlen(conn->host);
      if (fd > maxfd) {
  	maxfd = fd;
      }
***************
*** 142,173 ****
  }
  
  /*
!  * NAME:	conn->bnew()
!  * DESCRIPTION:	accept a new binary connection
   */
! connection *conn_bnew()
  {
!     int fd, len;
      struct sockaddr_in sin;
!     register connection *conn;
  
!     len = sizeof(sin);
!     fd = accept(binary, (struct sockaddr *) &sin, &len);
      if (fd < 0) {
  	return (connection *) NULL;
      }
  
-     conn = flist;
-     flist = conn->next;
-     conn->fd = fd;
-     memcpy(&conn->addr, (char *) &sin, len);
      FD_SET(fd, &fds);
!     if (fd > maxfd) {
! 	maxfd = fd;
      }
  
!     return conn;
  }
  
  /*
   * NAME:	conn->del()
--- 81,206 ----
  }
  
  /*
!  * NAME:	conn->listen()
!  * DESCRIPTION:	bind a connection to a local port
!  */
! connection *conn_listen(port, protocol)
! int port, protocol;
! {
!     int fd;
!     static struct sockaddr_in sin;
!     int on = 1;
! 
!     fd = socket(PF_INET, (protocol == PRC_UDP) ? SOCK_DGRAM : SOCK_STREAM, 0);
!     if (fd < 0) {
! 	return (connection *) NULL;
!     }
!     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 
! 		   sizeof(on)) < 0) {
!         close(fd);
!         return (connection *) NULL;
!     }
! 
!     sin.sin_family = AF_INET;
!     sin.sin_port = htons(port);
!     sin.sin_addr.s_addr = INADDR_ANY;  /* htonl? */
!     if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
! 	close(fd);
! 	return (connection *) NULL;
!     }
! 
!     if (protocol != PRC_UDP && listen(fd, 5) < 0) {
! 	close(fd);
! 	return (connection *) NULL;
!     }
! 
!     if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
! 	close(fd);
! 	return (connection *) NULL;
!     }
! 
!     FD_SET(fd, &fds);
!     return conn_new(fd, &sin);
! }
! 
! /*
!  * NAME:	conn->accept()
!  * DESCRIPTION:	accept a connection
   */
! connection *conn_accept(conn)
! connection *conn;
  {
!     int fd;
      struct sockaddr_in sin;
!     int len = sizeof(sin);
  
!     fd = accept(conn->fd, (struct sockaddr *) &sin, &len);
      if (fd < 0) {
  	return (connection *) NULL;
      }
  
      FD_SET(fd, &fds);
!     return conn_new(fd, &sin);
! }
! 
! /*
!  * NAME:	conn->connect()
!  * DESCRIPTION:	initiate a tcp connection
!  */
! connection *conn_connect(host, port, protocol)
! char *host;
! int port, protocol;
! {
!     int fd;
!     static struct sockaddr_in sin;
! 
!     if (protocol != PRC_TCP) {
!         return (connection *) NULL;
      }
  
!     fd = socket(PF_INET, SOCK_STREAM, 0);
!     if (fd < 0) {
! 	return (connection *) NULL;
!     }
! 
!     if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
! 	close(fd);
! 	return (connection *) NULL;
!     }
! 
!     sin.sin_family = AF_INET;
!     sin.sin_port = htons(port);
!     sin.sin_addr.s_addr = inet_addr(host);
!     if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0 &&
! 	errno != EINPROGRESS) {
! 	close(fd);
! 	return (connection *) NULL;
!     }
! 
!     FD_SET(fd, &connectfds);
!     return conn_new(fd, &sin);
! }
! 
! /*
!  * NAME:	conn->connected()
!  * DESCRIPTION:	mark a connecting socket as active
!  */
! int conn_connected(conn)
! register connection *conn;
! {
!     if (conn->fd == -1)
! 	return -1;
!     if (FD_ISSET(conn->fd, &failfds)) {
! 	FD_CLR(conn->fd, &connectfds);
! 	return -1;
!     } else if (FD_ISSET(conn->fd, &writefds)) {
! 	FD_CLR(conn->fd, &connectfds);
! 	FD_SET(conn->fd, &fds);
! 	return 1;
!     }
!     return 0;
  }
+     
  
  /*
   * NAME:	conn->del()
***************
*** 179,184 ****
--- 212,218 ----
      if (conn->fd >= 0) {
  	close(conn->fd);
  	FD_CLR(conn->fd, &fds);
+ 	FD_CLR(conn->fd, &connectfds);
  	conn->fd = -1;
      }
      conn->next = flist;
***************
*** 195,204 ****
      struct timeval timeout;
  
      memcpy(&readfds, &fds, sizeof(fd_set));
      timeout.tv_sec = (int) wait;
      timeout.tv_usec = 0;
!     return select(maxfd + 1, &readfds, (fd_set *) NULL, (fd_set *) NULL,
! 		  &timeout);
  }
  
  /*
--- 229,264 ----
      struct timeval timeout;
  
      memcpy(&readfds, &fds, sizeof(fd_set));
+     memcpy(&writefds, &connectfds, sizeof(fd_set));
+     memcpy(&failfds, &connectfds, sizeof(fd_set));
      timeout.tv_sec = (int) wait;
      timeout.tv_usec = 0;
!     return select(maxfd + 1, &readfds, &writefds, &failfds, &timeout);
! }
! 
! /*
!  * NAME:	conn->recvfrom()
!  * DESCRIPTION: read a datagram
!  */
! int conn_recvfrom(conn, buf, size)
! connection *conn;
! char *buf;
! int size;
! {
!     struct sockaddr_in sin;
!     int len = sizeof(sin);
!     
!     if (conn->fd < 0) {
! 	return -1;
!     }
!     if (!FD_ISSET(conn->fd, &readfds)) {
! 	return 0;
!     }
!     size = recvfrom(conn->fd, buf, size, 0, (struct sockaddr *)&sin, &len);
!     memcpy(&(conn->sin), &sin, len);
!     strcpy(conn->host, inet_ntoa(sin.sin_addr));
!     conn->hostlen = strlen(conn->host);
!     return size;  /* Size may legitimately be 0 */
  }
  
  /*
***************
*** 213,219 ****
      if (conn->fd < 0) {
  	return -1;
      }
!     if (!FD_ISSET(conn->fd, &readfds)) {
  	return 0;
      }
      size = read(conn->fd, buf, size);
--- 273,279 ----
      if (conn->fd < 0) {
  	return -1;
      }
!     if (!FD_ISSET(conn->fd, &readfds) || size == 0) {
  	return 0;
      }
      size = read(conn->fd, buf, size);
***************
*** 221,226 ****
--- 281,304 ----
  }
  
  /*
+  * NAME:	conn->sendto()
+  * DESCRIPTION: send a datagram
+  */
+ void conn_sendto(conn, data, size, host, port)
+ connection *conn;
+ char *data, *host;
+ int   size,  port;
+ {
+     static struct sockaddr_in sin;
+     if (conn->fd >= 0) {
+ 	sin.sin_family = AF_INET;
+ 	sin.sin_addr.s_addr = inet_addr(host);
+ 	sin.sin_port = htons(port);
+ 	sendto(conn->fd, data, size, 0, (struct sockaddr *)&sin, sizeof(sin));
+     }
+ }
+ 
+ /*
   * NAME:	conn->write()
   * DESCRIPTION:	write to a connection; return the amount of bytes written
   */
***************
*** 233,238 ****
--- 311,317 ----
  	if ((size=write(conn->fd, buf, size)) < 0 && errno != EWOULDBLOCK) {
  	    close(conn->fd);
  	    FD_CLR(conn->fd, &fds);
+ 	    FD_CLR(conn->fd, &connectfds);
  	    conn->fd = -1;
  	}
  	return size;
***************
*** 244,251 ****
   * NAME:	conn->ipnum()
   * DESCRIPTION:	return the ip number of a connection
   */
! char *conn_ipnum(conn)
  connection *conn;
  {
!     return inet_ntoa(conn->addr.sin_addr);
  }
--- 323,341 ----
   * NAME:	conn->ipnum()
   * DESCRIPTION:	return the ip number of a connection
   */
! string *conn_ipnum(conn)
! connection *conn;
! {
!     return str_new(conn->host, conn->hostlen);
! }
! 
! /*
!  * NAME:	conn->port()
!  * DESCRIPTION:	return the port number of a connection
!  */
! int conn_port(conn)
  connection *conn;
  {
!     return ntohs(conn->sin.sin_port);
  }
+ 
*** dgd/src/kfun/std.c.orig	Sat Aug 12 19:00:40 1995
--- dgd/src/kfun/std.c	Thu Aug 31 20:41:16 1995
***************
*** 602,615 ****
  
      obj = i_this_object();
      if (obj->count != 0) {
! 	if (obj->flags & O_USER) {
  	    if (sp->type == T_INT) {
  		comm_echo(obj, sp->u.number != 0);
  	    } else {
  		num = comm_send(obj, sp->u.string);
  	    }
- 	} else if ((obj->flags & O_DRIVER) && sp->type == T_STRING) {
- 	    P_message(sp->u.string->text);
  	}
      }
      if (sp->type == T_STRING) {
--- 602,615 ----
  
      obj = i_this_object();
      if (obj->count != 0) {
!         if ((obj->flags & O_DRIVER) && sp->type == T_STRING) {
! 	    P_message(sp->u.string->text);
! 	} else if (obj->flags & O_USER) {
  	    if (sp->type == T_INT) {
  		comm_echo(obj, sp->u.number != 0);
  	    } else {
  		num = comm_send(obj, sp->u.string);
  	    }
  	}
      }
      if (sp->type == T_STRING) {
***************
*** 621,626 ****
--- 621,747 ----
  }
  # endif
  
+ # ifdef FUNCDEF
+ FUNCDEF("open_port", kf_open_port, p_open_port)
+ # else
+ char p_open_port[] = { C_TYPECHECKED | C_STATIC, T_VOID,
+ 		    3, T_OBJECT, T_INT, T_STRING };
+ 
+ /*
+  * NAME:	kfun->open_port()
+  * DESCRIPTION:	start listening on a port
+  */
+ int kf_open_port()
+ {
+     object *obj;
+     char *str;
+     int protocol;
+ 
+     obj = i_this_object();
+     if (obj->count == 0) {
+ 	error("open_port() from destructed object");
+     }
+     if (!(obj->flags & O_DRIVER)) {
+ 	error("open_port() only from driver object");
+     }
+ 
+     str = sp->u.string->text;
+     if (strcmp(str, "tcp") == 0) {
+         protocol = PRC_TCP;
+     } else if (strcmp(str, "udp") == 0) {
+         protocol = PRC_UDP;
+     } else if (strcmp(str, "telnet") == 0) {
+         protocol = PRC_TELNET;
+     } else {
+ 	return 3;
+     }
+ 
+     obj = o_object(sp[2].oindex, sp[2].u.objcnt);
+     if (obj->flags & (O_USER | O_EDITOR)) {
+         error("object already used for socket or editor");
+     }
+     comm_listen(o_object(sp[2].oindex, sp[2].u.objcnt),
+ 		   sp[1].u.number, protocol);
+     str_del(sp->u.string);
+     sp += 2;
+     sp->type = T_INT;
+     sp->u.number = 0;
+     return 0;
+ }
+ # endif
+ 
+ # ifdef FUNCDEF
+ FUNCDEF("connect", kf_connect, p_connect)
+ # else
+ char p_connect[] = { C_TYPECHECKED | C_STATIC, T_VOID,
+ 		    4, T_OBJECT, T_STRING, T_INT, T_STRING  };
+ 
+ /*
+  * NAME:	kfun->connect()
+  * DESCRIPTION:	initiate an ip connection
+  */
+ int kf_connect()
+ {
+     object *obj;
+     char *str;
+     int protocol;
+ 
+     obj = i_this_object();
+     if (obj->count == 0) {
+ 	error("connect() from destructed object");
+     }
+     if (!(obj->flags & O_DRIVER)) {
+         error("connect() only from driver object");
+     }
+ 
+     str = sp->u.string->text;
+     if (strcmp(str, "tcp") == 0) {
+ 	protocol = PRC_TCP;
+     } else if (strcmp(str, "telnet") == 0) {
+ 	protocol = PRC_TELNET;
+     } else {
+ 	return 4;
+     }
+     
+     obj = o_object(sp[3].oindex, sp[3].u.objcnt);
+     if (obj->flags & (O_USER | O_EDITOR)) {
+         error("object already used for socket or editor");
+     }
+     comm_connect(obj, sp[2].u.string->text, sp[1].u.number, protocol);
+     str_del(sp->u.string);
+     str_del(sp[2].u.string);
+     sp += 3;
+     sp->type = T_INT;
+     sp->u.number = 0;
+     return 0;
+ }
+ # endif
+ 
+ # ifdef FUNCDEF
+ FUNCDEF("send_datagram", kf_send_datagram, p_send_datagram)
+ # else
+ char p_send_datagram[] = { C_TYPECHECKED | C_STATIC, T_VOID,
+ 			   3, T_STRING, T_STRING, T_INT };
+ 
+ /*
+  * NAME:	kfun->send_datagram()
+  * DESCRIPTION:	send a packet to a specific host and port (udp only)
+  */
+ int kf_send_datagram()
+ {
+     object *obj;
+ 
+     obj = i_this_object();
+     if (obj->count != 0 && obj->flags & O_USER) {
+ 	comm_sendto(obj, sp[2].u.string, sp[1].u.string->text, sp->u.number);
+     }
+     str_del((++sp)->u.string);
+     str_del((++sp)->u.string);
+     sp->type = T_INT;
+     sp->u.number = 0;
+     return 0;
+ }
+ # endif
  
  # ifdef FUNCDEF
  FUNCDEF("time", kf_time, p_time)