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