ArchWizard

DGD/

source navigation ]
diff markup ]
identifier search ]
file search ]
Version: [ 1.0.a0 ] [ 1.1 ] [ 1.2 ] [ 1.2p1 ] [ 1.2p2 ] [ 1.2p3 ] [ 1.2p4 ] [ 1.2.151 ]

  1 # define INCLUDE_TELNET
  2 # include "dgd.h"
  3 # include "str.h"
  4 # include "array.h"
  5 # include "object.h"
  6 # include "interpret.h"
  7 # include "data.h"
  8 # include "comm.h"
  9 
 10 # ifndef TELOPT_LINEMODE
 11 # define TELOPT_LINEMODE        34      /* linemode option */
 12 # define LM_MODE                1
 13 # define MODE_EDIT              0x01
 14 # endif
 15 
 16 # define MAXIACSEQLEN           7       /* longest IAC sequence sent */
 17 
 18 typedef struct _user_ {
 19     uindex oindex;              /* associated object index */
 20     struct _user_ *prev;        /* preceding user */
 21     struct _user_ *next;        /* next user */
 22     struct _user_ *flush;       /* next in flush list */
 23     char flags;                 /* connection flags */
 24     char state;                 /* telnet state */
 25     short newlines;             /* # of newlines in input buffer */
 26     connection *conn;           /* connection */
 27     char *inbuf;                /* input buffer */
 28     array *extra;               /* object's extra value */
 29     string *outbuf;             /* output buffer string */
 30     ssizet inbufsz;             /* bytes in input buffer */
 31     ssizet osdone;              /* bytes of output string done */
 32 } user;
 33 
 34 /* flags */
 35 # define CF_BINARY      0x00    /* binary connection */
 36 # define  CF_UDP        0x02    /* receive UDP datagrams */
 37 # define  CF_UDPDATA    0x04    /* UDP data received */
 38 # define CF_TELNET      0x01    /* telnet connection */
 39 # define  CF_ECHO       0x02    /* client echoes input */
 40 # define  CF_GA         0x04    /* send GA after prompt */
 41 # define  CF_SEENCR     0x08    /* just seen a CR */
 42 # define  CF_PROMPT     0x10    /* prompt in telnet output */
 43 # define CF_BLOCKED     0x20    /* input blocked */
 44 # define CF_FLUSH       0x40    /* in flush list */
 45 # define CF_ODONE       0x80    /* output done */
 46 
 47 /* state */
 48 # define TS_DATA        0
 49 # define TS_IAC         1
 50 # define TS_DO          2
 51 # define TS_DONT        3
 52 # define TS_WILL        4
 53 # define TS_WONT        5
 54 # define TS_SB          6
 55 # define TS_SE          7
 56 
 57 static user *users;             /* array of users */
 58 static user *lastuser;          /* last user checked */
 59 static user *freeuser;          /* linked list of free users */
 60 static user *flush;             /* flush list */
 61 static int maxusers;            /* max # of users */
 62 static int nusers;              /* # of users */
 63 static int odone;               /* # of users with output done */
 64 static long newlines;           /* # of newlines in all input buffers */
 65 static uindex this_user;        /* current user */
 66 
 67 /*
 68  * NAME:        comm->init()
 69  * DESCRIPTION: initialize communications
 70  */
 71 bool comm_init(n, telnet_port, binary_port)
 72 int n;
 73 unsigned int telnet_port, binary_port;
 74 {
 75     register int i;
 76     register user *usr;
 77 
 78     users = ALLOC(user, maxusers = n);
 79     for (i = n, usr = users + i; i > 0; --i) {
 80         --usr;
 81         usr->oindex = OBJ_NONE;
 82         usr->next = usr + 1;
 83     }
 84     users[n - 1].next = (user *) NULL;
 85     freeuser = usr;
 86     lastuser = (user *) NULL;
 87     flush = (user *) NULL;
 88     nusers = odone = newlines = 0;
 89     this_user = OBJ_NONE;
 90 
 91     return conn_init(n, telnet_port, binary_port);
 92 }
 93 
 94 /*
 95  * NAME:        comm->finish()
 96  * DESCRIPTION: terminate connections
 97  */
 98 void comm_finish()
 99 {
100     conn_finish();
101 }
102 
103 /*
104  * NAME:        comm->listen()
105  * DESCRIPTION: start listening on telnet port and binary port
106  */
107 void comm_listen()
108 {
109     conn_listen();
110 }
111 
112 /*
113  * NAME:        addtoflush()
114  * DESCRIPTION: add a user to the flush list
115  */
116 static void addtoflush(usr, arr)
117 register user *usr;
118 register array *arr;
119 {
120     usr->flags |= CF_FLUSH;
121     usr->flush = flush;
122     flush = usr;
123     arr_ref(usr->extra = arr);
124 
125     /* remember initial buffer */
126     if (d_get_elts(arr)[1].type == T_STRING) {
127         str_ref(usr->outbuf = arr->elts[1].u.string);
128     }
129 }
130 
131 /*
132  * NAME:        comm->new()
133  * DESCRIPTION: accept a new connection
134  */
135 static user *comm_new(obj, conn, telnet)
136 object *obj;
137 connection *conn;
138 bool telnet;
139 {
140     static char init[] = { (char) IAC, (char) WONT, (char) TELOPT_ECHO,
141                            (char) IAC, (char) DO,   (char) TELOPT_LINEMODE };
142     register user *usr;
143     dataspace *data;
144     array *arr;
145     value val;
146 
147     if (obj->flags & O_SPECIAL) {
148         error("User object is already special purpose");
149     }
150 
151     usr = freeuser;
152     freeuser = usr->next;
153     if (lastuser != (user *) NULL) {
154         usr->prev = lastuser->prev;
155         usr->prev->next = usr;
156         usr->next = lastuser;
157         lastuser->prev = usr;
158     } else {
159         usr->prev = usr;
160         usr->next = usr;
161         lastuser = usr;
162     }
163 
164     d_wipe_extravar(data = o_dataspace(obj));
165     arr = arr_new(data, 3L);
166     arr->elts[0] = zero_int;
167     arr->elts[1] = arr->elts[2] = nil_value;
168     PUT_ARRVAL_NOREF(&val, arr);
169     d_set_extravar(data, &val);
170 
171     usr->oindex = obj->index;
172     obj->flags |= O_USER;
173     obj->etabi = usr - users;
174     usr->conn = conn;
175     usr->outbuf = (string *) NULL;
176     usr->osdone = 0;
177     if (telnet) {
178         /* initialize connection */
179         usr->flags = CF_TELNET | CF_ECHO;
180         usr->state = TS_DATA;
181         usr->newlines = 0;
182         usr->inbufsz = 0;
183         m_static();
184         usr->inbuf = ALLOC(char, INBUF_SIZE + 1);
185         *usr->inbuf++ = LF;     /* sentinel */
186         m_dynamic();
187         addtoflush(usr, arr);
188 
189         arr->elts[0].u.number = CF_ECHO;
190         PUT_STRVAL_NOREF(&val, str_new(init, (long) sizeof(init)));
191         d_assign_elt(data, arr, &arr->elts[1], &val);
192         obj->flags |= O_PENDIO;
193     } else {
194         usr->flags = 0;
195     }
196     nusers++;
197 
198     return usr;
199 }
200 
201 /*
202  * NAME:        comm->del()
203  * DESCRIPTION: delete a connection
204  */
205 static void comm_del(f, usr, obj, force)
206 register frame *f;
207 register user *usr;
208 object *obj;
209 bool force;
210 {
211     dataspace *data;
212     uindex olduser;
213 
214     data = o_dataspace(obj);
215     if (!(usr->flags & CF_FLUSH)) {
216         addtoflush(usr, d_get_extravar(data)->u.array);
217     }
218 
219     obj->flags &= ~O_USER;
220     olduser = this_user;
221     if (ec_push((ec_ftn) NULL)) {
222         this_user = olduser;
223         error((char *) NULL);
224     } else {
225         this_user = obj->index;
226         PUSH_INTVAL(f, force);
227         if (i_call(f, obj, "close", 5, TRUE, 1)) {
228             i_del_value(f->sp++);
229         }
230         this_user = olduser;
231         ec_pop();
232     }
233 }
234 
235 /*
236  * NAME:        comm->write()
237  * DESCRIPTION: add bytes to output buffer
238  */
239 static int comm_write(usr, obj, str, text, len)
240 register user *usr;
241 object *obj;
242 register string *str;
243 char *text;
244 unsigned int len;
245 {
246     dataspace *data;
247     array *arr;
248     register value *v;
249     register ssizet osdone, olen;
250     value val;
251 
252     arr = d_get_extravar(data = o_dataspace(obj))->u.array;
253     if (!(usr->flags & CF_FLUSH)) {
254         addtoflush(usr, arr);
255     }
256 
257     v = arr->elts + 1;
258     if (v->type == T_STRING) {
259         /* append to existing buffer */
260         osdone = (usr->outbuf == v->u.string) ? usr->osdone : 0;
261         olen = v->u.string->len - osdone;
262         if (olen + len > MAX_STRLEN) {
263             len = MAX_STRLEN - olen;
264             if (len == 0 ||
265                 ((usr->flags & CF_TELNET) && text[0] == (char) IAC &&
266                  len < MAXIACSEQLEN)) {
267                 return 0;
268             }
269         }
270         str = str_new((char *) NULL, (long) olen + len);
271         memcpy(str->text, v->u.string->text + osdone, olen);
272         memcpy(str->text + olen, text, len);
273     } else {
274         /* create new buffer */
275         if (usr->flags & CF_ODONE) {
276             usr->flags &= ~CF_ODONE;
277             --odone;
278         }
279         obj->flags |= O_PENDIO;
280         if (str == (string *) NULL) {
281             str = str_new(text, (long) len);
282         }
283     }
284 
285     PUT_STRVAL_NOREF(&val, str);
286     d_assign_elt(data, arr, v, &val);
287     return len;
288 }
289 
290 /*
291  * NAME:        comm->send()
292  * DESCRIPTION: send a message to a user
293  */
294 int comm_send(obj, str)
295 object *obj;
296 string *str;
297 {
298     register user *usr;
299 
300     usr = &users[EINDEX(obj->etabi)];
301     if (usr->flags & CF_TELNET) {
302         char outbuf[OUTBUF_SIZE];
303         register char *p, *q;
304         register unsigned int len, size, n, length;
305 
306         /*
307          * telnet connection
308          */
309         p = str->text;
310         len = str->len;
311         q = outbuf;
312         size = 0;
313         length = 0;
314         for (;;) {
315             if (len == 0 || size >= OUTBUF_SIZE - 1 || UCHAR(*p) == IAC) {
316                 n = comm_write(usr, obj, (string *) NULL, outbuf, size);
317                 if (n != size) {
318                     /*
319                      * count how many bytes of original string were written
320                      */
321                     for (n = size - n; n != 0; --n) {
322                         if (*--p == *--q) {
323                             len++;
324                             if (UCHAR(*p) == IAC) {
325                                 break;
326                             }
327                         } else if (*q == CR) {
328                             /* inserted CR */
329                             p++;
330                         } else {
331                             /* skipped char */
332                             q++;
333                             len++;
334                         }
335                     }
336                     return str->len - len;
337                 }
338                 if (len == 0) {
339                     return str->len;
340                 }
341                 size = 0;
342                 q = outbuf;
343             }
344             if (UCHAR(*p) == IAC) {
345                 /*
346                  * double the telnet IAC character
347                  */
348                 *q++ = (char) IAC;
349                 size++;
350             } else if (*p == LF) {
351                 /*
352                  * insert CR before LF
353                  */
354                 *q++ = CR;
355                 size++;
356             } else if ((*p & 0x7f) < ' ' && *p != HT && *p != BEL && *p != BS) {
357                 /*
358                  * illegal character
359                  */
360                 p++;
361                 --len;
362                 continue;
363             }
364             *q++ = *p++;
365             --len;
366             size++;
367         }
368     } else {
369         /*
370          * binary connection
371          */
372         return comm_write(usr, obj, str, str->text, str->len);
373     }
374 }
375 
376 /*
377  * NAME:        comm->udpsend()
378  * DESCRIPTION: send a message on the UDP channel of a binary connection
379  */
380 int comm_udpsend(obj, str)
381 object *obj;
382 string *str;
383 {
384     register user *usr;
385     dataspace *data;
386     array *arr;
387     register value *v;
388     value val;
389 
390     usr = &users[EINDEX(obj->etabi)];
391     if ((usr->flags & (CF_TELNET | CF_UDP)) != CF_UDP) {
392         error("Object has no UDP channel");
393     }
394     if (!(usr->flags & CF_UDPDATA)) {
395         error("No datagrams received yet");
396     }
397 
398     arr = d_get_extravar(data = obj->data)->u.array;
399     if (!(usr->flags & CF_FLUSH)) {
400         addtoflush(usr, arr);
401     }
402 
403     v = arr->elts + 2;
404     if (v->type == T_STRING) {
405         return 0;       /* datagram queued already */
406     }
407     obj->flags |= O_PENDIO;
408     PUT_STRVAL_NOREF(&val, str);
409     d_assign_elt(data, arr, v, &val);
410 
411     return str->len;
412 }
413 
414 /*
415  * NAME:        comm->echo()
416  * DESCRIPTION: turn on/off input echoing for a user
417  */
418 bool comm_echo(obj, echo)
419 object *obj;
420 int echo;
421 {
422     register user *usr;
423     register dataspace *data;
424     array *arr;
425     register value *v;
426 
427     usr = &users[EINDEX(obj->etabi)];
428     if (usr->flags & CF_TELNET) {
429         arr = d_get_extravar(data = obj->data)->u.array;
430         v = d_get_elts(arr);
431         if (echo != (v->u.number & CF_ECHO) >> 1) {
432             value val;
433 
434             if (!(usr->flags & CF_FLUSH)) {
435                 addtoflush(usr, arr);
436             }
437             val = *v;
438             val.u.number ^= CF_ECHO;
439             d_assign_elt(data, arr, v, &val);
440         }
441         return TRUE;
442     }
443     return FALSE;
444 }
445 
446 /*
447  * NAME:        comm->block()
448  * DESCRIPTION: suspend or release input from a user
449  */
450 void comm_block(obj, block)
451 object *obj;
452 int block;
453 {
454     register user *usr;
455     register dataspace *data;
456     array *arr;
457     register value *v;
458 
459     usr = &users[EINDEX(obj->etabi)];
460     if (usr->flags & CF_TELNET) {
461         arr = d_get_extravar(data = obj->data)->u.array;
462         v = d_get_elts(arr);
463         if (block != (v->u.number & CF_BLOCKED) >> 5) {
464             value val;
465 
466             if (!(usr->flags & CF_FLUSH)) {
467                 addtoflush(usr, arr);
468             }
469             val = *v;
470             val.u.number ^= CF_BLOCKED;
471             d_assign_elt(data, arr, v, &val);
472         }
473     }
474 }
475 
476 /*
477  * NAME:        comm->uflush()
478  * DESCRIPTION: flush output buffers for a single user only
479  */
480 static void comm_uflush(usr, obj, data, arr)
481 register user *usr;
482 object *obj;
483 register dataspace *data;
484 array *arr;
485 {
486     register value *v;
487     register int n;
488 
489     v = d_get_elts(arr);
490 
491     if (v[1].type == T_STRING) {
492         if (conn_wrdone(usr->conn)) {
493             n = conn_write(usr->conn, v[1].u.string->text + usr->osdone,
494                            v[1].u.string->len - usr->osdone);
495             if (n >= 0) {
496                 n += usr->osdone;
497                 if (n == v[1].u.string->len) {
498                     /* buffer fully drained */
499                     n = 0;
500                     usr->flags |= CF_ODONE;
501                     odone++;
502                     obj->flags &= ~O_PENDIO;
503                     d_assign_elt(data, arr, &v[1], &nil_value);
504                 }
505                 usr->osdone = n;
506             } else {
507                 /* wait for conn_read() to discover the problem */
508                 obj->flags &= ~O_PENDIO;
509             }
510         }
511     } else {
512         /* just a datagram */
513         obj->flags &= ~O_PENDIO;
514     }
515 
516     if (v[2].type == T_STRING) {
517         conn_udpwrite(usr->conn, v[2].u.string->text, v[2].u.string->len);
518         d_assign_elt(data, arr, &v[2], &nil_value);
519     }
520 }
521 
522 /*
523  * NAME:        comm->flush()
524  * DESCRIPTION: flush state, output and connections
525  */
526 void comm_flush()
527 {
528     register user *usr;
529     object *obj;
530     array *arr;
531     register value *v;
532 
533     while (flush != (user *) NULL) {
534         usr = flush;
535         flush = usr->flush;
536 
537         /*
538          * status change
539          */
540         obj = OBJ(usr->oindex);
541         arr = usr->extra;
542         v = arr->elts;
543         if (usr->flags & CF_TELNET) {
544             if ((v->u.number ^ usr->flags) & CF_ECHO) {
545                 char buf[3];
546 
547                 /* change echo */
548                 buf[0] = (char) IAC;
549                 buf[1] = (v->u.number & CF_ECHO) ? WONT : WILL;
550                 buf[2] = TELOPT_ECHO;
551                 if (comm_write(usr, obj, (string *) NULL, buf, 3) != 0) {
552                     usr->flags ^= CF_ECHO;
553                 }
554             }
555             if (usr->flags & CF_PROMPT) {
556                 usr->flags &= ~CF_PROMPT;
557                 if ((usr->flags & CF_GA) && v[1].type == T_STRING &&
558                     usr->outbuf != v[1].u.string) {
559                     static char ga[] = { (char) IAC, (char) GA };
560 
561                     /* append go-ahead */
562                     comm_write(usr, obj, (string *) NULL, ga, 2);
563                 }
564             }
565         }
566         if ((v->u.number ^ usr->flags) & CF_BLOCKED) {
567             usr->flags ^= CF_BLOCKED;
568             conn_block(usr->conn, ((usr->flags & CF_BLOCKED) != 0));
569         }
570 
571         /*
572          * write
573          */
574         if (usr->outbuf != (string *) NULL) {
575             if (usr->outbuf != v[1].u.string) {
576                 usr->osdone = 0;        /* new mesg before buffer drained */
577             }
578             str_del(usr->outbuf);
579             usr->outbuf = (string *) NULL;
580         }
581         if (obj->flags & O_PENDIO) {
582             comm_uflush(usr, obj, obj->data, arr);
583         }
584 
585         /*
586          * disconnect
587          */
588         if ((obj->flags & O_SPECIAL) != O_USER) {
589             d_wipe_extravar(obj->data);
590             conn_del(usr->conn);
591             if (usr->flags & CF_TELNET) {
592                 newlines -= usr->newlines;
593                 FREE(usr->inbuf - 1);
594             }
595             if (usr->flags & CF_ODONE) {
596                 --odone;
597             }
598 
599             usr->oindex = OBJ_NONE;
600             if (usr->next == usr) {
601                 lastuser = (user *) NULL;
602             } else {
603                 usr->next->prev = usr->prev;
604                 usr->prev->next = usr->next;
605                 if (usr == lastuser) {
606                     lastuser = usr->next;
607                 }
608             }
609             usr->next = freeuser;
610             freeuser = usr;
611             --nusers;
612         }
613 
614         arr_del(arr);
615         usr->flags &= ~CF_FLUSH;
616     }
617 }
618 
619 /*
620  * NAME:        comm->receive()
621  * DESCRIPTION: receive a message from a user
622  */
623 void comm_receive(f, timeout, mtime)
624 register frame *f;
625 Uint timeout;
626 unsigned int mtime;
627 {
628     static char intr[] =        { '\177' };
629     static char brk[] =         { '\034' };
630     static char ayt[] =         { CR, LF, '[', 'Y', 'e', 's', ']', CR, LF };
631     static char tm[] =          { (char) IAC, (char) WONT, (char) TELOPT_TM };
632     static char will_sga[] =    { (char) IAC, (char) WILL, (char) TELOPT_SGA };
633     static char wont_sga[] =    { (char) IAC, (char) WONT, (char) TELOPT_SGA };
634     static char mode_edit[] =   { (char) IAC, (char) SB,
635                                   (char) TELOPT_LINEMODE, (char) LM_MODE,
636                                   (char) MODE_EDIT, (char) IAC, (char) SE };
637     char buffer[BINBUF_SIZE];
638     connection *conn;
639     object *obj;
640     register user *usr;
641     register int n, i, state, nls;
642     register char *p, *q;
643 
644     if (newlines != 0 || odone != 0) {
645         timeout = mtime = 0;
646     }
647     n = conn_select(timeout, mtime);
648     if (n <= 0 && newlines == 0 && odone == 0) {
649         /*
650          * call_out to do, or timeout
651          */
652         return;
653     }
654 
655     if (ec_push(errhandler)) {
656         endthread();
657         this_user = OBJ_NONE;
658         return;
659     }
660 
661     if (nusers < maxusers) {
662         /*
663          * accept new telnet connection
664          */
665         conn = conn_tnew();
666         if (conn != (connection *) NULL) {
667             if (ec_push((ec_ftn) NULL)) {
668                 conn_del(conn);         /* delete connection */
669                 error((char *) NULL);   /* pass on error */
670             }
671             call_driver_object(f, "telnet_connect", 0);
672             if (f->sp->type != T_OBJECT) {
673                 fatal("driver->telnet_connect() did not return an object");
674             }
675             obj = OBJ(f->sp->oindex);
676             f->sp++;
677             usr = comm_new(obj, conn, TRUE);
678             ec_pop();
679             endthread();
680 
681             usr->flags |= CF_PROMPT;
682             addtoflush(usr, d_get_extravar(o_dataspace(obj))->u.array);
683             this_user = obj->index;
684             if (i_call(f, obj, "open", 4, TRUE, 0)) {
685                 i_del_value(f->sp++);
686                 endthread();
687             }
688             this_user = OBJ_NONE;
689         }
690     }
691 
692     while (nusers < maxusers) {
693         /*
694          * accept new binary connection
695          */
696         conn = conn_bnew();
697         if (conn == (connection *) NULL) {
698             break;
699         }
700 
701         if (ec_push((ec_ftn) NULL)) {
702             conn_del(conn);             /* delete connection */
703             error((char *) NULL);       /* pass on error */
704         }
705         call_driver_object(f, "binary_connect", 0);
706         if (f->sp->type != T_OBJECT) {
707             fatal("driver->binary_connect() did not return an object");
708         }
709         obj = OBJ(f->sp->oindex);
710         f->sp++;
711         usr = comm_new(obj, conn, FALSE);
712         ec_pop();
713         endthread();
714 
715         this_user = obj->index;
716         if (i_call(f, obj, "open", 4, TRUE, 0)) {
717             if (VAL_TRUE(f->sp)) {
718                 i_del_value(f->sp);
719                 if ((obj->flags & O_SPECIAL) == O_USER) {
720                     /* open UDP channel */
721                     usr->flags |= CF_UDP;
722                     conn_udp(conn);
723                 }
724             }
725             f->sp++;
726             endthread();
727         }
728         this_user = OBJ_NONE;
729     }
730 
731     for (i = nusers; i > 0; --i) {
732         usr = lastuser;
733         lastuser = usr->next;
734 
735         obj = OBJ(usr->oindex);
736         if (obj->flags & O_PENDIO) {
737             dataspace *data;
738 
739             data = o_dataspace(obj);
740             comm_uflush(usr, obj, data, d_get_extravar(data)->u.array);
741         }
742         if (usr->flags & CF_ODONE) {
743             /* callback */
744             usr->flags &= ~CF_ODONE;
745             --odone;
746             this_user = obj->index;
747             if (i_call(f, obj, "message_done", 12, TRUE, 0)) {
748                 i_del_value(f->sp++);
749                 endthread();
750             }
751             this_user = OBJ_NONE;
752             if (obj->count == 0) {
753                 break;  /* continue, unless the connection was closed */
754             }
755         }
756 
757         if (usr->flags & CF_BLOCKED) {
758             continue;   /* no input on this connection */
759         }
760 
761         if (usr->flags & CF_TELNET) {
762             /*
763              * telnet connection
764              */
765             if (usr->inbufsz != INBUF_SIZE) {
766                 p = usr->inbuf + usr->inbufsz;
767                 n = conn_read(usr->conn, p, INBUF_SIZE - usr->inbufsz);
768                 if (n < 0) {
769                     if (usr->inbufsz != 0) {
770                         if (p[-1] != LF) {
771                             /*
772                              * add a newline at the end
773                              */
774                             *p = LF;
775                             n = 1;
776                         }
777                     } else if (!(obj->flags & O_PENDIO)) {
778                         /*
779                          * empty buffer, no more input, no pending output
780                          */
781                         comm_del(f, usr, obj, FALSE);
782                         endthread();    /* this cannot be in comm_del() */
783                         break;
784                     }
785                 }
786 
787                 state = usr->state;
788                 nls = usr->newlines;
789                 q = p;
790                 while (n > 0) {
791                     switch (state) {
792                     case TS_DATA:
793                         switch (UCHAR(*p)) {
794                         case '\0':
795                             usr->flags &= ~CF_SEENCR;
796                             break;
797 
798                         case IAC:
799                             state = TS_IAC;
800                             break;
801 
802                         case BS:
803                         case 0x7f:
804                             if (q[-1] != LF) {
805                                 --q;
806                             }
807                             usr->flags &= ~CF_SEENCR;
808                             break;
809 
810                         case CR:
811                             nls++;
812                             newlines++;
813                             *q++ = LF;
814                             usr->flags |= CF_SEENCR;
815                             break;
816 
817                         case LF:
818                             if ((usr->flags & CF_SEENCR) != 0) {
819                                 usr->flags &= ~CF_SEENCR;
820                                 break;
821                             }
822                             nls++;
823                             newlines++;
824                             /* fall through */
825                         default:
826                             *q++ = *p;
827                             usr->flags &= ~CF_SEENCR;
828                             break;
829                         }
830                         break;
831 
832                     case TS_IAC:
833                         switch (UCHAR(*p)) {
834                         case IAC:
835                             *q++ = *p;
836                             state = TS_DATA;
837                             break;
838 
839                         case DO:
840                             state = TS_DO;
841                             break;
842 
843                         case DONT:
844                             state = TS_DONT;
845                             break;
846 
847                         case WILL:
848                             state = TS_WILL;
849                             break;
850 
851                         case WONT:
852                             state = TS_WONT;
853                             break;
854 
855                         case SB:
856                             state = TS_SB;
857                             break;
858 
859                         case IP:
860                             comm_write(usr, obj, (string *) NULL, intr,
861                                        sizeof(intr));
862                             state = TS_DATA;
863                             break;
864 
865                         case BREAK:
866                             comm_write(usr, obj, (string *) NULL, brk,
867                                        sizeof(brk));
868                             state = TS_DATA;
869                             break;
870 
871                         case AYT:
872                             comm_write(usr, obj, (string *) NULL, ayt,
873                                        sizeof(ayt));
874                             state = TS_DATA;
875                             break;
876 
877                         default:
878                             /* let's hope it wasn't important */
879                             state = TS_DATA;
880                             break;
881                         }
882                         break;
883 
884                     case TS_DO:
885                         if (UCHAR(*p) == TELOPT_TM) {
886                             comm_write(usr, obj, (string *) NULL, tm,
887                                        sizeof(tm));
888                         } else if (UCHAR(*p) == TELOPT_SGA) {
889                             usr->flags &= ~CF_GA;
890                             comm_write(usr, obj, (string *) NULL, will_sga,
891                                        sizeof(will_sga));
892                         }
893                         state = TS_DATA;
894                         break;
895 
896                     case TS_DONT:
897                         if (UCHAR(*p) == TELOPT_SGA) {
898                             usr->flags |= CF_GA;
899                             comm_write(usr, obj, (string *) NULL, wont_sga,
900                                        sizeof(wont_sga));
901                         }
902                         state = TS_DATA;
903                         break;
904 
905                     case TS_WILL:
906                         if (UCHAR(*p) == TELOPT_LINEMODE) {
907                             /* linemode confirmed; now request editing */
908                             comm_write(usr, obj, (string *) NULL, mode_edit,
909                                        sizeof(mode_edit));
910                         }
911                         /* fall through */
912                     case TS_WONT:
913                         state = TS_DATA;
914                         break;
915 
916                     case TS_SB:
917                         /* skip to the end */
918                         if (UCHAR(*p) == IAC) {
919                             state = TS_SE;
920                         }
921                         break;
922 
923                     case TS_SE:
924                         if (UCHAR(*p) == SE) {
925                             /* end of subnegotiation */
926                             state = TS_DATA;
927                         } else {
928                             state = TS_SB;
929                         }
930                         break;
931                     }
932                     p++;
933                     --n;
934                 }
935                 usr->state = state;
936                 usr->newlines = nls;
937                 usr->inbufsz = q - usr->inbuf;
938                 if (nls == 0) {
939                     continue;
940                 }
941 
942                 /*
943                  * input terminated by \n
944                  */
945                 p = (char *) memchr(q = usr->inbuf, LF, usr->inbufsz);
946                 usr->newlines--;
947                 --newlines;
948                 n = p - usr->inbuf;
949                 p++;                    /* skip \n */
950                 usr->inbufsz -= n + 1;
951 
952                 PUSH_STRVAL(f, str_new(usr->inbuf, (long) n));
953                 for (n = usr->inbufsz; n != 0; --n) {
954                     *q++ = *p++;
955                 }
956             } else {
957                 /*
958                  * input buffer full
959                  */
960                 n = usr->inbufsz;
961                 usr->inbufsz = 0;
962                 PUSH_STRVAL(f, str_new(usr->inbuf, (long) n));
963             }
964             usr->flags |= CF_PROMPT;
965             if (!(usr->flags & CF_FLUSH)) {
966                 addtoflush(usr, d_get_extravar(o_dataspace(obj))->u.array);
967             }
968         } else {
969             /*
970              * binary connection
971              */
972             if (usr->flags & CF_UDP) {
973                 n = conn_udpread(usr->conn, buffer, BINBUF_SIZE);
974                 if (n >= 0) {
975                     /*
976                      * received datagram
977                      */
978                     usr->flags |= CF_UDPDATA;
979                     PUSH_STRVAL(f, str_new(buffer, (long) n));
980                     this_user = obj->index;
981                     if (i_call(f, obj, "receive_datagram", 16, TRUE, 1)) {
982                         i_del_value(f->sp++);
983                         endthread();
984                     }
985                     this_user = OBJ_NONE;
986                 }
987             }
988 
989             n = conn_read(usr->conn, p = buffer, BINBUF_SIZE);
990             if (n <= 0) {
991                 if (n < 0 && !(obj->flags & O_PENDIO)) {
992                     /*
993                      * no more input and no pending output
994                      */
995                     comm_del(f, usr, obj, FALSE);
996                     endthread();        /* this cannot be in comm_del() */
997                     break;
998                 }
999                 continue;
1000             }
1001 
1002             PUSH_STRVAL(f, str_new(buffer, (long) n));
1003         }
1004 
1005         this_user = obj->index;
1006         if (i_call(f, obj, "receive_message", 15, TRUE, 1)) {
1007             i_del_value(f->sp++);
1008             endthread();
1009         }
1010         this_user = OBJ_NONE;
1011         break;
1012     }
1013 
1014     ec_pop();
1015     comm_flush();
1016 }
1017 
1018 /*
1019  * NAME:        comm->ip_number()
1020  * DESCRIPTION: return the ip number of a user (as a string)
1021  */
1022 string *comm_ip_number(obj)
1023 object *obj;
1024 {
1025     char *ipnum;
1026 
1027     ipnum = conn_ipnum(users[EINDEX(obj->etabi)].conn);
1028     return str_new(ipnum, (long) strlen(ipnum));
1029 }
1030 
1031 /*
1032  * NAME:        comm->ip_name()
1033  * DESCRIPTION: return the ip name of a user
1034  */
1035 string *comm_ip_name(obj)
1036 object *obj;
1037 {
1038     char *ipname;
1039 
1040     ipname = conn_ipname(users[EINDEX(obj->etabi)].conn);
1041     return str_new(ipname, (long) strlen(ipname));
1042 }
1043 
1044 /*
1045  * NAME:        comm->close()
1046  * DESCRIPTION: remove a user
1047  */
1048 void comm_close(f, obj)
1049 frame *f;
1050 object *obj;
1051 {
1052     comm_del(f, &users[EINDEX(obj->etabi)], obj, TRUE);
1053 }
1054 
1055 /*
1056  * NAME:        comm->user()
1057  * DESCRIPTION: return the current user
1058  */
1059 object *comm_user()
1060 {
1061     object *obj;
1062 
1063     return (this_user != OBJ_NONE && (obj=OBJR(this_user))->count != 0) ?
1064             obj : (object *) NULL;
1065 }
1066 
1067 /*
1068  * NAME:        comm->users()
1069  * DESCRIPTION: return an array with all user objects
1070  */
1071 array *comm_users(data)
1072 dataspace *data;
1073 {
1074     array *a;
1075     register int i, n;
1076     register user *usr;
1077     register value *v;
1078     register object *obj;
1079 
1080     n = 0;
1081     for (i = nusers, usr = users; i > 0; usr++) {
1082         if (usr->oindex != OBJ_NONE) {
1083             --i;
1084             if (OBJR(usr->oindex)->count != 0) {
1085                 n++;
1086             }
1087         }
1088     }
1089 
1090     a = arr_new(data, (long) n);
1091     v = a->elts;
1092     for (usr = users; n > 0; usr++) {
1093         if (usr->oindex != OBJ_NONE && (obj=OBJR(usr->oindex))->count != 0) {
1094             PUT_OBJVAL(v, obj);
1095             v++;
1096             --n;
1097         }
1098     }
1099     return a;
1100 }
1101 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.