home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msvp98b1.lzh / MSNTND.C < prev    next >
Text File  |  1993-05-14  |  21KB  |  705 lines

  1. /* File MSNTND.C
  2.  * Telnet driver
  3.  *
  4.  * Copyright (C) 1985, 1992, Trustees of Columbia University in the 
  5.  * City of New York.  Permission is granted to any individual or institution
  6.  * to use this software as long as it is not sold for profit.  This copyright
  7.  * notice must be retained.  This software may not be included in commercial
  8.  * products without written permission of Columbia University.
  9.  *
  10.  * Written for MS-DOS Kermit by Joe R. Doupnik, 
  11.  *  Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet,
  12.  *  and by Frank da Cruz, Columbia Univ., fdc@watsun.cc.columbia.edu.
  13.  * With earlier contributions by Erick Engelke of the University of
  14.  *  Waterloo, Waterloo, Ontario, Canada.
  15.  *
  16.  * Last edit
  17.  * 25 May 1992
  18.  */
  19. #include "msntcp.h"
  20. #include "msnlib.h"
  21.  
  22. /* TCP/IP Telnet negotiation support code */
  23. #define IAC     255
  24. #define DONT    254
  25. #define DO      253
  26. #define WONT    252
  27. #define WILL    251
  28. #define SB      250
  29. #define BREAK   243
  30. #define SE      240
  31.  
  32. #define TELOPT_ECHO     1
  33. #define TELOPT_SGA      3
  34. #define TELOPT_STATUS   5
  35. #define TELOPT_TTYPE    24
  36. #define TELOPT_NAWS    31
  37. #define NTELOPTS        24
  38.  
  39. #define BAPICON        0xa0    /* 3Com BAPI, connect to port */
  40. #define BAPIDISC    0xa1    /* 3Com BAPI, disconnect */
  41. #define BAPIWRITE    0xa4    /* 3Com BAPI, write block */
  42. #define BAPIREAD    0xa5    /* 3Com BAPI, read block */
  43. #define BAPIBRK        0xa6    /* 3Com BAPI, send short break */
  44. #define BAPISTAT    0xa7    /* 3Com BAPI, read status (# chars avail) */
  45. #define BAPIHERE    0xaf    /* 3Com BAPI, presence check */
  46. #define BAPIEECM    0xb0    /* 3Com BAPI, enable/disable ECM char */
  47. #define BAPIECM        0xb1    /* 3Com BAPI, trap Enter Command Mode char */
  48. #define BAPISTAT_SUC    0    /* function successful */
  49. #define BAPISTAT_NCW    1    /* no character written */
  50. #define BAPISTAT_NCR    2    /* no character read */
  51. #define BAPISTAT_NSS    3    /* no such session */
  52. #define BAPISTAT_NOS    7    /* session aborted */
  53. #define BAPISTAT_NSF    9    /* no such function */
  54.  
  55. byte *termtype;            /* Telnet, used in negotiations */
  56. static int sgaflg = 0;        /* Telnet SGA flag */
  57. static tn_inited = 0;        /* Telnet Options initied */
  58. static ttinccnt = 0;        /* Telnet count of chars in read socket */
  59. int echo = 1;            /* Telnet echo, default on, but hate it */
  60.  
  61. struct    {
  62.     word ident;
  63.     char *name;
  64.     } termarray[]=        /* terminal type names, from mssdef.h */
  65.         {
  66.         {0,"UNKNOWN"}, {1,"H-19"}, {2,"VT52"}, {4,"VT100"},
  67.         {8,"VT102"}, {0x10,"VT220"}, {0x20,"VT320"}, {0x40,"TEK4014"},
  68.         {0x80,"VIP7809"}, {0x100, "PT200"}, {0xff,"UNKNOWN"}
  69.         };
  70.  
  71. extern    byte bapibuf[];        /* buffer of in/out chars, 512 long */
  72. extern    int bapireq, bapiret;    /* count of chars in/out */
  73. extern    int msgcnt;        /* count of chars in message buffer */
  74. extern    longword my_ip_addr, sin_mask; /* binary of our IP, netmask */
  75. extern    longword ipbcast;    /* binary IP of broadcast */
  76. extern    byte * def_domain;    /* default domain string */
  77. longword host;            /* binary IP of host */
  78. word sock_delay = 30;
  79. in_IAC = 0;                /* non-zero when doing Telnet Options*/
  80. static tcp_Socket *s, socketdata;
  81.  
  82. int doslevel = 1;            /* operating at DOS level if != 0 */
  83. int ktcpstate = 0;            /* remember if started or stopped */
  84. extern byte kmyip[];            /* our IP number */
  85. extern byte knetmask[];            /* our netmask */
  86. extern byte kdomain[];            /* our domain */
  87. extern byte kgateway[];            /* our gateway */
  88. extern byte kns1[];            /* our nameserver #1 */
  89. extern byte kns2[];            /* our nameserver #2 */
  90. extern byte kbcast[];            /* broadcast address pattern */
  91. extern byte khost[];            /* remote host name/IP # */
  92. extern word kport;            /* remote host TCP port */
  93. extern word kserver;            /* if Kermit is in server mode */
  94. extern word kdebug;
  95. extern byte ktttype[];            /* user term type override string */
  96. extern word kterm;            /* terminal type index, from mssdef.h*/
  97. extern byte kterm_lines;        /* terminal screen height */
  98. extern byte kterm_cols;            /* terminal screen width */
  99.  
  100. /* this runs at Kermit task level */
  101. int
  102. main()                    /* start TCP from Kermit */
  103. {
  104.     static int status = 0;
  105.     byte ch, * p;
  106.     int i;
  107.     extern longword bootphost;
  108.     int arp_add_gateway(byte *data, longword ip);
  109.     longword arp_rpt_gateway(int i);
  110.     extern int pkt_rarp_init(void);
  111.     extern int dobootp();
  112.     extern void ntoa(byte * p, longword ip);
  113.  
  114.     if (ktcpstate == 2)        /* if have started already */
  115.         return (ktcpstate);    /* say have started */
  116.     doslevel = 1;            /* say at DOS level here */
  117.  
  118.     tn_inited = 0;            /* Telnet Options initied */
  119.     ttinccnt = 0;            /* count of chars in read socket */
  120.     echo = 1;            /* Telnet echo, default on */
  121.     kecho(echo);            /* update Kermit main body */
  122.     msgcnt = 0;            /* output queue buffer count */
  123.     host = 0L;
  124.     def_domain = kdomain;        /* define our domain */
  125.     msgcnt = 0;            /* init msg queue */
  126.     in_IAC = 0;            /* setup for Options negotiations */
  127.     my_ip_addr = 0L;
  128.  
  129.     if (ktttype[0] != '\0')        /* if user override given */
  130.         termtype = ktttype;
  131.     else                /* get termtype from real use */
  132.         {
  133.         for (i = 0; termarray[i].ident != 0xff; i++)
  134.                 if (termarray[i].ident == kterm)    /* match */
  135.                 break;
  136.         termtype = termarray[i].name;
  137.         }
  138.  
  139.     s = NULL;            /* no TCP socket yet */
  140.     if (tcp_init() == 0)        /* init TCP code */
  141.         {
  142.         outs("\r\n Unable to initialize TCP/IP system, quitting");
  143.         goto anyerr;
  144.         }
  145.  
  146.     sin_mask = resolve(knetmask);
  147.     if (sin_mask == 0L)
  148.             {            /* something drastically wrong */
  149.         outs("\r\n Bad network submask, terminating");
  150.         goto anyerr;
  151.         }
  152.  
  153.         /* set Ethernet broadcast to all 1's or all 0's */
  154.     ipbcast = resolve(kbcast);    /* IP broadcast address */
  155.     bootphost = ipbcast;        /* set Bootp to this IP too */
  156.  
  157.     if ((p = strchr(kmyip, ' ')) != NULL)    /* have a space */
  158.         *p = '\0';            /* terminate on the space */
  159.  
  160.     if (stricmp(kmyip, "bootp") == 0)
  161.         {
  162.         if (dobootp() != 0)    /* use BOOTP for Internet address */
  163.             {
  164.             outs("\r\n BOOTP query failed. Quitting.");
  165.             goto anyerr;
  166.             }
  167.         else
  168.             {
  169.             kmyip[0] = '\0';
  170.             ntoa(&kmyip[strlen(kmyip)], my_ip_addr);
  171.             ntoa(knetmask, sin_mask);
  172.             ntoa(kgateway, arp_rpt_gateway(0));
  173.             ntoa(kns1, def_nameservers[0]);
  174.             ntoa(kns2, def_nameservers[1]);
  175.             readback();    /* readback these to Kermit main */
  176.             }
  177.         }
  178.     else
  179.         {
  180.         if (stricmp(kmyip, "rarp") == 0)
  181.             {
  182.             my_ip_addr = 0L;    /* clear our IP for RARP */
  183.             if (pkt_rarp_init() == 0)
  184.                 goto anyerr;    /* no RARP handle */
  185.             if (do_rarp() == 0)     /* use RARP */
  186.                 {
  187.                 outs("\r\n RARP query failed.");
  188.                 goto anyerr;
  189.                 }
  190.             else
  191.                 {
  192.                 kmyip[0] = '\0';
  193.                 ntoa(&kmyip[strlen(kmyip)], my_ip_addr);
  194.                 readback();
  195.                 }
  196.             }
  197.         else                 /* convert to 32 bit binary */
  198.             my_ip_addr = resolve(kmyip);
  199.         }
  200.  
  201.     if (my_ip_addr == 0L)
  202.             {            /* something drastically wrong */
  203.         outs("\r\n Cannot understand my IP address, terminating");
  204.         goto anyerr;
  205.         }
  206.  
  207.     if (stricmp(kns1, "unknown"))
  208.         add_server(&last_nameserver, MAX_NAMESERVERS, def_nameservers,
  209.             resolve(kns1));
  210.     if (stricmp(kns2, "unknown"))
  211.         add_server(&last_nameserver, MAX_NAMESERVERS, def_nameservers,
  212.         resolve(kns2));
  213.  
  214.     if (stricmp(kgateway, "unknown"))
  215.         arp_add_gateway(kgateway, 0L);
  216.     s = &socketdata;
  217.  
  218.     /* kserver is set by main body SERVER command. If khost[0] is '*'
  219.     then also behave as a server/listener for any main body mode. */
  220.  
  221.     if ((khost[0] == '*') || (kserver != 0))
  222.         {
  223.         host = 0L;        /* force no host IP at this stage */
  224.         tcp_listen(s, kport, host, 0, NULL, 0); /* post a listen */
  225.         }
  226.     else                    /* normal client mode */
  227.         {
  228.         outs("\r\n Resolving address of host ");
  229.         outs(khost); outs(" ...");
  230.         if ((host = resolve(khost)) == 0)
  231.             {
  232.             outs( "\r\n Cannot resolve address of host ");
  233.             outs(khost);
  234.             goto anyerr;
  235.             }
  236.         outs("\r\n");        /* get clean screen line */
  237.         }
  238.  
  239.     if (host == my_ip_addr)
  240.         {
  241.         outs("\r\n Cannot talk to myself, sorry.");
  242.         sock_wait_established( s, 0, NULL, &status );
  243.         goto anyerr;
  244.         }
  245.  
  246.     if (hookvect() == 0)
  247.         {
  248.         doslevel = 1;            /* at DOS level i/o */
  249.         outs("\r\n Hooking vectors failed");
  250.           if (s != NULL)
  251.             {
  252.             sock_close(s);
  253.             sock_wait_closed(s, sock_delay, NULL, &status);
  254.             }
  255.         goto anyerr;
  256.         }
  257.  
  258.     if ((khost[0] == '*') || (kserver != 0)) /* if server */
  259.         {
  260.         doslevel = 0;            /* end of DOS level i/o */
  261.         if (kserver == 0)
  262.             outs("\r\n Operating as a Telnet server. Waiting...");
  263.         }
  264.     else                    /* we are a client */
  265.         {
  266.         if (tcp_open(s, 0, host, kport, NULL) == 0)
  267.             {
  268.             outs("\r\n Unable to contact the host.");
  269.             outs("\r\n The host may be down or");
  270.             outs(" a gateway may be needed.");
  271.             goto anyerr;
  272.             }
  273.         sock_wait_established(s, sock_delay, NULL, &status);
  274.         }
  275.  
  276.     if (sock_mode(s, TCP_MODE_NAGLE) == 0)
  277.         {
  278.         outs("\r\n Unable to set socket mode");
  279.         goto anyerr;
  280.         }
  281.     doslevel = 0;                /* end of DOS level i/o */
  282.     return (ktcpstate = 2);        /* say we are active */
  283.  
  284.  
  285. sock_err:
  286.     switch (status)
  287.         {
  288.         case 1 : outs("\r\n Session is closed");
  289.             break;
  290.         case -1: outs("\r\n Cannot start a connection");
  291.             break;
  292.         }
  293. anyerr:    sock_close(s);
  294.     kecho(echo = 0);
  295.     tcp_shutdown();
  296.     eth_release();            /* do absolutely */
  297.     unhookvect();
  298.     doslevel = 1;            /* at DOS level i/o */
  299.     return (ktcpstate = 1);        /* say have stopped */
  300. }
  301.  
  302. /* this runs at Kermit task level */
  303. int
  304. exit(value)                /* stop TCP from Kermit */
  305. int value;
  306. {
  307.     doslevel = 1;            /* tell i/o routines this is DOS */
  308.     sock_close(s);            /* graceful way */
  309.     kecho(echo = 0);
  310.     tcp_shutdown();            /* force the issue if necessary */
  311.     eth_release();            /* do absolutely */
  312.     unhookvect();
  313.     return (ktcpstate = 1);        /* state is down */
  314. }
  315.  
  316. /* This is called by the main body of Kermit to transfer data. It returns
  317.    the transfer status as a BAPI valued int. */
  318.  
  319. serial_handler(cmd)
  320. unsigned int cmd;
  321. {
  322.     int i, status, cmdstatus;
  323.     register int ch;
  324.     register byte * bp;
  325.     word ttinc();
  326.     extern int sock_findch(tcp_Socket *, byte);
  327.  
  328.     if (tn_inited == 0)        /* if not initialized yet */
  329.          {
  330.         tn_inited = 1;        /* say we are doing this */
  331.         if (tn_ini() == -1)    /* init Telnet negotiations */
  332.             return (BAPISTAT_NOS);    /* fatal error, quit */
  333.         }
  334.  
  335.     tcp_tick(s);            /* catch up on packet reading */
  336.  
  337.     cmdstatus = BAPISTAT_SUC;    /* success so far */
  338.     switch (cmd)            /* cmd is function code */
  339.         {
  340.         case BAPIWRITE:        /* write a block, bapireq chars */
  341.             if (khost[0] == '*' && s->state != tcp_StateESTAB)
  342.                 {
  343.                 bapiret = bapireq; /* discard output and */
  344.                 break;    /* send nothing until client appears*/
  345.                 }
  346.             if (echo)
  347.                 if (sock_flushnext(s) == 0) /* send next now */
  348.                     cmdstatus = BAPISTAT_NOS; /* no sess*/
  349.             bapiret = sock_write(s, bapibuf, bapireq);
  350.  
  351.         /* if terminal serving with no local echoing do echo here */
  352.             if (echo == 0 && khost[0] == '*' && kserver == 0)
  353.                 outsn(bapibuf, bapiret); /* echo to us */
  354.             break;
  355.  
  356.         case BAPIREAD:        /* read block, count of bapireq */
  357.             i = sock_findch(s, IAC);    /* is IAC present? */
  358.             if (i < 0)
  359.                 {
  360.                 cmdstatus = BAPISTAT_NCR;/* nothing present */
  361.                 break;
  362.                 }
  363.             if (i > 0 && in_IAC == 0)  /* read up to IAC */
  364.                 {
  365.                 if (i > bapireq) i = bapireq;
  366.                  bapiret = sock_fastread(s, bapibuf, i);
  367.  
  368.         /* if terminal serving with local echoing then echo to host */
  369.                 if (echo != 0 && khost[0] == '*' && 
  370.                                 kserver == 0)
  371.                     sock_write(s, bapibuf, bapiret);
  372.                 break;
  373.                 }
  374.  
  375.             bp = bapibuf;    /* use slow reading for Options */
  376.             ttinccnt = 0;    /* setup to read from buffer */
  377.                 /* state is here, IAC style, vs fast mode */
  378.             in_IAC = 1;
  379.             for (i = 0; i < bapireq; i++)
  380.                 {
  381.                 if ((ch = ttinc()) == -1)
  382.                     break;        /* no char */
  383.                 ch &= 0xff;
  384.                     if ( ch == IAC )  /* Telnet options intro */
  385.                     {        /* do Options */
  386.                     if ((ch = ttinc()) == -1)
  387.                         break;    /* do more later */
  388.                     if ((ch &= 0xff) != IAC)
  389.                         {   /* IAC IAC means IAC */
  390.                         tn_doop(ch); /* negotiate */
  391.                         continue;
  392.                         }
  393.                     }
  394.                 in_IAC = 0;         /* end of mode */
  395.                 *bp++ = ch & 0xff;
  396.                 bapiret++;
  397.                 }
  398.             break;
  399.  
  400.         case BAPIBRK:            /* send BREAK */
  401.             sock_putc(s, IAC);    /* char to socket buffer */
  402.             sock_putc(s, BREAK);
  403.             if (sock_flush(s) == 0)    /* send it now, with push */
  404.                 cmdstatus = BAPISTAT_NOS; /* no session */
  405.             break;
  406.         case BAPISTAT:        /* check read status (chars avail) */
  407.             bapiret = sock_dataready(s); /* # chars available */
  408.              break;
  409.         default: cmdstatus = BAPISTAT_NSF;/* unsupported function */
  410.             break;
  411.         }
  412.  
  413.     if ((sock_dataready(s) == 0) && (msgcnt == 0) && 
  414.         (s->state == tcp_StateCLOSED))    /* no data and no session */
  415.             return (BAPISTAT_NOS);    /* means exit TCP */
  416.     else
  417.         return (cmdstatus);        /* stuff is yet unread */
  418. }
  419.  
  420. /* ttinc   - destructively read char from socket buffer, return -1 if fail */
  421.  
  422. word 
  423. ttinc(void)
  424. {
  425.     byte ch;
  426.     
  427.     if (ttinccnt <= 0)            /* if no known chars */
  428.         {
  429.         tcp_tick(s);            /* read another packet */
  430.         ttinccnt = sock_dataready(s); /* count available, if any */
  431.         }
  432.     if (sock_fastread(s, &ch, 1) != 0)    /* qty chars returned */
  433.         {
  434.         ttinccnt--;            /* one less char in socket */
  435.         return (0xff & ch);
  436.         }
  437.     return (-1);
  438. }
  439.  
  440. /* Initialize a telnet connection */
  441. /* Returns -1 on error, 0 is ok */
  442.  
  443. int 
  444. tn_ini(void)
  445. {
  446.     sgaflg = 0;                         /* SGA flag starts out this way */
  447.     if (khost[0] == '*' || kserver != 0 || 
  448.             kport != 23) /* if not server or not Telnet port */
  449.             return (0);        /* don't go first */
  450.     if (send_iac( WILL, TELOPT_TTYPE )) return( -1 );
  451.     if (send_iac( WILL, TELOPT_NAWS)) return(-1);
  452.     if (send_iac( DO, TELOPT_SGA )) return( -1 );
  453.     return(0);
  454. }
  455.  
  456. /*
  457.  * send_iac - send interupt character and pertanent stuff
  458.  *        - return 0 on success
  459.  */
  460.  
  461. send_iac(cmd, opt)
  462. byte cmd, opt;
  463. {
  464.     byte io_data[3];
  465.  
  466.     io_data[0] = IAC;
  467.     io_data[1] = cmd;
  468.     io_data[2] = opt;
  469.     sock_fastwrite(s, io_data, 3);
  470.     return(!tcp_tick(s));
  471. }
  472.  
  473. /*
  474.  * Process in-band Telnet negotiation characters from the remote host.
  475.  * Call with the telnet IAC character and the current duplex setting
  476.  * (0 = remote echo, 1 = local echo).
  477.  * Returns:
  478.  *  -1 on success or char 0x255 (IAC) when IAC is the first char read here.
  479.  */
  480.  
  481. #define TSBUFSIZ 41
  482. byte sb[TSBUFSIZ];                      /* Buffer for subnegotiations */
  483.  
  484. int 
  485. tn_doop(ch)
  486. word ch;
  487. {                    /* enter after reading IAC char */
  488.     register int c, x;
  489.     word y, n, flag, ttinc();
  490.     
  491.         if (ch < SB) return(0);        /* ch is not in range of Options */
  492.  
  493.     if ((x = ttinc()) == -1)    /* read Option character */
  494.         return (-1);        /* nothing there */
  495.     x &= 0xff;
  496.     c = ch;                /* use register'd character */
  497.  
  498.     switch (x) {
  499.  
  500.       case TELOPT_ECHO:                 /* ECHO negotiation */
  501.     if (c == WILL)            /* Host says it will echo */
  502.         {
  503.         if (echo != 0)        /* reply only if change required */
  504.             {
  505.             send_iac(DO,x);    /* Please do */
  506.             kecho(echo = 0); /* echo is from the other side */
  507.             }
  508.         break;
  509.         }
  510.  
  511.         if (c == WONT)            /* Host says it won't echo */
  512.         {
  513.         if (echo == 0)            /* If we not echoing now */
  514.             send_iac(DONT,x);    /* agree to no host echo */
  515.         break;
  516.         }
  517.  
  518.     if (c == DO)
  519.         {            /* Host wants me to echo to it */
  520.         send_iac(WONT,x);    /* I say I won't */
  521.         break;
  522.             }
  523.     break;                /* do not respond to DONT */
  524.  
  525.       case TELOPT_SGA:                  /* Suppress Go-Ahead */
  526.     if (c == WONT)            /* Host says it won't sup go-aheads */
  527.         {
  528.         if (sgaflg == 0)
  529.             send_iac(DONT, x);    /* acknowledge */
  530.         sgaflg = 1;            /* suppress, remember */
  531.         if (echo == 0)            /* if we're not echoing, */
  532.             kecho(echo = 1);    /* switch to local echo */
  533.         break;
  534.         }
  535.  
  536.         if (c == WILL)            /* Host says it will use go aheads */
  537.         {
  538.         if (sgaflg != 0)        /* if suppressed */
  539.             {
  540.             sgaflg = 0;        /* do go-aheads, remember */
  541.             send_iac(DO,x);        /* this is a change, so ACK */
  542.                     }
  543.         break;
  544.             }
  545.     break;                /* no response to other cases */
  546.  
  547.       case TELOPT_TTYPE:                /* Terminal Type */
  548.         switch (c) {
  549.           case DO:                      /* DO terminal type */
  550.         send_iac(WILL, x);    /* say I'll send it if asked */
  551.         break;
  552.  
  553.           case SB:            /* enter subnegotiations */
  554.             n = flag = 0;               /* flag for when done reading SB */
  555.             while (n < TSBUFSIZ)
  556.             {            /* loop looking for IAC SE */
  557.                 if ((y = ttinc()) == -1)
  558.             break;        /* nothing there */
  559.         y &= 0xff;              /* make sure it's just 8 bits */
  560.         sb[n++] = y;        /* save what we got in buffer */
  561.  
  562.         if (y == IAC)         /* If this is an IAC */
  563.             {
  564.             if (flag)        /* If previous char was IAC */
  565.                 {
  566.             n--;        /* it's quoted, keep one IAC */
  567.             flag = 0;    /* and turn off the flag. */
  568.             }
  569.             else flag = 1;    /* Otherwise set the flag. */
  570.             }
  571.         else if (flag)      /* Something else following IAC */
  572.             {
  573.             if (y != SE)    /* If not SE, it's a protocol error */
  574.               flag = 0;
  575.             break;
  576.                     }        /* end of if (y == IAC) */
  577.         }            /* end while */
  578.         if (flag == 0 || y == -1)    /* no terminal type IAC SE */
  579.            break;            /* flag == 0 is invalid SB */
  580.  
  581.         if ( *sb == 1 )        /* wants us to report terminal type */
  582.         tn_sttyp();        /* do so */
  583.         break;
  584.  
  585.           default:                      /* ignore other TTYPE Options */
  586.         break;
  587.         }                /* end of inner switch (c) */
  588.     break;
  589.  
  590.     case TELOPT_NAWS:        /* terminal width and height */
  591.         switch (c)
  592.         {
  593.         case DO: tn_snaws();    /* host wants report, send it */
  594.         default: break;        /* other actions, discard */
  595.         }
  596.     break;
  597.  
  598.  
  599.       default:                /* all other Options: refuse nicely */
  600.     switch(c) {
  601.           case WILL:                    /* You will? */
  602.         send_iac(DONT,x);    /* Please don't */
  603.         break;
  604.           case DO:                      /* You want me to? */
  605.         send_iac(WONT,x);    /* I won't */
  606.             send_iac(DONT,x);    /* Don't you either */
  607.         break;
  608.  
  609.           case DONT:
  610.         send_iac(WONT,x);    /* I won't */
  611.         break;
  612.  
  613.           case WONT:                    /* You won't? */
  614.         break;            /* Good */
  615.  
  616.       default:
  617.           break;            /* unknown character, discard */
  618.           }                /* end of default switch (c) */
  619.         break;
  620.     }                    /* end switch (x) */
  621.     return (-1);            /* say done with Telnet Options */
  622. }
  623.  
  624. /* Telnet send terminal type */
  625. /* Returns -1 on error, 0 on success */
  626.  
  627. int 
  628. tn_sttyp()
  629. {                            /* Send telnet terminal type. */
  630.     register byte *ttn;
  631.     register int ttnl;        /* Name & length of terminal type. */
  632.  
  633.     ttn = termtype;        /* we already got this from environment */
  634.     if ((*ttn == 0) || ((ttnl = strlen(ttn)) >= TSBUFSIZ)) {
  635.         ttn = "UNKNOWN";
  636.         ttnl = 7;
  637.     }
  638.  
  639.     ttn = strcpy(&sb[1], ttn);        /* Copy to subnegotiation buffer */
  640.     while (*ttn != NULL)
  641.         {
  642.         if (*ttn >= 'a' && *ttn <= 'z') *ttn += (- 'a' + 'A');
  643.         ttn++;
  644.         }
  645.     *sb    = 0;                /* 'is'... */
  646.     *ttn++ = IAC;
  647.     *ttn   = SE;
  648.  
  649.     send_iac((byte)SB, TELOPT_TTYPE);    /* Send: Terminal Type */
  650.     sock_flushnext(s);            /* send on next write */
  651.     sock_fastwrite(s, sb, ttnl + 3);
  652.     return (0);
  653. }
  654.  
  655. /* Send terminal width and height (characters). RFC 1073 */
  656. int
  657. tn_snaws()
  658. {
  659.     static char sbuf[6] = {0,0, 0,0, IAC, SE};
  660.  
  661.     sbuf[1] = kterm_cols;
  662.     sbuf[3] = kterm_lines;
  663.     send_iac((byte)SB, TELOPT_NAWS);    /* Send: Terminal size */
  664.     sock_flushnext(s);            /* send on next write */
  665.     sock_fastwrite(s, sbuf, 6);
  666.     return (0);
  667. }
  668.  
  669. /* Compose a nice greeting message for incoming Telnet connections. Called
  670.    by tcp_handler() in the tcp_StateLISTEN section. It also notifies the
  671.    local terminal emulator of the client's presence and address. */
  672.  
  673. void
  674. server_hello(tcp_Socket *s)
  675. {
  676.     char hellomsg[256];            /* work buffer, keep short */
  677.     register int len;
  678.  
  679.     strcpy(hellomsg,
  680.         "\r\n Welcome to the MS-DOS Kermit Telnet server at [");
  681.     ntoa(&hellomsg[strlen(hellomsg)], my_ip_addr);        /* our IP */
  682.     strcat(hellomsg, "].\r\n");        /* as [dotted decimal] */
  683.     if (kserver != 0)            /* if file serving */
  684.         {
  685.         strcat(hellomsg," Escape back to your Kermit prompt and");
  686.         strcat(hellomsg," issue Kermit file server commands.\r\n\n");
  687.         }
  688.     else                    /* if terminal emulating */
  689.         {
  690.         strcat(hellomsg,
  691.             " You are talking to the terminal emulator,\r\n");
  692.         strcat(hellomsg, " adjust local echoing accordingly.\r\n");
  693.         }
  694.  
  695.         /* stuff string in socket buffer, adjust socket data length */
  696.     bcopy(hellomsg, &s->data[s->datalen], len = strlen(hellomsg));
  697.     s->datalen += len;
  698.                 /* tell main body the news */
  699.     strcpy(hellomsg, "\r\n Connection starting from [");
  700.     ntoa(&hellomsg[strlen(hellomsg)], s->hisaddr);    /* their IP */
  701.     strcat(hellomsg, "].\r\n");
  702.     outs(hellomsg);        /* send connection info to main body */
  703. }
  704.     
  705.