home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / TELNET.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  9KB  |  452 lines

  1. /* Internet Telnet client
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: telnet.c 1.2 93/07/16 11:51:27 ROOT_DOS Exp $
  7. *    08 May 93    1.2        GT    Fix warnings.                                    *
  8. ****************************************************************************/
  9.  
  10. #include <stdio.h>
  11. #ifdef    __TURBOC__
  12. #include <io.h>
  13. #include <fcntl.h>
  14. #endif
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "socket.h"
  18. #include "telnet.h"
  19. #include "session.h"
  20. #include "proc.h"
  21. #include "tty.h"
  22. #include "commands.h"
  23. #include "netuser.h"
  24.  
  25. static int filemode __ARGS((FILE *fp,int mode));
  26. #define    CTLZ    26
  27.  
  28. int Refuse_echo = 0;
  29. int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  30.  
  31. #ifdef    DEBUG
  32. char *T_options[] = {
  33.     "Transmit Binary",
  34.     "Echo",
  35.     "",
  36.     "Suppress Go Ahead",
  37.     "",
  38.     "Status",
  39.     "Timing Mark"
  40. };
  41. #endif
  42.  
  43. /* Execute user telnet command */
  44. int
  45. dotelnet(argc,argv,p)
  46. int argc;
  47. char *argv[];
  48. void *p;
  49. {
  50.     struct session *sp;
  51.     struct sockaddr_in fsocket;
  52.  
  53.     /* Allocate a session descriptor */
  54.     if((sp = newsession(argv[1],TELNET)) == NULLSESSION){
  55.         tprintf("Too many sessions\n");
  56.         return 1;
  57.     }
  58.     fsocket.sin_family = AF_INET;
  59.     if(argc < 3)
  60.         fsocket.sin_port = IPPORT_TELNET;
  61.     else
  62.         fsocket.sin_port = atoi(argv[2]);
  63.  
  64.     tprintf("Resolving %s... ",sp->name);
  65.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  66.         tprintf(Badhost,sp->name);
  67.         keywait(NULLCHAR,1);
  68.         freesession(sp);
  69.         return 1;
  70.     }
  71.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  72.         tprintf("Can't create socket\n");
  73.         keywait(NULLCHAR,1);
  74.         freesession(sp);
  75.         return 1;
  76.     }
  77.     return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
  78. }
  79. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  80. int
  81. tel_connect(sp,fsocket,len)
  82. struct session *sp;
  83. char *fsocket;
  84. int len;
  85. {
  86.     unsigned int index;
  87.     struct telnet tn;
  88.  
  89.     index = (unsigned int) (sp - Sessions);
  90.     memset((char *)&tn,0,sizeof(tn));
  91.     tn.eolmode = Tn_cr_mode;
  92.     tn.session = sp;    /* Upward pointer */
  93.     sp->cb.telnet = &tn;    /* Downward pointer */
  94.     sockmode(sp->s,SOCK_ASCII);    /* Default to ascii mode */
  95.  
  96.     tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
  97.     if(connect(sp->s,fsocket,len) == -1){
  98.           tprintf("%s session %u failed: %s errno %d\n",
  99.          Sestypes[sp->type], index, sockerr(sp->s),errno);
  100.  
  101.         keywait(NULLCHAR,1);
  102.         freesession(sp);
  103.         return 1;
  104.     }
  105.     tprintf("%s session ",Sestypes[sp->type]);
  106.     tprintf("%u connected to %s\n",index,sp->name);
  107.     tnrecv(&tn);
  108.     return 0;
  109. }
  110.  
  111. /* Telnet input routine, common to both telnet and ttylink */
  112. void
  113. tnrecv(tn)
  114. struct telnet *tn;
  115. {
  116.     int c,s,index;
  117.     struct session *sp;
  118.     char *cp;
  119.  
  120.     sp = tn->session;
  121.     s = sp->s;
  122.  
  123.     index = (int) (sp - Sessions);
  124.  
  125.     /* Fork off the transmit process */
  126.     sp->proc1 = newproc("tel_out",1024,tel_output,0,tn,NULL,0);
  127.  
  128.     /* Process input on the connection */
  129.     while((c = recvchar(s)) != -1){
  130.         if(c != IAC){
  131.             /* Ordinary character */
  132.             if(!tn->remote[TN_TRANSMIT_BINARY])
  133.                 c &= 0x7f;
  134.  
  135.             tputc((char)c);
  136.             continue;
  137.         }
  138.         /* IAC received, get command sequence */
  139.         c = recvchar(s);
  140.         switch(c){
  141.         case WILL:
  142.             c = recvchar(s);
  143.             willopt(tn,c);
  144.             break;
  145.         case WONT:
  146.             c = recvchar(s);
  147.             wontopt(tn,c);
  148.             break;
  149.         case DO:
  150.             c = recvchar(s);
  151.             doopt(tn,c);
  152.             break;
  153.         case DONT:
  154.             c = recvchar(s);
  155.             dontopt(tn,c);
  156.             break;
  157.         case IAC:    /* Escaped IAC */
  158.             tputc(IAC);
  159.             break;
  160.         }
  161.     }
  162. quit:    /* A close was received from the remote host.
  163.      * Notify the user, kill the output task and wait for a response
  164.      * from the user before freeing the session.
  165.      */
  166.     sockmode(sp->output,SOCK_ASCII); /* Restore newline translation */
  167.     cp = sockerr(s);
  168.     tprintf("%s session %u", Sestypes[sp->type],index);
  169.     tprintf(" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
  170.     killproc(sp->proc1);
  171.     sp->proc1 = NULLPROC;
  172.     close_s(sp->s);
  173.     sp->s = -1;
  174.     keywait(NULLCHAR,1);
  175.     freesession(sp);
  176. }
  177.  
  178. /* User telnet output task, started by user telnet command */
  179. void
  180. tel_output(unused,tn1,p)
  181. int unused;
  182. void *tn1;
  183. void *p;
  184. {
  185.     struct session *sp;
  186.     int c;
  187.     struct telnet *tn;
  188.  
  189.     tn = (struct telnet *)tn1;
  190.     sp = tn->session;
  191.  
  192.     /* Send whatever's typed on the terminal */
  193.     while((c = recvchar(sp->input)) != EOF){
  194.         usputc(sp->s,(char)c);
  195.         if(!tn->remote[TN_ECHO] && sp->record != NULLFILE)
  196.             putc(c,sp->record);
  197.  
  198.         /* By default, output is transparent in remote echo mode.
  199.          * If eolmode is set, turn a cr into cr-null.
  200.          * This can only happen when in remote echo (raw) mode, since
  201.          * the tty driver normally maps \r to \n in cooked mode.
  202.          */
  203.         if(c == '\r' && tn->eolmode)
  204.             usputc(sp->s,'\0');
  205.  
  206.         if(tn->remote[TN_ECHO])
  207.             usflush(sp->s);
  208.     }
  209.     /* Make sure our parent doesn't try to kill us after we exit */
  210.     sp->proc1 = NULLPROC;
  211. }
  212. int
  213. doecho(argc,argv,p)
  214. int argc;
  215. char *argv[];
  216. void *p;
  217. {
  218.     if(argc < 2){
  219.         if(Refuse_echo)
  220.             tprintf("Refuse\n");
  221.         else
  222.             tprintf("Accept\n");
  223.     } else {
  224.         if(argv[1][0] == 'r')
  225.             Refuse_echo = 1;
  226.         else if(argv[1][0] == 'a')
  227.             Refuse_echo = 0;
  228.         else
  229.             return -1;
  230.     }
  231.     return 0;
  232. }
  233. /* set for unix end of line for remote echo mode telnet */
  234. int
  235. doeol(argc,argv,p)
  236. int argc;
  237. char *argv[];
  238. void *p;
  239. {
  240.     if(argc < 2){
  241.         if(Tn_cr_mode)
  242.             tprintf("null\n");
  243.         else
  244.             tprintf("standard\n");
  245.     } else {
  246.         if(argv[1][0] == 'n')
  247.             Tn_cr_mode = 1;
  248.         else if(argv[1][0] == 's')
  249.             Tn_cr_mode = 0;
  250.         else {
  251.             tprintf("Usage: %s [standard|null]\n",argv[0]);
  252.             return -1;
  253.         }
  254.     }
  255.     return 0;
  256. }
  257.  
  258. /* The guts of the actual Telnet protocol: negotiating options */
  259. void
  260. willopt(tn,opt)
  261. struct telnet *tn;
  262. int opt;
  263. {
  264.     int ack;
  265.  
  266. #ifdef    DEBUG
  267.     printf("recv: will ");
  268.     if(uchar(opt) <= NOPTIONS)
  269.         printf("%s\n",T_options[opt]);
  270.     else
  271.         printf("%u\n",opt);
  272. #endif
  273.     
  274.     switch(uchar(opt)){
  275.     case TN_TRANSMIT_BINARY:
  276.     case TN_ECHO:
  277.     case TN_SUPPRESS_GA:
  278.         if(tn->remote[uchar(opt)] == 1)
  279.             return;        /* Already set, ignore to prevent loop */
  280.         if(uchar(opt) == TN_ECHO){
  281.             if(Refuse_echo){
  282.                 /* User doesn't want to accept */
  283.                 ack = DONT;
  284.                 break;
  285.             } else {
  286.                 /* Put tty into raw mode */
  287.                 tn->session->ttystate.edit = 0;
  288.                 tn->session->ttystate.echo = 0;
  289.                 sockmode(tn->session->s,SOCK_BINARY);
  290.                 sockmode(tn->session->input,SOCK_BINARY);
  291.                 sockmode(tn->session->output,SOCK_BINARY);
  292.                 if(tn->session->record != NULLFILE)
  293.                     filemode(tn->session->record,SOCK_BINARY);
  294.  
  295.             }
  296.         }
  297.         tn->remote[uchar(opt)] = 1;
  298.         ack = DO;            
  299.         break;
  300.     default:
  301.         ack = DONT;    /* We don't know what he's offering; refuse */
  302.     }
  303.     answer(tn,ack,opt);
  304. }
  305. void
  306. wontopt(tn,opt)
  307. struct telnet *tn;
  308. int opt;
  309. {
  310. #ifdef    DEBUG
  311.     printf("recv: wont ");
  312.     if(uchar(opt) <= NOPTIONS)
  313.         printf("%s\n",T_options[uchar(opt)]);
  314.     else
  315.         printf("%u\n",uchar(opt));
  316. #endif
  317.     if(uchar(opt) <= NOPTIONS){
  318.         if(tn->remote[uchar(opt)] == 0)
  319.             return;        /* Already clear, ignore to prevent loop */
  320.         tn->remote[uchar(opt)] = 0;
  321.         if(uchar(opt) == TN_ECHO){
  322.             /* Put tty into cooked mode */
  323.             tn->session->ttystate.edit = 1;
  324.             tn->session->ttystate.echo = 1;
  325.             sockmode(tn->session->s,SOCK_ASCII);
  326.             sockmode(tn->session->input,SOCK_ASCII);
  327.             sockmode(tn->session->output,SOCK_ASCII);
  328.             if(tn->session->record != NULLFILE)
  329.                 filemode(tn->session->record,SOCK_ASCII);
  330.         }
  331.     }
  332.     answer(tn,DONT,opt);    /* Must always accept */
  333. }
  334. void
  335. doopt(tn,opt)
  336. struct telnet *tn;
  337. int opt;
  338. {
  339.     int ack;
  340.  
  341. #ifdef    DEBUG
  342.     printf("recv: do ");
  343.     if(uchar(opt) <= NOPTIONS)
  344.         printf("%s\n",T_options[uchar(opt)]);
  345.     else
  346.         printf("%u\n",uchar(opt));
  347. #endif
  348.     switch(uchar(opt)){
  349.     case TN_SUPPRESS_GA:
  350.         if(tn->local[uchar(opt)] == 1)
  351.             return;        /* Already set, ignore to prevent loop */
  352.         tn->local[uchar(opt)] = 1;
  353.         ack = WILL;
  354.         break;
  355.     default:
  356.         ack = WONT;    /* Don't know what it is */
  357.     }
  358.     answer(tn,ack,opt);
  359. }
  360. void
  361. dontopt(tn,opt)
  362. struct telnet *tn;
  363. int opt;
  364. {
  365. #ifdef    DEBUG
  366.     printf("recv: dont ");
  367.     if(uchar(opt) <= NOPTIONS)
  368.         printf("%s\n",T_options[uchar(opt)]);
  369.     else
  370.         printf("%u\n",uchar(opt));
  371. #endif
  372.     if(uchar(opt) <= NOPTIONS){
  373.         if(tn->local[uchar(opt)] == 0){
  374.             /* Already clear, ignore to prevent loop */
  375.             return;
  376.         }
  377.         tn->local[uchar(opt)] = 0;
  378.     }
  379.     answer(tn,WONT,opt);
  380. }
  381. void
  382. answer(tn,r1,r2)
  383. struct telnet *tn;
  384. int r1,r2;
  385. {
  386.     char s[3];
  387.  
  388. #ifdef    DEBUG
  389.     switch(r1){
  390.     case WILL:
  391.         printf("sent: will ");
  392.         break;
  393.     case WONT:
  394.         printf("sent: wont ");
  395.         break;
  396.     case DO:
  397.         printf("sent: do ");
  398.         break;
  399.     case DONT:
  400.         printf("sent: dont ");
  401.         break;
  402.     }
  403.     if(r2 <= NOPTIONS)
  404.         printf("%s\n",T_options[r2]);
  405.     else
  406.         printf("%u\n",r2);
  407. #endif
  408.  
  409.     s[0] = IAC;
  410.     s[1] = r1;
  411.     s[2] = r2;
  412.     send(tn->session->s,s,3,0);
  413. }
  414. #ifdef    __TURBOC__
  415. /* Set end-of-line translation mode on file */
  416. static int
  417. filemode(fp,mode)
  418. FILE *fp;
  419. int mode;
  420. {
  421.     int omode;
  422.  
  423.     if(fp == NULLFILE)
  424.         return -1;
  425.  
  426.     if(fp->flags & _F_BIN)
  427.         omode = SOCK_BINARY;
  428.     else
  429.         omode = SOCK_ASCII;
  430.  
  431.     switch(mode){
  432.     case SOCK_BINARY:
  433.         fp->flags = _F_BIN;
  434.         setmode(fileno(fp),O_BINARY);
  435.         break;
  436.     case SOCK_ASCII:
  437.         fp->flags &= ~_F_BIN;
  438.         setmode(fileno(fp),O_TEXT);
  439.         break;
  440.     }
  441.     return omode;
  442. }
  443. #else
  444. static int
  445. filemode(fp,mode)
  446. FILE *fp;
  447. int mode;
  448. {
  449.     return 0;
  450. }
  451. #endif
  452.