home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / internet / tcpip / src205 / TCPIP_Src / Telnet / c / telnet next >
Encoding:
Text File  |  1994-07-05  |  11.6 KB  |  527 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "domain.h"
  7. #include "timer.h"
  8. #include "icmp.h"
  9. #include "netuser.h"
  10. #include "tcp.h"
  11. #include "telnet.h"
  12. #include "session.h"
  13. #include "misc.h"
  14. #include "Terminal.h"
  15. #include "vterm.h"
  16.  
  17. extern cwnputs(Terminal *Window, char *s, int n);
  18.  
  19. static void free_telnet(struct telnet *);
  20. static void willopt(struct telnet *, char);
  21. static void wontopt(struct telnet *, char);
  22. static void doopt(struct telnet *, char);
  23. static void dontopt(struct telnet *, char);
  24. static void answer(struct telnet *, int, int);
  25.  
  26. #define CTLZ    26
  27.  
  28. extern char nospace[];
  29. extern char badhost[];
  30. int refuse_echo = 0;
  31. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  32.  
  33. #ifdef  DEBUG
  34. char *t_options[] = {
  35.   "Transmit Binary",
  36.   "Echo",
  37.   "",
  38.   "Suppress Go Ahead",
  39.   "",
  40.   "Status",
  41.   "Timing Mark"
  42. };
  43. #endif
  44.  
  45. /* Execute user telnet command */
  46. int dotelnet(int argc, char **argv)
  47. {
  48.   int used_args;
  49.   struct session *s;
  50.   struct telnet *tn;
  51.   struct tcb *tcb;
  52.   struct socket lsocket,fsocket;
  53.  
  54.   lsocket.address = ip_addr;
  55.   lsocket.port = lport++;
  56.   if((fsocket.address = resolve(argv[1])) == 0)
  57.   {
  58.     cwprintf(NULL, badhost,argv[1]);
  59.     return 1;
  60.   }
  61.  
  62.   if (argc<3)
  63.   {
  64.     fsocket.port = TELNET_PORT;
  65.     used_args = 2;
  66.   }
  67.   else
  68.   {
  69.     if (*argv[2]!='\\')
  70.     {
  71.       fsocket.port = atoi(argv[2]);
  72.       used_args = 3;
  73.     }
  74.     else
  75.     {
  76.       fsocket.port = TELNET_PORT;
  77.       used_args = 2;
  78.     }
  79.   }
  80.   /* Allocate a session descriptor */
  81.   if((s = newsession()) == NULLSESSION)
  82.   {
  83.     cwprintf(NULL, "Too many sessions\r\n");
  84.     return 1;
  85.   }
  86.   if((s->name = malloc((unsigned)strlen(argv[1]) + 1)) != NULLCHAR)
  87.     strcpy(s->name, argv[1]);
  88.   s->type = TELNET;
  89.   if ((refuse_echo == 0) && (unix_line_mode != 0))
  90.   {
  91.     s->parse = (void (*)())unix_send_tel;
  92.   }
  93.   else
  94.   {
  95.     s->parse = (void (*)())send_tel;
  96.   }
  97.  
  98.   /* Create and initialize a Telnet protocol descriptor */
  99.   if ((tn = (struct telnet *)calloc(1, sizeof(struct telnet))) == NULLTN)
  100.   {
  101.     cwprintf(NULL, nospace);
  102.     s->type = FREE;
  103.     return 1;
  104.   }
  105.   tn->window = Window_Open(s, "Telnet", term_SIXTEEN | term_CARET);
  106.   vterm_parse(tn->window->vt, argc-used_args, &argv[used_args]);
  107.   current = s;
  108.   tn->session  = s;        /* Upward pointer */
  109.   tn->state    = TS_DATA;
  110.   s->cb.telnet = tn;       /* Downward pointer */
  111.   s->window    = tn->window;
  112.   tn->session->echo = TRUE;
  113.  
  114.   tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, 0,
  115.   (void (*)())rcv_char, (void(*)())tn_tx, (void(*)())t_state, 0, (char *)tn);
  116.  
  117.   tn->tcb = tcb;  /* Downward pointer */
  118.   go(s);
  119.   return 0;
  120. }
  121.  
  122. /* Process typed characters */
  123. void unix_send_tel(struct session *window, char *buf, int16 n)
  124. {
  125.   int i;
  126.  
  127.   for (i=0; (i<n) && (buf[i] != '\r'); i++)
  128.     ;
  129.   if (buf[i] == '\r')
  130.   {
  131.     buf[i] = '\n';
  132.     n = i+1;
  133.   }
  134.   send_tel(window, buf, n);
  135. }
  136.  
  137. void send_tel(struct session *active, char *buf, int16 n)
  138. {
  139.   extern int ttyflow;
  140.   struct mbuf *bp;
  141.  
  142.   if (active == NULL)
  143.     active = current;
  144.  
  145.   if (active->window == NULL && (ttyflow == 0 || current == NULLSESSION || current->cb.telnet == NULLTN || current->cb.telnet->tcb == NULLTCB))
  146.     return;
  147.   /* If we're doing our own echoing and recording is enabled, record it */
  148.   if (!active->cb.telnet->remote[TN_ECHO] && active->record != NULLFILE)
  149.     fwrite(buf, 1, n, active->record);
  150.   bp = qdata(buf, n);
  151.   send_tcp(active->cb.telnet->tcb, bp);
  152. }
  153.  
  154. /* Process incoming TELNET characters */
  155. void tel_input(register struct telnet *tn, struct mbuf *bp)
  156. {
  157.   char c;
  158.   FILE *record;
  159.   register char *s;
  160.   char *line;
  161.  
  162.   if ((line = s = malloc(len_mbuf(bp) + 1)) == NULL)
  163.   {
  164.     cwprintf(tn->window, "Out of memory in TELNET\r\n");
  165.     free_p(bp);
  166.     return;
  167.   }
  168.  
  169.   /* Optimization for very common special case -- no special chars */
  170.   if(tn->state == TS_DATA)
  171.   {
  172.     while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR)
  173.     {
  174.       while(bp->cnt-- != 0)
  175.       {
  176.         *s++ = *bp->data;
  177.         bp->data++;
  178.       }
  179.       bp = free_mbuf(bp);
  180.     }
  181.   }
  182.   while (pullone(&bp,&c) == 1)
  183.   {
  184.     switch(tn->state)
  185.     {
  186.     case TS_DATA:
  187.       if(uchar(c) == IAC)
  188.       {
  189.         tn->state = TS_IAC;
  190.       }
  191.       else
  192.       {
  193.         if(!tn->remote[TN_TRANSMIT_BINARY] && c != 0)
  194.           *s++ = c & 0x7f;
  195.       }
  196.       break;
  197.     case TS_IAC:
  198.       switch(uchar(c))
  199.       {
  200.       case WILL:
  201.         tn->state = TS_WILL;
  202.         break;
  203.       case WONT:
  204.         tn->state = TS_WONT;
  205.         break;
  206.       case DO:
  207.         tn->state = TS_DO;
  208.         break;
  209.       case DONT:
  210.         tn->state = TS_DONT;
  211.         break;
  212.       case IAC:
  213.         cwputchar(tn->window, c);
  214.         tn->state = TS_DATA;
  215.         break;
  216.       default:
  217.         tn->state = TS_DATA;
  218.         break;
  219.       }
  220.       break;
  221.     case TS_WILL:
  222.       willopt(tn,c);
  223.       tn->state = TS_DATA;
  224.       break;
  225.     case TS_WONT:
  226.       wontopt(tn,c);
  227.       tn->state = TS_DATA;
  228.       break;
  229.     case TS_DO:
  230.       doopt(tn,c);
  231.       tn->state = TS_DATA;
  232.       break;
  233.     case TS_DONT:
  234.       dontopt(tn,c);
  235.       tn->state = TS_DATA;
  236.       break;
  237.     }
  238.   }
  239.   if ((record = tn->session->record) != NULLFILE)
  240.   {
  241.     fwrite(line, 1, s - line, record);
  242.     fflush(record);
  243.   }
  244.   *s = '\0';
  245.   cwnputs(tn->window, line, s - line);
  246.   free(line);
  247. }
  248.  
  249. /* Telnet receiver upcall routine */
  250. void rcv_char(register struct tcb *tcb, int16 cnt)
  251. {
  252.   extern int ttyflow;
  253.   struct mbuf *bp;
  254.   struct telnet *tn;
  255.   FILE *record;
  256.  
  257.   if((tn = (struct telnet *)tcb->user) == NULLTN)
  258.   {
  259.     /* Unknown connection; ignore it */
  260.     return;
  261.   }
  262.   /* Hold output if we're not the current session */
  263.   if (tn->window == NULL && (mode != CONV_MODE || current == NULLSESSION || ttyflow == 0 || current->type != TELNET || current->cb.telnet != tn))
  264.     return;
  265.  
  266.   if(recv_tcp(tcb, &bp, cnt) > 0)
  267.     tel_input(tn, bp);
  268.  
  269.   if((record = tn->session->record) != NULLFILE)
  270.     fflush(record);
  271. }
  272.  
  273. /* Handle transmit upcalls. Used only for file uploading */
  274. void tn_tx(struct tcb *tcb, int16 cnt)
  275. {
  276.   struct telnet *tn;
  277.   struct session *s;
  278.   struct mbuf *bp;
  279.   int size;
  280.  
  281.   if((tn = (struct telnet *)tcb->user) == NULLTN
  282.       || (s = tn->session) == NULLSESSION
  283.       || s->upload == NULLFILE)
  284.     return;
  285.   if((bp = alloc_mbuf(cnt)) == NULLBUF)
  286.     return;
  287.   if((size = fread(bp->data,1,cnt,s->upload)) > 0)
  288.   {
  289.     bp->cnt = (int16)size;
  290.     send_tcp(tcb,bp);
  291.   }
  292.   else
  293.   {
  294.     free_p(bp);
  295.   }
  296.   if(size != cnt)
  297.   {
  298.     /* Error or end-of-file */
  299.     fclose(s->upload);
  300.     s->upload = NULLFILE;
  301.     free(s->ufile);
  302.     s->ufile = NULLCHAR;
  303.   }
  304. }
  305.  
  306. /* State change upcall routine */
  307. void t_state(register struct tcb *tcb, char old, char new)
  308. {
  309.   extern int ttyflow;
  310.   struct telnet *tn;
  311.   char notify = 0;
  312.   extern char *tcpstates[];
  313.   extern char *reasons[];
  314.   extern char *unreach[];
  315.   extern char *exceed[];
  316.  
  317.   old = old;
  318.  
  319.   /* Can't add a check for unknown connection here, it would loop
  320.      on a close upcall! We're just careful later on. */
  321.   tn = (struct telnet *)tcb->user;
  322.  
  323.   if(tn->window != NULL || (ttyflow && current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn))
  324.     notify = 1;
  325.  
  326.   switch(new)
  327.   {
  328.   case CLOSE_WAIT:
  329.     if(notify)
  330.       cwprintf(tn->window, "%s\r\n",tcpstates[new]);
  331.     close_tcp(tcb);
  332.     break;
  333.   case CLOSED:    /* court adjourned */
  334.     if(notify)
  335.     {
  336.       cwprintf(tn->window, "%s (%s",tcpstates[new],reasons[tcb->reason]);
  337.       if(tcb->reason == NETWORK)
  338.       {
  339.         switch(tcb->type)
  340.         {
  341.         case DEST_UNREACH:
  342.           cwprintf(tn->window, ": %s unreachable",unreach[tcb->code]);
  343.           break;
  344.         case TIME_EXCEED:
  345.           cwprintf(tn->window, ": %s time exceeded",exceed[tcb->code]);
  346.           break;
  347.         }
  348.       }
  349.       cwprintf(tn->window, ")\r\n");
  350.       cmdmode();
  351.     }
  352.     del_tcp(tcb);
  353.     if(tn != NULLTN)
  354.       free_telnet(tn);
  355.     break;
  356.   default:
  357.     if(notify)
  358.       cwprintf(tn->window, "%s\r\n",tcpstates[new]);
  359.     break;
  360.   }
  361. }
  362. /* Delete telnet structure */
  363. static void free_telnet(struct telnet *tn)
  364. {
  365.   if(tn->session != NULLSESSION)
  366.     freesession(tn->session);
  367.   if (tn->window)
  368.   {
  369.     tn->window->Attr = ATTR_REVERSE;
  370.     tn->window->Flags.flags.dont_destroy = FALSE;
  371.     Window_CloseDown(tn->window);
  372.   }
  373.  
  374.   if(tn != NULLTN)
  375.     free((char *)tn);
  376. }
  377.  
  378. /* The guts of the actual Telnet protocol: negotiating options */
  379. static void willopt(struct telnet *tn, char opt)
  380. {
  381.   int ack;
  382.  
  383. #ifdef  DEBUG
  384.   cwprintf(tn->window, "recv: will ");
  385.   if(uchar(opt) <= NOPTIONS)
  386.     cwprintf(tn->window, "%s\r\n",t_options[opt]);
  387.   else
  388.       cwprintf(tn->window, "%u\r\n",opt);
  389. #endif
  390.  
  391.   switch(uchar(opt))
  392.   {
  393.   case TN_TRANSMIT_BINARY:
  394.   case TN_ECHO:
  395.   case TN_SUPPRESS_GA:
  396.     if(tn->remote[uchar(opt)] == 1)
  397.       return;         /* Already set, ignore to prevent loop */
  398.     if(uchar(opt) == TN_ECHO)
  399.     {
  400.       if(refuse_echo)
  401.       {
  402.         /* User doesn't want to accept */
  403.         ack = DONT;
  404.         break;
  405.       }
  406.       else
  407.       {
  408.         raw();          /* Put tty into raw mode */
  409.         vterm_setflags(tn->window->vt,
  410.            /* Clear */ VTSW_CHAT|VTSW_LINE|VTSW_NEWLINE|VTSW_WRAP|VTSW_ECHO,
  411.            /* Set */   0 );
  412.  
  413.         tn->session->raw = TRUE;
  414.       }
  415.     }
  416.     tn->remote[uchar(opt)] = 1;
  417.     ack = DO;
  418.     break;
  419.   default:
  420.     ack = DONT;     /* We don't know what he's offering; refuse */
  421.   }
  422.   answer(tn,ack,opt);
  423. }
  424. static void wontopt(struct telnet *tn, char opt)
  425. {
  426. #ifdef  DEBUG
  427.   cwprintf(tn->window, "recv: wont ");
  428.   if(uchar(opt) <= NOPTIONS)
  429.     cwprintf(tn->window, "%s\r\n",t_options[uchar(opt)]);
  430.   else
  431.     cwprintf(tn->window, "%u\r\n",uchar(opt));
  432. #endif
  433.   if(uchar(opt) <= NOPTIONS)
  434.   {
  435.     if(tn->remote[uchar(opt)] == 0)
  436.       return;         /* Already clear, ignore to prevent loop */
  437.     tn->remote[uchar(opt)] = 0;
  438.     if(uchar(opt) == TN_ECHO)
  439.     {
  440.       cooked();       /* Put tty into cooked mode  (old code) */
  441.       tn->session->raw = FALSE;
  442.         vterm_setflags(tn->window->vt,
  443.            /* Clear */ VTSW_CHAT|VTSW_LINE|VTSW_NEWLINE|VTSW_WRAP|VTSW_ECHO,
  444.            /* Set */   VTSW_LINE|VTSW_NEWLINE|VTSW_WRAP|VTSW_ECHO );
  445.     }
  446.   }
  447.   answer(tn,DONT,opt);    /* Must always accept */
  448. }
  449. static void doopt(struct telnet *tn, char opt)
  450. {
  451.   int ack;
  452.  
  453. #ifdef  DEBUG
  454.   cwprintf(tn->window, "recv: do ");
  455.   if(uchar(opt) <= NOPTIONS)
  456.     cwprintf(tn->window, "%s\r\n",t_options[uchar(opt)]);
  457.   else
  458.       cwprintf(tn->window, "%u\r\n",uchar(opt));
  459. #endif
  460.   switch(uchar(opt))
  461.   {
  462. #ifdef  FUTURE  /* Use when local options are implemented */
  463.     if(tn->local[uchar(opt)] == 1)
  464.       return;         /* Already set, ignore to prevent loop */
  465.     tn->local[uchar(opt)] = 1;
  466.     ack = WILL;
  467.     break;
  468. #endif
  469.   default:
  470.     ack = WONT;     /* Don't know what it is */
  471.   }
  472.   answer(tn,ack,opt);
  473. }
  474. static void dontopt(struct telnet *tn, char opt)
  475. {
  476. #ifdef  DEBUG
  477.   cwprintf(tn->window, "recv: dont ");
  478.   if(uchar(opt) <= NOPTIONS)
  479.     cwprintf(tn->window, "%s\r\n",t_options[uchar(opt)]);
  480.   else
  481.       cwprintf(tn->window, "%u\r\n",uchar(opt));
  482. #endif
  483.   if(uchar(opt) <= NOPTIONS)
  484.   {
  485.     if(tn->local[uchar(opt)] == 0)
  486.     {
  487.       /* Already clear, ignore to prevent loop */
  488.       return;
  489.     }
  490.     tn->local[uchar(opt)] = 0;
  491.   }
  492.   answer(tn,WONT,opt);
  493. }
  494. static void answer(struct telnet *tn, int r1, int r2)
  495. {
  496.   struct mbuf *bp;
  497.   char s[3];
  498.  
  499. #ifdef  DEBUG
  500.   switch(r1)
  501.   {
  502.   case WILL:
  503.     cwprintf(tn->window, "sent: will ");
  504.     break;
  505.   case WONT:
  506.     cwprintf(tn->window, "sent: wont ");
  507.     break;
  508.   case DO:
  509.     cwprintf(tn->window, "sent: do ");
  510.     break;
  511.   case DONT:
  512.     cwprintf(tn->window, "sent: dont ");
  513.     break;
  514.   }
  515.   if(r2 <= 6)
  516.     cwprintf(tn->window, "%s\r\n",t_options[r2]);
  517.   else
  518.       cwprintf(tn->window, "%u\r\n",r2);
  519. #endif
  520.  
  521.   s[0] = IAC;
  522.   s[1] = r1;
  523.   s[2] = r2;
  524.   bp = qdata(s,(int16)3);
  525.   send_tcp(tn->tcb,bp);
  526. }
  527.