home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / t / tel2305s.zip / ENGINE / NEGOTIAT.C < prev    next >
C/C++ Source or Header  |  1992-03-08  |  43KB  |  867 lines

  1. /*
  2. *   negotiat.c
  3. *
  4. *   Telnet option negotiation functions
  5. *
  6. *   Quincey Koziol
  7. *
  8. *    Date        Notes
  9. *    --------------------------------------------
  10. *   11/91       Started
  11. */
  12.  
  13. /*
  14. * Includes
  15. */
  16.  
  17. #define USETEK
  18. /* #define USERAS */
  19.  
  20. #define NEGOTIATEDEBUG  /* define this to print the raw network data to the console */
  21.  
  22. #ifdef __TURBOC__
  23. #include "turboc.h"
  24. #endif
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <io.h>
  29. #include <ctype.h>
  30. #ifdef MSC
  31. #include <malloc.h>
  32. #endif
  33. #include "telopts.h"
  34. #include "externs.h"
  35.  
  36. /*
  37. *    Global Variables
  38. */
  39. extern unsigned char s[550],
  40.     parsedat[256];
  41.  
  42. extern int temptek,             /* where drawings go by default */
  43.     rgdevice;                   /* tektronix device to draw on */
  44.  
  45. extern struct config def;       /* Default settings obtained from host file */
  46.  
  47. /* Local functions */
  48. static void parse_subnegotiat(struct twin *tw,int end_sub);
  49.  
  50. /* Local variables */
  51. static char *telstates[]={
  52.     "EOF",
  53.     "Suspend Process",
  54.     "Abort Process",
  55.     "Unknown (239)",
  56.     "Subnegotiation End",
  57.     "NOP",
  58.     "Data Mark",
  59.     "Break",
  60.     "Interrupt Process",
  61.     "Abort Output",
  62.     "Are You There",
  63.     "Erase Character",
  64.     "Erase Line",
  65.     "Go Ahead",
  66.     "Subnegotiate",
  67.     "Will",
  68.     "Won't",
  69.     "Do",
  70.     "Don't"
  71. };
  72.  
  73. static char *teloptions[256]={      /* ascii strings for Telnet options */
  74.     "Binary",                /* 0 */
  75.     "Echo",
  76.     "Reconnection",
  77.     "Supress Go Ahead",
  78.     "Message Size Negotiation",
  79.     "Status",                /* 5 */
  80.     "Timing Mark",
  81.     "Remote Controlled Trans and Echo",
  82.     "Output Line Width",
  83.     "Output Page Size",
  84.     "Output Carriage-Return Disposition",    /* 10 */
  85.     "Output Horizontal Tab Stops",
  86.     "Output Horizontal Tab Disposition",
  87.     "Output Formfeed Disposition",
  88.     "Output Vertical Tabstops",
  89.     "Output Vertical Tab Disposition",        /* 15 */
  90.     "Output Linefeed Disposition",
  91.     "Extended ASCII",
  92.     "Logout",
  93.     "Byte Macro",
  94.     "Data Entry Terminal",                    /* 20 */
  95.     "SUPDUP",
  96.     "SUPDUP Output",
  97.     "Send Location",
  98.     "Terminal Type",
  99.     "End of Record",                        /* 25 */
  100.     "TACACS User Identification",
  101.     "Output Marking",
  102.     "Terminal Location Number",
  103.     "3270 Regime",
  104.     "X.3 PAD",                                /* 30 */
  105.     "Negotiate About Window Size",
  106.     "Terminal Speed",
  107.     "Toggle Flow Control",
  108.     "Linemode",
  109.     "X Display Location",                    /* 35 */
  110.     "Environment",
  111.     "Authentication",
  112.     "Data Encryption",
  113.     "39",
  114.     "40","41","42","43","44","45","46","47","48","49",
  115.     "50","51","52","53","54","55","56","57","58","59",
  116.     "60","61","62","63","64","65","66","67","68","69",
  117.     "70","71","72","73","74","75","76","77","78","79",
  118.     "80","81","82","83","84","85","86","87","88","89",
  119.     "90","91","92","93","94","95","96","97","98","99",
  120.     "100","101","102","103","104","105","106","107","108","109",
  121.     "110","111","112","113","114","115","116","117","118","119",
  122.     "120","121","122","123","124","125","126","127","128","129",
  123.     "130","131","132","133","134","135","136","137","138","139",
  124.     "140","141","142","143","144","145","146","147","148","149",
  125.     "150","151","152","153","154","155","156","157","158","159",
  126.     "160","161","162","163","164","165","166","167","168","169",
  127.     "170","171","172","173","174","175","176","177","178","179",
  128.     "180","181","182","183","184","185","186","187","188","189",
  129.     "190","191","192","193","194","195","196","197","198","199",
  130.     "200","201","202","203","204","205","206","207","208","209",
  131.     "210","211","212","213","214","215","216","217","218","219",
  132.     "220","221","222","223","224","225","226","227","228","229",
  133.     "230","231","232","233","234","235","236","237","238","239",
  134.     "240","241","242","243","244","245","246","247","248","249",
  135.     "250","251","252","253","254",
  136.     "Extended Options List"        /* 255 */
  137. };
  138.  
  139. static char *LMoptions[]={      /* ascii strings for Linemode sub-options */
  140.     "None",
  141.     "MODE",
  142.     "FORWARDMASK",
  143.     "SLC"
  144. };
  145.  
  146. static char *ModeOptions[]={      /* ascii strings for Linemode edit options */
  147.     "None",
  148.     "EDIT",
  149.     "TRAPSIG",
  150.     "ACK",
  151.     "SOFT TAB",
  152.     "LIT ECHO"
  153. };
  154.  
  155. static char *SLCoptions[]={     /* ascii strings for Linemode SLC characters */
  156.     "None",
  157.     "SYNCH",
  158.     "BREAK",
  159.     "IP",
  160.     "ABORT OUTPUT",
  161.     "AYT",
  162.     "EOR",
  163.     "ABORT",
  164.     "EOF",
  165.     "SUSP",
  166.     "EC",
  167.     "EL",
  168.     "EW",
  169.     "RP",
  170.     "LNEXT",
  171.     "XON",
  172.     "XOFF",
  173.     "FORW1",
  174.     "FORW2",
  175.     "MCL",
  176.     "MCR",
  177.     "MCWL",
  178.     "MCWR",
  179.     "MCBOL",
  180.     "MCEOL",
  181.     "INSRT",
  182.     "OVER",
  183.     "ECR",
  184.     "EWR",
  185.     "EBOL",
  186.     "EEOL"
  187. };
  188.  
  189. static char *SLCflags[]={      /* ascii strings for Linemode SLC flags */
  190.     "SLC_NOSUPPORT",
  191.     "SLC_CANTCHANGE",
  192.     "SLC_VALUE",
  193.     "SLC_DEFAULT"
  194. };
  195.  
  196. static unsigned char LMdefaults[NUMLMODEOPTIONS+1]={   /* Linemode default character for each function */
  197.     -1,         /* zero isn't used */
  198.     -1,         /* we don't support SYNCH */
  199.     3,          /* ^C is default for BRK */
  200.     3,          /* ^C is default for IP */
  201.     15,         /* ^O is default for AO */
  202.     25,         /* ^Y is default for AYT */             /* 5 */
  203.     -1,         /* we don't support EOR */
  204.     3,          /* ^C is default for ABORT */
  205.     4,          /* ^D is default for EOF */
  206.     26,         /* ^Z is default for SUSP */
  207.     8,          /* ^H is default for EC */              /* 10 */
  208.     21,         /* ^U is default for EL */
  209.     23,         /* ^W is default for EW */
  210.     18,         /* ^R is default for RP */
  211.     22,         /* ^V is default for LNEXT */
  212.     17,         /* ^Q is default for XON */             /* 15 */
  213.     19,         /* ^S is default for XOFF */
  214.     22,         /* ^V is default for FORW1 */
  215.     5,          /* ^E is default for FORW2 */
  216.     -1,         /* we don't support MCL */
  217.     -1,         /* we don't support MCR */              /* 20 */
  218.     -1,         /* we don't support MCWL */
  219.     -1,         /* we don't support MCWR */
  220.     -1,         /* we don't support MCBOL */
  221.     -1,         /* we don't support MCEOL */
  222.     -1,         /* we don't support INSRT */            /* 25 */
  223.     -1,         /* we don't support OVER */
  224.     -1,         /* we don't support ECR */
  225.     -1,         /* we don't support EWR */
  226.     -1,         /* we don't support EBOL */
  227.     -1          /* we don't support EEOL */             /* 30 */
  228. };
  229.  
  230.  
  231. /**********************************************************************
  232. *  Function :   start_negotiation()
  233. *  Purpose  :   Send the initial negotiations on the network and print
  234. *               the negotitations to the console screen.
  235. *  Parameters   :
  236. *           dat - the port number to write to
  237. *           cvs - the console's virtual screen
  238. *  Returns  :   none
  239. *  Calls    :   tprintf(), netprintf()
  240. *  Called by    :   dosessions()
  241. **********************************************************************/
  242. void start_negotiation(struct twin *tw,int cvs)
  243. {
  244.     /* Send the initial tlnet negotiations */
  245.     netprintf(tw->pnum,"%c%c%c",IAC,DOTEL,ECHO);
  246.     netprintf(tw->pnum,"%c%c%c",IAC,DOTEL,SGA);
  247.     netprintf(tw->pnum,"%c%c%c",IAC,WILLTEL,NAWS);
  248.     if(tw->mapoutput) { /* check whether we are going to be output mapping */
  249.         netprintf(tw->pnum,"%c%c%c",IAC,DOTEL,BINARY);
  250.         tw->uwantbinary=1;  /* set the flag indicating we wanted server to start transmitting binary */
  251.         netprintf(tw->pnum,"%c%c%c",IAC,WILLTEL,BINARY);
  252.         tw->iwantbinary=1;  /* set the flag indicating we want to start transmitting binary */
  253.       } /* end if */
  254.  
  255.     /* Print to the console what we just did */
  256.     if(tw->condebug>0) {
  257.         tprintf(cvs,"SEND: %s %s\r\n",telstates[DOTEL-LOW_TEL_OPT],teloptions[ECHO]);
  258.         tprintf(cvs,"SEND: %s %s\r\n",telstates[DOTEL-LOW_TEL_OPT],teloptions[SGA]);
  259.         tprintf(cvs,"SEND: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[NAWS]);
  260.         if(tw->mapoutput) { /* check whether we are going to be output mapping */
  261.             tprintf(cvs,"SEND: %s %s\r\n",telstates[DOTEL-LOW_TEL_OPT],teloptions[BINARY]);
  262.             tprintf(cvs,"SEND: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[BINARY]);
  263.           } /* end if */
  264. #ifdef QAK
  265.         tprintf(cvs,"SEND: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[TERMTYPE]);
  266.         tprintf(cvs,"SEND: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[LINEMODE]);
  267. #endif
  268.       } /* end if */
  269. }   /* end start_negotiation() */
  270.  
  271. /**********************************************************************
  272. *  Function :   parse_subnegotiat()
  273. *  Purpose  :   Parse the telnet sub-negotiations read into the parsedat
  274. *               array.
  275. *  Parameters   :
  276. *           end_sub - index of the character in the 'parsedat' array which
  277. *                           is the last byte in a sub-negotiation
  278. *  Returns  :   none
  279. *  Calls    :
  280. *  Called by    :   parse()
  281. **********************************************************************/
  282. static void parse_subnegotiat(struct twin *tw,int end_sub)
  283. {
  284.     int cv,                     /* virtual screen of the console */
  285.         i;                      /* local counting variable */
  286.     int line_opt_flag;          /* flag to indicate that line mode options were sent and need to be finished */
  287.  
  288.     cv=console->vs;             /* get the virtual screen of the console screen */
  289.  
  290.     switch(parsedat[0]) {
  291.         case TERMTYPE:
  292.             if(parsedat[1]==1) {
  293. /* QAK!!! */    netprintf(tw->pnum,"%c%c%c%c%s%c%c",IAC,SB,TERMTYPE,0,def.termtype,IAC,SE);
  294.                 if(tw->condebug>0)
  295.                     tprintf(cv,"RECV: SB TERMINAL-TYPE SEND\r\nSEND: SB TERMINAL-TYPE IS %s\r\n",def.termtype);
  296.               } /* end if */
  297.             break;
  298.  
  299.         case LINEMODE:
  300.             switch(parsedat[1]) {
  301.                 case MODE:
  302.                     if(tw->condebug>0) {    /* check for debugging ouput */
  303.                         tprintf(cv,"RECV: SB LINEMODE %s ",LMoptions[parsedat[1]]);
  304.                         if(parsedat[2]&MODE_EDIT)
  305.                             tprintf(cv,"%s|",ModeOptions[1]);
  306.                         if(parsedat[2]&MODE_TRAPSIG)
  307.                             tprintf(cv,"%s|",ModeOptions[2]);
  308.                         if(parsedat[2]&MODE_ACK)
  309.                             tprintf(cv,"%s|",ModeOptions[3]);
  310.                         if(parsedat[2]&MODE_SOFT_TAB)
  311.                             tprintf(cv,"%s|",ModeOptions[4]);
  312.                         if(parsedat[2]&MODE_LIT_ECHO)
  313.                             tprintf(cv,"%s",ModeOptions[5]);
  314.                         tprintf(cv,"\r\n");
  315.                       } /* end if */
  316.                     if((parsedat[2]&(~MODE_ACK))!=tw->linemode_mask && !(parsedat[2]&MODE_ACK)) { /* ignore the mode change if it is the same as the current one, or if the MODE_ACK bit is set */
  317.                         if(parsedat[2]&MODE_EDIT)   /* check for line buffering/editting */
  318.                             tw->lmedit=1;
  319.                         else    /* character buffering */
  320.                             tw->lmedit=0;
  321.                         if(parsedat[2]&MODE_TRAPSIG)   /* check for local signal trapping */
  322.                             tw->trapsig=1;
  323.                         else
  324.                             tw->trapsig=0;
  325.                         if(parsedat[2]&MODE_SOFT_TAB)   /* check for tab expansion */
  326.                             tw->softtab=1;
  327.                         else
  328.                             tw->softtab=0;
  329.                         if(parsedat[2]&MODE_SOFT_TAB)   /* check for literal echo */
  330.                             tw->litecho=1;
  331.                         else
  332.                             tw->litecho=0;
  333.                         parsedat[2]&=LINEMODE_MODES_SUPPORTED;  /* mask off any modes we don't support */
  334.  
  335.                         tw->linemode_mask=parsedat[2];  /* save the new linemode MODE */
  336.                         netprintf(tw->pnum,"%c%c%c%c%c%c%c",IAC,SB,LINEMODE,MODE,parsedat[2]|MODE_ACK,IAC,SE);
  337.                         if(tw->condebug>0) {    /* check for debugging ouput */
  338.                             tprintf(cv,"SEND: SB LINEMODE MODE ");
  339.                             if(parsedat[2]&MODE_EDIT)
  340.                                 tprintf(cv,"%s|",ModeOptions[1]);
  341.                             if(parsedat[2]&MODE_TRAPSIG)
  342.                                 tprintf(cv,"%s|",ModeOptions[2]);
  343.                             if(parsedat[2]&MODE_SOFT_TAB)
  344.                                 tprintf(cv,"%s|",ModeOptions[4]);
  345.                             if(parsedat[2]&MODE_LIT_ECHO)
  346.                                 tprintf(cv,"%s|",ModeOptions[5]);
  347.                             tprintf(cv,"MODE_ACK IAC SE\r\n");
  348.                           } /* end if */
  349.                       } /* end if */
  350.                     break;
  351.  
  352.                 case DOTEL:
  353.                     netprintf(tw->pnum,"%c%c%c%c%c%c%c",IAC,SB,LINEMODE,WONTTEL,parsedat[2],IAC,SE);
  354.                     if(tw->condebug>0) {    /* check for debugging ouput */
  355.                         tprintf(cv,"RECV: SB LINEMODE %s %s\r\n",telstates[DOTEL-LOW_TEL_OPT],LMoptions[parsedat[2]]);
  356.                         tprintf(cv,"SEND: SB LINEMODE WONTTEL %s IAC SE\r\n",LMoptions[parsedat[2]]);
  357.                       } /* end if */
  358.                     break;
  359.  
  360.                 case WILLTEL:
  361.                     netprintf(tw->pnum,"%c%c%c%c%c%c%c",IAC,SB,LINEMODE,DONTTEL,parsedat[2],IAC,SE);
  362.                     if(tw->condebug>0) {    /* check for debugging ouput */
  363.                         tprintf(cv,"RECV: SB LINEMODE %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],LMoptions[parsedat[2]]);
  364.                         tprintf(cv,"SEND: SB LINEMODE DONTTEL %s IAC SE\r\n",LMoptions[parsedat[2]]);
  365.                       } /* end if */
  366.                     break;
  367.  
  368.                 case SLC:
  369.                     line_opt_flag=0;    /* reset the flag indicating that we sent the line mode begin option */
  370.                     if(tw->condebug>0)  /* check for debugging ouput */
  371.                         tprintf(cv,"RECV: SB LINEMODE SLC\r\n");
  372.                     for(i=2; i<end_sub; i+=3) {
  373.                         if(tw->condebug>0) {    /* check for debugging ouput */
  374.                             tprintf(cv,"     [%2.2X %2.2X %2.2X] (%2d) %s %s",(unsigned)parsedat[i],(unsigned)parsedat[i+1],(unsigned)parsedat[i+2],(unsigned)parsedat[i],SLCoptions[parsedat[i]],SLCflags[parsedat[i+1]&SLC_LEVELBITS]);
  375.                             if(parsedat[i+1]&SLC_FLUSHIN)   /* check for FLUSH INPUT flag */
  376.                                 tprintf(cv,"|SLC_FLUSHIN");
  377.                             if(parsedat[i+1]&SLC_FLUSHOUT)  /* check for FLUSH OUTPUT flag */
  378.                                 tprintf(cv,"|SLC_FLUSHOUT");
  379.                             if(parsedat[i+1]&SLC_ACK)       /* check for ACK flag */
  380.                                 tprintf(cv,"|SLC_ACK");
  381.                             tprintf(cv," %d\r\n",(unsigned)parsedat[i+2]);
  382.                           } /* end if */
  383.                         if(tw->slc[parsedat[i]]!=parsedat[i+2]) { /* check the new character for the function against our current character for that function */
  384.                             if((tw->slm[parsedat[i]]&SLC_LEVELBITS)==(parsedat[i+1]&SLC_LEVELBITS) && (parsedat[i+1]&SLC_ACK)) {   /* if it's the same level as we have, and the ACK flag is set, just use the new value */
  385.                                 tw->slc[parsedat[i]]=parsedat[i+2];
  386.                               } /* end if */
  387.                             else {  /* level for the function is not the same, or the ACK flag is not set */
  388.                                 if(!(parsedat[i+1]&SLC_ACK)) {      /* if the ACK bit isn't set, then work with it */
  389.                                     if(line_opt_flag==0) { /* check whether we've started the negotiations yet */
  390.                                         line_opt_flag=1;
  391.                                         netprintf(tw->pnum,"%c%c%c%c",IAC,SB,LINEMODE,SLC);
  392.                                         if(tw->condebug>0)  /* check for debugging ouput */
  393.                                             tprintf(cv,"SEND: SB LINEMODE SLC\r\n");
  394.                                       } /* end if */
  395.                                     if((parsedat[i]<=NUMLMODEOPTIONS) && (tw->slm[parsedat[i]]&SLC_SUPPORTED)) {  /* only try to parse linemode sub-options we have a clue about, and we support */
  396.                                         switch(parsedat[i+1]&SLC_LEVELBITS) {
  397.                                             case SLC_NOSUPPORT:     /* other side doesn't support this function */
  398.                                                 tw->slc[parsedat[i]]=(-1);  /* make certain we don't match it */
  399.                                                 tw->slm[parsedat[i]]&=~SLC_LEVELBITS;    /* mask off the correct characters */
  400.                                                 netprintf(tw->pnum,"%c%c%c",parsedat[i],(unsigned char)(SLC_NOSUPPORT|SLC_ACK),0);
  401.                                                 if(tw->condebug>0)  /* check for debugging ouput */
  402.                                                     tprintf(cv, "        [%2.2X %2.2X %2.2X] (%d) %s SLC_NOSUPPORT|SLC_ACK %d\r\n",(unsigned)parsedat[i],(unsigned)parsedat[i+1],(unsigned)parsedat[i+2],(unsigned)parsedat[i],SLCoptions[parsedat[i]],0);
  403.                                                 break;
  404.  
  405.                                             case SLC_CANTCHANGE:    /* other side can't change the character for this function */
  406.                                                 tw->slc[parsedat[i]]=parsedat[i+2]; /* set the character */
  407.                                                 tw->slm[parsedat[i]]&=~SLC_LEVELBITS;    /* mask off the correct characters */
  408.                                                 tw->slm[parsedat[i]]|=SLC_CANTCHANGE;   /* turn on the cant change mode */
  409.                                                 if(parsedat[i+2]!=IAC)  /* check for character being a 255 */
  410.                                                     netprintf(tw->pnum,"%c%c%c",parsedat[i],(unsigned char)(SLC_CANTCHANGE|SLC_ACK),parsedat[i+2]);
  411.                                                 else
  412.                                                     netprintf(tw->pnum,"%c%c%c%c",parsedat[i],(unsigned char)(SLC_CANTCHANGE|SLC_ACK),IAC,parsedat[i+2]);
  413.                                                 if(tw->condebug>0)  /* check for debugging ouput */
  414.                                                     tprintf(cv, "        [%2.2X %2.2X %2.2X] (%d) %s SLC_CANTCHANGE|SLC_ACK %d\r\n",(unsigned)parsedat[i],(unsigned)parsedat[i+1],(unsigned)parsedat[i+2],(unsigned)parsedat[i],SLCoptions[parsedat[i]],parsedat[i+2]);
  415.                                                 break;
  416.  
  417.                                             case SLC_VALUE:     /* other side has a value it wants us to use */
  418.                                                 tw->slc[parsedat[i]]=parsedat[i+2]; /* set the character */
  419.                                                 tw->slm[parsedat[i]]&=~SLC_LEVELBITS;    /* mask off the correct characters */
  420.                                                 tw->slm[parsedat[i]]|=SLC_VALUE;   /* turn on the cant change mode */
  421.                                                 if(parsedat[i+2]!=IAC)  /* check for character being a 255 */
  422.                                                     netprintf(tw->pnum,"%c%c%c",parsedat[i],(unsigned char)(SLC_VALUE|SLC_ACK),parsedat[i+2]);
  423.                                                 else
  424.                                                     netprintf(tw->pnum,"%c%c%c%c",parsedat[i],(unsigned char)(SLC_VALUE|SLC_ACK),IAC,parsedat[i+2]);
  425.                                                 if(tw->condebug>0)  /* check for debugging ouput */
  426.                                                     tprintf(cv, "        [%2.2X %2.2X %2.2X] (%d) %s SLC_VALUE|SLC_ACK %d\r\n",(unsigned)parsedat[i],(unsigned)parsedat[i+1],(unsigned)parsedat[i+2],(unsigned)parsedat[i],SLCoptions[parsedat[i]],parsedat[i+2]);
  427.                                                 break;
  428.  
  429.                                             case SLC_DEFAULT:   /* other side wants us to use our default */
  430.                                                 tw->slc[parsedat[i]]=LMdefaults[parsedat[i]]; /* set the character */
  431.                                                 tw->slm[parsedat[i]]&=~SLC_LEVELBITS;    /* mask off the correct characters */
  432.                                                 tw->slm[parsedat[i]]|=SLC_VALUE;   /* turn on the cant change mode */
  433.                                                 netprintf(tw->pnum,"%c%c%c",parsedat[i],(unsigned char)SLC_VALUE,LMdefaults[parsedat[i]]);
  434.                                                 if(tw->condebug>0)  /* check for debugging ouput */
  435.                                                     tprintf(cv, "        [%2.2X %2.2X %2.2X] (%d) %s SLC_VALUE %d\r\n",(unsigned)parsedat[i],(unsigned)parsedat[i+1],(unsigned)LMdefaults[parsedat[i]],(unsigned)parsedat[i],SLCoptions[parsedat[i]],LMdefaults[parsedat[i]]);
  436.                                                 break;
  437.                                           } /* end switch */
  438.                                       } /* end if */
  439.                                     else {  /* we don't know what this linemode sub-option is, or we don't support it */
  440.                                         if((parsedat[i+1]&SLC_LEVELBITS)==SLC_NOSUPPORT) {  /* check if we doesn't support it either */
  441.                                             netprintf(tw->pnum,"%c%c%c",parsedat[i],(unsigned char)(SLC_NOSUPPORT|SLC_ACK),0);
  442.                                             if(tw->condebug>0)  /* check for debugging ouput */
  443.                                                 tprintf(cv, "        [%2.2X %2.2X %2.2X] (%d) %s SLC_NOSUPPORT|SLC_ACK %d\r\n",(unsigned)parsedat[i],(unsigned)parsedat[i+1],(unsigned)parsedat[i+2],(unsigned)parsedat[i],SLCoptions[parsedat[i]],0);
  444.                                           } /* end if */
  445.                                         else {
  446.                                             netprintf(tw->pnum,"%c%c%c",parsedat[i],(unsigned char)SLC_NOSUPPORT,0);
  447.                                             if(tw->condebug>0)  /* check for debugging ouput */
  448.                                                 tprintf(cv, "        [%2.2X %2.2X %2.2X] (%d) %s SLC_NOSUPPORT %d\r\n",(unsigned)parsedat[i],(unsigned)parsedat[i+1],(unsigned)parsedat[i+2],(unsigned)parsedat[i],SLCoptions[parsedat[i]],0);
  449.                                           } /* end else */
  450.                                       } /* end else */
  451.                                   } /* end if */
  452.                               } /* end else */
  453.                           } /* end if */
  454.                       } /* end for */
  455.                     if(line_opt_flag) {    /* check if we had to reply */
  456.                         netprintf(tw->pnum,"%c%c",IAC,SE);
  457.                         if(tw->condebug>0)  /* check for debugging ouput */
  458.                             tprintf(cv,"SEND: IAC SE\r\n");
  459.                       } /* end if */
  460.                     break;
  461.  
  462.                 default:    /* otherwise just exit */
  463.                     break;
  464.               } /* end switch */
  465.             break;
  466.  
  467.         default:
  468.             break;
  469.       } /* end switch */
  470. }   /* end parse_subnegotiat() */
  471.  
  472. /*********************************************************************/
  473. /*  parse
  474. *   Do the telnet negotiation parsing.
  475. *
  476. *   look at the string which has just come in from outside and
  477. *   check for special sequences that we are interested in.
  478. *
  479. *   Tries to pass through routine strings immediately, waiting for special
  480. *   characters ESC and IAC to change modes.
  481. */
  482. void parse(struct twin *tw,unsigned char *st,int cnt)
  483. {
  484.     int cv,                     /* virtual screen of the console */
  485.         i;                      /* local counting variable */
  486.     static int sub_pos;         /* the position we are in the subnegotiation parsing */
  487.     int end_sub;                /* index of the character in the 'parsedat' array which is the last byte in a subnegotiation */
  488.     unsigned char *mark,*orig;
  489.  
  490.     cv=console->vs;
  491.  
  492. #ifdef NEGOTIATEDEBUG
  493.     if(tw->condebug>1) {  /* check for debugging ouput */
  494.         tprintf(cv,"\r\n");
  495.         for(i=0; i<cnt; i++) {
  496.             int j;
  497.  
  498.             for(j=0; (j < 16) && ((i + j) < cnt); j++)
  499.                 tprintf(cv,"%2.2X  ", *(unsigned char *) (st + i + j));
  500.             i+=j-1;
  501.             tprintf(cv,"\r\n");
  502.           } /* end for */
  503.         tprintf(cv,"\r\n");
  504.       } /* end if */
  505. #endif /* NEGOTIATEDEBUG */
  506.  
  507.     orig=st;                /* remember beginning point */
  508.     mark=st+cnt;            /* set to end of input string */
  509.     netpush(tw->pnum);
  510.  
  511. /*
  512. *  traverse string, looking for any special characters which indicate that
  513. *  we need to change modes.
  514. */
  515.     while(st<mark) {
  516.         while(tw->telstate!=STNORM && st<mark) {   /* try to handle the negotiations better */
  517.             switch(tw->telstate) {
  518.                 case ESCFOUND:
  519. #ifdef USETEK
  520.                     if((*st==12) && (def.tek))    {               /* esc-FF */
  521.                         if(tw->termstate==VTEKTYPE) {
  522.                             tprintf(cv,"\r\n Entering Tek mode \r\n");
  523.                             tw->termstate=TEKTYPE;
  524.                             VGgmode(rgdevice);
  525.                             VGuncover(temptek);
  526.                             current=tw;
  527.                           } /* end if */
  528.                         VGwrite(temptek,"\033\014",2);
  529.                         orig=++st;                  /* pass by ESC-FF in data */
  530.                         tw->telstate=STNORM;
  531.                         break;
  532.                       } /* end if */
  533. #endif
  534.  
  535. #ifdef USERAS
  536.                     if(*st=='^') {                  /* esc-^ */
  537.                         tw->termstate=RASTYPE;
  538.                         tw->telstate=STNORM;
  539.                         current=tw;
  540.                         VRwrite("\033^",2);          /* echo ^ */
  541.                         orig=++st;
  542.                         break;
  543.                       } /* end if */
  544. #endif
  545.  
  546.                     parsewrite(tw,"\033",1);        /* send the missing ESC */
  547.                     tw->telstate=STNORM;
  548.                     break;
  549.  
  550.                 case IACFOUND:              /* telnet option negotiation */
  551.                     if(*st==IAC) {          /* real data=255 */
  552.                         st++;               /* real 255 will get sent */
  553.                         tw->telstate=STNORM;
  554.                         break;
  555.                       } /* end if */
  556.  
  557.                     if(*st>239) {
  558.                         tw->telstate=*st++; /* by what the option is */
  559.                         break;
  560.                       } /* end if */
  561.  
  562.                     tprintf(cv,"\r\n strange telnet option %s",itoa(*st,s,10));
  563.                     orig=++st;
  564.                     tw->telstate=STNORM;
  565.                     break;
  566.  
  567.                 case EL:        /* received a telnet erase line command */
  568.                 case EC:        /* received a telnet erase character command */
  569.                 case AYT:       /* received a telnet Are-You-There command */
  570.                 case AO:        /* received a telnet Abort Output command */
  571.                 case IP:        /* received a telnet Interrupt Process command */
  572.                 case BREAK:     /* received a telnet Break command */
  573.                 case DM:        /* received a telnet Data Mark command */
  574.                 case NOP:       /* received a telnet No Operation command */
  575.                 case SE:        /* received a telnet Subnegotiation End command */
  576.                 case ABORT:     /* received a telnet Abort Process command */
  577.                 case SUSP:      /* received a telnet Suspend Process command */
  578.                 case TEL_EOF:   /* received a telnet EOF command */
  579.                     if(tw->condebug>0)    /* check for debugging ouput */
  580.                         tprintf(cv,"RECV: %s\r\n",telstates[tw->telstate-LOW_TEL_OPT]);
  581.                     tw->telstate=STNORM;
  582.                     orig=++st;
  583.                     break;
  584.  
  585.                 case GOAHEAD:       /* telnet go ahead option*/
  586.                     if(tw->condebug>0)    /* check for debugging ouput */
  587.                         tprintf(cv,"RECV: %s\r\n",telstates[tw->telstate-LOW_TEL_OPT]);
  588.                     tw->telstate=STNORM;
  589.                     orig=++st;
  590.                     break;
  591.  
  592.                 case DOTEL:     /* received a telnet DO negotiation */
  593.                     if(tw->condebug>0)    /* check for debugging ouput */
  594.                         tprintf(cv,"RECV: %s %s\r\n",telstates[tw->telstate-LOW_TEL_OPT],teloptions[*st]);
  595.                     switch(*st) {
  596.                         case BINARY:       /* binary transmission */
  597.                             if(!tw->ibinary) { /* binary */
  598.                                 if(!tw->iwantbinary) {   /* check whether we asked for this */
  599.                                     netprintf(tw->pnum,"%c%c%c",IAC,WILLTEL,BINARY);
  600.                                     if(tw->condebug>0)    /* check for debugging ouput */
  601.                                         tprintf(cv,"SEND: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[BINARY]);
  602.                                   } /* end if */
  603.                                 else
  604.                                     tw->iwantbinary=0;  /* turn off this now */
  605.                                 tw->ibinary=1;
  606.                               } /* end if */
  607.                             else {
  608.                                 if(tw->condebug>0)    /* check for debugging ouput */
  609.                                     tprintf(cv,"NO REPLY NEEDED: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[BINARY]);
  610.                               } /* end else */
  611.                             break;
  612.  
  613.                         case SGA:       /* Suppress go-ahead */
  614.                             if(!tw->igoahead) { /* suppress go-ahead */
  615.                                 netprintf(tw->pnum,"%c%c%c",IAC,WILLTEL,SGA);
  616.                                 if(tw->condebug>0)    /* check for debugging ouput */
  617.                                     tprintf(cv,"SEND: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[SGA]);
  618.                                 tw->igoahead=1;
  619.                               } /* end if */
  620.                             else {
  621.                                 if(tw->condebug>0)    /* check for debugging ouput */
  622.                                     tprintf(cv,"NO REPLY NEEDED: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[SGA]);
  623.                               } /* end else */
  624.                             break;
  625.  
  626.                         case TERMTYPE:      /* terminal type negotiation */
  627.                             if(!tw->termsent) {
  628.                                 tw->termsent=1;
  629.                                 netprintf(tw->pnum,"%c%c%c",IAC,WILLTEL,TERMTYPE);
  630.                                 if(tw->condebug>0)    /* check for debugging ouput */
  631.                                     tprintf(cv,"SEND: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[TERMTYPE]);
  632.                               } /* end if */
  633.                             else {
  634.                                 if(tw->condebug>0)    /* check for debugging ouput */
  635.                                     tprintf(cv,"NO REPLY NEEDED: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[TERMTYPE]);
  636.                               } /* end else */
  637.                             break;
  638.  
  639.                         case LINEMODE:      /* linemode negotiation */
  640.                             tw->lmflag=1;   /* set the linemode flag for this connection */
  641.                             netprintf(tw->pnum,"%c%c%c",IAC,WILLTEL,LINEMODE);
  642.                             netprintf(tw->pnum,"%c%c%c%c",IAC,SB,LINEMODE,SLC,0,SLC_DEFAULT,0,IAC,SE);  /* Tell the other side to send us it's default character set */
  643.                             if(tw->condebug>0) {    /* check for debugging ouput */
  644.                                 tprintf(cv,"SEND: %s %s\r\n",telstates[WILLTEL-LOW_TEL_OPT],teloptions[LINEMODE]);
  645.                                 tprintf(cv,"SEND: SB LINEMODE SLC 0 SLC_DEFAULT 0 IAC SE\r\n");
  646.                               } /* end if */
  647.                             break;
  648.  
  649.                         case NAWS:      /* Negotiate About Window Size */
  650.                             netprintf(tw->pnum,"%c%c%c%c%c%c%c%c%c",IAC,SB,NAWS,(char)0,(char)tw->width,(char)0,(char)tw->rows,IAC,SE);
  651.                             if(tw->condebug>0)      /* check for debugging ouput */
  652.                                 tprintf(cv,"SEND: SB NAWS 0 %d 0 %d IAC SE\r\n",tw->width,tw->rows);
  653.                             break;
  654.  
  655.                         default:
  656.                             netprintf(tw->pnum,"%c%c%c",IAC,WONTTEL,*st);
  657.                             if(tw->condebug>0)      /* check for debugging ouput */
  658.                                 tprintf(cv,"SEND: %s %s\r\n",telstates[WONTTEL-LOW_TEL_OPT],teloptions[*st]);
  659.                             break;
  660.  
  661.                       } /* end switch */
  662.                     tw->telstate=STNORM;
  663.                     orig=++st;
  664.                     break;
  665.  
  666.                 case DONTTEL:       /* Received a telnet DONT option */
  667.                     if(tw->condebug>0)      /* check for debugging ouput */
  668.                         tprintf(cv,"RECV: %s %s\r\n",telstates[tw->telstate-LOW_TEL_OPT],teloptions[*st]);
  669.                     if((*st)==BINARY) {     /* check for binary negoatiations */
  670.                         if(tw->ibinary) {   /* binary */
  671.                             if(!tw->iwantbinary) {   /* check whether we asked for this */
  672.                                 netprintf(tw->pnum,"%c%c%c",IAC,WONTTEL,BINARY);
  673.                                 if(tw->condebug>0)    /* check for debugging ouput */
  674.                                     tprintf(cv,"SEND: %s %s\r\n",telstates[WONTTEL-LOW_TEL_OPT],teloptions[BINARY]);
  675.                               } /* end if */
  676.                             else
  677.                                 tw->iwantbinary=0;  /* turn off this now */
  678.                             tw->ibinary=0;
  679.                             tw->mapoutput=0;    /* turn output mapping off */
  680.                           } /* end if */
  681.                         else {
  682.                             if(tw->condebug>0)    /* check for debugging ouput */
  683.                                 tprintf(cv,"NO REPLY NEEDED: %s %s\r\n",telstates[WONTTEL-LOW_TEL_OPT],teloptions[BINARY]);
  684.                           } /* end else */
  685.                       } /* end if */
  686.  
  687.                     tw->telstate=STNORM;
  688.                     orig=++st;
  689.                     break;
  690.  
  691.                 case WILLTEL:       /* received a telnet WILL option */
  692.                     if(tw->condebug>0)      /* check for debugging ouput */
  693.                         tprintf(cv,"RECV: %s %s\r\n",telstates[tw->telstate-LOW_TEL_OPT],teloptions[*st]);
  694.                     switch(*st) {
  695.                         case BINARY:                /* binary */
  696.                             if(!tw->ubinary) {   /* binary */
  697.                                 if(!tw->uwantbinary) {   /* check whether we asked for this */
  698.                                     netprintf(tw->pnum,"%c%c%c",IAC,DOTEL,BINARY);
  699.                                     if(tw->condebug>0)    /* check for debugging ouput */
  700.                                         tprintf(cv,"SEND: %s %s\r\n",telstates[DOTEL-LOW_TEL_OPT],teloptions[BINARY]);
  701.                                   } /* end if */
  702.                                 else
  703.                                     tw->uwantbinary=0;  /* turn off this now */
  704.                                 tw->ubinary=1;
  705.                               } /* end if */
  706.                             else {
  707.                                 if(tw->condebug>0)    /* check for debugging ouput */
  708.                                     tprintf(cv,"NO REPLY NEEDED: %s %s\r\n",telstates[DOTEL-LOW_TEL_OPT],teloptions[BINARY]);
  709.                               } /* end else */
  710.                             break;
  711.  
  712.                         case SGA:                   /* suppress go-ahead */
  713.                             if(!tw->ugoahead) {
  714.                                 tw->ugoahead=1;
  715.                                 netprintf(tw->pnum,"%c%c%c",IAC,DOTEL,SGA); /* ack */
  716.                                 if(tw->condebug>0)      /* check for debugging ouput */
  717.                                     tprintf(cv,"SEND: %s %s\r\n",telstates[DOTEL-LOW_TEL_OPT],teloptions[SGA]);
  718.                               } /* end if */
  719.                             break;
  720.  
  721.                         case ECHO:                      /* echo */
  722.                             if(!tw->echo) {
  723.                                 tw->echo=1;
  724.                                 netprintf(tw->pnum,"%c%c%c",IAC,DOTEL,ECHO); /* ack */
  725.                                 if(tw->condebug>0)      /* check for debugging ouput */
  726.                                     tprintf(cv,"SEND: %s %s\r\n",telstates[DOTEL-LOW_TEL_OPT],teloptions[ECHO]);
  727. #ifdef OLD_WAY
  728. /* QAK!!! */                    netwrite(tw->pnum,tw->linemode,strlen(tw->linemode));
  729.                                 tw->linemode[0]='\0';
  730. #endif
  731.                               } /* end if */
  732.                             break;
  733.  
  734.                         case TIMING:        /* Timing mark */
  735.                             tw->timing=0;
  736.                             break;
  737.  
  738.                         default:
  739.                             netprintf(tw->pnum,"%c%c%c",IAC,DONTTEL,*st);
  740.                             if(tw->condebug>0)      /* check for debugging ouput */
  741.                                 tprintf(cv,"SEND: %s %s\r\n",telstates[DONTTEL-LOW_TEL_OPT],teloptions[*st]);
  742.                             break;
  743.                       } /* end switch */
  744.                     tw->telstate=STNORM;
  745.                     orig=++st;
  746.                     break;
  747.  
  748.                 case WONTTEL:       /* Received a telnet WONT option */
  749.                     if(tw->condebug>0)      /* check for debugging ouput */
  750.                         tprintf(cv,"RECV: %s %s\r\n",telstates[tw->telstate-LOW_TEL_OPT],teloptions[*st]);
  751.                     tw->telstate=STNORM;
  752.                     switch(*st++) {     /* which option? */
  753.                         case BINARY:            /* binary */
  754.                             if(tw->ubinary) {  /* binary */
  755.                                 if(!tw->uwantbinary) {   /* check whether we asked for this */
  756.                                     netprintf(tw->pnum,"%c%c%c",IAC,DONTTEL,BINARY);
  757.                                     if(tw->condebug>0)    /* check for debugging ouput */
  758.                                         tprintf(cv,"SEND: %s %s\r\n",telstates[DONTTEL-LOW_TEL_OPT],teloptions[BINARY]);
  759.                                   } /* end if */
  760.                                 else
  761.                                     tw->uwantbinary=0;  /* turn off this now */
  762.                                 tw->ubinary=0;
  763.                                 tw->mapoutput=0;    /* turn output mapping off */
  764.                               } /* end if */
  765.                             else {
  766.                                 if(tw->condebug>0)    /* check for debugging ouput */
  767.                                     tprintf(cv,"NO REPLY NEEDED: %s %s\r\n",telstates[DONTTEL-LOW_TEL_OPT],teloptions[BINARY]);
  768.                               } /* end else */
  769.                             break;
  770.  
  771.                         case ECHO:              /* echo */
  772.                             if(tw->echo) {
  773.                                 tw->echo=0;
  774.                                 netprintf(tw->pnum,"%c%c%c",IAC,DONTTEL,ECHO);
  775.                                 if(tw->condebug>0)      /* check for debugging ouput */
  776.                                     tprintf(cv,"SEND: %s %s\r\n",telstates[DONTTEL-LOW_TEL_OPT],teloptions[ECHO]);
  777.                               } /* end if */
  778.                             break;
  779.  
  780.                         case TIMING:    /* Telnet timing mark option */
  781.                             tw->timing=0;
  782.                             break;
  783.  
  784.                         default:
  785.                             break;
  786.                       } /* end switch */
  787.                     orig=st;
  788.                     break;
  789.  
  790.                 case SB:        /* telnet sub-options negotiation */
  791.                     tw->telstate=NEGOTIATE;
  792.                     orig=st;
  793.                     end_sub=0;
  794.                     sub_pos=tw->substate=0;     /* Defined for each */
  795. #ifdef OLD_WAY
  796.                     break;
  797. #endif
  798.  
  799.                 case NEGOTIATE:
  800.                     if(tw->substate==0) { /* until we change sub-negotiation states, accumulate bytes */
  801.                         if(*st==IAC) {  /* check if we found an IAC byte */
  802.                             if(*(st+1)==IAC) {  /* skip over double IAC's */
  803.                                 st++;
  804.                                 parsedat[sub_pos++]=*st++;
  805.                               } /* end if */
  806.                             else {
  807.                                 end_sub=sub_pos;
  808.                                 tw->substate=*st++;
  809.                               } /* end else */
  810.                           } /* end if */
  811.                         else     /* otherwise, just stash the byte */
  812.                             parsedat[sub_pos++]=*st++;
  813.                       } /* end if */
  814.                     else {
  815.                         tw->substate=*st++;
  816.                         if(tw->substate==SE)    /* check if we've really ended the sub-negotiations */
  817.                             parse_subnegotiat(tw,end_sub);
  818.                         orig=st;
  819.                         tw->telstate=STNORM;
  820.                       } /* end else */
  821.                     break;
  822.  
  823.                 default:
  824.                     tw->telstate=STNORM;
  825.                     break;
  826.               } /* end switch */
  827.           } /* end while */
  828.  
  829. /*
  830. * quick scan of the remaining string, skip chars while they are
  831. * uninteresting
  832. */
  833.         if(tw->telstate==STNORM && st<mark) {
  834. /*
  835. *  skip along as fast as possible until an interesting character is found
  836. */
  837.             while(st<mark && *st!=27 && *st!=IAC) {
  838.                 if(!tw->ubinary)
  839.                     *st&=127;                 /* mask off high bit */
  840.                 st++;
  841.               } /* end while */
  842.             if(!tw->timing) 
  843.                 parsewrite(tw,orig,st-orig);
  844.             orig=st;                /* forget what we have sent already */
  845.             if(st<mark)
  846.                 switch(*st) {
  847.                     case IAC:            /* telnet IAC */
  848.                         tw->telstate=IACFOUND;
  849.                         st++;
  850.                         break;
  851.  
  852.                     case 27:            /* ESCape code */
  853.                         if(st==mark-1 || *(st+1)==12 || *(st+1)=='^')
  854.                             tw->telstate=ESCFOUND;
  855.                         st++;            /* strip or accept ESC char */
  856.                         break;
  857.  
  858.                     default:
  859.                         tprintf(cv," strange char>128\r\n");
  860.                         st++;
  861.                         break;
  862.                   }    /* end switch */
  863.           }    /* end if */
  864.       } /* end while */
  865. }   /* end parse() */
  866.  
  867.