|
|
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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.