home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / TELNET.C < prev    next >
C/C++ Source or Header  |  1992-06-03  |  9KB  |  403 lines

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