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;
305 
306         /*
307          * telnet connection
308          */
309         p = str->text;
310         len = str->len;
311         q = outbuf;
312         size = 0;
313         for (;;) {
314             if (len == 0 || size >= OUTBUF_SIZE - 1 || UCHAR(*p) == IAC) {
315                 n = comm_write(usr, obj, (string *) NULL, outbuf, size);
316                 if (n != size) {
317                     /*
318                      * count how many bytes of original string were written
319                      */
320                     for (n = size - n; n != 0; --n) {
321                         if (*--p == *--q) {
322                             len++;
323                             if (UCHAR(*p) == IAC) {
324                                 break;
325                             }
326                         } else if (*q == CR) {
327                             /* inserted CR */
328                             p++;
329                         } else {
330                             /* skipped char */
331                             q++;
332                             len++;
333                         }
334                     }
335                     return str->len - len;
336                 }
337                 if (len == 0) {
338                     return str->len;
339                 }
340                 size = 0;
341                 q = outbuf;
342             }
343             if (UCHAR(*p) == IAC) {
344                 /*
345                  * double the telnet IAC character
346                  */
347                 *q++ = (char) IAC;
348                 size++;
349             } else if (*p == LF) {
350                 /*
351                  * insert CR before LF
352                  */
353                 *q++ = CR;
354                 size++;
355             } else if ((*p & 0x7f) < ' ' && *p != HT && *p != BEL && *p != BS) {
356                 /*
357                  * illegal character
358                  */
359                 p++;
360                 --len;
361                 continue;
362             }
363             *q++ = *p++;
364             --len;
365             size++;
366         }
367     } else {
368         /*
369          * binary connection
370          */
371         return comm_write(usr, obj, str, str->text, str->len);
372     }
373 }
374 
375 /*
376  * NAME:        comm->udpsend()
377  * DESCRIPTION: send a message on the UDP channel of a binary connection
378  */
379 int comm_udpsend(obj, str)
380 object *obj;
381 string *str;
382 {
383     register user *usr;
384     dataspace *data;
385     array *arr;
386     register value *v;
387     value val;
388 
389     usr = &users[EINDEX(obj->etabi)];
390     if ((usr->flags & (CF_TELNET | CF_UDP)) != CF_UDP) {
391         error("Object has no UDP channel");
392     }
393     if (!(usr->flags & CF_UDPDATA)) {
394         error("No datagrams received yet");
395     }
396 
397     arr = d_get_extravar(data = obj->data)->u.array;
398     if (!(usr->flags & CF_FLUSH)) {
399         addtoflush(usr, arr);
400     }
401 
402     v = arr->elts + 2;
403     if (v->type == T_STRING) {
404         return 0;       /* datagram queued already */
405     }
406     obj->flags |= O_PENDIO;
407     PUT_STRVAL_NOREF(&val, str);
408     d_assign_elt(data, arr, v, &val);
409 
410     return str->len;
411 }
412 
413 /*
414  * NAME:        comm->echo()
415  * DESCRIPTION: turn on/off input echoing for a user
416  */
417 bool comm_echo(obj, echo)
418 object *obj;
419 int echo;
420 {
421     register user *usr;
422     register dataspace *data;
423     array *arr;
424     register value *v;
425 
426     usr = &users[EINDEX(obj->etabi)];
427     if (usr->flags & CF_TELNET) {
428         arr = d_get_extravar(data = obj->data)->u.array;
429         v = d_get_elts(arr);
430         if (echo != (v->u.number & CF_ECHO) >> 1) {
431             value val;
432 
433             if (!(usr->flags & CF_FLUSH)) {
434                 addtoflush(usr, arr);
435             }
436             val = *v;
437             val.u.number ^= CF_ECHO;
438             d_assign_elt(data, arr, v, &val);
439         }
440         return TRUE;
441     }
442     return FALSE;
443 }
444 
445 /*
446  * NAME:        comm->block()
447  * DESCRIPTION: suspend or release input from a user
448  */
449 void comm_block(obj, block)
450 object *obj;
451 int block;
452 {
453     register user *usr;
454     register dataspace *data;
455     array *arr;
456     register value *v;
457 
458     usr = &users[EINDEX(obj->etabi)];
459     arr = d_get_extravar(data = obj->data)->u.array;
460     v = d_get_elts(arr);
461     if (block != (v->u.number & CF_BLOCKED) >> 5) {
462         value val;
463 
464         if (!(usr->flags & CF_FLUSH)) {
465             addtoflush(usr, arr);
466         }
467         val = *v;
468         val.u.number ^= CF_BLOCKED;
469         d_assign_elt(data, arr, v, &val);
470     }
471 }
472 
473 /*
474  * NAME:        comm->uflush()
475  * DESCRIPTION: flush output buffers for a single user only
476  */
477 static void comm_uflush(usr, obj, data, arr)
478 register user *usr;
479 object *obj;
480 register dataspace *data;
481 array *arr;
482 {
483     register value *v;
484     register int n;
485 
486     v = d_get_elts(arr);
487 
488     if (v[1].type == T_STRING) {
489         if (conn_wrdone(usr->conn)) {
490             n = conn_write(usr->conn, v[1].u.string->text + usr->osdone,
491                            v[1].u.string->len - usr->osdone);
492             if (n >= 0) {
493                 n += usr->osdone;
494                 if (n == v[1].u.string->len) {
495                     /* buffer fully drained */
496                     n = 0;
497                     usr->flags |= CF_ODONE;
498                     odone++;
499                     obj->flags &= ~O_PENDIO;
500                     d_assign_elt(data, arr, &v[1], &nil_value);
501                 }
502                 usr->osdone = n;
503             } else {
504                 /* wait for conn_read() to discover the problem */
505                 obj->flags &= ~O_PENDIO;
506             }
507         }
508     } else {
509         /* just a datagram */
510         obj->flags &= ~O_PENDIO;
511     }
512 
513     if (v[2].type == T_STRING) {
514         conn_udpwrite(usr->conn, v[2].u.string->text, v[2].u.string->len);
515         d_assign_elt(data, arr, &v[2], &nil_value);
516     }
517 }
518 
519 /*
520  * NAME:        comm->flush()
521  * DESCRIPTION: flush state, output and connections
522  */
523 void comm_flush()
524 {
525     register user *usr;
526     object *obj;
527     array *arr;
528     register value *v;
529 
530     while (flush != (user *) NULL) {
531         usr = flush;
532         flush = usr->flush;
533 
534         /*
535          * status change
536          */
537         obj = OBJ(usr->oindex);
538         arr = usr->extra;
539         v = arr->elts;
540         if (usr->flags & CF_TELNET) {
541             if ((v->u.number ^ usr->flags) & CF_ECHO) {
542                 char buf[3];
543 
544                 /* change echo */
545                 buf[0] = (char) IAC;
546                 buf[1] = (v->u.number & CF_ECHO) ? WONT : WILL;
547                 buf[2] = TELOPT_ECHO;
548                 if (comm_write(usr, obj, (string *) NULL, buf, 3) != 0) {
549                     usr->flags ^= CF_ECHO;
550                 }
551             }
552             if (usr->flags & CF_PROMPT) {
553                 usr->flags &= ~CF_PROMPT;
554                 if ((usr->flags & CF_GA) && v[1].type == T_STRING &&
555                     usr->outbuf != v[1].u.string) {
556                     static char ga[] = { (char) IAC, (char) GA };
557 
558                     /* append go-ahead */
559                     comm_write(usr, obj, (string *) NULL, ga, 2);
560                 }
561             }
562         }
563         if ((v->u.number ^ usr->flags) & CF_BLOCKED) {
564             usr->flags ^= CF_BLOCKED;
565             conn_block(usr->conn, ((usr->flags & CF_BLOCKED) != 0));
566         }
567 
568         /*
569          * write
570          */
571         if (usr->outbuf != (string *) NULL) {
572             if (usr->outbuf != v[1].u.string) {
573                 usr->osdone = 0;        /* new mesg before buffer drained */
574             }
575             str_del(usr->outbuf);
576             usr->outbuf = (string *) NULL;
577         }
578         if (obj->flags & O_PENDIO) {
579             comm_uflush(usr, obj, obj->data, arr);
580         }
581 
582         /*
583          * disconnect
584          */
585         if ((obj->flags & O_SPECIAL) != O_USER) {
586             d_wipe_extravar(obj->data);
587             conn_del(usr->conn);
588             if (usr->flags & CF_TELNET) {
589                 newlines -= usr->newlines;
590                 FREE(usr->inbuf - 1);
591             }
592             if (usr->flags & CF_ODONE) {
593                 --odone;
594             }
595 
596             usr->oindex = OBJ_NONE;
597             if (usr->next == usr) {
598                 lastuser = (user *) NULL;
599             } else {
600                 usr->next->prev = usr->prev;
601                 usr->prev->next = usr->next;
602                 if (usr == lastuser) {
603                     lastuser = usr->next;
604                 }
605             }
606             usr->next = freeuser;
607             freeuser = usr;
608             --nusers;
609         }
610 
611         arr_del(arr);
612         usr->flags &= ~CF_FLUSH;
613     }
614 }
615 
616 /*
617  * NAME:        comm->receive()
618  * DESCRIPTION: receive a message from a user
619  */
620 void comm_receive(f, timeout, mtime)
621 register frame *f;
622 Uint timeout;
623 unsigned int mtime;
624 {
625     static char intr[] =        { '\177' };
626     static char brk[] =         { '\034' };
627     static char ayt[] =         { CR, LF, '[', 'Y', 'e', 's', ']', CR, LF };
628     static char tm[] =          { (char) IAC, (char) WONT, (char) TELOPT_TM };
629     static char will_sga[] =    { (char) IAC, (char) WILL, (char) TELOPT_SGA };
630     static char wont_sga[] =    { (char) IAC, (char) WONT, (char) TELOPT_SGA };
631     static char mode_edit[] =   { (char) IAC, (char) SB,
632                                   (char) TELOPT_LINEMODE, (char) LM_MODE,
633                                   (char) MODE_EDIT, (char) IAC, (char) SE };
634     char buffer[BINBUF_SIZE];
635     connection *conn;
636     object *obj;
637     register user *usr;
638     register int n, i, state, nls;
639     register char *p, *q;
640 
641     if (newlines != 0 || odone != 0) {
642         timeout = mtime = 0;
643     }
644     n = conn_select(timeout, mtime);
645     if (n <= 0 && newlines == 0 && odone == 0) {
646         /*
647          * call_out to do, or timeout
648          */
649         return;
650     }
651 
652     if (ec_push(errhandler)) {
653         endthread();
654         this_user = OBJ_NONE;
655         return;
656     }
657 
658     if (nusers < maxusers) {
659         /*
660          * accept new telnet connection
661          */
662         conn = conn_tnew();
663         if (conn != (connection *) NULL) {
664             if (ec_push((ec_ftn) NULL)) {
665                 conn_del(conn);         /* delete connection */
666                 error((char *) NULL);   /* pass on error */
667             }
668             call_driver_object(f, "telnet_connect", 0);
669             if (f->sp->type != T_OBJECT) {
670                 fatal("driver->telnet_connect() did not return an object");
671             }
672             obj = OBJ(f->sp->oindex);
673             f->sp++;
674             usr = comm_new(obj, conn, TRUE);
675             ec_pop();
676             endthread();
677 
678             usr->flags |= CF_PROMPT;
679             addtoflush(usr, d_get_extravar(o_dataspace(obj))->u.array);
680             this_user = obj->index;
681             if (i_call(f, obj, "open", 4, TRUE, 0)) {
682                 i_del_value(f->sp++);
683                 endthread();
684             }
685             this_user = OBJ_NONE;
686         }
687     }
688 
689     while (nusers < maxusers) {
690         /*
691          * accept new binary connection
692          */
693         conn = conn_bnew();
694         if (conn == (connection *) NULL) {
695             break;
696         }
697 
698         if (ec_push((ec_ftn) NULL)) {
699             conn_del(conn);             /* delete connection */
700             error((char *) NULL);       /* pass on error */
701         }
702         call_driver_object(f, "binary_connect", 0);
703         if (f->sp->type != T_OBJECT) {
704             fatal("driver->binary_connect() did not return an object");
705         }
706         obj = OBJ(f->sp->oindex);
707         f->sp++;
708         usr = comm_new(obj, conn, FALSE);
709         ec_pop();
710         endthread();
711 
712         this_user = obj->index;
713         if (i_call(f, obj, "open", 4, TRUE, 0)) {
714             if (VAL_TRUE(f->sp)) {
715                 i_del_value(f->sp);
716                 if ((obj->flags & O_SPECIAL) == O_USER) {
717                     /* open UDP channel */
718                     usr->flags |= CF_UDP;
719                     conn_udp(conn);
720                 }
721             }
722             f->sp++;
723             endthread();
724         }
725         this_user = OBJ_NONE;
726     }
727 
728     for (i = nusers; i > 0; --i) {
729         usr = lastuser;
730         lastuser = usr->next;
731 
732         obj = OBJ(usr->oindex);
733         if (obj->flags & O_PENDIO) {
734             dataspace *data;
735 
736             data = o_dataspace(obj);
737             comm_uflush(usr, obj, data, d_get_extravar(data)->u.array);
738         }
739         if (usr->flags & CF_ODONE) {
740             /* callback */
741             usr->flags &= ~CF_ODONE;
742             --odone;
743             this_user = obj->index;
744             if (i_call(f, obj, "message_done", 12, TRUE, 0)) {
745                 i_del_value(f->sp++);
746                 endthread();
747             }
748             this_user = OBJ_NONE;
749             if (obj->count == 0) {
750                 break;  /* continue, unless the connection was closed */
751             }
752         }
753 
754         if (usr->flags & CF_BLOCKED) {
755             continue;   /* no input on this connection */
756         }
757 
758         if (usr->flags & CF_TELNET) {
759             /*
760              * telnet connection
761              */
762             if (usr->inbufsz != INBUF_SIZE) {
763                 p = usr->inbuf + usr->inbufsz;
764                 n = conn_read(usr->conn, p, INBUF_SIZE - usr->inbufsz);
765                 if (n < 0) {
766                     if (usr->inbufsz != 0) {
767                         if (p[-1] != LF) {
768                             /*
769                              * add a newline at the end
770                              */
771                             *p = LF;
772                             n = 1;
773                         }
774                     } else if (!(obj->flags & O_PENDIO)) {
775                         /*
776                          * empty buffer, no more input, no pending output
777                          */
778                         comm_del(f, usr, obj, FALSE);
779                         endthread();    /* this cannot be in comm_del() */
780                         break;
781                     }
782                 }
783 
784                 state = usr->state;
785                 nls = usr->newlines;
786                 q = p;
787                 while (n > 0) {
788                     switch (state) {
789                     case TS_DATA:
790                         switch (UCHAR(*p)) {
791                         case '\0':
792                             usr->flags &= ~CF_SEENCR;
793                             break;
794 
795                         case IAC:
796                             state = TS_IAC;
797                             break;
798 
799                         case BS:
800                         case 0x7f:
801                             if (q[-1] != LF) {
802                                 --q;
803                             }
804                             usr->flags &= ~CF_SEENCR;
805                             break;
806 
807                         case CR:
808                             nls++;
809                             newlines++;
810                             *q++ = LF;
811                             usr->flags |= CF_SEENCR;
812                             break;
813 
814                         case LF:
815                             if ((usr->flags & CF_SEENCR) != 0) {
816                                 usr->flags &= ~CF_SEENCR;
817                                 break;
818                             }
819                             nls++;
820                             newlines++;
821                             /* fall through */
822                         default:
823                             *q++ = *p;
824                             usr->flags &= ~CF_SEENCR;
825                             break;
826                         }
827                         break;
828 
829                     case TS_IAC:
830                         switch (UCHAR(*p)) {
831                         case IAC:
832                             *q++ = *p;
833                             state = TS_DATA;
834                             break;
835 
836                         case DO:
837                             state = TS_DO;
838                             break;
839 
840                         case DONT:
841                             state = TS_DONT;
842                             break;
843 
844                         case WILL:
845                             state = TS_WILL;
846                             break;
847 
848                         case WONT:
849                             state = TS_WONT;
850                             break;
851 
852                         case SB:
853                             state = TS_SB;
854                             break;
855 
856                         case IP:
857                             comm_write(usr, obj, (string *) NULL, intr,
858                                        sizeof(intr));
859                             state = TS_DATA;
860                             break;
861 
862                         case BREAK:
863                             comm_write(usr, obj, (string *) NULL, brk,
864                                        sizeof(brk));
865                             state = TS_DATA;
866                             break;
867 
868                         case AYT:
869                             comm_write(usr, obj, (string *) NULL, ayt,
870                                        sizeof(ayt));
871                             state = TS_DATA;
872                             break;
873 
874                         default:
875                             /* let's hope it wasn't important */
876                             state = TS_DATA;
877                             break;
878                         }
879                         break;
880 
881                     case TS_DO:
882                         if (UCHAR(*p) == TELOPT_TM) {
883                             comm_write(usr, obj, (string *) NULL, tm,
884                                        sizeof(tm));
885                         } else if (UCHAR(*p) == TELOPT_SGA) {
886                             usr->flags &= ~CF_GA;
887                             comm_write(usr, obj, (string *) NULL, will_sga,
888                                        sizeof(will_sga));
889                         }
890                         state = TS_DATA;
891                         break;
892 
893                     case TS_DONT:
894                         if (UCHAR(*p) == TELOPT_SGA) {
895                             usr->flags |= CF_GA;
896                             comm_write(usr, obj, (string *) NULL, wont_sga,
897                                        sizeof(wont_sga));
898                         }
899                         state = TS_DATA;
900                         break;
901 
902                     case TS_WILL:
903                         if (UCHAR(*p) == TELOPT_LINEMODE) {
904                             /* linemode confirmed; now request editing */
905                             comm_write(usr, obj, (string *) NULL, mode_edit,
906                                        sizeof(mode_edit));
907                         }
908                         /* fall through */
909                     case TS_WONT:
910                         state = TS_DATA;
911                         break;
912 
913                     case TS_SB:
914                         /* skip to the end */
915                         if (UCHAR(*p) == IAC) {
916                             state = TS_SE;
917                         }
918                         break;
919 
920                     case TS_SE:
921                         if (UCHAR(*p) == SE) {
922                             /* end of subnegotiation */
923                             state = TS_DATA;
924                         } else {
925                             state = TS_SB;
926                         }
927                         break;
928                     }
929                     p++;
930                     --n;
931                 }
932                 usr->state = state;
933                 usr->newlines = nls;
934                 usr->inbufsz = q - usr->inbuf;
935                 if (nls == 0) {
936                     continue;
937                 }
938 
939                 /*
940                  * input terminated by \n
941                  */
942                 p = (char *) memchr(q = usr->inbuf, LF, usr->inbufsz);
943                 usr->newlines--;
944                 --newlines;
945                 n = p - usr->inbuf;
946                 p++;                    /* skip \n */
947                 usr->inbufsz -= n + 1;
948 
949                 PUSH_STRVAL(f, str_new(usr->inbuf, (long) n));
950                 for (n = usr->inbufsz; n != 0; --n) {
951                     *q++ = *p++;
952                 }
953             } else {
954                 /*
955                  * input buffer full
956                  */
957                 n = usr->inbufsz;
958                 usr->inbufsz = 0;
959                 PUSH_STRVAL(f, str_new(usr->inbuf, (long) n));
960             }
961             usr->flags |= CF_PROMPT;
962             if (!(usr->flags & CF_FLUSH)) {
963                 addtoflush(usr, d_get_extravar(o_dataspace(obj))->u.array);
964             }
965         } else {
966             /*
967              * binary connection
968              */
969             if (usr->flags & CF_UDP) {
970                 n = conn_udpread(usr->conn, buffer, BINBUF_SIZE);
971                 if (n >= 0) {
972                     /*
973                      * received datagram
974                      */
975                     usr->flags |= CF_UDPDATA;
976                     PUSH_STRVAL(f, str_new(buffer, (long) n));
977                     this_user = obj->index;
978                     if (i_call(f, obj, "receive_datagram", 16, TRUE, 1)) {
979                         i_del_value(f->sp++);
980                         endthread();
981                     }
982                     this_user = OBJ_NONE;
983                 }
984             }
985 
986             n = conn_read(usr->conn, p = buffer, BINBUF_SIZE);
987             if (n <= 0) {
988                 if (n < 0 && !(obj->flags & O_PENDIO)) {
989                     /*
990                      * no more input and no pending output
991                      */
992                     comm_del(f, usr, obj, FALSE);
993                     endthread();        /* this cannot be in comm_del() */
994                     break;
995                 }
996                 continue;
997             }
998 
999             PUSH_STRVAL(f, str_new(buffer, (long) n));
1000         }
1001 
1002         this_user = obj->index;
1003         if (i_call(f, obj, "receive_message", 15, TRUE, 1)) {
1004             i_del_value(f->sp++);
1005             endthread();
1006         }
1007         this_user = OBJ_NONE;
1008         break;
1009     }
1010 
1011     ec_pop();
1012     comm_flush();
1013 }
1014 
1015 /*
1016  * NAME:        comm->ip_number()
1017  * DESCRIPTION: return the ip number of a user (as a string)
1018  */
1019 string *comm_ip_number(obj)
1020 object *obj;
1021 {
1022     char *ipnum;
1023 
1024     ipnum = conn_ipnum(users[EINDEX(obj->etabi)].conn);
1025     return str_new(ipnum, (long) strlen(ipnum));
1026 }
1027 
1028 /*
1029  * NAME:        comm->ip_name()
1030  * DESCRIPTION: return the ip name of a user
1031  */
1032 string *comm_ip_name(obj)
1033 object *obj;
1034 {
1035     char *ipname;
1036 
1037     ipname = conn_ipname(users[EINDEX(obj->etabi)].conn);
1038     return str_new(ipname, (long) strlen(ipname));
1039 }
1040 
1041 /*
1042  * NAME:        comm->close()
1043  * DESCRIPTION: remove a user
1044  */
1045 void comm_close(f, obj)
1046 frame *f;
1047 object *obj;
1048 {
1049     comm_del(f, &users[EINDEX(obj->etabi)], obj, TRUE);
1050 }
1051 
1052 /*
1053  * NAME:        comm->user()
1054  * DESCRIPTION: return the current user
1055  */
1056 object *comm_user()
1057 {
1058     object *obj;
1059 
1060     return (this_user != OBJ_NONE && (obj=OBJR(this_user))->count != 0) ?
1061             obj : (object *) NULL;
1062 }
1063 
1064 /*
1065  * NAME:        comm->users()
1066  * DESCRIPTION: return an array with all user objects
1067  */
1068 array *comm_users(data)
1069 dataspace *data;
1070 {
1071     array *a;
1072     register int i, n;
1073     register user *usr;
1074     register value *v;
1075     register object *obj;
1076 
1077     n = 0;
1078     for (i = nusers, usr = users; i > 0; usr++) {
1079         if (usr->oindex != OBJ_NONE) {
1080             --i;
1081             if (OBJR(usr->oindex)->count != 0) {
1082                 n++;
1083             }
1084         }
1085     }
1086 
1087     a = arr_new(data, (long) n);
1088     v = a->elts;
1089     for (usr = users; n > 0; usr++) {
1090         if (usr->oindex != OBJ_NONE && (obj=OBJR(usr->oindex))->count != 0) {
1091             PUT_OBJVAL(v, obj);
1092             v++;
1093             --n;
1094         }
1095     }
1096     return a;
1097 }
1098 

~ [ 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.