From 885f8cc426a8840ae61023b75f3f0e4a1e268082 Mon Sep 17 00:00:00 2001 From: Michael Krelin Date: Mon, 05 Jul 2004 01:53:09 +0000 Subject: initial commit into svn repository git-svn-id: http://svn.klever.net/kin/kinsole/trunk@1 fe716a7a-6dde-0310-88d9-d003556173a8 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2ee9ee --- a/dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ + +# / +/Debug +/Release +/debug +/release +/releast +/DEBUG +/RELEASE +/*.mdp +/*.ncb +/*.aps + +# /help/ +/help/KINSOLE.HLP +/help/kinsole.LOG +/help/kinsole.GID + +# /install/ +/install/debug +/install/release +/install/Debug +/install/Release +/install/DEBUG +/install/RELEASE +/install/*.aps diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..997e508 --- a/dev/null +++ b/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 1998, 2002 Klever Group (http://www.klever.net/) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/KTAGS b/KTAGS new file mode 100644 index 0000000..dfc79bb --- a/dev/null +++ b/KTAGS @@ -0,0 +1,12 @@ +help-license-date ./help/kinsole.xml />8; + sbd[1]=csbi.dwSize.X&0xFF; + sbd[2]=csbi.dwSize.Y>>8; + sbd[3]=csbi.dwSize.Y&0xFF; + return SubNegotiate(toNAWS,sbd,sizeof(sbd)); +} + +BOOL nawsOnDo() +{ + TRACE0("DO NAWS\n"); + AskWill(toNAWS); + return SendNAWS(); +} diff --git a/NEW-ENVIRON.cpp b/NEW-ENVIRON.cpp new file mode 100644 index 0000000..370ff73 --- a/dev/null +++ b/NEW-ENVIRON.cpp @@ -0,0 +1,272 @@ + +enum _NESB { + nesbSend = 1, + nesbIs = 0, + nesbInfo = 2, + + nesbVar = 0, + nesbValue = 1, + nesbESC = 2, + nesbUserVar = 3, + + nesbNothing = 256 +}; + +struct _envariable { + BYTE type; + char* name; + char* value; + _envariable() : type(0), name(NULL), value(NULL) {} + ~_envariable() { ItIsNot(); } + void ItIsNot() { + if(name) delete name; + if(value) delete value; + } + BOOL ItIs(BYTE t,LPCTSTR n,LPCTSTR v) { + ItIsNot(); + name = new CHAR[strlen(n)+1]; strcpy(name,n); + value = new CHAR[strlen(v)+1]; strcpy(value,v); + type=t; + return TRUE; + } + int TransmitSize() { + char* v = value; + for(int rv=0;*v;v++,rv++){ + switch(*v){ + case nesbVar: + case nesbValue: + case nesbUserVar: + case nesbESC: + rv++; + break; + } + } + for(v=name;*v;v++,rv++){ + switch(*v){ + case nesbVar: + case nesbValue: + case nesbUserVar: + case nesbESC: + rv++; + break; + } + } + return rv+2; // VAR/VAL + } + int Paste(CHAR* data) { + int rv=0; + ASSERT(type==nesbVar || type==nesbUserVar); + data[rv++]=type; + for(CHAR* v=name;*v;v++){ + switch(*v){ + case nesbVar: + case nesbValue: + case nesbUserVar: + case nesbESC: + data[rv++]=nesbESC; + default: + data[rv++]=*v; + } + } + data[rv++]=nesbValue; + for(v=value;*v;v++){ + switch(*v){ + case nesbVar: + case nesbValue: + case nesbUserVar: + case nesbESC: + data[rv++]=nesbESC; + default: + data[rv++]=*v; + } + } + return rv; + } + BOOL IsIt(CHAR* n,int l) { + BOOL bESC = FALSE; + CHAR* nPtr = name; + for(int tmp=0;tmp=nEnvarsAllocated){ + ASSERT(nEnvars==nEnvarsAllocated); + _envariable* ne = new _envariable[nEnvarsAllocated+ENVGROW]; + ASSERT(ne); + if(nEnvarsAllocated){ + memmove(ne,Envars,sizeof(_envariable)*nEnvarsAllocated); + delete Envars; + } + Envars=ne; + nEnvarsAllocated+=ENVGROW; + } + return Envars[nEnvars++].ItIs(type,name,value); +} +BOOL CleanEnvars() +{ + if(Envars){ + ASSERT(nEnvarsAllocated); + delete[] Envars; + } + return TRUE; +} + +BOOL newenvironOnDont() +{ + TRACE0("DONT NEW-ENVIRON\n"); + return TRUE; +} +BOOL newenvironOnDo() +{ + TRACE0("DO NEW-ENVIRON\n"); + return (Envars && nEnvars)?TRUE:FALSE; +} +BOOL newenvironOnSB(LPBYTE data,UINT size) +{ + if(!size) + return FALSE; + if(data[0]!=nesbSend) + return FALSE; + if(!(Envars && nEnvars)){ + BYTE no = nesbIs; + return SubNegotiate(toNewEnviron,&no,1); + } +UINT totalSize = 1; // IS byte + if(size>1 ){ + int type = 0; + int name = 0; + BOOL bESC = FALSE; + for(UINT tmp=1;tmp<=size;tmp++){ + switch((tmp==size)?nesbNothing:(UINT)data[tmp]){ + case nesbESC: + bESC=TRUE; + break; + case nesbVar: + case nesbUserVar: + case nesbNothing: + if(!bESC){ + if(type){ + if(name){ + _envariable* ev = FindEnvar(data[type],(CHAR*)&data[name],tmp-name); + if(ev){ + totalSize+=ev->TransmitSize(); + } + }else{ + for(int tmp=0;tmpPaste(&d[ptr]); + } + }else{ + for(int tmp=0;tmpm_tmpScrollBufferSize || !m_tmpScrollBuffer){ + if(m_tmpScrollBuffer) delete m_tmpScrollBuffer; + VERIFY(m_tmpScrollBuffer=new CHAR_INFO[newSize]); + m_tmpScrollBufferSize=newSize; + } + } + + CVT100() : m_tmpScrollBuffer(NULL) { } + virtual ~CVT100() { if(m_tmpScrollBuffer) delete m_tmpScrollBuffer; } + + enum _state { + stateNone,stateESeq,stateEBSeq, stateEPOSeq, stateEPCSeq, stateEPSSeq, + stateEY52Seq1, stateEY52Seq2 + } state; + + enum _attrs { + attrNone = 0, attrBold = 1, attrUnderline = 2, attrBlink = 4, attrReverse = 8 + }; + int attrs; // Screen attributes from _attrs enumeration + int sr0,sr1; // Scroll Region + int m_Attrs; // Screen attributes in console terms + int m_bgAttr; // Background color + int m_fgAttr; // Foreground color + + CONSOLE_SCREEN_BUFFER_INFO + m_CSBI; // Tracking of SB information + + void FillScreen(int x,int y,int n,TCHAR c,WORD a) { + COORD tmp = {x,y}; + VERIFY(FillConsoleOutputCharacter(hConsoleOutput,c,n,tmp,&dummyWritten)); + VERIFY(FillConsoleOutputAttribute(hConsoleOutput,a,n,tmp,&dummyWritten)); + } + void HScroll(int x,int y,int n,int x1=-1) { + if(!n) + return; + if(x1<0) + x1=m_CSBI.dwSize.X-1; + else + x1=max(x,min(x1,m_CSBI.dwSize.X-1)); + static + COORD zero = {0,0}; + if(n>0){ + int r = max(0,min(n,x1-x+1)); + if(!r) + return; + if((x+r)<=x1){ + ASSERT(m_tmpScrollBuffer); + SMALL_RECT sr = { x,y,x1-r,y }; + VERIFY(ReadConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&sr)); + sr.Left+=r; + sr.Right+=r; + VERIFY(WriteConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&sr)); + } + FillScreen(x,y,r,' ',m_Attrs); + }else{ + int r = max(0,min(-n,x1-x+1)); + if(!r) + return; + if((x+r)<=x1){ + ASSERT(m_tmpScrollBuffer); + SMALL_RECT sr = {x+r,y,x1,y }; + VERIFY(ReadConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&sr)); + sr.Left-=r; + sr.Right-=r; + VERIFY(WriteConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&sr)); + } + FillScreen(x1-r+1,y,r,' ',m_Attrs); + } + } + + void VScroll(int y,int n,int y1=-1) { + static + COORD zero = {0,0}; + if(!n) + return; + if(y1<0) + y1 = m_CSBI.dwSize.Y; + else + y1 = max(y,min(y1,m_CSBI.dwSize.Y-1)); + if(n>0){ + int r = max(0,min(n,y1-y+1)); + if(!r) + return; + if((y+r)<=y1){ + ASSERT(m_tmpScrollBuffer); + SMALL_RECT sr = { 0,y,m_CSBI.dwSize.X-1,y1-r }; + VERIFY(ReadConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&sr)); + sr.Top+=r; + sr.Bottom+=r; + VERIFY(WriteConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&sr)); + } + FillScreen(0,y,r*m_CSBI.dwSize.X,' ',m_Attrs); + }else{ + int r = max(0,min(-n,y1-y+1)); + if(!r) + return; + if((y+r)<=y1){ + ASSERT(m_tmpScrollBuffer); + SMALL_RECT sr = {0,y+r,m_CSBI.dwSize.X-1,y1 }; + VERIFY(ReadConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&sr)); + sr.Top-=r; + sr.Bottom-=r; + VERIFY(WriteConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&sr)); + } + FillScreen(0,y1-r+1,r*m_CSBI.dwSize.X,' ',m_Attrs); + } + } + + BOOL DoNAWS() { + VERIFY(GetConsoleScreenBufferInfo(hConsoleOutput,&m_CSBI)); + AllocateTmpBuffer(); + VERIFY(TerminalUpdateTitle()); + if(Options[toNAWS].m_StateU==TOption::stateYes) + SendNAWS(); + else + AskWill(toNAWS); + return TRUE; + } + + BOOL ResizeWindow(COORD ns) { + if(m_CSBI.dwCursorPosition.X>=ns.X) + m_CSBI.dwCursorPosition.X=0; + if(m_CSBI.dwCursorPosition.Y>=ns.Y){ + VScroll(0,-(m_CSBI.dwCursorPosition.Y-ns.Y+1),m_CSBI.dwCursorPosition.Y); + m_CSBI.dwCursorPosition.Y=ns.Y-1; + } + if(!SetConsoleCursorPosition(hConsoleOutput,m_CSBI.dwCursorPosition)) + return FALSE; + if(ns.X=m_CSBI.dwSize.Y){ + sr0=0; sr1=m_CSBI.dwSize.Y-1; + }else if(sr1>=m_CSBI.dwSize.Y){ + sr1=m_CSBI.dwSize.Y-1; + if(sr0>=sr1) + sr0=0; + } + } + return TRUE; + } + + WORD ReverseAttribute(WORD a) { + WORD rv = 0; + if(a&FOREGROUND_RED) + rv|=BACKGROUND_RED; + if(a&FOREGROUND_GREEN) + rv|=BACKGROUND_GREEN; + if(a&FOREGROUND_BLUE) + rv|=BACKGROUND_BLUE; + if(a&FOREGROUND_INTENSITY) + rv|=BACKGROUND_INTENSITY; + if(a&BACKGROUND_RED) + rv|=FOREGROUND_RED; + if(a&BACKGROUND_GREEN) + rv|=FOREGROUND_GREEN; + if(a&BACKGROUND_BLUE) + rv|=FOREGROUND_BLUE; + if(a&BACKGROUND_INTENSITY) + rv|=FOREGROUND_INTENSITY; + return rv; + } + + void ReverseScreen() { + static + COORD zero = {0,0}; + SMALL_RECT whole = {0,0,m_CSBI.dwSize.X-1,m_CSBI.dwSize.Y-1}; + ASSERT(m_tmpScrollBuffer); + VERIFY(ReadConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&whole)); + for(int tmp=0;tmp<(m_CSBI.dwSize.X*m_CSBI.dwSize.Y);tmp++) + m_tmpScrollBuffer[tmp].Attributes = ReverseAttribute(m_tmpScrollBuffer[tmp].Attributes); + VERIFY(WriteConsoleOutput(hConsoleOutput,m_tmpScrollBuffer,m_CSBI.dwSize,zero,&whole)); + } + + BOOL SetAttrs() { + WORD a = (attrs&attrReverse)?BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE: + FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE; + if(m_fgAttr>=0){ + a&=~(FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE); + a|=m_fgAttr|FOREGROUND_INTENSITY; + } + if(m_bgAttr>=0){ + a&=~(BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE); + a|=m_bgAttr; + } + if(attrs&attrBold) + a|=FOREGROUND_INTENSITY; + if((attrs&attrUnderline) && (m_fgAttr<0)){ + if(attrs&attrReverse) // Is it right way to underline? - we make foreground blue. + a|=FOREGROUND_BLUE; + else + a&=~(FOREGROUND_RED|FOREGROUND_GREEN); + } + if(attrs&attrBlink) + a|=BACKGROUND_INTENSITY; + if(m_bTR) + m_Attrs=ReverseAttribute(a); + else + m_Attrs = a; + return TRUE; + } + + virtual BOOL Input(UINT c) { + VERIFY(SendLiteral(c)); + if(c=='\r' && m_bLNM) + VERIFY(SendLiteral('\n')); + if( + ( + Options[toEcho].m_StateU==TOption::stateYes + || Options[toEcho].m_StateU==TOption::stateNone + ) && ( + Options[toEcho].m_StateH!=TOption::stateYes + || Options[toEcho].m_StateH==TOption::stateNone + ) + ){ + PreOutput(); + Output(c); + if(c=='\r' && m_bLNM) + Output('\n'); + PostOutput(); + } + return TRUE; + } + virtual BOOL VInput(WORD vk,DWORD cks) { +#define AROKEY(c,n) ( \ + m_bVT52 \ + ? "\33" c \ + :( \ + (cks&ENHANCED_KEY) \ + ? (m_bCKM?"\33O" c:"\33[" c) \ + : (m_bKPN \ + ?"\33O" n \ + :(m_bCKM?"\33O" c:"\33[" c) \ + ) \ + ) \ +) +#define FUNKEY(c,s) ( \ + (cks&SHIFT_PRESSED) \ + ?( \ + m_bVT52 \ + ? NULL \ + : "\33" s \ + ) \ + :( \ + m_bVT52 \ + ? "\33" c \ + : "\33O" c \ + ) \ +) + if(cks&(LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)){ + COORD ns = {m_CSBI.dwSize.X,m_CSBI.dwSize.Y}; + switch(vk){ + case VK_UP: + if(ns.Y<2) + return TRUE; + ns.Y--; + break; + case VK_DOWN: + ns.Y++; + break; + case VK_LEFT: + if(ns.X<2) + return TRUE; + ns.X--; + break; + case VK_RIGHT: + ns.X++; + break; + default: + return TRUE; + } + ResizeWindow(ns); + return TRUE; + } + switch(vk){ + case VK_F1: return VIn(FUNKEY("P","[23~")); + case VK_F2: return VIn(FUNKEY("Q","[24~")); + case VK_F3: return VIn(FUNKEY("R","[25~")); + case VK_F4: return VIn(FUNKEY("S","[26~")); + case VK_F5: return VIn(FUNKEY("t","[28~")); + case VK_F6: return VIn(FUNKEY("u","[29~")); + case VK_F7: return VIn(FUNKEY("v","[31~")); + case VK_F8: return VIn(FUNKEY("l","[32~")); + case VK_F9: return VIn(FUNKEY("w","[33~")); + case VK_F10: return VIn(FUNKEY("x","[34~")); // terminfo says kf10 "y" + case VK_F11: return VIn("\33[23~"); + case VK_F12: return VIn("\33[24~"); + case VK_UP: + case VK_NUMPAD8: return VIn(AROKEY("A","x")); + case VK_DOWN: + case VK_NUMPAD2: return VIn(AROKEY("B","r")); + case VK_LEFT: + case VK_NUMPAD4: return VIn(AROKEY("D","t")); + case VK_RIGHT: + case VK_NUMPAD6: return VIn(AROKEY("C","v")); + case VK_HOME: + case VK_NUMPAD7: return VIn((cks&ENHANCED_KEY) + ? (NULL) + : (m_bKPN?"\33Ow":"\33[1~") + ); + case VK_END: + case VK_NUMPAD1: return VIn((cks&ENHANCED_KEY) + ? (NULL) + : (m_bKPN?"\33Oq":"\33[4~") + ); + case VK_PRIOR: + case VK_NUMPAD9: return VIn((cks&ENHANCED_KEY) + ? (NULL) + : (m_bKPN?"\33Oy":"\33[5~") + ); + case VK_INSERT: + case VK_NUMPAD0: return VIn((cks&ENHANCED_KEY) + ? ("\33Op") + : (m_bKPN?"\33[3~":"\33Op") + ); + case VK_DELETE: + case VK_DECIMAL: return VIn((cks&ENHANCED_KEY) + ? ("\33On") + : (m_bKPN?"\33[3~":"\33On") + ); + } + + return FALSE; +#undef FUNKEY +#undef AROKEY + } + BOOL VIn(LPCTSTR str) { + if(!str) + return TRUE; + int l = strlen(str); + VERIFY(SendLiteral(str,l)); + if( + ( + Options[toEcho].m_StateU==TOption::stateYes + || Options[toEcho].m_StateU==TOption::stateNone + ) && ( + Options[toEcho].m_StateH!=TOption::stateYes + || Options[toEcho].m_StateH==TOption::stateNone + ) + ){ + PreOutput(); + for(;l>0;l--) + Output(*(str++)); + PostOutput(); + } + return TRUE; + } + + UINT ParseParms() { + ASSERT(m_Sequenced>2); + m_Parms[m_nParms=0]=0; + m_ParmPtrs[m_nParms]=2; + BOOL bWas = FALSE; + for(UINT tmp=2;tmp<(m_Sequenced-1);tmp++){ + if(isdigit(m_Sequence[tmp])){ + m_Parms[m_nParms]*=10; + m_Parms[m_nParms]+=m_Sequence[tmp]-'0'; + bWas = TRUE; + }else{ + if((m_nParms+1)>=(sizeof(m_Parms)/sizeof(*m_Parms))){ + TRACE0("Way too many parameters in ESC[ sequence\n"); + return m_nParms=0; + } + m_Parms[++m_nParms]=0; + m_ParmPtrs[m_nParms]=tmp+1; + bWas = FALSE; + } + } + if(bWas) + m_nParms++; + return m_nParms; + } + + void DoIL(int y,int n) { + VScroll(y,n,(y<=sr1)?sr1:-1); + } + void DoDL(int y,int n) { + VScroll(y,-n,(y<=sr1)?sr1:-1); + } + + + BOOL DoRI() { + m_CSBI.dwCursorPosition.Y--; + if(m_CSBI.dwCursorPosition.Y==(sr0-1)){ + m_CSBI.dwCursorPosition.Y++; + DoIL(m_CSBI.dwCursorPosition.Y,1); + } + return TRUE; + } + BOOL DoIND(BOOL bCR=FALSE) { + m_CSBI.dwCursorPosition.Y++; + if(m_CSBI.dwCursorPosition.Y==sr1+1){ + m_CSBI.dwCursorPosition.Y--; + DoDL(sr0,1); + } + if(bCR) + m_CSBI.dwCursorPosition.X=0; + return TRUE; + } + BOOL DoNEL() { + return DoIND(TRUE); + } + + BOOL DoEBS() { + ASSERT(m_Sequenced>2); + ParseParms(); + CHAR c = m_Sequence[m_Sequenced-1]; + switch(c){ + UINT tmp; + case '@': // ICH Insert blank characters (default:1) + // VT102 Feature + if(m_nParms==0 || m_nParms==1){ + Flush(); + HScroll(m_CSBI.dwCursorPosition.X,m_CSBI.dwCursorPosition.Y,m_nParms?m_Parms[0]:1); + }else + TRACE0("Invalid number of blanks for ESC[@\n"); + break; + case 'A': + case 'F': // With horizontal homing at the end ?? VT102? rxvt? + Flush(); + if(m_nParms==0) + m_CSBI.dwCursorPosition.Y--; + else + m_CSBI.dwCursorPosition.Y-=max(1,m_Parms[0]); + if(m_CSBI.dwCursorPosition.Y<(m_bOM?sr0:0)) + m_CSBI.dwCursorPosition.Y=m_bOM?sr0:0; + if(c=='F') + m_CSBI.dwCursorPosition.X=0; + break; + case 'B': + case 'E': // With horizontal homing at the end ?? VT102? rxvt? + Flush(); + if(m_nParms==0) + m_CSBI.dwCursorPosition.Y++; + else + m_CSBI.dwCursorPosition.Y+=max(1,m_Parms[0]); + if(m_CSBI.dwCursorPosition.Y>(m_bOM?sr1:(m_CSBI.dwSize.Y-1))) + m_CSBI.dwCursorPosition.Y=m_bOM?sr1:(m_CSBI.dwSize.Y-1); + if(c=='E') + m_CSBI.dwCursorPosition.X=0; + break; + case 'C': + Flush(); + if(m_nParms==0) + m_CSBI.dwCursorPosition.X++; + else + m_CSBI.dwCursorPosition.X+=max(1,m_Parms[0]); + if(m_CSBI.dwCursorPosition.X>=m_CSBI.dwSize.X) + m_CSBI.dwCursorPosition.X=m_CSBI.dwSize.X-1; + break; + case 'D': + Flush(); + if(m_nParms==0) + m_CSBI.dwCursorPosition.X--; + else + m_CSBI.dwCursorPosition.X-=max(1,m_Parms[0]); + if(m_CSBI.dwCursorPosition.X<0) + m_CSBI.dwCursorPosition.X=0; + break; + case 'G': // HPA + if(m_nParms<2){ + Flush(); + m_CSBI.dwCursorPosition.X=min(m_CSBI.dwSize.X-1,m_nParms?max(0,(int)m_Parms[0]-1):0); + }else + TRACE0("Invalid args for ESC[G\n"); + break; + case 'H': // CUP + case 'f': // HVP + { + Flush(); + if(m_nParms==0){ + m_CSBI.dwCursorPosition.X = m_CSBI.dwCursorPosition.Y = 0; + }else if(m_nParms==1){ + m_CSBI.dwCursorPosition.Y = max( + m_bOM?sr0:0, + min( + (m_bOM?sr0:0)+(int)m_Parms[0]-1, + m_CSBI.dwSize.Y-1 + ) + ); + }else if(m_nParms==2){ + m_CSBI.dwCursorPosition.Y = max( + m_bOM?sr0:0, + min( + (m_bOM?sr0:0)+(int)m_Parms[0]-1, + m_CSBI.dwSize.Y-1 + ) + ); + m_CSBI.dwCursorPosition.X = max( + 0, + min( + (int)m_Parms[1]-1, + m_CSBI.dwSize.X-1 + ) + ); + }else{ + TRACE0("Invalid arguments for ESC[H\n"); + break; + } + } + break; + case 'J': + Flush(); + if(m_nParms==0 || m_Parms[0]==0){ + // Erase from cursor to the end of the screen. + FillScreen(m_CSBI.dwCursorPosition.X,m_CSBI.dwCursorPosition.Y, + (m_CSBI.dwSize.X-m_CSBI.dwCursorPosition.X) + + (m_CSBI.dwSize.Y-m_CSBI.dwCursorPosition.Y-1)*m_CSBI.dwSize.X, + ' ',m_Attrs); + }else if(m_Parms[0]==1){ + // Erase from the beggining of the screen up to cursor. + FillScreen(0,0,m_CSBI.dwSize.X*m_CSBI.dwCursorPosition.Y+m_CSBI.dwCursorPosition.X+1, + ' ',m_Attrs); + }else if(m_Parms[0]==2){ + // Erase entire screen area + FillScreen(0,0,m_CSBI.dwSize.X*m_CSBI.dwSize.Y,' ',m_Attrs); + }else + TRACE0("Invalid argument for ESC[J\n"); + break; + case 'K': + Flush(); + if(m_nParms==0 || m_Parms[0]==0){ + // From cursor to the end of line + FillScreen(m_CSBI.dwCursorPosition.X,m_CSBI.dwCursorPosition.Y, + m_CSBI.dwSize.X-m_CSBI.dwCursorPosition.X,' ',m_Attrs); + }else if(m_Parms[0]==1){ + // From beginning to cursor + FillScreen(0,m_CSBI.dwCursorPosition.Y,m_CSBI.dwCursorPosition.X+1,' ',m_Attrs); + }else if(m_Parms[0]==2){ + // Entire line + FillScreen(0,m_CSBI.dwCursorPosition.Y,m_CSBI.dwSize.X,' ',m_Attrs); + }else + TRACE0("Invalid argument for ESC[K\n"); + break; + case 'L': // IL - Insert Line(s) - VT102 + if(m_nParms<2){ + Flush(); + DoIL(m_CSBI.dwCursorPosition.Y,m_nParms?m_Parms[0]:1); + }else + TRACE0("Invalid args for ESC[L\n"); + break; + case 'M': // DL - Delete Line(s) - VT102 + if(m_nParms<2){ + Flush(); + DoDL(m_CSBI.dwCursorPosition.Y,m_nParms?m_Parms[0]:1); + }else + TRACE0("Invalid args for ESC[M\n"); + break; + case 'P': // DCH - Delete Character(s) - VT102 + if(m_nParms<2){ + Flush(); + int dlc = m_nParms?m_Parms[0]:1; + HScroll(m_CSBI.dwCursorPosition.X,m_CSBI.dwCursorPosition.Y,-dlc); + }else + TRACE0("Invalid args for ESC[P\n"); + break; + case 'X': // ECH - Erase characters VT102 + if(m_nParms<2){ + Flush(); + int ec = m_nParms?m_Parms[0]:1; + if((m_CSBI.dwCursorPosition.X+ec)>m_CSBI.dwSize.X) + ec = m_CSBI.dwSize.X-m_CSBI.dwCursorPosition.X; + FillScreen(m_CSBI.dwCursorPosition.X,m_CSBI.dwCursorPosition.Y,ec,' ',m_Attrs); + }else + TRACE0("Invalid args for ESC[X\n"); + break; + case 'c': // DA - Device attribute + if(m_nParms==0 || m_Parms[0]==0){ + SendLiteral("\33[?1;3c"); // This is supposed to mean + // STP & AVO - not sure what + // is STP, though.. + }else + TRACE0("Invalid argument for ESC[c\n"); + break; + case 'd': // VPA + if(m_nParms<2){ + Flush(); + m_CSBI.dwCursorPosition.Y=min(m_CSBI.dwSize.Y-1,m_nParms?max(0,(int)m_Parms[0]-1):0); + }else + TRACE0("Invalid args for ESC[d\n"); + break; + case 'g': // TBC - Tabulation clear + if(m_nParms==0 || m_Parms[0]==0){ + Flush(); + ClearTAB(m_CSBI.dwCursorPosition.X); + }else if(m_Parms[0]==3){ + m_TABs[0]=-1; + }else + TRACE1("Invalid argument for ESC[g - %d\n",m_nParms?m_Parms[0]:-1); + break; + case 'h': // SM - Set Mode + { + BOOL bQ = FALSE; + for(tmp=0;tmp=m_CSBI.dwSize.Y) + sr0=m_CSBI.dwSize.Y-1; + sr1=max((UINT)sr0,m_Parms[1]-1); + if(sr1>=m_CSBI.dwSize.Y) + sr1=m_CSBI.dwSize.Y-1; + TRACE2("SCROLL{%d,%d}\n",(int)sr0,(int)sr1); + }else{ + sr0=0; sr1 = m_CSBI.dwSize.Y-1; + } + m_CSBI.dwCursorPosition.X=0; + m_CSBI.dwCursorPosition.Y=sr0; + break; + case 'x': // DECREQTPARM - Request Terminal Parameters + // if parameter is zero - we'll send unsolicited reports when we exit SET-UP. + // if not - we won't. Actually, we won't, anyway. + // Actually, first value is not made up according to any standard that I know of + // It's to make vttest happy. + SendLiteral((m_nParms==0 || m_Parms[0]==0)?"\33[2;1;1;112;112;1;0x":"\33[3;1;1;112;112;1;0x"); + break; + case 'y': // Invoke Confidence Test + if(m_nParms==2 && m_Parms[0]==2){ + if(m_Parms[1]==0){ + Flush(); + Init(); + FillScreen(0,0,m_CSBI.dwSize.X*m_CSBI.dwSize.Y,' ',m_Attrs); + m_CSBI.dwCursorPosition.X = m_CSBI.dwCursorPosition.Y = 0; + }else + TRACE1("Terminal is now invoking tests - %d\n",m_Parms[0]); + }else + TRACE0("Invalid args for ESC[y\n"); + break; + default: + TRACE2("ESC[ SEQUENCE ENDING WITH '%c' AND %d PARS ",(CHAR)c,(INT)m_nParms); + for(tmp=0;tmp=(sizeof(m_Buffer)/sizeof(*m_Buffer))) + Flush(); + if(m_CT && m_CT[(BYTE)c]) + c = m_CT[(BYTE)c]; + m_Buffer[m_Buffered].Char.AsciiChar=c; + m_Buffer[m_Buffered].Attributes=m_Attrs; + m_Buffered++; + return TRUE; + } + BOOL Flush() { + for(UINT tmp=0;tmp=m_CSBI.dwSize.X){ + ASSERT(m_CSBI.dwCursorPosition.X==m_CSBI.dwSize.X); + m_bRight=TRUE; + m_CSBI.dwCursorPosition.X--; + }else{ + m_bRight=FALSE; + } + } + m_Buffered=0; + //PulseOutput(); + return TRUE; + } + + BOOL ProcessSingleChar(CHAR c) { + switch(c){ + case 0: + break; // Ignore NULLs + case '\t': + { + Flush(); + for(int tmp=0;tmp<(sizeof(m_TABs)/sizeof(*m_TABs)) && m_TABs[tmp]>=0;tmp++){ + if(m_TABs[tmp]>m_CSBI.dwCursorPosition.X){ + m_CSBI.dwCursorPosition.X=m_TABs[tmp]; + break; + } + } + if(tmp==(sizeof(m_TABs)/sizeof(*m_TABs)) || m_TABs[tmp]<0) + m_CSBI.dwCursorPosition.X=m_CSBI.dwSize.X-1; + if(m_CSBI.dwCursorPosition.X>=m_CSBI.dwSize.X) + m_CSBI.dwCursorPosition.X=m_CSBI.dwSize.X-1; + } + break; + case '\n': // Handle this manually because of the glitch in windows handling.. + case '\13': // VT + case '\14': // FF + Flush(); + DoIND(); + break; + case '\a': // bell + Flush(); + MessageBeep(0xFFFFFFFF); + break; + case '\b': // back + Flush(); + m_CSBI.dwCursorPosition.X--; + if(m_CSBI.dwCursorPosition.X<0) + m_CSBI.dwCursorPosition.X=0; + break; + case '\r': + Flush(); + if(m_bLNM) + DoIND(); + else + m_CSBI.dwCursorPosition.X=0; + break; + case '\16': // SO - Select G1 + m_CT = m_ctG1; + m_ctG = 1; + break; + case '\17': // SI - Select G0 + m_CT = m_ctG0; + m_ctG = 0; + break; + case '\5': // ENQ - Transmit ANSWERBACK message + return VIn( + "From kintucky to kinecticut,\n" + "Kinky kinglet kindly rules,\n" + "Makin' KINs that're most kinetic, but,\n" + "Please, admit, they're kinda kool!\n\n" + ); + default: + return FALSE; + } + return TRUE; + } + + + virtual BOOL Output(UINT c) { + static + COORD zero = {0,0}; + switch(state) { + case stateEY52Seq1: + m_vt52Y1=c-037-1; + state=stateEY52Seq2; + break; + case stateEY52Seq2: + m_vt52Y2=c-037-1; + Flush(); + m_CSBI.dwCursorPosition.Y = max( + m_bOM?sr0:0, + min( + (m_bOM?sr0:0)+(int)m_vt52Y1, + m_CSBI.dwSize.Y-1 + ) + ); + m_CSBI.dwCursorPosition.X = max( + 0, + min( + m_vt52Y2, + m_CSBI.dwSize.X-1 + ) + ); + state=stateNone; + break; + case stateEPSSeq: // Pound Sign + switch(c){ + case '8': // DECALN - Screen Alignment Display + Flush(); + FillScreen(0,0,m_CSBI.dwSize.X*m_CSBI.dwSize.Y,'E',FOREGROUND_RED|FOREGROUND_GREEN| + FOREGROUND_BLUE); + break; + default: + TRACE1("ESC# %c\n",c); + break; + } + state = stateNone; + break; + case stateEPOSeq: // Parenthesis Opening + switch(c){ + case 'A': + case 'B': + case '1': + m_ctG0 =NULL; + break; + case '0': + case '2': + m_ctG0 = m_ctGraphs; + break; + default: + TRACE1("Invalide ESC( %c\n",c); + break; + } + if(m_ctG==0) + m_CT = m_ctG0; + state = stateNone; + break; + case stateEPCSeq: // Parenthesis Closing + switch(c){ + case 'A': + case 'B': + case '1': + m_ctG1 =NULL; + break; + case '0': + case '2': + m_ctG1 = m_ctGraphs; + break; + default: + TRACE1("Invalide ESC( %c\n",c); + break; + } + if(m_ctG) + m_CT = m_ctG1; + state = stateNone; + break; + case stateEBSeq: // Bracket + if(ProcessSingleChar(c)) + break; + if(m_Sequenced>=sizeof(m_Sequence)){ + m_bEBFailure=TRUE; + m_Sequenced=2; + } + m_Sequence[m_Sequenced++]=c; + if(isalpha(c) || c=='~' || c=='@'){ // *** Maybe we should reconsider these critera + if(m_bEBFailure){ + m_Sequenced=0; + state = stateNone; + }else + DoEBS(); + }else if(c==030){ // CAN + m_Sequenced=0; + state = stateNone; + // *** DO WE PUT OUT the checkerboard (error character?) + } + break; + case stateESeq: // Escape + if(m_bVT52){ + state=stateNone; + switch(c){ + case 'A': + Flush(); + if(m_nParms==0) + m_CSBI.dwCursorPosition.Y--; + else + m_CSBI.dwCursorPosition.Y-=max(1,m_Parms[0]); + if(m_CSBI.dwCursorPosition.Y<(m_bOM?sr0:0)) + m_CSBI.dwCursorPosition.Y=m_bOM?sr0:0; + if(c=='F') + m_CSBI.dwCursorPosition.X=0; + break; + case 'B': + Flush(); + if(m_nParms==0) + m_CSBI.dwCursorPosition.Y++; + else + m_CSBI.dwCursorPosition.Y+=max(1,m_Parms[0]); + if(m_CSBI.dwCursorPosition.Y>(m_bOM?sr1:(m_CSBI.dwSize.Y-1))) + m_CSBI.dwCursorPosition.Y=m_bOM?sr1:(m_CSBI.dwSize.Y-1); + if(c=='E') + m_CSBI.dwCursorPosition.X=0; + break; + case 'C': + Flush(); + if(m_nParms==0) + m_CSBI.dwCursorPosition.X++; + else + m_CSBI.dwCursorPosition.X+=max(1,m_Parms[0]); + if(m_CSBI.dwCursorPosition.X>=m_CSBI.dwSize.X) + m_CSBI.dwCursorPosition.X=m_CSBI.dwSize.X-1; + break; + case 'D': + Flush(); + if(m_nParms==0) + m_CSBI.dwCursorPosition.X--; + else + m_CSBI.dwCursorPosition.X-=max(1,m_Parms[0]); + if(m_CSBI.dwCursorPosition.X<0) + m_CSBI.dwCursorPosition.X=0; + break; + case 'F': + m_CT=m_ctG1; + m_ctG=1; + break; + case 'G': + m_CT=m_ctG0; + m_ctG=0; + break; + case 'H': + Flush(); + m_CSBI.dwCursorPosition.X = m_CSBI.dwCursorPosition.Y = 0; + break; + case 'I': + Flush(); + DoRI(); + break; + case 'J': + Flush(); + // Erase from cursor to the end of the screen. + FillScreen(m_CSBI.dwCursorPosition.X,m_CSBI.dwCursorPosition.Y, + (m_CSBI.dwSize.X-m_CSBI.dwCursorPosition.X) + + (m_CSBI.dwSize.Y-m_CSBI.dwCursorPosition.Y-1)*m_CSBI.dwSize.X, + ' ',m_Attrs); + break; + case 'K': + Flush(); + FillScreen(m_CSBI.dwCursorPosition.X,m_CSBI.dwCursorPosition.Y, + m_CSBI.dwSize.X-m_CSBI.dwCursorPosition.X,' ',m_Attrs); + break; + case 'Y': + state=stateEY52Seq1; + break; + case 'Z': + VIn("\33/Z"); + break; + case '<': + m_bVT52=FALSE; + break; + default: + TRACE0("Invalid ESC sequence in VT52 mode\n"); + break; + } + }else{ + switch(c){ + case '[': + ASSERT(m_Sequenced==1); + m_Sequence[m_Sequenced++]=c; + state = stateEBSeq; + break; + case 'H': // Set TAB at cursor + InsertTAB(m_CSBI.dwCursorPosition.X); + state = stateNone; + break; + case 'M': // Arrow Up and scroll if needed. + Flush(); + DoRI(); + state = stateNone; + break; + case 'D': // Arrow Dn and scroll if needed. + Flush(); + DoIND(); + state = stateNone; + break; + case 'E': // Next Line - about identical to \r\n + Flush(); + DoNEL(); + state = stateNone; + break; + case 'c': // RIS - Reset to Initial State + { + Flush(); + Init(); + FillScreen(0,0,m_CSBI.dwSize.X*m_CSBI.dwSize.Y,' ',m_Attrs); + m_CSBI.dwCursorPosition.X = m_CSBI.dwCursorPosition.Y = 0; + } + break; + case '(': + state = stateEPOSeq; + break; + case ')': + state = stateEPCSeq; + break; + case '#': + state = stateEPSSeq; + break; + case '=': // DECKPAM - Keypad sends sequences + TRACE0("KP - CS\n"); + m_bKPN = FALSE; + state = stateNone; + break; + case '>': // DECKPNM - Keypad sends numerics + TRACE0("KP - Numeric\n"); + m_bKPN = TRUE; + state = stateNone; + break; + case '7': // Save Cursor and charsets + m_savedCTG0 = m_ctG0; m_savedCTG1 = m_ctG1; m_savedCT = m_CT; + m_savedCTG=m_ctG; + memmove(&m_savedCP,&m_CSBI.dwCursorPosition,sizeof(m_savedCP)); + m_savedAttrs = attrs; + state = stateNone; + break; + case '8': // Restore cursor and charsets + Flush(); + m_ctG0 = m_savedCTG0; m_ctG1 = m_savedCTG1; m_CT = m_savedCT; + m_ctG=m_savedCTG; + memmove(&m_CSBI.dwCursorPosition,&m_savedCP,sizeof(m_CSBI.dwCursorPosition)); + state = stateNone; + attrs = m_savedAttrs; + SetAttrs(); + break; + default: + TRACE1("ESCNON[ SEQ - '%c'\n",c); + state = stateNone; + break; + } + } + break; + default: + case stateNone: + ASSERT(state==stateNone); + if(isprint(c&0x7F) || (c&0x7F)==0x7F){ + DoPrintable(c); + }else{ + switch(c){ + case '\33': + m_Sequenced=0;m_Sequence[m_Sequenced++]=c; + state = stateESeq; + break; + default: + if(!ProcessSingleChar(c)) + TRACE1("Unrecognized character 0x%02X\n",(WORD)c); + break; + } + } + m_bRight=FALSE; + break; + } + return TRUE; + } + + virtual BOOL PreOutput() { + return TRUE; + } + virtual BOOL PostOutput() { + Flush(); + VERIFY(SetConsoleCursorPosition(hConsoleOutput,m_CSBI.dwCursorPosition)); + return TRUE; + } + BOOL PulseOutput() { + Flush(); + VERIFY(SetConsoleCursorPosition(hConsoleOutput,m_CSBI.dwCursorPosition)); + return TRUE; + } + + virtual BOOL Init() { + m_Sequenced=0; + state = stateNone; + attrs=0; + DoNAWS(); + sr0 = 0; sr1 = m_CSBI.dwSize.Y-1; + m_bRight = FALSE; + m_Buffered=0; + m_savedCT = m_CT = NULL; + m_savedCTG0 = m_ctG0 = NULL; + m_savedCTG1 = m_ctG1 = m_ctGraphs; + m_savedCTG = m_ctG; + m_savedCP.X=m_savedCP.Y=0; + m_bKPN = TRUE; + m_bCKM = FALSE; + m_bAWM = TRUE; + m_bOM = FALSE; + m_bLNM = FALSE; + m_bIM = FALSE; + m_bVT52 = FALSE; + m_bTR = FALSE; + m_bgAttr=-1; + m_fgAttr=-1; + SetAttrs(); + InitCT(); + InitTAB(); + SizeWindowToAll(); + return TRUE; + } + + virtual LPCTSTR GetTitle() { + static + CHAR consoleTitle[1024]; + if(TTTermType<0) + return "WEIRDO"; + sprintf(consoleTitle,"%s [%dx%d]",TTypes[TTTermType].m_Name,m_CSBI.dwSize.X,m_CSBI.dwSize.Y); + return consoleTitle; + } + + BOOL SizeWindowToAll() { + SMALL_RECT wi = {0,0, + min(m_CSBI.dwSize.X-2,m_CSBI.dwMaximumWindowSize.X-1), + min(m_CSBI.dwSize.Y-1,m_CSBI.dwMaximumWindowSize.Y-1) + }; + SetConsoleWindowInfo(hConsoleOutput,TRUE,&wi); + wi.Right++; + return SetConsoleWindowInfo(hConsoleOutput,TRUE,&wi); + } + + BOOL ClearTAB(INT tab) { + for(int tmp=0;tmp<(sizeof(m_TABs)/sizeof(*m_TABs)) && m_TABs[tmp]>=0;tmp++) + if(tab==m_TABs[tmp]){ + memmove(&m_TABs[tmp],&m_TABs[tmp+1],sizeof(m_TABs)-sizeof(*m_TABs)*(tmp+1)); + m_TABs[(sizeof(m_TABs)/sizeof(*m_TABs))-1]=-1; + return TRUE; + } + return FALSE; + } + BOOL InsertTAB(INT tab) { + for(int tmp=0;tmp<(sizeof(m_TABs)/sizeof(*m_TABs));tmp++){ + if(tab==m_TABs[tmp]) + return TRUE; + else if(m_TABs[tmp]>tab || m_TABs[tmp]<0){ + if(tmp!=((sizeof(m_TABs)/sizeof(*m_TABs))-1)) + memmove(&m_TABs[tmp+1],&m_TABs[tmp],sizeof(m_TABs)-sizeof(*m_TABs)*(tmp+1)); + m_TABs[tmp]=tab; + return TRUE; + } + } + return FALSE; + } + void InitTAB() { + ASSERT(m_CSBI.dwSize.X<=(sizeof(m_TABs)/sizeof(*m_TABs))); + for(int tmp=0,tab=0;tmp= + m_ctGraphs['{'] = (CHAR)0xE3; // Pi symbol + m_ctGraphs['|'] = (CHAR)0xD8; // Not equal != + m_ctGraphs['}'] = (CHAR)0xE0; // UK pound symbol + m_ctGraphs['~'] = (CHAR)0xF9; // Centered dot + } +} + TT_VT100; + +DWORD CVT100::dummyWritten = 0; +CHAR CVT100::m_ctGraphs[256]; +// ?? CHAR CVT100::sfCrap[256]; diff --git a/help/kinsole.cnt b/help/kinsole.cnt new file mode 100644 index 0000000..9a8af90 --- a/dev/null +++ b/help/kinsole.cnt @@ -0,0 +1,9 @@ +:Base KINSole.hlp>Standard +:Title KINSole +1 KINSole +2 About KINSole=About +2 Using KINSole=Using +2 Command Line Options=CmdOptions +2 Keyboard Shortcuts=HotKeys +2 Beta Notes=BetaNotes +2 Beta News=News diff --git a/help/kinsole.hpj b/help/kinsole.hpj new file mode 100644 index 0000000..62b1b55 --- a/dev/null +++ b/help/kinsole.hpj @@ -0,0 +1,17 @@ +; This file is maintained by HCW. Do not modify this file directly. + +[OPTIONS] +HCW=0 +COMPRESS=12 Hall Zeck +LCID=0x409 0x0 0x0 ;English (United States) +REPORT=Yes +CONTENTS=About +TITLE=KINSole +CNT=kinsole.cnt +HLP=KINSOLE.HLP + +[FILES] +KINSole.rtf + +[WINDOWS] +Standard="",(32,64,949,175),28932,(r14876671),(r12632256),f2 diff --git a/help/kinsole.rtf b/help/kinsole.rtf new file mode 100644 index 0000000..2cfd296 --- a/dev/null +++ b/help/kinsole.rtf @@ -0,0 +1,97 @@ +{\rtf1\ansi +@{\footnote +THIS FILE WAS AUTOMATICALLY GENERATED FROM XML DOCUMENT. +DO NOT MODIFY THIS FILE DIRECTLY. EDIT XML DOCUMENT INSTEAD +} +{\fonttbl{\f0\froman Times New Roman;}{\f1\fswiss Arial;}{\f3\froman Symbol;}}{\colortbl; + \red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0; + \red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255; + \red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128; + \red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;} + +\pard\plain\keepn +#{\footnote About} +${\footnote About KINSole} +{ \f1\fs18\b\sb120 About KINSole} +\par\sa120\sb120\qj\pard \f1\fs18\sb120 {\b KINSole} is our {\i Win32} implementation of client side of the {\i telnet} protocol described in details in the {\uldb {\b RFC854}}{\v %!ExecFile("http://www.rfc-editor.org/rfc/rfc854.txt")} and related RFCs (namely {\uldb {\b RFC855}}{\v %!ExecFile("http://www.rfc-editor.org/rfc/rfc855.txt")}, {\uldb {\b RFC857}}{\v %!ExecFile("http://www.rfc-editor.org/rfc/rfc857.txt")}, {\uldb {\b RFC1091}}{\v %!ExecFile("http://www.rfc-editor.org/rfc/rfc1091.txt")}, {\uldb {\b RFC1073}}{\v %!ExecFile("http://www.rfc-editor.org/rfc/rfc1073.txt")}, {\uldb {\b RFC1572}}{\v %!ExecFile("http://www.rfc-editor.org/rfc/rfc1572.txt")} and others). It uses {\i Win32} console and, therefore, can be run both windowed and in fullscreen mode. +\par\sa120\sb120\qj\pard \f1\fs18\sb120 +\par\sa120\sb120\qj\pard \f1\fs18\sb120 {\b {\i Enjoy!}} +{ +\par\pard\plain\sb360\sa120 \f1\fs16 Copyright (c) 1998, 2002 {\uldb\cf0 Klever Group (http://www.klever.net/)}{\v %!ExecFile("http://www.klever.net/")} +\par\qj\sb120\sa120Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +\par The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +\par \sa360 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +} +\par \sa0\sb120\ql \f1\fs16 Author: {\b\uldb\cf11 Michael Krelin ({\i hacker@klever.net})}{\v %!ExecFile("mailto:hacker@klever.net")} +\par \sa0\sb0 Fan mail send to {\i\uldb gefilte@klever.net}{\v %!ExecFile("mailto:gefilte@klever.net")} +\page + +\pard\plain\keepn +#{\footnote News} +${\footnote Beta News} +{ \f1\fs18\b\sb120 Beta News} +\par\pard\plain\f1\fs24\qc\cf2\b 1.00 Beta 3 - August 19st, 2002 +\par\pard\plain\fi0\li0\f1\fs18 \bullet No changes in code. License change. +\par\pard\plain\f1\fs24\qc\cf2\b 1.00 Beta 2 - March 7th, 1998 +\par\pard\plain\fi0\li0\f1\fs18 \bullet Better copying from {\b KINSole} window. +\par\pard\plain\fi0\li0\f1\fs18 \bullet Better handling of cursor position when resizing window. +\par\pard\plain\fi0\li0\f1\fs18 \bullet Sending {\b CR/LF} pair when pressing {\b ENTER}. This is of help when telnetting to non-telnet ports. +\par\pard\plain\fi0\li0\f1\fs18 \bullet Corrected bug, preventing {\b KINSole} from pasting text to remote twice. +\par\pard\plain\fi0\li0\f1\fs18 \bullet Improved handling of echoing. Previously {\b KINSole} didn't turn echo off on some systems, namely {\b Solaris}. +\par\pard\plain\fi0\li0\f1\fs18 \bullet Typo causing {\b KINSole} not to show diamond characters in {\b VT10x} mode corrected. +\par\pard\plain\fi0\li0\f1\fs18 \bullet {\b GPF} when invoking {\b KINSole} with {\b -t} option fixed. +\par\pard\plain\fi0\li0\f1\fs18 \bullet Hotkey ({\b Alt-INS}) for copy operation added. Not supposed to work under {\b\cf6 Windows NT}. +\par\pard\plain\fi0\li0\f1\fs18 \bullet {\b Paste} is made aware of local echoing. +\par\pard\plain\fi0\li0\f1\fs18 \bullet Default terminal type when telnetting to non-telnet port is now {\b TTY}. +\par\pard\plain\fi0\li0\f1\fs18 \bullet {\b Timing Mark} telnet option ({\uldb {\b RFC860}}{\v %!ExecFile("http://www.rfc-editor.org/rfc/rfc860.txt")}) implemented ({\b Alt-T}). +\par\pard\plain\fi0\li0\f1\fs18 \bullet Improved handling of window icon when starting from other {\i Win32} command line application. +\page + +\pard\plain\keepn +#{\footnote Using} +${\footnote Using KINSole} +{ \f1\fs18\b\sb120 Using {\b KINSole}} +\par\sa120\sb120\qj\pard \f1\fs18\sb120 You may run {\b KINSole} from your MS-DOS prompt by typing '{\i kinsole host port}'. +\par\sa120\sb120\qj\pard \f1\fs18\sb120 If you need to know more about custom options, please proceed to the {\uldb Command Line Options}{\v CmdOptions} section. +\page + +\pard\plain\keepn +#{\footnote CmdOptions} +${\footnote Command Line Options} +{ \f1\fs18\b\sb120 Command Line Options} +\par\sa120\sb120\qj\pard \f1\fs18\sb120 Usage: +\par\sa120\sb120\qj\pard \f1\fs18\sb120 KINSole [{\i options} ]{\i host}[ {\i port}] +\par\sa120\sb120\qj\pard \f1\fs18\sb120 Available options are:\pard +\par \fi0\li0 \bullet {\b -r {\i ##}} or {\b -{\i ##}} - Try to set the number of rows in console screen buffer. +\par \fi0\li0 \bullet {\b -c {\i ##}} - Try to set the number of columns in console screenbuffer. +\par \fi0\li0 \bullet +\par\sa120\sb120\qj\f1\fs16 Note: Changing of console's screenbuffer size either from command line or on remote host's request (ESC[?3h vt100/vt102 control sequence) may not work when in fullscreen mode. +\par \fi0\li0 \bullet {\b -l {\i username}} - Pass username to remote server in environment if remote server allows. +\par \fi0\li0 \bullet {\b -e {\i var}={\i val}} - Pass environment variable to remote server. +\par \fi0\li0 \bullet {\b -v {\i var}={\i val}} - Pass user environment variable to remote server. +\par \fi0\li0 \bullet {\b -t {\i termtype}} - Change preferred terminal type to pass to remote server. This option does not really force specific terminal emulation. Final decision on terminal type is left up to server. Both sides are supposed to negotiate terminal type when connecting so that both sides may feel satisfied. Default preference is {\b vt102}.\pard +\page + +\pard\plain\keepn +#{\footnote HotKeys} +${\footnote Hot Keys} +{ \f1\fs18\b\sb120 Hot Keys} +\par\sa120\sb120\qj\pard \f1\fs18\sb120 While running {\b KINSole} you may use these key combinations:\pard +\par \fi0\li0 \bullet {\b Alt-X/Alt-Q} - Terminate telnet session and leave {\b KINSole}. +\par \fi0\li0 \bullet {\b Alt-Y} - Send {\b AYT (Are You There)} telnet command. Remote host (if it supports telnet protocol as it's supposed to) should provide you with visible/printable/audible feedback stating that it's alive. You may want to use it when running program which takes unusually long time to finish and you suspect that your connection is dead. +\par \fi0\li0 \bullet {\b Shift-INS} Paste text from Windows Clipboard. +\par \fi0\li0 \bullet {\b Ctrl-Break} Send {\b IP (Interrupt Process)} telnet command. Usually effectively equivalent to Ctrl-C, but it's up to server to decide what to do in each case. +\par \fi0\li0 \bullet {\b Alt-INS} - Invoke {\b copying} from {\b KINSole} screen buffer. +\par \fi0\li0 \bullet {\b Alt-T} - Send {\b TIMING-MARK} request. As soon as response comes {\b KINSole} will flash window thrice or beep if window handle is not available for some reason.\pard +\page + +\pard\plain\keepn +#{\footnote BetaNotes} +${\footnote Beta Notes} +{ \f1\fs18\b\sb120 Beta Notes} +\par\sa120\sb120\qj\pard \f1\fs18\sb120 A few things you may want to know about this Beta Release:\pard +\par \fi0\li0 \bullet Only two terminal emulation modules are included in this beta release - one for dumb terminal and one for vt100/102. If you try to select ANSI terminal type vt100 emulation will be selected, which is actually close enough to ANSI so you shouldn't suffer too much. Why would one want to use ANSI terminal emulation, anyway? +\par \fi0\li0 \bullet Telnet {\b LINEMODE} option ({\uldb {\b RFC1184}}{\v %!ExecFile("http://www.rfc-editor.org/rfc/rfc1184.txt")}) is still to come. +\par \fi0\li0 \bullet Pasting of text using console toolbar button may cause {\b KINSole} to lock up. Use {\b Shift-INS} instead.\pard +\page +} \ No newline at end of file diff --git a/help/kinsole.xml b/help/kinsole.xml new file mode 100644 index 0000000..7d15eed --- a/dev/null +++ b/help/kinsole.xml @@ -0,0 +1,72 @@ + + + + About KINSole +

KINSole is our Win32 implementation of client side of the telnet protocol described in details in the and related RFCs (namely , , , , and others). It uses Win32 console and, therefore, can be run both windowed and in fullscreen mode.

+

+

Enjoy!

+ + +
+ + Beta News + + No changes in code. License change. + + + Better copying from KINSole window. + Better handling of cursor position when resizing window. + Sending CR/LF pair when pressing ENTER. This is of help when telnetting to non-telnet ports. + Corrected bug, preventing KINSole from pasting text to remote twice. + Improved handling of echoing. Previously KINSole didn't turn echo off on some systems, namely Solaris. + Typo causing KINSole not to show diamond characters in VT10x mode corrected. + GPF when invoking KINSole with -t option fixed. + Hotkey (Alt-INS) for copy operation added. Not supposed to work under Windows NT. + Paste is made aware of local echoing. + Default terminal type when telnetting to non-telnet port is now TTY. + Timing Mark telnet option () implemented (Alt-T). + Improved handling of window icon when starting from other Win32 command line application. + + + + Using KINSole +

You may run KINSole from your MS-DOS prompt by typing 'kinsole host port'.

+

If you need to know more about custom options, please proceed to the Command Line Options section.

+
+ + Command Line Options +

Usage:

+

KINSole [options ]host[ port]

+

Available options are:

+
    +
  • -r ## or -## - Try to set the number of rows in console screen buffer.
  • +
  • -c ## - Try to set the number of columns in console screenbuffer.
  • +
  • Note: Changing of console's screenbuffer size either from command line or on remote host's request (ESC[?3h vt100/vt102 control sequence) may not work when in fullscreen mode.
  • +
  • -l username - Pass username to remote server in environment if remote server allows.
  • +
  • -e var=val - Pass environment variable to remote server.
  • +
  • -v var=val - Pass user environment variable to remote server.
  • +
  • -t termtype - Change preferred terminal type to pass to remote server. This option does not really force specific terminal emulation. Final decision on terminal type is left up to server. Both sides are supposed to negotiate terminal type when connecting so that both sides may feel satisfied. Default preference is vt102.
  • +
+
+ + Hot Keys +

While running KINSole you may use these key combinations:

+
    +
  • Alt-X/Alt-Q - Terminate telnet session and leave KINSole.
  • +
  • Alt-Y - Send AYT (Are You There) telnet command. Remote host (if it supports telnet protocol as it's supposed to) should provide you with visible/printable/audible feedback stating that it's alive. You may want to use it when running program which takes unusually long time to finish and you suspect that your connection is dead.
  • +
  • Shift-INS Paste text from Windows Clipboard.
  • +
  • Ctrl-Break Send IP (Interrupt Process) telnet command. Usually effectively equivalent to Ctrl-C, but it's up to server to decide what to do in each case.
  • +
  • Alt-INS - Invoke copying from KINSole screen buffer.
  • +
  • Alt-T - Send TIMING-MARK request. As soon as response comes KINSole will flash window thrice or beep if window handle is not available for some reason.
  • +
+
+ + Beta Notes +

A few things you may want to know about this Beta Release:

+
    +
  • Only two terminal emulation modules are included in this beta release - one for dumb terminal and one for vt100/102. If you try to select ANSI terminal type vt100 emulation will be selected, which is actually close enough to ANSI so you shouldn't suffer too much. Why would one want to use ANSI terminal emulation, anyway?
  • +
  • Telnet LINEMODE option () is still to come.
  • +
  • Pasting of text using console toolbar button may cause KINSole to lock up. Use Shift-INS instead.
  • +
+
+
diff --git a/install/custom.rch b/install/custom.rch new file mode 100644 index 0000000..8b3a590 --- a/dev/null +++ b/install/custom.rch @@ -0,0 +1,3 @@ +KINSole.ex_ RCDATA DISCARDABLE "../release/kinsole.ex_" +KINSole.hl_ RCDATA DISCARDABLE "../release/kinsole.hl_" +KINSole.cn_ RCDATA DISCARDABLE "../release/kinsole.cn_" diff --git a/install/install.cpp b/install/install.cpp new file mode 100644 index 0000000..e6f4e5a --- a/dev/null +++ b/install/install.cpp @@ -0,0 +1,65 @@ +#include "resource.h" +#include "../shared-code/install.h" + +#define KINAME "KINSole 1.00 Beta 3" +#define SKINAME "KINSole" + +BOOL Install(void) +{ +STRING tPath = strFETCH_REG_KEY(HKEY_LOCAL_MACHINE,"Software\\Klever Group, Inc.",SKINAME "Path"); +STRING kPath = strFETCH_REG_KEY(HKEY_LOCAL_MACHINE,"Software\\Klever Group, Inc.","KINPath"); +LPCSTR qPath = ((LPCSTR)tPath)?(LPCSTR)tPath:(((LPCSTR)kPath)?(LPSTR)kPath:"C:\\Program Files\\Klever\\Nothings"); +STRING path = REQUESTPATH(" " KINAME,"Note: KINSole program file will be installed into your windows directory so that you can rely on it's presence in your search path\nEnter destination path:",qPath); + if(!path) + return NULL; +STRING winDir(_MAX_PATH); + + GetWindowsDirectory(winDir,_MAX_PATH); + INSTALLFILE("KINSole.ex_",winDir,"KINSole.exe"); + MAKE_PATH(path); +STRING shortPath = GET_SHORT_PATH(path); + if(!shortPath){ + MessageBox(NULL,"Failed to install " KINAME " in specified directory",NULL,MB_ICONERROR|MB_OK); + return FALSE; + } + if(!( + INSTALLFILE("KINSole.hl_",path,"KINSole.hlp") && + INSTALLFILE("KINSole.cn_",path,"KINSole.cnt") + )){ + MessageBox(NULL,"Failed to install " KINAME " in specified directory",NULL,MB_ICONERROR|MB_OK); + return FALSE; + } + ADDMENU("Accessories\\Klever Co.","KINSole Help",path,SKINAME ".hlp"); + strSET_REG_KEY(HKEY_LOCAL_MACHINE,"Software\\Klever Group, Inc.", SKINAME "Path",path); + strSET_REG_KEY(HKEY_LOCAL_MACHINE,"Software\\Klever Group, Inc.","KINPath",path); +FILE* inf=CREATE_INF_FILE(path, SKINAME ".INF"); + if(!inf){ + MessageBox(NULL,"Failed to install " KINAME,NULL,MB_ICONERROR|MB_OK); + return FALSE; + } + INF_FILE_HEADER(inf); + INF_FILE_SECTION(inf,"Uninstall"); + fprintf(inf,"AddReg=kFiles\nDelReg=kReg\nUpdateInis=kMenu\n"); + + INF_FILE_SECTION(inf,"kFiles"); + INF_REMOVE_ROOT(inf,SKINAME "Files",shortPath); + INF_REMOVE_HELP_FILE(inf,SKINAME "Files",SKINAME); + INF_REMOVE_FILE(inf,SKINAME "Files",SKINAME ".inf"); + + INF_REMOVE_ROOT(inf,SKINAME "WFiles",winDir); + INF_REMOVE_FILE(inf,SKINAME "WFiles",SKINAME ".exe"); + + INF_FILE_SECTION(inf,"kReg"); + INF_UNINSTALL_REG(inf,SKINAME); + + INF_FILE_SECTION(inf,"kMenu"); + INF_MENU_GROUP(inf,1,"Accessories\\Klever Co."); + INF_MENU_ITEM(inf,1,"KINSole Help"); + fclose(inf); + + REG_UNINSTALL_COMMAND(SKINAME,"Klever " KINAME,shortPath,SKINAME ".INF","Uninstall"); + + MessageBox(NULL,KINAME " installed successfully, you may now run it from command line, read documentation in Programs/Accessories/Klever Co. menu or simply remove it using Control Panel Add/Remove Programs applet."," Rejoice!",MB_ICONINFORMATION|MB_OK); + + return TRUE; +} diff --git a/install/install.rc b/install/install.rc new file mode 100644 index 0000000..d7780b6 --- a/dev/null +++ b/install/install.rc @@ -0,0 +1,182 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +#if defined(APSTUDIO_INVOKED) || defined(FALSE) +#if defined(APSTUDIO_INVOKED) +IDD_INSTALLING$(FALSE) DIALOGEX 0, 0, 200, 74 +#else +IDD_INSTALLING DIALOGEX 0, 0, 200, 74 +#endif +STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + PUSHBUTTON "Cancel",IDCANCEL,143,53,50,14,BS_CENTER | BS_VCENTER | + BS_NOTIFY | BS_FLAT,WS_EX_DLGMODALFRAME + CONTROL "Animate1",IDC_DISKS,"SysAnimate32",ACS_TRANSPARENT | + ACS_AUTOPLAY | WS_TABSTOP,161,7,32,32 + LTEXT "",IDC_STATE,7,7,150,32,SS_NOPREFIX | SS_NOTIFY + CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",0x0,7,45, + 186,7,WS_EX_DLGMODALFRAME +END +#endif + +IDD_PATH DIALOGEX 0, 0, 255, 73 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_POPUP | + WS_VISIBLE | WS_CAPTION +EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "",IDC_PROMPT,7,7,241,30 + EDITTEXT IDC_PATH,7,37,195,12,ES_AUTOHSCROLL + PUSHBUTTON "B&rowse..",IDC_BROWSE,208,37,40,12 + DEFPUSHBUTTON "OK",IDOK,69,52,50,14 + PUSHBUTTON "Cancel",IDCANCEL,135,52,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + "IDD_INSTALLING$(FALSE)", DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 193 + TOPMARGIN, 7 + BOTTOMMARGIN, 67 + HORZGUIDE, 39 + END + + IDD_PATH, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 248 + VERTGUIDE, 202 + VERTGUIDE, 208 + TOPMARGIN, 7 + BOTTOMMARGIN, 66 + HORZGUIDE, 37 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""custom.rch""\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON ICON DISCARDABLE "../shared-data/install-icon.ico" + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,3 + PRODUCTVERSION 1,0,0,3 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Klever Group (http://www.klever.net/)\0" + VALUE "FileDescription", "INSTALL: KINSole, telnet client\0" + VALUE "FileVersion", "1, 0, 0, 3\0" + VALUE "InternalName", "INSTALL\0" + VALUE "LegalCopyright", "Copyright © 1998, 2002 Klever Group (http://www.klever.net/)\0" + VALUE "LegalTrademarks", "Klever Group (http://www.klever.net/)\0" + VALUE "OriginalFilename", "INSTALL.EXE\0" + VALUE "ProductName", "KINSole\0" + VALUE "ProductVersion", "1, 0, 0, 3\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "custom.rch" +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/install/resource.h b/install/resource.h new file mode 100644 index 0000000..ebf7991 --- a/dev/null +++ b/install/resource.h @@ -0,0 +1,24 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Install.rc +// +#define IDD_INSTALLING 101 +#define IDD_PATH 102 +#define IDI_ICON 105 +#define IDC_DISKS 1000 +#define IDC_STATE 1001 +#define IDC_PROGRESS 1002 +#define IDC_PROMPT 1003 +#define IDC_PATH 1004 +#define IDC_BROWSE 1005 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1006 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/kinsole.cpp b/kinsole.cpp new file mode 100644 index 0000000..463db1c --- a/dev/null +++ b/kinsole.cpp @@ -0,0 +1,736 @@ +#include + +#ifdef _DEBUG +#include +#else +#define ASSERT(f) ((void)0) +#define VERIFY(f) ((void)(f)) +#define TRACE0(sz) +#define TRACE1(sz, p1) +#define TRACE2(sz, p1, p2) +#define TRACE3(sz, p1, p2, p3) +#endif + +#include +#include "resource.h" +#include "windowsx.h" + +#define DAMN_KIN_NAME "KINSole" +#define DAMN_KIN_VERSION "v1.00 Beta 3" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +enum { + WM_USERSOCKET = WM_USER+16, + WM_USERKEY, + WM_USERNOP +}; +enum { + tnIAC = 255, + tnSE = 240, + tnNOP = 241, + tnDM = 242, + tnBreak = 243, + tnIP = 244, + tnAO = 245, + tnAYT = 246, + tnEC = 247, + tnEL = 248, + tnGA = 249, + tnSB = 250, + tnWILL = 251, + tnWONT = 252, + tnDO = 253, + tnDONT = 254 +}; + +WSADATA wsaData; +ATOM wsaWC = NULL; +HWND wsaW = NULL; + +CHAR remoteHost[256]; +CHAR remoteProt[256]; +sockaddr_in remoteSIN; + + +SOCKET telnetSocket; +HANDLE hConsoleInput; +HANDLE hConsoleOutput; +HWND hConsoleWindow; +HANDLE hConsoleThread; +DWORD consoleThreadID; +HANDLE hDispatchThread; +DWORD dispatchThreadID; +BOOL bTelnet,bTermPulled; + +enum _cState { + cstateNone = 0, cstateIAC, cstateDO, cstateSB, cstateSBData, + cstateSBDataIAC, cstateWILL, cstateDONT,cstateWONT, +} connState = cstateNone; +BYTE negOption = 0; + + +BOOL SelectSocket() { + return WSAAsyncSelect(telnetSocket,wsaW,WM_USERSOCKET,FD_READ|FD_OOB|FD_CLOSE)!=SOCKET_ERROR; +} + +BOOL ShowWill(BYTE o) +{ + TRACE1("We're WILLing to %d\n",(WORD)o); +static +BYTE d[3] = {tnIAC,tnWILL,0}; + d[2] = o; +BOOL rv = send(telnetSocket,(char*)d,sizeof(d),0)==sizeof(d); + SelectSocket(); + return rv; +} +BOOL ShowUnwill(BYTE o) +{ + TRACE1("We're NOT WILLing to %d\n",(WORD)o); +static +BYTE d[3] = {tnIAC,tnWONT,0}; + d[2] = o; +BOOL rv = send(telnetSocket,(char*)d,sizeof(d),0)==sizeof(d); + SelectSocket(); + return rv; +} +BOOL BegDo(BYTE o) +{ + TRACE1("We beg to DO %d\n",(WORD)o); +static +BYTE d[3] = {tnIAC,tnDO,0}; + d[2] = o; +BOOL rv = send(telnetSocket,(char*)d,sizeof(d),0)==sizeof(d); + SelectSocket(); + return rv; +} +BOOL BegDont(BYTE o) +{ + TRACE1("We beg DONT'T %d\n",(WORD)o); +static +BYTE d[3] = {tnIAC,tnDONT,0}; + d[2] = o; +BOOL rv = send(telnetSocket,(char*)d,sizeof(d),0)==sizeof(d); + SelectSocket(); + return rv; +} +BOOL SubNegotiate(BYTE o,LPBYTE data,UINT size) +{ +LPBYTE d = new BYTE[3+size*2+2]; +int ds = 0; + d[ds++]=tnIAC; d[ds++]=tnSB; d[ds++]=o; + for(UINT tmp=0;tmpp_proto:6; + telnetSocket = socket(sin.sin_family,SOCK_STREAM,proto); + if(telnetSocket==INVALID_SOCKET){ + printf("Failed to create socket\n"); + return FALSE; + } +static +BOOL bOOBInline = FALSE; + if(setsockopt(telnetSocket,SOL_SOCKET,SO_OOBINLINE,(const char*)&bOOBInline,sizeof(bOOBInline))){ + TRACE0("Failed to setsockopt for OOB data\n"); + } + printf("Trying %s..",inet_ntoa(sin.sin_addr)); + if(connect(telnetSocket,(sockaddr*)&sin,sizeof(sin))){ + switch(WSAGetLastError()){ + case WSAECONNREFUSED: printf("\nConnection refused\n"); break; + case WSAEHOSTUNREACH: printf("\nNo route to host\n"); break; + case WSAENETDOWN: printf("\nNetwork is down\n"); break; + case WSAENETUNREACH: printf("\nNetwork is unreachable\n"); break; + case WSAETIMEDOUT: printf("\nConnection timed out\n"); break; + default: printf("\nFailed to connect\n"); break; + } + return FALSE; + } + printf("\nConnected. Alt-X/Alt-Q - Close telnet connection\n"); +//*** hConsoleInput = ::GetStdHandle(STD_INPUT_HANDLE); +//*** hConsoleOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + hConsoleInput = CreateFile("CONIN$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL,OPEN_EXISTING,0,NULL); + hConsoleOutput = CreateFile("CONOUT$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL,OPEN_EXISTING,0,NULL); + ASSERT(hConsoleInput!=INVALID_HANDLE_VALUE && + hConsoleOutput!=INVALID_HANDLE_VALUE); + if(!(bTelnet || bTermPulled)) + TerminalPullType("TTY"); + InitOptionsTable(); + TRACE0("Connected\n"); + VERIFY(SetConsoleCtrlHandler(&consoleCtrlHandler,TRUE)); + hConsoleThread = CreateThread(NULL,0,ConsoleThreadProc,NULL,0,&consoleThreadID); + ASSERT(hConsoleThread); + if(bTelnet){ + AskDo(toSuppressGA); + AskWill(toTerminalType); + AskWill(toNAWS); + AskUnwill(toEcho); + AskDo(toEcho); + if(Envars && nEnvars) + AskWill(toNewEnviron); // *** Or better (what's better?) + // AskWill(toLineMode); + // *** STATUS + } +MSG msg; +int rvgm; + PostMessage(wsaW,WM_USERNOP,0,0); + VERIFY(SelectSocket()); + while(rvgm=GetMessage(&msg,NULL,NULL,NULL)){ + if(rvgm<0) + break; // Some wheeping needed + TranslateMessage(&msg); + DispatchMessage(&msg); +// LRESULT CALLBACK WSWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam); +// WSWndProc(msg.hwnd,msg.message,msg.wParam,msg.lParam); + VERIFY(SelectSocket()); + } + VERIFY(TerminateThread(hConsoleThread,0xFFFFFFFF)); + VERIFY(SetConsoleCtrlHandler(&consoleCtrlHandler,FALSE)); + closesocket(telnetSocket); + return TRUE; +} + +BOOL Telnet(LPCTSTR hostName,UINT port) +{ + memset(&remoteSIN,0,sizeof(remoteSIN)); + remoteSIN.sin_family = AF_INET; + remoteSIN.sin_port = htons(port); + + remoteSIN.sin_addr.s_addr = inet_addr(hostName); + if(remoteSIN.sin_addr.s_addr==INADDR_NONE){ + hostent* he = gethostbyname(hostName); + if(!he){ + printf("Failed to resolve host name\n"); + return FALSE; + } + ASSERT(he->h_addrtype==AF_INET); + ASSERT(he->h_length==sizeof(remoteSIN.sin_addr)); + memmove(&remoteSIN.sin_addr,*he->h_addr_list,sizeof(remoteSIN.sin_addr)); + } + strcpy(remoteHost,hostName); + return SINTelnet(remoteSIN); +} + + +void ProcessIACByte(BYTE c) +{ + connState = cstateNone; + switch(c){ + case tnIAC: + TerminalOut(c); + break; + case tnSE: + TRACE0("SE\n");break; + case tnNOP: + TRACE0("NOP\n");break; + case tnDM: + TRACE0("DM\n");break; + case tnBreak: + TRACE0("Break\n");break; + case tnIP: + TRACE0("IP\n");break; + case tnAO: + TRACE0("AO\n");break; + case tnAYT: + TRACE0("AYT\n");break; + case tnEC: + TRACE0("EC\n");break; + case tnEL: + TRACE0("EL\n");break; + case tnGA: + TRACE0("GA\n");break; + case tnSB: + connState = cstateSB; + break; + case tnWILL: + connState = cstateWILL; + break; + case tnWONT: + connState = cstateWONT; + break; + case tnDO: + connState = cstateDO; + break; + case tnDONT: + connState = cstateDONT; + break; + default: + TRACE1("Unknown OpCode = %d\n",(WORD)c); + break; + } +} + +void ProcessNetByte(BYTE c) +{ +// TRACE1("<%d>",connState); + switch(connState){ + case cstateWONT: + ProcessWONT(c); + break; + case cstateDO: + ProcessDO(c); + break; + case cstateWILL: + ProcessWILL(c); + break; + case cstateDONT: + ProcessDONT(c); + break; + case cstateSB: + negOption = c; + connState = cstateSBData; + break; + case cstateSBData: + case cstateSBDataIAC: + ProcessSBData(c); + break; + case cstateIAC: + ProcessIACByte(c); + break; + case cstateNone: + default: + ASSERT(connState==cstateNone); + if(c==tnIAC) + connState=cstateIAC; + else + TerminalOut(c); + break; + } +} + +LRESULT WSMessage(WPARAM wP,LPARAM lP) +{ + if(WSAGETSELECTERROR(lP)){ + TRACE0("SelectError\n"); + PostMessage(wsaW,WM_QUIT,0,0); + return 0; + } + if(WSAGETSELECTEVENT(lP)&FD_READ){ +//?? TRACE0("FD_READ\n"); + BYTE input[80*12]; + int got; + TerminalPreO(); +//?? TRACE0("rv\n"); + got=recv(telnetSocket,(CHAR*)input,sizeof(input),0); +//?? TRACE1("/rv %d\n",got); + for(int tmp=0;tmp ][ ]\n\n" + "Options are:\n" + "-r## or -##\tSet number of rows in console screenbuffer\n" + "-c##\t\tSet number of columns in console screenbuffer\n" + "\tnote: changing console screenbuffer size may not work properly\n" + "\twhen in full-screen mode\n" + "-l\tPass username to remote server in environment\n" + "-e=\tPass environment variable to remote server\n" + "-v=\tPass user environment variable to remote server\n" + "-t\tChange preferred terminal type\n" + "\tnote: there are only two different terminal emulations in this\n" + "\tbeta release - one for dumb terminal and one for vt terminal\n" + ); + CleanEnvars(); + return 1; + } + if(!InitializeWinsock()){ + DeinitializeWinsock(); + return 2; + } +CONSOLE_SCREEN_BUFFER_INFO csbi; +int ac = 0; +CHAR *ho = NULL, *po = NULL; +HANDLE hConsole = CreateFile("CONOUT$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL,OPEN_EXISTING,0,NULL); + ASSERT(hConsole); +// *** GetStdHandle(STD_OUTPUT_HANDLE); // *?*?* Do something about redirections and not only here. + VERIFY(GetConsoleScreenBufferInfo(hConsole,&csbi)); +BOOL bSized=FALSE; + bTermPulled=FALSE; + for(int tmp=1;tmp= VAR + CHAR* n = &v[2]; + CHAR* vv = strchr(&v[2],'='); + if(!vv) + goto usagebye; + *(vv++)=0; + VERIFY(AddEnvar(nesbVar,n,vv)); + }else if(v[1]=='v'){ // -v= USERVAR + CHAR* n = &v[2]; + CHAR* vv = strchr(n,'='); + if(!vv) + goto usagebye; + *(vv++)=0; + VERIFY(AddEnvar(nesbUserVar,n,vv)); + }else if(v[1]=='t'){ // -t -t= + CHAR* n = &v[2]; + CHAR* nn = strchr(n,'='); + if(nn){ + *(nn++)=0; + if(!*nn) + nn=NULL; + } + if(!TerminalPullType(nn?nn:n,nn?n:NULL)){ + printf("Available terminal types are:"); + TerminalPrintTypes(); + printf("\n"); + goto usagebye; + } + bTermPulled=TRUE; + }else if(v[1]=='#'){ + int cp = atoi(&v[2]); +#ifdef _DEBUG + TRACE2("SetCP(%d)=%d\n",cp,SetConsoleCP(cp)); + TRACE2("SetOutCP(%d)=%d\n",cp,SetConsoleOutputCP(cp)); +#else + SetConsoleCP(cp); + SetConsoleOutputCP(cp); +#endif + TRACE2("CP,OCP=%d,%d\n",GetConsoleCP(),GetConsoleOutputCP()); + }else + goto usagebye; + }else{ + if(ac==0){ + ho = v; + ac++; + }else if(ac==1){ + po = v; + ac++; + }else + goto usagebye; + } + } + if(!ho) + goto usagebye; +servent* se = getservbyname("telnet","tcp"); +UINT port = po?atol(po):(se?ntohs(se->s_port):23); + if(port==23 || (se && port==ntohs(se->s_port))) + bTelnet = TRUE; + if(po && !port){ + se = getservbyname(po,"tcp"); + if(!se){ + printf("Failed to resolve tcp-service port name\n"); + DeinitializeWinsock(); + return 2; + } + port = ntohs(se->s_port); + if(!stricmp(po,"telnet")) + bTelnet = TRUE; + else + bTelnet = FALSE; + }else{ + se = getservbyport(htons(port),"tcp"); + if(se){ + po = se->s_name; + if(!stricmp(po,"telnet")) + bTelnet=TRUE; + }else{ + VERIFY(_itoa(port,remoteProt,10)); + po = NULL; + bTelnet=FALSE; + } + } + if(po) + strcpy(remoteProt,po); +HICON hIcon = LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(IDI_IKON)); +LONG oldBIcon = NULL, oldSIcon = NULL; + hConsoleWindow = GetThisConsoleWnd(); + if(hConsoleWindow){ + oldBIcon = SendMessage(hConsoleWindow,WM_SETICON,ICON_BIG,(LPARAM)hIcon); + oldSIcon = SendMessage(hConsoleWindow,WM_SETICON,ICON_SMALL,(LPARAM)hIcon); + } + Telnet(ho,port); + CleanEnvars(); + if(hConsoleWindow){ + SendMessage(hConsoleWindow,WM_SETICON,ICON_BIG,(LPARAM)oldBIcon); + SendMessage(hConsoleWindow,WM_SETICON,ICON_SMALL,(LPARAM)oldSIcon); + } + Sleep(150); + if(bSized){ + CONSOLE_SCREEN_BUFFER_INFO CSBI; + VERIFY(GetConsoleScreenBufferInfo(hConsole,&CSBI)); + if(CSBI.dwSize.Y>csbi.dwSize.Y || CSBI.dwSize.X>csbi.dwSize.X){ + SMALL_RECT wi = {0,0,csbi.dwSize.X-1,csbi.dwSize.Y-1}; + VERIFY(SetConsoleWindowInfo(hConsole,TRUE,&wi)); + } + COORD ns = {csbi.dwSize.X,csbi.dwSize.Y}; + VERIFY(SetConsoleScreenBufferSize(hConsole,ns)); + } + Sleep(100); + DeinitializeWinsock(); + Sleep(100); + return 0; +} diff --git a/kinsole.mak b/kinsole.mak new file mode 100644 index 0000000..b25a32d --- a/dev/null +++ b/kinsole.mak @@ -0,0 +1,612 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Install - Win32 Debug +!MESSAGE No configuration specified. Defaulting to Install - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "KINSole - Win32 Release" && "$(CFG)" !=\ + "KINSole - Win32 Debug" && "$(CFG)" != "Install - Win32 Release" && "$(CFG)" !=\ + "Install - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "kinsole.mak" CFG="Install - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "KINSole - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "KINSole - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "Install - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "Install - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Install - Win32 Debug" + +!IF "$(CFG)" == "KINSole - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +OUTDIR=.\Release +INTDIR=.\Release +# Begin Custom Macros +OutDir=.\Release +TargetName=kinsole +# End Custom Macros + +ALL : "$(OUTDIR)\kinsole.exe" "$(OUTDIR)\kinsole.ex_" "$(OUTDIR)\kinsole.hlp"\ + "$(OUTDIR)\kinsole.cnt" "$(OUTDIR)\kinsole.hl_" "$(OUTDIR)\kinsole.cn_" + +CLEAN : + -@erase "$(INTDIR)\kinsole.cn_" + -@erase "$(INTDIR)\kinsole.cnt" + -@erase "$(INTDIR)\kinsole.hl_" + -@erase "$(INTDIR)\kinsole.hlp" + -@erase "$(INTDIR)\KINSole.obj" + -@erase "$(INTDIR)\KINSole.res" + -@erase "$(OUTDIR)\kinsole.ex_" + -@erase "$(OUTDIR)\kinsole.exe" + -@erase "$(OUTDIR)\kinsole.map" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /c +# SUBTRACT CPP /YX +CPP_PROJ=/nologo /ML /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS=.\. + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/KINSole.res" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/kinsole.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:console /map /machine:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib wsock32.lib /nologo /subsystem:console /incremental:no\ + /pdb:"$(OUTDIR)/kinsole.pdb" /map:"$(INTDIR)/kinsole.map" /machine:I386\ + /out:"$(OUTDIR)/kinsole.exe" +LINK32_OBJS= \ + "$(INTDIR)\KINSole.obj" \ + "$(INTDIR)\KINSole.res" + +"$(OUTDIR)\kinsole.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +# Begin Custom Build - Performing Custom Build Step +OutDir=.\Release +TargetName=kinsole +InputPath=.\Release\kinsole.exe +SOURCE=$(InputPath) + +"$(OutDir)\$(TargetName).ex_" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + compress $(OutDir)\$(TargetName).exe $(OutDir)\$(TargetName).ex_ + +# End Custom Build + +!ELSEIF "$(CFG)" == "KINSole - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +TargetName=kinsole +# End Custom Macros + +ALL : "$(OUTDIR)\kinsole.exe" "$(OUTDIR)\kinsole.ex_" "$(OUTDIR)\kinsole.hlp"\ + "$(OUTDIR)\kinsole.cnt" "$(OUTDIR)\kinsole.hl_" "$(OUTDIR)\kinsole.cn_" + +CLEAN : + -@erase "$(INTDIR)\kinsole.cn_" + -@erase "$(INTDIR)\kinsole.cnt" + -@erase "$(INTDIR)\kinsole.hl_" + -@erase "$(INTDIR)\kinsole.hlp" + -@erase "$(INTDIR)\KINSole.obj" + -@erase "$(INTDIR)\KINSole.res" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(OUTDIR)\kinsole.ex_" + -@erase "$(OUTDIR)\kinsole.exe" + -@erase "$(OUTDIR)\kinsole.ilk" + -@erase "$(OUTDIR)\kinsole.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_AFXDLL" /D "_MBCS" /c +# SUBTRACT CPP /YX +CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /D "_AFXDLL" /D "_MBCS" /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS=.\. + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/KINSole.res" /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/kinsole.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 wsock32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib /nologo /subsystem:console /incremental:yes\ + /pdb:"$(OUTDIR)/kinsole.pdb" /debug /machine:I386 /out:"$(OUTDIR)/kinsole.exe" +LINK32_OBJS= \ + "$(INTDIR)\KINSole.obj" \ + "$(INTDIR)\KINSole.res" + +"$(OUTDIR)\kinsole.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +# Begin Custom Build +OutDir=.\Debug +TargetName=kinsole +InputPath=.\Debug\kinsole.exe +SOURCE=$(InputPath) + +"$(OutDir)\$(TargetName).ex_" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + compress $(OutDir)\$(TargetName).exe $(OutDir)\$(TargetName).ex_ + +# End Custom Build + +!ELSEIF "$(CFG)" == "Install - Win32 Release" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Install\Release" +# PROP BASE Intermediate_Dir "Install\Release" +# PROP BASE Target_Dir "Install" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Install\Release" +# PROP Intermediate_Dir "Install\Release" +# PROP Target_Dir "Install" +OUTDIR=.\Install\Release +INTDIR=.\Install\Release + +ALL : "KINSole - Win32 Release" "$(OUTDIR)\Install.exe" + +CLEAN : + -@erase "$(INTDIR)\install.obj" + -@erase "$(INTDIR)\Install.res" + -@erase "$(OUTDIR)\Install.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D\ + "_MBCS" /Fp"$(INTDIR)/Install.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Install\Release/ +CPP_SBRS=.\. + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +MTL=mktyplib.exe +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /win32 +MTL_PROJ=/nologo /D "NDEBUG" /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/Install.res" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/Install.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /machine:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib version.lib /nologo /subsystem:windows /incremental:no\ + /pdb:"$(OUTDIR)/Install.pdb" /machine:I386 /out:"$(OUTDIR)/Install.exe" +LINK32_OBJS= \ + "$(INTDIR)\install.obj" \ + "$(INTDIR)\Install.res" + +"$(OUTDIR)\Install.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Install - Win32 Debug" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Install\Debug" +# PROP BASE Intermediate_Dir "Install\Debug" +# PROP BASE Target_Dir "Install" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Install\Debug" +# PROP Intermediate_Dir "Install\Debug" +# PROP Target_Dir "Install" +OUTDIR=.\Install\Debug +INTDIR=.\Install\Debug + +ALL : "KINSole - Win32 Debug" "$(OUTDIR)\Install.exe" + +CLEAN : + -@erase "$(INTDIR)\install.obj" + -@erase "$(INTDIR)\Install.res" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(OUTDIR)\Install.exe" + -@erase "$(OUTDIR)\Install.ilk" + -@erase "$(OUTDIR)\Install.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /D "_MBCS" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /c +CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\ + /D "_MBCS" /Fp"$(INTDIR)/Install.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Install\Debug/ +CPP_SBRS=.\. + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +MTL=mktyplib.exe +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /win32 +MTL_PROJ=/nologo /D "_DEBUG" /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/Install.res" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/Install.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /debug /machine:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib version.lib /nologo /subsystem:windows /incremental:yes\ + /pdb:"$(OUTDIR)/Install.pdb" /debug /machine:I386 /out:"$(OUTDIR)/Install.exe" +LINK32_OBJS= \ + "$(INTDIR)\install.obj" \ + "$(INTDIR)\Install.res" + +"$(OUTDIR)\Install.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +################################################################################ +# Begin Target + +# Name "KINSole - Win32 Release" +# Name "KINSole - Win32 Debug" + +!IF "$(CFG)" == "KINSole - Win32 Release" + +!ELSEIF "$(CFG)" == "KINSole - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\KINSole.cpp +DEP_CPP_KINSO=\ + ".\NAWS.cpp"\ + ".\NEW-ENVIRON.cpp"\ + ".\options.cpp"\ + ".\status.cpp"\ + ".\terminal.cpp"\ + ".\TIMING-MARK.cpp"\ + ".\TTY.cpp"\ + ".\VT100.cpp"\ + + +"$(INTDIR)\KINSole.obj" : $(SOURCE) $(DEP_CPP_KINSO) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\kinsole.rc +DEP_RSC_KINSOL=\ + ".\res\kinsole.ico"\ + + +"$(INTDIR)\KINSole.res" : $(SOURCE) $(DEP_RSC_KINSOL) "$(INTDIR)" + $(RSC) $(RSC_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\VT100.cpp +# PROP Exclude_From_Build 1 +# End Source File +################################################################################ +# Begin Source File + +SOURCE=".\NEW-ENVIRON.cpp" +# PROP Exclude_From_Build 1 +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\help\kinsole.hpj + +!IF "$(CFG)" == "KINSole - Win32 Release" + +# Begin Custom Build - Building Help +OutDir=.\Release +TargetName=kinsole +InputPath=.\help\kinsole.hpj + +BuildCmds= \ + makehelp \ + compress $(OutDir)\$(TargetName).hlp $(OutDir)\$(TargetName).hl_ \ + compress $(OutDir)\$(TargetName).cnt $(OutDir)\$(TargetName).cn_ \ + + +"$(OutDir)\$(TargetName).hlp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(OutDir)\$(TargetName).cnt" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(OutDir)\$(TargetName).hl_" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(OutDir)\$(TargetName).cn_" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ELSEIF "$(CFG)" == "KINSole - Win32 Debug" + +# Begin Custom Build - Building Help +OutDir=.\Debug +TargetName=kinsole +InputPath=.\help\kinsole.hpj + +BuildCmds= \ + makehelp \ + compress $(OutDir)\$(TargetName).hlp $(OutDir)\$(TargetName).hl_ \ + compress $(OutDir)\$(TargetName).cnt $(OutDir)\$(TargetName).cn_ \ + + +"$(OutDir)\$(TargetName).hlp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(OutDir)\$(TargetName).cnt" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(OutDir)\$(TargetName).hl_" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(OutDir)\$(TargetName).cn_" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) +# End Custom Build + +!ENDIF + +# End Source File +# End Target +################################################################################ +# Begin Target + +# Name "Install - Win32 Release" +# Name "Install - Win32 Debug" + +!IF "$(CFG)" == "Install - Win32 Release" + +!ELSEIF "$(CFG)" == "Install - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\Install\Install.rc +DEP_RSC_INSTA=\ + ".\Install\Custom.rch"\ + ".\shared-data\install-icon.ico"\ + + +!IF "$(CFG)" == "Install - Win32 Release" + + +"$(INTDIR)\Install.res" : $(SOURCE) $(DEP_RSC_INSTA) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)/Install.res" /i "Install" /d "NDEBUG"\ + $(SOURCE) + + +!ELSEIF "$(CFG)" == "Install - Win32 Debug" + + +"$(INTDIR)\Install.res" : $(SOURCE) $(DEP_RSC_INSTA) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)/Install.res" /i "Install" /d "_DEBUG"\ + $(SOURCE) + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\Install\install.cpp +DEP_CPP_INSTAL=\ + ".\shared-code\install.h"\ + + +"$(INTDIR)\install.obj" : $(SOURCE) $(DEP_CPP_INSTAL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Project Dependency + +# Project_Dep_Name "KINSole" + +!IF "$(CFG)" == "Install - Win32 Release" + +"KINSole - Win32 Release" : + $(MAKE) /$(MAKEFLAGS) /F ".\kinsole.mak" CFG="KINSole - Win32 Release" + +!ELSEIF "$(CFG)" == "Install - Win32 Debug" + +"KINSole - Win32 Debug" : + $(MAKE) /$(MAKEFLAGS) /F ".\kinsole.mak" CFG="KINSole - Win32 Debug" + +!ENDIF + +# End Project Dependency +################################################################################ +# Begin Source File + +SOURCE=.\help\kinsole.hpj + +!IF "$(CFG)" == "Install - Win32 Release" + +!ELSEIF "$(CFG)" == "Install - Win32 Debug" + +!ENDIF + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/kinsole.rc b/kinsole.rc new file mode 100644 index 0000000..b789f37 --- a/dev/null +++ b/kinsole.rc @@ -0,0 +1,115 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_IKON ICON DISCARDABLE "res/kinsole.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,3 + PRODUCTVERSION 1,0,0,3 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x29L +#else + FILEFLAGS 0x28L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x3L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Klever Group (http://www.klever.net)\0" + VALUE "FileDescription", "KINSole, telnet client\0" + VALUE "FileVersion", "1, 0, 0, 3\0" + VALUE "InternalName", "KINSOLE\0" + VALUE "LegalCopyright", "Copyright © 1998, 2002 Klever Group (http://www.klever.net/)\0" + VALUE "LegalTrademarks", "Klever Group (http://www.klevernet/)\0" + VALUE "OriginalFilename", "KINSOLE.EXE\0" + VALUE "ProductName", "KINSole\0" + VALUE "ProductVersion", "1, 0, 0, 3\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/makehelp.bat b/makehelp.bat new file mode 100644 index 0000000..531b2dc --- a/dev/null +++ b/makehelp.bat @@ -0,0 +1,11 @@ +@echo off +echo Building RTF file +xsltproc -o help/kinsole.rtf shared-code/kinhelp.xsl help/kinsole.xml +echo Building Win32 Help files +start /wait hcrtf -x "help\kinsole.hpj" +echo. +if exist Debug\nul copy "help\kinsole.hlp" Debug +if exist Debug\nul copy "help\kinsole.cnt" Debug +if exist Release\nul copy "help\kinsole.hlp" Release +if exist Release\nul copy "help\kinsole.cnt" Release +echo. diff --git a/options.cpp b/options.cpp new file mode 100644 index 0000000..171ae4a --- a/dev/null +++ b/options.cpp @@ -0,0 +1,371 @@ + +enum _TOption { + toBinaryTransmission = 0, + toEcho = 1, // Done. + toReconnection = 2, + toSuppressGA = 3, // Eaten + toApproxMsgSizeNegotiation = 4, + toStatus = 5, // Half-implemented + toTimingMark = 6, + toRemoteControlledTransAndEcho = 7, + toOutputLineWidth = 8, + toOutputPageSize = 9, + toOutputCRDisposition = 10, + toOutputHTabstops = 11, + toOutputHTabDisposition = 12, + toOutputFFDisposition = 13, + toOutputVTabstops = 14, + toOutputVTabDisposition = 15, + toOutputLFDisposition = 16, + toExtendedASCII = 17, + toLogout = 18, + toByteMacro = 19, + toDET = 20, + toSUPDUP = 22, // ??? + toSUPDUPOutput = 22, + toSendLocation = 23, + toTerminalType =24, // Done. + toEndOfRecord = 25, + toTACACSUserId = 26, + toOutputMarking = 27, + toTerminalLocationNumber = 28, + toTelnet3270Regime = 29, + toX3PAD = 30, + toNAWS = 31, // Done. + toTerminalSpeed = 32, // No need to implement, really. + toRemoteFlowControl = 33, // !!! + toLineMode = 34, + toXDisplayLocation = 35, // No need to implement until we + // do our own X-Server. + toEnvironmentOption = 36, + toAuthenticationOption = 37, + toEncryptionOption = 38, + toNewEnviron = 39, // Need to implement + toTN3270E = 40, + toExtendedOptionsList = 255 +}; + +struct TOption { + enum _state { + stateNone=0, stateNo, stateYes, stateWantNo, stateWantYes + }; + UINT m_StateU:3; // State - US + UINT m_StateH:3; // State - HIM + int m_Q:1; + int m_Supported:1; + UINT m_SBCluster; + UINT m_AllocatedSB; + UINT m_StoredSB; + LPBYTE m_SB; + + BOOL (*m_OnDo)(); + BOOL (*m_OnDont)(); + BOOL (*m_OnWill)(); + BOOL (*m_OnWont)(); + BOOL (*m_OnSB)(LPBYTE data,UINT size); + BOOL (*m_OnInit)(); + + BOOL OnDo() { return m_OnDo?(*m_OnDo)():FALSE; } + BOOL OnDont() { return m_OnDont?(*m_OnDont)():FALSE; } + BOOL OnWill() { return m_OnWill?(*m_OnWill)():FALSE; } + BOOL OnWont() { return m_OnWont?(*m_OnWont)():FALSE; } + BOOL OnSB(LPBYTE data,UINT size) { return m_OnSB?(*m_OnSB)(data,size):FALSE; } + BOOL OnInit() { return m_OnInit?(*m_OnInit)():FALSE; } + + BOOL StoreSByte(BYTE c) { + if(m_AllocatedSB>=m_StoredSB){ + ASSERT(m_SBCluster); + LPBYTE nsb = new BYTE[m_AllocatedSB+m_SBCluster]; + ASSERT(nsb); + if(m_StoredSB){ + ASSERT(m_SB); + memmove(nsb,m_SB,m_StoredSB); + } + if(m_SB) + delete m_SB; + m_SB = nsb; + } + ASSERT(m_SB); + m_SB[m_StoredSB++]=c; + return TRUE; + } + BOOL CleanSB() { + if(m_SB) + delete m_SB; + m_SB = NULL; + m_AllocatedSB=m_StoredSB=0; + return TRUE; + } + +} Options[256]; + + +BOOL AskWill(BYTE o); +BOOL AskWont(BYTE o); +BOOL AskDo(BYTE o); +BOOL AskDont(BYTE o); + +#include "NAWS.cpp" +#include "terminal.cpp" +#include "status.cpp" +#include "NEW-ENVIRON.cpp" +#include "TIMING-MARK.cpp" + +BOOL On_ACK() { return TRUE; } + + +void InitOptionsTable() +{ + memset(Options,0,sizeof(Options)); + // Echo + Options[toEcho].m_OnDo = On_ACK; + Options[toEcho].m_OnDont = On_ACK; + Options[toEcho].m_OnWill = On_ACK; + Options[toEcho].m_OnWont = On_ACK; + // Suppress Go-Ahead + Options[toSuppressGA].m_OnWill = On_ACK; + Options[toSuppressGA].m_OnDo = On_ACK; + // Status + Options[toStatus].m_OnWill = statusOnWill; + Options[toStatus].m_OnDo = statusOnDo; + Options[toStatus].m_OnSB = statusOnSB; + // Terminal Type; + Options[toTerminalType].m_OnDo = terminaltypeOnDo; + Options[toTerminalType].m_OnSB = terminaltypeOnSB; + Options[toTerminalType].m_OnInit = terminaltypeOnInit; + Options[toTerminalType].m_SBCluster = 32; + // NAWS + Options[toNAWS].m_OnDo = nawsOnDo; + Options[toNAWS].m_SBCluster = 16; + // New Environment + Options[toNewEnviron].m_OnDo = newenvironOnDo; + Options[toNewEnviron].m_OnDont = newenvironOnDont; + Options[toNewEnviron].m_OnSB = newenvironOnSB; + Options[toNewEnviron].m_SBCluster = 32; + // Timing Mark + Options[toTimingMark].m_OnDo = tmOnDo; + Options[toTimingMark].m_OnWill = tmOnWill; + + for(int tmp=0;tmp<(sizeof(Options)/sizeof(*Options));tmp++){ + TOption& to = Options[tmp]; + to.OnInit(); + if(to.m_OnDo || to.m_OnDont || to.m_OnWill || to.m_OnWont + || to.m_OnSB || to.m_OnInit) + to.m_Supported=TRUE; + if(!to.m_SBCluster) + to.m_SBCluster=128; + } +} + +void ProcessDO(BYTE c) +{ +TOption& to = Options[c]; + // Ignore this junk if we're already in desired mode of operation + if(to.m_StateU==TOption::stateYes){ + connState = cstateNone; + return; + } + TRACE1("He want us to DO %d\n",(WORD)c); + if(!to.m_Supported){ + TRACE1("Unsupported option = %d\n",(WORD)c); + // Option is not suported - send WONT and switch to stateNo unless + // we've already denied this option. + if(to.m_StateU == TOption::stateNone){ + VERIFY(ShowUnwill(c)); + to.m_StateU = TOption::stateNo; + } + }else{ + // Okay, if we do - we do and tell him so, unless we asked for it. + // Otherwise - Tell him we're not about to. + if(to.OnDo()){ + if(to.m_StateU!=TOption::stateWantYes) + VERIFY(ShowWill(c)); + to.m_StateU = TOption::stateYes; + }else{ + if(to.m_StateU!=TOption::stateWantNo) + VERIFY(ShowUnwill(c)); + to.m_StateU = TOption::stateNo; + } + } + connState = cstateNone; +} + +void ProcessWILL(BYTE c) +{ +TOption& to = Options[c]; + // Ignore this junk if we consider him already in this mode + if(to.m_StateH==TOption::stateYes){ + connState = cstateNone; + return; + } + TRACE1("He WILL %d\n",(WORD)c); + if(!to.m_Supported){ + TRACE1("Unsupported option = %d\n",(WORD)c); + // Since we don't expect remote end to use this option - beg him + // not to go for it unless we think we already did. + if(to.m_StateH == TOption::stateNone){ + VERIFY(BegDont(c)); + to.m_StateH = TOption::stateNo; + } + }else{ + if(to.OnWill()){ + // We've accepted this - tell him to go ahead if we thought he's + // in opposite state and adjust our vision/ + if(to.m_StateH!=TOption::stateWantYes) + VERIFY(BegDo(c)); + to.m_StateH = TOption::stateYes; + }else{ + if(to.m_StateH!=TOption::stateWantNo) + VERIFY(BegDont(c)); + to.m_StateH = TOption::stateNo; + } + } + connState = cstateNone; +} + +void ProcessWONT(BYTE c) +{ +TOption& to = Options[c]; + // Ignore this junk if we consider him already in this mode + if(to.m_StateH==TOption::stateNo){ + connState = cstateNone; + return; + } + TRACE1("He WONT %d\n",(WORD)c); + if(!to.m_Supported){ + TRACE1("Unsupported option = %d\n",(WORD)c); + // Since we don't expect remote end to use this option - beg him + // not to go for it unless we think we already did. + if(to.m_StateH == TOption::stateNone){ + VERIFY(BegDont(c)); + to.m_StateH = TOption::stateNo; + } + }else{ + if(to.OnWont()){ + // We've accepted this - tell him to go ahead if we thought he's + // in opposite state and adjust our vision/ + if(to.m_StateH!=TOption::stateWantNo) + VERIFY(BegDont(c)); + to.m_StateH = TOption::stateNo; + }else{ + if(to.m_StateH!=TOption::stateWantYes) + VERIFY(BegDo(c)); + to.m_StateH = TOption::stateYes; + } + } + connState = cstateNone; +} + +void ProcessDONT(BYTE c) +{ +TOption& to = Options[c]; + // Ignore this junk if we consider him already in this mode + if(to.m_StateU==TOption::stateNo){ + connState = cstateNone; + return; + } + TRACE1("He want us to DONT %d\n",(WORD)c); + if(!to.m_Supported){ + TRACE1("DONT for unsupported option = %d\n",(WORD)c); + // Since we don't expect remote end to use this option - beg him + // not to go for it unless we think we already did. + if(to.m_StateU == TOption::stateNone){ + VERIFY(ShowUnwill(c)); + to.m_StateU = TOption::stateNo; + } + }else{ + if(to.OnDont()){ + if(to.m_StateU!=TOption::stateWantNo) + VERIFY(ShowUnwill(c)); + to.m_StateU = TOption::stateNo; + }else{ + if(to.m_StateU!=TOption::stateWantYes) + VERIFY(ShowWill(c)); + to.m_StateU = TOption::stateYes; + } + } + connState = cstateNone; +} + +void ProcessSBData(BYTE c) +{ + switch(connState){ + case cstateSBData: + if(c==tnIAC){ + connState=cstateSBDataIAC; + return; + } + break; + case cstateSBDataIAC: + if(c==tnSE){ + // Just let option handler process the data + TOption& to = Options[negOption]; + to.OnSB(to.m_SB,to.m_StoredSB); + to.CleanSB(); + connState = cstateNone; + return; + } + break; + default: + ASSERT(FALSE); + break; + } +TOption& to = Options[negOption]; + to.StoreSByte(c); +} + +BOOL AskWill(BYTE o) +{ +TOption& to = Options[o]; + if(to.m_StateU==TOption::stateYes || to.m_StateU==TOption::stateWantYes) + return TRUE; +#ifdef _DEBUG + if(to.m_StateU==TOption::stateWantNo) + TRACE1("NEED TO QUEUE %d\n",(WORD)o); +#endif + VERIFY(ShowWill(o)); + to.m_StateU=TOption::stateWantYes; + return TRUE; +} + +BOOL AskUnwill(BYTE o) +{ +TOption& to = Options[o]; + if(to.m_StateU==TOption::stateNo || to.m_StateU==TOption::stateWantNo) + return TRUE; +#ifdef _DEBUG + if(to.m_StateU==TOption::stateWantNo) + TRACE1("NEED TO QUEUE %d\n",(WORD)o); +#endif + VERIFY(ShowUnwill(o)); + to.m_StateU=TOption::stateWantNo; + return TRUE; +} + +BOOL AskDo(BYTE o) +{ +TOption& to = Options[o]; + if(to.m_StateH==TOption::stateYes || to.m_StateH==TOption::stateWantYes) + return TRUE; +#ifdef _DEBUG + if(to.m_StateH==TOption::stateWantNo) + TRACE1("NEED TO QUEUE %d\n",(WORD)o); +#endif + VERIFY(BegDo(o)); + to.m_StateH=TOption::stateWantYes; + return TRUE; +} + +BOOL AskDont(BYTE o) +{ +TOption& to = Options[o]; + if(to.m_StateH==TOption::stateNo || to.m_StateH==TOption::stateWantNo) + return TRUE; +#ifdef _DEBUG + if(to.m_StateH==TOption::stateWantYes) + TRACE1("NEED TO QUEUE %d\n",(WORD)o); +#endif + VERIFY(BegDont(o)); + to.m_StateH=TOption::stateWantNo; + return TRUE; +} diff --git a/res/kinsole.ico b/res/kinsole.ico new file mode 100644 index 0000000..e355485 --- a/dev/null +++ b/res/kinsole.ico Binary files differ diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..64dd500 --- a/dev/null +++ b/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by KINSole.rc +// +#define IDI_IKON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/shared-code/BTreendex.h b/shared-code/BTreendex.h new file mode 100644 index 0000000..88109ab --- a/dev/null +++ b/shared-code/BTreendex.h @@ -0,0 +1,595 @@ +#ifndef __BTREENDEX_H +#define __BTREENDEX_H + +#include "Dynamide.h" + +namespace Klever { + +template +class CBTreendex : public CObject { +public: + typedef LONG CBTPageRef; + struct CBTRecordRef { + CBTPageRef m_Page; + INT m_Offset; + CBTRecordRef(CBTPageRef page=-1,INT offset=-1) : m_Page(page), m_Offset(offset) {} + }; + class CBTRecord : public CObject { + public: + CBTPageRef m_ptrLeft; + CBTPageRef m_ptrRight; + key m_Key; + value m_Value; + CBTRecord() : m_ptrLeft(-1), m_ptrRight(-1) {} + CBTRecord(key& _key,value& _value,CBTPageRef left=-1,CBTPageRef right=-1) : m_Key(_key), m_Value(_value), m_ptrLeft(left), m_ptrRight(right) {} + CBTRecord(CBTRecord& r) : m_Key(r.m_Key), m_Value(r.m_Value), m_ptrLeft(r.m_ptrLeft), m_ptrRight(r.m_ptrRight) {} + + CBTRecord& operator=(CBTRecord& r) {m_Key=r.m_Key, m_Value=r.m_Value, m_ptrLeft=r.m_ptrLeft, m_ptrRight=r.m_ptrRight;return *this;} + + void Serialize(CArchive& ar) { + if(ar.IsStoring()){ + ar << m_ptrLeft; + ar << m_ptrRight; + }else{ + ar >> m_ptrLeft; + ar >> m_ptrRight; + } + SerializeElements(ar,&m_Key,1); + SerializeElements(ar,&m_Value,1); + } + }; + class CBTPage : public CArray { + public: + void Serialize(CArchive& ar) { + int nCount = -1; + if(ar.IsStoring()){ + nCount = GetSize(); + ar << nCount; + }else{ + nCount = 0; + ar >> nCount; + RemoveAll(); + SetSize(nCount); + } + for(int tmp=0;tmp CBTDyna; + typedef CBTDyna::CDynaFile CBTDynaFile; + typedef CArray CBTRStack; + + CBTDyna m_BT; + struct _btCrap { + BOOL m_bRootSet; + CBTPageRef m_Root; + } *m_BTCrap; + BOOL m_bRO; + CBTRStack m_btStack; + CBTPage m_stackTop; + + CBTreendex() {} + ~CBTreendex() { Close(); } + BOOL Attach(CFile* file,BOOL bAutodelete) { + m_bRO = FALSE; + if(!m_BT.Attach(file,bAutodelete)) + return FALSE; + return Attach(); + } + BOOL Open(LPCTSTR file,BOOL bReadOnly) { + if(!m_BT.Open(file,bReadOnly)) + return FALSE; + m_bRO = bReadOnly; + return Attach(); + } + BOOL Create(LPCTSTR file) { + try{ + CFile* f = new CFile(file,CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyRead|CFile::shareDenyWrite|CFile::typeBinary); + ASSERT(f); + return Attach(f,TRUE); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + } + BOOL Attach() { + ASSERT(m_BT.IsOpened()); + m_BTCrap = (_btCrap*)m_BT.m_FB.crap; + if(!m_BTCrap->m_bRootSet){ + m_BTCrap->m_Root = AllocatePage(); + if(m_BTCrap->m_Root<0) + return FALSE; + m_BTCrap->m_bRootSet = TRUE; + m_BT.Write1stBlock(); + } + return TRUE; + } + BOOL Close() { + m_BT.Close(); + return TRUE; + } + BOOL IsOpened() { + return m_BT.IsOpened(); + } + + BOOL Lookup(key& _key,value& value) { + if(!IsOpened()) + return FALSE; + ASSERT(m_BTCrap->m_bRootSet); + if(!SeekToPage(_key)) + return FALSE; + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(rr.m_Offset<0) + return FALSE; + ASSERT(rr.m_Offsetm_bRootSet); + if(!SeekToPage(_key)) + return FALSE; + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + CBTRecord nuRecord(_key,_value); + if(rr.m_Offset<0){ + if(m_stackTop.GetSize()) + nuRecord.m_ptrLeft = m_stackTop[m_stackTop.GetUpperBound()].m_ptrRight; + }else if(rr.m_Offset==0){ + nuRecord.m_ptrRight = m_stackTop[0].m_ptrLeft; + }else{ + nuRecord.m_ptrLeft = m_stackTop[rr.m_Offset-1].m_ptrRight; + nuRecord.m_ptrRight = m_stackTop[rr.m_Offset].m_ptrLeft; + } +// ASSERT(rr.m_Offset==0 || (m_stackTop[rr.m_Offset-1].m_Key<_key && m_stackTop[rr.m_Offset-1].m_ptrRight<0)); +// ASSERT(rr.m_Offset<0 || m_stackTop[rr.m_Offset].m_Key>=_key && m_stackTop[rr.m_Offset].m_ptrLeft<0); + if(rr.m_Offset>=0 && m_stackTop[rr.m_Offset].m_Key==_key){ + // Exact match found - just replace. + m_stackTop[rr.m_Offset].m_Value = _value; + if(!SavePage(rr.m_Page,m_stackTop)) + return FALSE; + return TRUE; + } + // Split the page and propagate the split if needed.. + // Insert new element at rr.m_Offset.. + BOOL nuisnew = TRUE; + for(int sp=m_btStack.GetUpperBound();sp>=0;sp--){ + CBTPageRef opr = m_btStack[sp].m_Page; + int iAt = m_btStack[sp].m_Offset; + CBTPage op; + VERIFY(LoadPage(opr,op)); + if(iAt<0) + iAt = op.GetSize(); + else{ + if(op[iAt].m_Key nuRecord.m_Key); + } + op.InsertAt(iAt,nuRecord); + if(iAt>0) + op[iAt-1].m_ptrRight=nuRecord.m_ptrLeft; + if(iAt=0); + CBTPage np; + ASSERT(LoadPage(npr,np)); + ASSERT(!np.GetSize()); + nuRecord = op[treeOrder]; + if(iAt==treeOrder){ + // We're inserting central element! - drop out the stack top if this is still new one + for(int tmp=0;tmp=0); + CBTPage nurpa; + ASSERT(LoadPage(nuroot,nurpa)); + ASSERT(!nurpa.GetSize()); + nurpa.Add(nuRecord); + VERIFY(SavePage(nuroot,nurpa)); + m_btStack.InsertAt(0,CBTRecordRef(nuroot,0)); + m_BTCrap->m_Root = nuroot; + m_BT.Write1stBlock(); + return TRUE; + } + BOOL Delete(key& _key) { + if(!IsOpened()) + return FALSE; + ASSERT(m_BTCrap->m_bRootSet); + value _value; + if(!Lookup(_key,_value)) + return FALSE; + // Found key, check if it's a leaf + { + CBTRecordRef* rr = &m_btStack[m_btStack.GetUpperBound()]; + int rrIdx = m_btStack.GetUpperBound(); + if(m_stackTop[rr->m_Offset].m_ptrLeft>=0){ + ASSERT(m_stackTop[rr->m_Offset].m_ptrRight>=0); + // It isn't - scan for the _next_ key and do dirty deeds + m_btStack.Add(CBTRecordRef(m_stackTop[rr->m_Offset].m_ptrRight,0)); + for(;;){ + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + if(m_stackTop[0].m_ptrLeft<0) + break; + m_btStack.Add(CBTRecordRef(m_stackTop[0].m_ptrLeft,0)); + } + // We have a leaf node here, replace victim with the first element and kill it. + CBTPage uppage; + rr = &m_btStack[rrIdx]; + if(!LoadPage(rr->m_Page,uppage)) + return FALSE; + uppage[rr->m_Offset].m_Key=m_stackTop[0].m_Key; uppage[rr->m_Offset].m_Value=m_stackTop[0].m_Value; + m_stackTop.RemoveAt(0); + if(!(SavePage(rr->m_Page,uppage) && SavePage(m_btStack[m_btStack.GetUpperBound()].m_Page,m_stackTop))) + return FALSE; + }else{ + ASSERT(m_stackTop[rr->m_Offset].m_ptrRight<0); + m_stackTop.RemoveAt(rr->m_Offset); + if(!SavePage(rr->m_Page,m_stackTop)) + return FALSE; + } + } + // We have a page to check for underflow at the top of the stack now. + for(;;){ + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + if(m_stackTop.GetSize()>=treeOrder || m_btStack.GetSize()==1) + return TRUE; + CBTRecordRef& rr1 = m_btStack[m_btStack.GetUpperBound()-1]; + CBTPage daddy; + if(!LoadPage(rr1.m_Page,daddy)) + return FALSE; + CBTPageRef nPage = daddy[rr1.m_Offset].m_ptrRight; + BOOL bRight=TRUE; + if(nPage<0 || nPage==rr.m_Page){ + nPage = daddy[rr1.m_Offset].m_ptrLeft; + bRight = FALSE; + } + ASSERT(nPage>=0 && nPage!=rr.m_Page); + CBTPage neighbor; + if(!LoadPage(nPage,neighbor)) + return FALSE; + // Here we have possibly two cases: + // 1. Neighboring page can share some data with use, then do share and leave + // 2. Neighboring page is of treeorder in size, then merge and propagate + if(neighbor.GetSize()>treeOrder){ + TRACE0("Redistributing..\n"); + // Borrow some data from there. + int toBorrow = neighbor.GetSize()-treeOrder; + toBorrow=toBorrow/2+1; + ASSERT(toBorrow); + if(bRight) + m_stackTop.Add(CBTRecord(daddy[rr1.m_Offset].m_Key,daddy[rr1.m_Offset].m_Value,m_stackTop[m_stackTop.GetUpperBound()].m_ptrRight,neighbor[0].m_ptrLeft)); + else + m_stackTop.InsertAt(0,CBTRecord(daddy[rr1.m_Offset].m_Key,daddy[rr1.m_Offset].m_Value,neighbor[neighbor.GetUpperBound()].m_ptrRight,m_stackTop[0].m_ptrLeft)); + for(toBorrow--;toBorrow;toBorrow--){ + if(bRight){ + m_stackTop.Add(neighbor[0]); + neighbor.RemoveAt(0); + }else{ + m_stackTop.InsertAt(0,neighbor[neighbor.GetUpperBound()]); + neighbor.RemoveAt(neighbor.GetUpperBound()); + } + } + daddy[rr1.m_Offset].m_Key = neighbor[bRight?0:neighbor.GetUpperBound()].m_Key; daddy[rr1.m_Offset].m_Value = neighbor[bRight?0:neighbor.GetUpperBound()].m_Value; + neighbor.RemoveAt(bRight?0:neighbor.GetUpperBound()); + if(!(SavePage(rr1.m_Page,daddy) && SavePage(nPage,neighbor) && SavePage(rr.m_Page,m_stackTop))) + return FALSE; + rr.m_Offset = -1; // *** Point to the next?? + return TRUE; + } + TRACE0("Merging..\n"); + // We need to merge pages here.. + // We will merge them at stacktop, then we'll discard neighbor guy.. + if(bRight) + m_stackTop.Add(CBTRecord(daddy[rr1.m_Offset].m_Key,daddy[rr1.m_Offset].m_Value,m_stackTop[m_stackTop.GetUpperBound()].m_ptrRight,neighbor[0].m_ptrLeft)); + else + m_stackTop.InsertAt(0,CBTRecord(daddy[rr1.m_Offset].m_Key,daddy[rr1.m_Offset].m_Value,neighbor[neighbor.GetUpperBound()].m_ptrRight,m_stackTop[0].m_ptrLeft)); + if(bRight){ + while(neighbor.GetSize()){ + m_stackTop.Add(neighbor[0]); + neighbor.RemoveAt(0); + } + }else{ + while(neighbor.GetSize()){ + m_stackTop.InsertAt(0,neighbor[neighbor.GetUpperBound()]); + neighbor.RemoveAt(neighbor.GetUpperBound()); + } + } + if(rr1.m_Offset>0) + daddy[rr1.m_Offset-1].m_ptrRight=rr.m_Page; + if(rr1.m_Offsetm_bRootSet); + m_btStack.RemoveAll(); + m_btStack.Add(CBTRecordRef(m_BTCrap->m_Root,-1)); + for(;;){ + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + if(!m_stackTop.GetSize()){ + ASSERT(m_btStack.GetSize()==1); + return FALSE; + } + rr.m_Offset = 0; + if(m_stackTop[rr.m_Offset].m_ptrLeft<0) + return TRUE; + m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset].m_ptrLeft,-1)); + } + } + BOOL GoLast() { + if(!IsOpened()) + return FALSE; + ASSERT(m_BTCrap->m_bRootSet); + m_btStack.RemoveAll(); + m_btStack.Add(CBTRecordRef(m_BTCrap->m_Root,-1)); + for(;;){ + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + if(!m_stackTop.GetSize()){ + ASSERT(m_btStack.GetSize()==1); + return FALSE; + } + rr.m_Offset = m_stackTop.GetUpperBound(); + if(m_stackTop[rr.m_Offset].m_ptrRight<0) + return TRUE; + m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset++].m_ptrRight,-1)); + } + } + BOOL GoNext() { + if(!IsOpened()) + return FALSE; + if(!(m_btStack.GetSize() && m_btStack[m_btStack.GetUpperBound()].m_Offset>=0)) + return FALSE; + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + ASSERT(rr.m_Offset=0){ + // Advance pointer in this page and dive into subtree + // going left and left until we have nowhere to go. +// TRACE1("Dive into page %lu",m_stackTop[rr.m_Offset].m_ptrRight); + m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset++].m_ptrRight,0)); + for(;;){ + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + ASSERT(rr.m_Offset==0); + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + if(m_stackTop[rr.m_Offset].m_ptrLeft<0) + break; +// TRACE1(", %lu",m_stackTop[rr.m_Offset].m_ptrLeft); + m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset].m_ptrLeft,0)); + } +// TRACE0("\n"); + return TRUE; + }else if(rr.m_Offset=0)) + return FALSE; + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + ASSERT(rr.m_Offset=0){ + // Dive in and go right and right from the rightmost until + // we have nowhere to go. + m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset].m_ptrLeft,-1)); + for(;;){ + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + rr.m_Offset = m_stackTop.GetUpperBound(); + if(m_stackTop[rr.m_Offset].m_ptrRight<0) + return TRUE; + m_btStack.Add(CBTRecordRef(m_stackTop[rr.m_Offset++].m_ptrRight,-1)); + } + return TRUE; + }else if(rr.m_Offset>0){ + rr.m_Offset--; + return TRUE; + } + // We're at the leftmost element in page - go up and left until we're + // done or we have data. + m_btStack.RemoveAt(m_btStack.GetUpperBound()); + while(m_btStack.GetSize()){ + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + rr.m_Offset--; + if(rr.m_Offset>=0) + return TRUE; + m_btStack.RemoveAt(m_btStack.GetUpperBound()); + } + // No more data - we were at the first element in tree. + return FALSE; + } + BOOL GetThis(key& _key,value& _value) { + if(!IsOpened()) + return FALSE; + // *** MORE CHECKING + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + _key = m_stackTop[rr.m_Offset].m_Key; + _value = m_stackTop[rr.m_Offset].m_Value; + return TRUE; + } + + BOOL SeekToPage(const key& _key) { + ASSERT(IsOpened()); + ASSERT(m_BTCrap->m_bRootSet); + m_btStack.RemoveAll(); + m_btStack.Add(CBTRecordRef(m_BTCrap->m_Root,-1)); + for(;;){ + CBTRecordRef& rr = m_btStack[m_btStack.GetUpperBound()]; + if(!LoadPage(rr.m_Page,m_stackTop)) + return FALSE; + ASSERT(m_stackTop.GetSize() || !m_btStack.GetUpperBound()); + if(!m_stackTop.GetSize()){ + rr.m_Offset=-1; + return TRUE; + } + for(rr.m_Offset=0;rr.m_OffsetDelete(); + rv = FALSE; + } + delete pageFile; + return rv; + } + BOOL SavePage(CBTPageRef ref,CBTPage& page) { + CFile* pageFile = m_BT.OpenFile(ref); + if(!pageFile) + return FALSE; + BOOL rv = TRUE; + try{ + CArchive ar(pageFile,CArchive::store); + page.Serialize(ar); + ar.Close(); + }catch(CException* e){ + e->Delete(); + rv = FALSE; + } + delete pageFile; + return rv; + } + CBTPageRef AllocatePage() { + CBTDynaFile* pageFile = m_BT.CreateFile(); + if(!pageFile) + return -1; + CBTPage nothing; + CBTPageRef rv = pageFile->GetFile(); + try{ + CArchive ar(pageFile,CArchive::store); + nothing.Serialize(ar); + ar.Close(); + }catch(CException* e){ + e->Delete(); + rv = -1; + } + delete pageFile; + return rv; + } + BOOL DeallocatePage(CBTPageRef ref) { + return m_BT.DeleteFile(ref); + } + +}; + +}; + +#endif // __BTREENDEX_H diff --git a/shared-code/BellsNWhistles.h b/shared-code/BellsNWhistles.h new file mode 100644 index 0000000..1de77ae --- a/dev/null +++ b/shared-code/BellsNWhistles.h @@ -0,0 +1,146 @@ +#ifndef __BELLSNWHISTLES_H +#define __BELLSNWHISTLES_H + +class CBellsNWhistles { +public: + class CBang { + public: + CString m_codeName; + enum _bangType { + bangNone, bangSpeaker, bangSystem, bangResource, + bangWaveform + } m_type; + BOOL m_bLoop; + union { + UINT system; + LPCTSTR resource; + LPCTSTR wave; + + LPCTSTR str; + UINT id; + }; + CString m_strWave; + CBang() : m_type(bangNone), m_bLoop(FALSE) {} + }; + typedef CTypedPtrMap CBangs; + struct CBelling { + LPCSTR snd; + HMODULE hm; + DWORD flags; + CBelling(LPCSTR snd,HMODULE hm,DWORD flags) : snd(snd), hm(hm), + flags(flags) {} + CBelling(CBelling& s) : snd(s.snd), hm(s.hm), flags(s.flags) {} + CBelling& operator=(CBelling& s) { + snd=s.snd; hm=s.hm; flags=s.flags; + return *this; + } + }; + typedef CBelling* Whistling; + + CBangs m_bangs; + + ~CBellsNWhistles() { + POSITION p = m_bangs.GetStartPosition(); + while(p){ + CString s; CBang* b; + m_bangs.GetNextAssoc(p,s,b); + delete b; + } + m_bangs.RemoveAll(); + } + + BOOL AssignSound(LPCTSTR codeName,LPCTSTR id,CBang::_bangType type=CBang::bangWaveform) { + CString cn = codeName; + cn.MakeLower(); + CBang* b; + if(!m_bangs.Lookup(cn,b)) { + b = new CBang; + b->m_codeName=cn; + m_bangs[cn]=b; + } + b->m_type=type; + b->str = id; + if(type==CBang::bangWaveform){ + b->m_strWave=id; b->str = b->m_strWave; + } + return TRUE; + } + BOOL AssignSound(LPCTSTR codeName,UINT nID,CBang::_bangType type=CBang::bangResource) { + CString cn = codeName; + cn.MakeLower(); + CBang* b; + if(!m_bangs.Lookup(cn,b)) { + b = new CBang; + b->m_codeName=cn; + m_bangs[cn]=b; + } + b->m_type=type; + b->id = nID; + ASSERT(type!=CBang::bangWaveform); + return TRUE; + } + BOOL UnassignSound(LPCTSTR codeName) { + CString cn = codeName; + cn.MakeLower(); + CBang* b; + if(m_bangs.Lookup(cn,b)) { + m_bangs.RemoveKey(cn); + delete b; + return TRUE; + } + return FALSE; + } + + Whistling StartSound(LPCTSTR codeName) { + Whistling* rv = NULL; + CString cn = codeName; + CBang* b; + if(!m_bangs.Lookup(cn,b)){ + ::PlaySound(cn,AfxGetInstanceHandle(),SND_ASYNC|SND_NODEFAULT|SND_NOWAIT|SND_FILENAME); + return NULL; + } + UINT flags = SND_ASYNC|SND_NODEFAULT|SND_NOWAIT; + LPCSTR snd = NULL; + switch(b->m_type){ + case CBang::bangNone: return NULL; + case CBang::bangSpeaker: MessageBeep(0xFFFFFFFF); return NULL; + case CBang::bangSystem: MessageBeep(b->system); return NULL; + case CBang::bangResource: + snd = b->resource; + flags|=SND_RESOURCE; break; + case CBang::bangWaveform: + snd = b->wave; + flags|=SND_FILENAME; break; +#ifdef _DEBUG + default: + ASSERT(FALSE); return NULL; +#endif + } + if(b->m_bLoop) + flags|=SND_LOOP; + HMODULE hm = AfxGetInstanceHandle(); + if(!::PlaySound(snd,hm,flags)) + return NULL; + return b->m_bLoop?new CBelling(snd,hm,flags):NULL; + } + BOOL StopSound(Whistling whistle) { + if(!whistle) + return FALSE; + ::PlaySound(whistle->snd,whistle->hm,whistle->flags|SND_PURGE); + delete whistle; + return TRUE; + } + UINT FillInCombo(CComboBox* combo) { + POSITION p = m_bangs.GetStartPosition(); + UINT rv = 0; + while(p) { + CString s; + CBang* b; + m_bangs.GetNextAssoc(p,s,b); + combo->AddString(s); + } + return rv; + } +}; + +#endif // _BELLSNWHISTLES_H \ No newline at end of file diff --git a/shared-code/BitSet.h b/shared-code/BitSet.h new file mode 100644 index 0000000..cf36e3b --- a/dev/null +++ b/shared-code/BitSet.h @@ -0,0 +1,105 @@ +#ifndef __BITSET_H +#define __BITSET_H + +namespace Klever { + +class CBitSet : public CObject { +public: + CWordArray m_Bits; + ULONG m_BitsInSet; + enum { + bitsPerWord = sizeof(WORD)*8 + }; + + CBitSet(ULONG size = 0) : m_BitsInSet(0) { SetSize(size); } + CBitSet(CBitSet& o) : m_BitsInSet(0) { CopyFrom(o); } + + void SetSize(ULONG size,BOOL bFillOnes=FALSE) { + UINT os = m_Bits.GetSize(); + UINT ns = (size+bitsPerWord-1)/bitsPerWord; + if(os==ns){ + if(os){ + if(bFillOnes) + m_Bits[m_BitsInSet/bitsPerWord]|=(~(WORD)0)<<(m_BitsInSet%bitsPerWord); + else + m_Bits[m_BitsInSet/bitsPerWord]&=~((~(WORD)0)<<(m_BitsInSet%bitsPerWord)); + } + m_BitsInSet=size; + }else{ + // *?* ASSERT((!os) || (((os-1)*bitsPerWord)<=m_BitsInSet && m_BitsInSet<(os*bitsPerWord))); + if(os=0;i--) + m_Bits[i]=~m_Bits[i]; + } + CBitSet& operator&=(CBitSet& o) { + if(o.m_BitsInSet=0;i--) + m_Bits[i]&=o.m_Bits[i]; + return *this; + } + CBitSet& operator|=(CBitSet& o) { + if(o.m_BitsInSet>m_BitsInSet) + SetSize(o.m_BitsInSet); + for(int i=o.m_Bits.GetUpperBound();i>=0;i--) + m_Bits[i]|=o.m_Bits[i]; + return *this; + } + CBitSet& operator=(CBitSet& o) { + CopyFrom(o); + return *this; + } + void CopyFrom(CBitSet& o) { + m_BitsInSet=o.m_BitsInSet; + m_Bits.Copy(o.m_Bits); + } + void Serialize(CArchive& ar) { + if(ar.IsStoring()){ + ar << m_BitsInSet; + m_Bits.Serialize(ar); + }else{ + ar >> m_BitsInSet; + m_Bits.Serialize(ar); + } + } +}; + +}; + +#endif // __BITSET_H diff --git a/shared-code/Dynamide.h b/shared-code/Dynamide.h new file mode 100644 index 0000000..32c93f7 --- a/dev/null +++ b/shared-code/Dynamide.h @@ -0,0 +1,443 @@ +#ifndef __DYNAMIDE_H +#define __DYNAMIDE_H + +#include "LRUCache.h" + +namespace Klever { + +template +class CDynamide : public CObject { + struct firstBlock { + LONG freeFile; + BYTE crap[fbSize-sizeof(LONG)]; + }; + struct theBlock { + LONG next; + BYTE data[bSize-sizeof(LONG)]; + }; +public: + static firstBlock FirstBlock; + static theBlock TheBlock; +private: + class CDynaCache : public CLRUCache { + public: + CFile* m_File; + BOOL m_bAutodelete; + CDynaCache(CFile* file,BOOL bAutodelete=TRUE) : CLRUCache(64) { + m_File=file; + m_bAutodelete=bAutodelete; + } + virtual ~CDynaCache() { + Flush(); + if(m_bAutodelete){ + m_File->Close(); + delete m_File; + } + } + virtual BOOL _ReadIn(DWORD idx,theBlock* data) { + LONG p = sizeof(firstBlock)+idx*sizeof(theBlock); + LONG s = m_File->Seek(p,CFile::begin); + if(p==s){ + UINT rb = m_File->Read(data,sizeof(*data)); + if(rb==sizeof(*data)) + return TRUE; + if(rb) + return FALSE; + memset(data,0,sizeof(*data)); + data->next=-1; + try{ + m_File->Write(data,sizeof(*data)); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + }else{ + LONG togo = p-s; + ASSERT(togo>0); + ASSERT(!(togo%sizeof(theBlock))); + memset(data,0,sizeof(*data)); + data->next=-1; + while(togo>=0){ + try{ + m_File->Write(data,sizeof(*data)); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + } + } + return TRUE; + } + virtual BOOL _WriteOut(DWORD idx,theBlock* data) { + LONG p = sizeof(firstBlock)+idx*sizeof(theBlock); + LONG s = m_File->Seek(p,CFile::begin); + if(p!=s) + return FALSE; + try{ + m_File->Write(data,sizeof(*data)); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + return TRUE; + } + DWORD AllocateNode() { + LONG l = m_File->GetLength(); + ASSERT(!((l-sizeof(firstBlock))%sizeof(theBlock))); + m_File->SetLength(l+sizeof(theBlock)); + return (l-sizeof(firstBlock))/sizeof(theBlock); + } + BOOL Read1stBlock(firstBlock* fb) { + m_File->SeekToBegin(); + UINT rb = m_File->Read(fb,sizeof(*fb)); + if(rb==sizeof(*fb)) + return TRUE; + if(rb) + return FALSE; + memset(fb,0,sizeof(*fb)); + fb->freeFile = -1; + try{ + m_File->Write(fb,sizeof(*fb)); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + return TRUE; + } + BOOL Write1stBlock(firstBlock* fb) { + m_File->SeekToBegin(); + try{ + m_File->Write(fb,sizeof(*fb)); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + return TRUE; + } + }; +public: + class CDynaFile : public CFile { + public: + CDynamide* m_Daddy; + CArray m_Blocks; + LONG m_Position; + + CDynaFile(CDynamide* daddy) : m_Daddy(NULL) { AttachToDaddy(daddy); } + virtual ~CDynaFile() { Close(); DetachFromDaddy(); } + + void AttachToDaddy(CDynamide* daddy) { + ASSERT(!m_Daddy); + ASSERT(daddy); + m_Daddy=daddy; + m_Daddy->AttachDynaFile(this); + } + void DetachFromDaddy() { + ASSERT(m_Daddy); + ASSERT(!IsOpened()); + m_Daddy->DetachDynaFile(this); + m_Daddy=NULL; + } + + BOOL Create() { + if(IsOpened()) + return FALSE; + m_Blocks.SetAtGrow(0,m_Daddy->Allocate()); + ASSERT(m_Blocks[0]>=0); + m_Position=0; + return TRUE; + } + BOOL Open(LONG fb) { + if(IsOpened()) + return FALSE; + ASSERT(fb>=0); + theBlock* b; + do{ + m_Blocks.Add(fb); + b = m_Daddy->m_File->GetCached(fb); + ASSERT(b); + fb=b->next; + if(m_Blocks[m_Blocks.GetUpperBound()]==fb) + return FALSE; + }while(fb>=0); + m_Position=0; + return TRUE; + } + + LONG GetFile() { + if(!IsOpened()) + return -1; + return m_Blocks[0]; + } + virtual DWORD GetPosition() const { + if(!IsOpened()) + return 0; + if(m_Position<0) + return 0; + if(m_Position>GetLength()) + return GetLength(); + return m_Position; + } + virtual CString GetFileName() { + CString rv; + if(IsOpened()) + rv.Format("0x%08lX",m_Blocks[0]); + else + rv.Format("None"); + return rv; + } + virtual CString GetFileTitle() { return GetFileName(); } + virtual CString GetFilePath() { return GetFileName(); } + virtual void SetFilePath(LPCTSTR lpszNewName) { ASSERT(FALSE); } + + virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL) { ASSERT(FALSE); return FALSE; } + virtual CFile* Duplicate() { ASSERT(FALSE); return NULL; } + + virtual LONG Seek(LONG lOff, UINT nFrom) { + if(!IsOpened()) + return -1; + switch(nFrom){ + case CFile::begin: + m_Position=lOff; + break; + case CFile::current: + m_Position+=lOff; + break; + case CFile::end: + m_Position=GetLength()+lOff; + break; + default: + ASSERT(FALSE); + return -1; + } + if(m_Position<0) + m_Position=0; + if(m_Position>GetLength()) + m_Position=GetLength(); + return m_Position; + } + virtual void SetLength(DWORD dwNewLen) { + if(!IsOpened()) + return; + if(dwNewLen1){ + LONG mb = m_Blocks[m_Blocks.GetUpperBound()]; + LONG mb1 = m_Blocks[m_Blocks.GetUpperBound()-1]; + theBlock* b = m_Daddy->m_File->GetCached(mb1); + ASSERT(b); + ASSERT(b->next==mb); + b->next=-1; + m_Daddy->m_File->MakeDirty(mb1); + m_Daddy->Deallocate(mb); + m_Blocks.SetSize(m_Blocks.GetSize()-1); + } + }else{ + while(dwNewLen>GetLength()){ + LONG mb = m_Blocks[m_Blocks.GetUpperBound()]; + LONG newBlock = m_Daddy->Allocate(); + ASSERT(newBlock>=0); + theBlock* b = m_Daddy->m_File->GetCached(mb); + ASSERT(b); + ASSERT(b->next<0); + b->next=newBlock; + m_Daddy->m_File->MakeDirty(mb); + m_Blocks.Add(newBlock); + } + } + } + virtual DWORD GetLength() const { + return ((long)m_Blocks.GetSize())*((long)sizeof(TheBlock.data)); + } + + virtual UINT Read(void* lpBuf, UINT nCount) { + UINT rv = 0; + ASSERT(m_Position>=0 && m_Position<=GetLength()); + LPBYTE data = (LPBYTE)lpBuf; + while(nCount && m_Positionm_File->GetCached(m_Blocks[bn]); + ASSERT(b); + UINT bc = min(nCount,sizeof(TheBlock.data)-bo); + memmove(data,&b->data[bo],bc); + nCount-=bc; + data=&data[bc]; + rv+=bc; + m_Position+=bc; + } + return rv; + } + virtual void Write(const void* lpBuf, UINT nCount) { + ASSERT(m_Position>=0 && m_Position<=GetLength()); + LPBYTE data = (LPBYTE)lpBuf; + while(nCount){ + UINT bn = m_Position/sizeof(TheBlock.data); + UINT bo = m_Position%sizeof(TheBlock.data); + while(bn>=m_Blocks.GetSize()){ + LONG mb = m_Blocks[m_Blocks.GetUpperBound()]; + LONG newBlock = m_Daddy->Allocate(); + ASSERT(newBlock>=0); + theBlock* b = m_Daddy->m_File->GetCached(mb); + ASSERT(b); + ASSERT(b->next<0); + b->next=newBlock; + m_Daddy->m_File->MakeDirty(mb); + m_Blocks.Add(newBlock); + } + theBlock* b = m_Daddy->m_File->GetCached(m_Blocks[bn]); + ASSERT(b); + UINT bc = min(nCount,sizeof(TheBlock.data)-bo); + memmove(&b->data[bo],data,bc); + m_Daddy->m_File->MakeDirty(m_Blocks[bn]); + nCount-=bc; + data=&data[bc]; + m_Position+=bc; + } + } + + virtual void LockRange(DWORD dwPos, DWORD dwCount) { ASSERT(FALSE); } + virtual void UnlockRange(DWORD dwPos, DWORD dwCount) { ASSERT(FALSE); } + + virtual void Abort() { ASSERT(FALSE); } + virtual void Flush() { + m_Daddy->m_File->Flush(); + } + virtual void Close() { + m_Blocks.RemoveAll(); + } + + BOOL IsOpened() const { return m_Blocks.GetSize()!=0; } + }; + + CDynaCache* m_File; + firstBlock m_FB; + + CDynamide() : m_File(NULL) {} + ~CDynamide() { Close(); } + + BOOL AttachDynaFile(CDynaFile* f) { + // ASSERT(!m_Files.Find(f)); + // m_Files.AddHead(f); + return TRUE; + } + BOOL DetachDynaFile(CDynaFile* f) { + //POSITION p = m_Files.Find(f); + // ASSERT(p); + // m_Files.RemoveAt(p); + return TRUE; + } + + BOOL Open(LPCTSTR file,BOOL bRO=FALSE) { + Close(); + try{ + CFile* f = new CFile(file,CFile::typeBinary|(bRO?CFile::modeRead|CFile::shareDenyWrite:CFile::modeReadWrite|CFile::shareDenyRead)); + return Attach(f,TRUE); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + } + BOOL Create(LPCTSTR file) { + Close(); + try{ + CFile* f = new CFile(file,CFile::typeBinary|CFile::modeCreate|CFile::modeReadWrite|CFile::shareDenyRead); + return Attach(f,TRUE); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + } + BOOL Attach(CFile* file,BOOL bAutodelete=TRUE) { + if(IsOpened()) + return FALSE; + m_File = new CDynaCache(file,bAutodelete); + if(!m_File->Read1stBlock(&m_FB)){ + memset(&m_FB,0,sizeof(m_FB)); + m_FB.freeFile=-1; + VERIFY(m_File->Write1stBlock(&m_FB)); + } + return IsOpened(); + } + // CFile* Detach(); + BOOL Close() { + if(!IsOpened()) + return FALSE; + m_File->Write1stBlock(&m_FB); + delete m_File; + m_File=NULL; + return TRUE; + } + BOOL IsOpened() { + return m_File != NULL; + } + BOOL Write1stBlock(void) { + if(!IsOpened()) + return FALSE; + VERIFY(m_File->Write1stBlock(&m_FB)); + return TRUE; + } + + CDynaFile* CreateFile() { + CDynaFile* rv = new CDynaFile(this); + if(rv->Create()) + return rv; + delete rv; + return NULL; + } + CDynaFile* OpenFile(LONG fb) { + CDynaFile* rv = new CDynaFile(this); + if(rv->Open(fb)) + return rv; + delete rv; + return NULL; + } + BOOL DeleteFile(LONG fb) { + while(fb>=0){ + theBlock* b = m_File->GetCached(fb); + LONG nb = b->next; + Deallocate(fb); + fb=nb; + } + return TRUE; + } + + LONG Allocate() { + if(!IsOpened()) + return -1; + if(m_FB.freeFile<0){ + LONG rv = m_File->AllocateNode(); + theBlock *b = m_File->GetCached(rv); + b->next=-1; + m_File->MakeDirty(rv); + return rv; + } + LONG rv = m_FB.freeFile; + theBlock *b = m_File->GetCached(rv); + m_FB.freeFile=b->next; + b->next=-1; + m_File->MakeDirty(rv); + m_File->Write1stBlock(&m_FB); + return rv; + } + BOOL Deallocate(LONG bk) { + if(!IsOpened()) + return FALSE; + theBlock* b = m_File->GetCached(bk); + ASSERT(b); + if(m_FB.freeFile<0){ + b->next=-1; + m_FB.freeFile=bk; + }else{ + b->next=m_FB.freeFile; + m_FB.freeFile=bk; + } + m_File->MakeDirty(bk); + m_File->Write1stBlock(&m_FB); + return TRUE; + } +}; + +}; + +#endif // __DYNAMIDE_H diff --git a/shared-code/FindIFace.h b/shared-code/FindIFace.h new file mode 100644 index 0000000..8dec8c4 --- a/dev/null +++ b/shared-code/FindIFace.h @@ -0,0 +1,125 @@ +#ifndef __FINDIFACE_H +#define __FINDIFACE_H + +#include "SNMPeer.h" +#include "SNMPExtDLL.h" +#include "SNMPOIDs.h" + +namespace Klever { + +inline BOOL FindIFace(in_addr& target,in_addr& source) +{ +DEFINE_OID(ipRouteDest, OIDipRouteDest); +DEFINE_OID(ipRouteMask, OIDipRouteMask); +DEFINE_OID(ipRouteIfIndex, OIDipRouteIfIndex); +DEFINE_OID(ipRouteMetric1, OIDipRouteMetric1); +DEFINE_OID(ipAdEntIfIndex, OIDipAdEntIfIndex); +DEFINE_OID(ipAdEntAddr, OIDipAdEntAddr); +struct _route { + int iface; + int metric; + DWORD nm; +} routes[16]; +int nRoutes = 0; +CSNMPVarBindList vbl; + vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipRouteDest,sizeof(ipRouteDest)))); + vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipRouteMask,sizeof(ipRouteMask)))); + vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipRouteIfIndex,sizeof(ipRouteIfIndex)))); + vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipRouteMetric1,sizeof(ipRouteMetric1)))); +CSNMPExtDLL snmp("INETMIB1"); + while(nRoutes<(sizeof(routes)/sizeof(routes[0]))){ + if( + snmp.Request(CASNAny::typeASNGetNextRequest,vbl,vbl) + && vbl.GetCount() == 4 + ){ + POSITION p = vbl.GetHeadPosition(); + _route r = {-1,-1}; + in_addr d, m; + BOOL bD = FALSE, bM = FALSE; + while(p){ + CSNMPVarBind& vb = vbl.GetNext(p); + if( + vb.IsName(ipRouteDest,sizeof(ipRouteDest)) + && vb.value.type==CASNAny::typeASNIP + ){ + d.s_addr=vb.value.value.ip.s_addr; bD = TRUE; + }else if( + vb.IsName(ipRouteMask,sizeof(ipRouteMask)) + && vb.value.type==CASNAny::typeASNIP + ){ + m.s_addr=vb.value.value.ip.s_addr; bM = TRUE; + }else if( + vb.IsName(ipRouteIfIndex,sizeof(ipRouteIfIndex)) + && vb.value.type==CASNAny::typeASNInteger + ){ + r.iface=vb.value.value.number; + }else if( + vb.IsName(ipRouteMetric1,sizeof(ipRouteMetric1)) + && vb.value.type==CASNAny::typeASNInteger + ){ + r.metric=vb.value.value.number; + }else + break; + } + if(r.iface<0 || r.metric<0 || (!bD) || (!bM)) + break; + if((target.s_addr&m.s_addr)==(d.s_addr&m.s_addr)){ + r.nm=htonl(m.s_addr); + memmove(&routes[nRoutes++],&r,sizeof(routes[0])); + } + }else + break; + } + if(!nRoutes) + return FALSE; +int rn = 0; + if(nRoutes>1){ + for(int tmp=1;tmproutes[rn].nm + ) + rn = tmp; + } +int iface = routes[rn].iface; + vbl.RemoveAll(); + vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipAdEntAddr,sizeof(ipAdEntAddr)))); + vbl.AddTail(CSNMPVarBind(CASNAny(CASNAny::typeASNOID,ipAdEntIfIndex,sizeof(ipAdEntIfIndex)))); + for(;;){ + if( + snmp.Request(CASNAny::typeASNGetNextRequest,vbl,vbl) + && vbl.GetCount()==2 + ){ + in_addr a; a.s_addr = INADDR_NONE; + int ifn = -1; + POSITION p = vbl.GetHeadPosition(); + while(p){ + CSNMPVarBind& vb = vbl.GetNext(p); + if( + vb.IsName(ipAdEntAddr,sizeof(ipAdEntAddr)) + && vb.value.type==CASNAny::typeASNIP + ){ + a.s_addr=vb.value.value.ip.s_addr; + }else if( + vb.IsName(ipAdEntIfIndex,sizeof(ipAdEntIfIndex)) + && vb.value.type==CASNAny::typeASNInteger + ){ + ifn = vb.value.value.number; + }else + break; + } + if(ifn<0) + break; + if(ifn==iface){ + source.s_addr=a.s_addr; + return TRUE; + } + }else + break; + } + return FALSE; +} + +}; + +#endif // __FINDIFACE_H diff --git a/shared-code/LRUCache.h b/shared-code/LRUCache.h new file mode 100644 index 0000000..569e829 --- a/dev/null +++ b/shared-code/LRUCache.h @@ -0,0 +1,113 @@ +#ifndef __LRUCACHE_H +#define __LRUCACHE_H + +namespace Klever { + +template +class CLRUCache : public CObject { +public: + struct CacheEntry { + enum cacheState { + cacheClean, cacheDirty, cacheEmpty + }; + cacheState m_State; + UINT m_hits; + + IDX m_idx; + DATA* m_pData; + + CacheEntry() { m_State=cacheEmpty; VERIFY(m_pData=new DATA); m_hits=0; } + virtual ~CacheEntry() { delete m_pData; } + }; + typedef CMap CCacheMap; + typedef CList CCacheList; + + CCacheList m_Cache; + CCacheMap m_Map; + + CLRUCache(UINT cacheSize) { + for(int tmp=0;tmpm_hits++; + PopUp(rv); + return rv->m_pData; + } + if(!bLoad) + return NULL; + rv = m_Cache.GetTail(); + ASSERT(rv); + switch(rv->m_State){ + case CacheEntry::cacheDirty: + FlushEntry(rv); + case CacheEntry::cacheClean: + m_Map.RemoveKey(rv->m_idx); + rv->m_State=CacheEntry::cacheEmpty; + case CacheEntry::cacheEmpty: + break; + default: + ASSERT(FALSE); + } + if(!_ReadIn(idx,rv->m_pData)) + return NULL; + rv->m_hits=1; + rv->m_State=CacheEntry::cacheClean; + rv->m_idx=idx; + m_Map[idx]=rv; + PopUp(rv); + return rv->m_pData; + } + BOOL MakeDirty(ARGIDX idx) { + CacheEntry* pEntry; + if(m_Map.Lookup(idx,pEntry)){ + ASSERT(pEntry->m_State==CacheEntry::cacheClean || pEntry->m_State==CacheEntry::cacheDirty); + pEntry->m_State=CacheEntry::cacheDirty; + return TRUE; + } + return FALSE; + } + BOOL Flush() { + POSITION p = m_Cache.GetHeadPosition(); + while(p){ + CacheEntry* pEntry = m_Cache.GetNext(p); + ASSERT(pEntry); + FlushEntry(pEntry); + } + return TRUE; + } + BOOL FlushEntry(CacheEntry* pEntry) { + if(pEntry->m_State==CacheEntry::cacheDirty){ + BOOL rv = _WriteOut(pEntry->m_idx,pEntry->m_pData); + if(rv) + pEntry->m_State=CacheEntry::cacheClean; + } + return FALSE; + } + void PopUp(CacheEntry* pEntry) { + POSITION p = m_Cache.Find(pEntry); + ASSERT(p); + m_Cache.RemoveAt(p); + VERIFY(m_Cache.AddHead(pEntry)); + } + + virtual BOOL _ReadIn(ARGIDX idx,DATA* data) = 0; + virtual BOOL _WriteOut(ARGIDX idx,DATA* data) = 0; +}; + +}; + +#endif // __LRUCACHE_H diff --git a/shared-code/RegEx.cpp b/shared-code/RegEx.cpp new file mode 100644 index 0000000..b7bab62 --- a/dev/null +++ b/shared-code/RegEx.cpp @@ -0,0 +1,1697 @@ +#include "../stdafx.h" +#include "RegEx.h" + +#define isWordableChar(c) (isalnum(c) || (c)=='_') + +BOOL CRegEx::Compile(LPCTSTR regex,int flags) +{ + ASSERT(!((flags®Extended) && (flags®Literal))); + m_Matches.RemoveAll(); + m_Strip.RemoveAll(); + m_Strip.SetSize(0,15); + m_Pattern=regex; + m_ParsePointer=0; + m_Error=0; + m_Sets.RemoveAll(); + m_Flags=flags; + m_iFlags=0; + m_BOLs=m_EOLs=0; + m_Subexps = 0; + m_Categories=1; // 0 is 'everything else' + m_bBackRefs=FALSE; + memset(m_Category,0,sizeof(m_Category)); + + // Go ahead. + m_Error || m_Strip.Add(CSop(CSop::opEnd)); + if(flags®Extended){ + ParseERE(); + }else if(flags®Literal){ + ParseLiteral(); + }else{ + ParseBRE(); + } + m_Error || m_Strip.Add(CSop(CSop::opEnd)); + Categorize(); + m_Strip.FreeExtra(); + FigureMust(); + m_Pluses=CountPluses(); + if(m_iFlags&iflagsBad){ + m_Error || (m_Error=regeAssert); + // ??? point to nuls? ;-) + } + // We may wish to free some memory here if we're erroneous (ie. m_Error..) + m_ParseParens.RemoveAll(); +#ifdef _DEBUG + if(m_Error){ + CString tmp; + tmp.Format("RE: ParseError: %d\n",m_Error); + TRACE0(tmp); + } +// DumpStrip(afxDump); +#endif + return (m_bCompiled=(!m_Error)); +} + +BOOL CRegEx::Match(LPCTSTR src,int flags) +{ + if(!m_bCompiled) + return FALSE; + if(m_iFlags&iflagsBad) + return FALSE; + m_Input=src; + m_mFlags=flags; + m_mPointer=m_Input; + m_mBegin=m_Input; + m_mEnd=&m_mBegin[m_Input.GetLength()]; + ASSERT(m_mPointer<=m_mEnd); + m_Matches.RemoveAll(); + if(!m_Must.IsEmpty()){ + if(m_Input.Find(m_Must)<0) + return FALSE; + } + // Go ahead.. +int stripLen = m_Strip.GetSize(); + m_mLastPos.SetSize(0); + for(int tmp=0;tmp0 && !m_mLastPos.GetSize()) + m_mLastPos.SetSize(m_Pluses); + dp = MatchBackRef(m_cOldP,endp,1,stripLen-1,0); + } + if(dp) + break; + // Uh.. oh.. we couldn't find a subexpression-level match + ASSERT(m_bBackRefs); + ASSERT(m_Pluses==0 || m_mLastPos.GetSize()); + for(;;){ + if(dp || endp <= m_cOldP) + break; // defeat.. ? + endp = MatchSlow(m_cOldP,endp-1,1,stripLen-1); + if(!endp) + break; // defeat.. ? + // Try it on a shorter possibility.. +#ifdef _DEBUG + for(tmp=1;tmp<=m_Subexps;tmp++) + ASSERT(m_Matches[tmp].m_Begin<0 && m_Matches[tmp].m_End<0); +#endif + dp = MatchBackRef(m_cOldP,endp,1,stripLen-1,0); + } + ASSERT((!dp) || dp==endp); + if(dp) // Found a shorter one.. + break; + // Despite initial appearances, there is no match here + beginp = m_cOldP+1; + ASSERT(beginp<=m_mEnd); + } + // Fill in the detail if so requested.. + if(!(m_mFlags®NoSubExpressions)){ + if(!m_Matches.GetSize()) + m_Matches.SetSize(1); + m_Matches[0].m_Begin=m_cOldP-m_mBegin; + m_Matches[0].m_End=endp-m_mBegin; + } + m_mLastPos.RemoveAll(); + return TRUE; +} + +CString CRegEx::Replace(LPCTSTR src,LPCTSTR rep,int flags) +{ + // *** + return CString(); +} + +void CRegEx::ParseERE(int stop) +{ +UCHAR c; +BOOL first=TRUE; +int prevF, prevB; + for(;;){ + int co = m_Strip.GetSize(); + while(m_ParsePointer < m_Pattern.GetLength() && ((c=m_Pattern[m_ParsePointer])!='|') && c!=stop) + ParseEREexp(); + if(m_Strip.GetSize()==co){ + m_Error || (m_Error=regeEmpty); + // ??? point to nuls? + } + if(m_ParsePointer>=m_Pattern.GetLength() || m_Pattern[m_ParsePointer]!='|') + break; + else + m_ParsePointer++; + if(first){ + StripInsert(co,CSop(CSop::opChoice0,m_Strip.GetSize()-co+1)); + prevF = prevB = co; + first=FALSE; + } + m_Error || m_Strip.Add(CSop(CSop::opOr0,m_Strip.GetSize()-prevB)); + prevB = m_Strip.GetSize()-1; + m_Error || (m_Strip[prevF].m_Operand=m_Strip.GetSize()-prevF); + prevF = m_Strip.GetSize(); + m_Error || m_Strip.Add(CSop(CSop::opOr1,0)); // offset isn't really right.. very so.. + } + if(!first){ + m_Error || (m_Strip[prevF].m_Operand=m_Strip.GetSize()-prevF); + m_Error || m_Strip.Add(CSop(CSop::opChoice1,m_Strip.GetSize()-prevB)); + } + ASSERT(m_ParsePointer >= m_Pattern.GetLength() || m_Pattern[m_ParsePointer]==stop); +} + +void CRegEx::ParseEREexp() +{ + ASSERT(m_ParsePointer < m_Pattern.GetLength()); +UCHAR c = m_Pattern[m_ParsePointer++]; +int pos = m_Strip.GetSize(); +int subno; +int count, count2; +BOOL wascaret=FALSE; + switch(c){ + case '(': + if(!(m_ParsePointer=m_Pattern.GetLength() || m_Pattern[m_ParsePointer]!=')') + ParseERE(')'); + VERIFY(m_ParseParens[m_Subexps].m_End = m_Strip.GetSize()); + m_Error || m_Strip.Add(CSop(CSop::opRightParen,subno)); + if(m_ParsePointer >= m_Pattern.GetLength() || m_Pattern[m_ParsePointer++]!=')'){ + TRACE0("RE: No matching ')'\n"); + if(!m_Error) + m_Error = regeParen; + // ??? point to nuls? + } + break; + case '^': + m_Error || m_Strip.Add(CSop(CSop::opBOL)); + m_iFlags|=iflagsUseBOL; + m_BOLs++; + wascaret=TRUE; + break; + case '$': + m_Error || m_Strip.Add(CSop(CSop::opEOL)); + m_iFlags|=iflagsUseEOL; + m_EOLs++; + break; + case '|': + TRACE0("RE: '|' outside of expression\n"); + if(!m_Error) + m_Error = regeEmpty; + // ??? point to nuls? + break; + case '*': + case '+': + case '?': + TRACE0("RE: '*'/'+'/'?' with no previous expression\n"); + if(!m_Error) + m_Error = regeBadRepeat; + // ??? point to nuls? + break; + case '.': + if(m_Flags®NewLine) + EmitNonNewLineAny(); + else + m_Error || m_Strip.Add(CSop(CSop::opAny)); + break; + case '[': + ParseBracket(); + break; + case '\\': + if(m_ParsePointer >= m_Pattern.GetLength()){ + TRACE0("RE: '\\' at the end of the pattern\n"); + if(!m_Error) + m_Error = regeEscape; + // ??? point to nuls? + }else{ + c = m_Pattern[m_ParsePointer++]; + EmitOrdinary(c); + } + break; + case '{': + if(m_ParsePointer >= m_Pattern.GetLength() || !isdigit(m_Pattern[m_ParsePointer])){ + TRACE0("RE: '{' with no repeat count\n"); + if(!m_Error) + m_Error = regeBadRepeat; + // ??? point to nuls? + } + // Fallthrough.. + default: + EmitOrdinary(c); + break; + } + if(m_ParsePointer >= m_Pattern.GetLength()) + return; + c = m_Pattern[m_ParsePointer]; + // Call a '{' repetition if followed by a digit + if (!(c=='*' || c=='+' || c=='?' || ( c=='{' && (m_ParsePointer+1) < m_Pattern.GetLength() && isdigit(m_Pattern[m_ParsePointer+1])) )) + return; // No repetitor - done. + m_ParsePointer++; + if(wascaret){ + TRACE0("RE: repetitive '^' detected\n"); + if(!m_Error) + m_Error = regeBadRepeat; + // ??? point to nuls? + } + switch(c){ + case '*': // Implemeted as +? + // + expression + StripInsert(pos,CSop(CSop::opPlus0,m_Strip.GetSize()-pos+1)); + m_Error || m_Strip.Add(CSop(CSop::opPlus1,m_Strip.GetSize()-pos)); + // ? expression + StripInsert(pos,CSop(CSop::opQuest0,m_Strip.GetSize()-pos+1)); + m_Error || m_Strip.Add(CSop(CSop::opQuest1,m_Strip.GetSize()-pos)); + break; + case '+': + // + expression + StripInsert(pos,CSop(CSop::opPlus0,m_Strip.GetSize()-pos+1)); + m_Error || m_Strip.Add(CSop(CSop::opPlus1,m_Strip.GetSize()-pos)); + break; + case '?': + // Kludge - emit y? as (y|) until subtle bug gets fixed :-) + StripInsert(pos,CSop(CSop::opChoice0,m_Strip.GetSize()-pos+1)); + m_Error || m_Strip.Add(CSop(CSop::opOr0,m_Strip.GetSize()-pos)); + m_Error || (m_Strip[pos].m_Operand=m_Strip.GetSize()-pos); + m_Error || m_Strip.Add(CSop(CSop::opOr1,1)); + m_Error || m_Strip.Add(CSop(CSop::opChoice1,2)); + break; + case '{': + count = ParseCount(); + if(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]==','){ + m_ParsePointer++; + if(isdigit(m_Pattern[m_ParsePointer])){ // HHH Personally, I doubt it is always available + count2=ParseCount(); + if(!(count<=count2)){ + TRACE0("RE: Disbalanced counts in '{}' repeater\n"); + m_Error || (m_Error=regeBadBrace); + // ??? point to nuls? + } + }else // Single number with comma + count2=256; // Infinity + }else // Single number + count2=count; + EmitRepeat(pos,count,count2); + if(m_ParsePointer >= m_Pattern.GetLength() || m_Pattern[m_ParsePointer]!='}'){ + // No '}'.. + TRACE0("RE: No immediately following '}' of '{' expression\n"); + while(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]!='}') + m_ParsePointer++; + if(m_ParsePointer >= m_Pattern.GetLength()){ + TRACE0("RE: No closing '}' found\n"); + m_Error || (m_Error=regeBrace); + }else + m_Error || (m_Error=regeBadBrace); + // ??? point to nuls? + }else + m_ParsePointer++; + break; + } + if(m_ParsePointer >= m_Pattern.GetLength()) + return; + c = m_Pattern[m_ParsePointer]; + if(!(c=='*' || c=='+' || c=='?' || (c=='{' && (m_ParsePointer+1)=pos) + m_ParseParens[tmp].m_Begin++; + if(m_ParseParens[tmp].m_End>=pos) + m_ParseParens[tmp].m_End++; + } +} + +void CRegEx::EmitOrdinary(UCHAR c) +{ + if(m_Flags®IgnoreCase && isalpha(c) && (tolower(c) !=toupper(c))){ + // Emit both cases + CString savePattern = m_Pattern; + int savePointer = m_ParsePointer; + m_Pattern=c; + m_Pattern+=']'; + m_ParsePointer=0; + ParseBracket(); + m_Pattern=savePattern; + m_ParsePointer=savePointer; + }else{ + m_Error || m_Strip.Add(CSop(CSop::opChar,c)); + if(!m_Category[(BYTE)c]) + m_Category[(BYTE)c]=m_Categories++; + } +} + +void CRegEx::EmitNonNewLineAny() +{ + // Kludges're going on and on.. +CString savePattern = m_Pattern; +int savePointer = m_ParsePointer; + m_Pattern="^\n]"; + m_ParsePointer=0; + ParseBracket(); + m_Pattern=savePattern; + m_ParsePointer=savePointer; +} + +int CRegEx::ParseCount() +{ +BOOL nonEmpty=FALSE; +int rv = 0; +UCHAR c; + while(m_ParsePointer < m_Pattern.GetLength() && isdigit(c=m_Pattern[m_ParsePointer]) && rv <=255){ + rv = rv*10 + c-'0'; + nonEmpty=TRUE; + m_ParsePointer++; + } + if(rv>255 || !nonEmpty){ + m_Error || (m_Error=regeBadBrace); + // ??? point to nuls? + } + return rv; +} + +void CRegEx::ParseBracket() +{ + // Dept. of truly sickening special case kludges + if((m_ParsePointer+5) < m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,6).Compare("[:<]]")){ + m_Error || m_Strip.Add(CSop(CSop::opBOW)); + m_ParsePointer+=6; + return; + } + if((m_ParsePointer+5) < m_Pattern.GetLength() && !m_Pattern.Mid(m_ParsePointer,6).Compare("[:>]]")){ + m_Error || m_Strip.Add(CSop(CSop::opEOW)); + m_ParsePointer+=6; + return; + } +BOOL invert=TRUE; + if(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]=='^') + m_ParsePointer++; + else + invert=FALSE; +CSet cset; + if(m_ParsePointer < m_Pattern.GetLength()){ + switch(m_Pattern[m_ParsePointer]){ + case ']': + case '-': + cset.Add(m_Pattern[m_ParsePointer]); + m_ParsePointer++; + break; + } + } + while(m_ParsePointer < m_Pattern.GetLength() && m_Pattern[m_ParsePointer]!=']' && !((m_ParsePointer+1)=0;tmp--){ + if(cset.IsIn(tmp) && isalpha(tmp) && (toupper(tmp)!=tolower(tmp))) + cset.Add(isupper(tmp)?tolower(tmp):toupper(tmp)); + } + /* + if(!cset->m_Multis.IsEmpty()) + cset.CollatingCase(); + */ + } + if(invert){ + for(int tmp=CSet::size-1;tmp>=0;tmp--) + if(cset.IsIn(tmp)) + cset.Sub(tmp); + else + cset.Add(tmp); + if(m_Flags®NewLine) + cset.Sub('\n'); + /* + if(!cset.m_Multis.IsEmpty()) + cset.CollatingInvert(); + */ + } +UCHAR c = cset.GetOnly(); + if(c){ + EmitOrdinary(c); + }else + m_Error || m_Strip.Add(CSop(CSop::opAnyOf,StoreSet(cset))); +} + +void CRegEx::CSet::Add(UCHAR c) +{ + m_Set[(BYTE)c]=TRUE; + m_Hash+=c; +} + +BOOL CRegEx::CSet::IsIn(UCHAR c) +{ + return m_Set[(BYTE)c]; +} + +void CRegEx::CSet::Sub(UCHAR c) +{ + m_Set[(BYTE)c]=FALSE; + m_Hash-=c; +} + +UCHAR CRegEx::CSet::GetOnly() +{ +int rv = 0; +UCHAR only = 0; + for(int tmp=0;tmp=m_Pattern.GetLength()){ + m_Error || (m_Error=regeBracket); + // ??? point to nuls? + } + c = m_Pattern[m_ParsePointer]; + if(c== '-' || c==']'){ + m_Error || (m_Error=regeCType); + // ??? point to nuls? + } + ParseBracketCClass(cset); + if(m_ParsePointer>=m_Pattern.GetLength()){ + m_Error || (m_Error=regeBracket); + // ??? point to nuls? + } + if((m_ParsePointer+1)>=m_Pattern.GetLength() || (m_Pattern.Mid(m_ParsePointer,2).Compare(":]"))){ + m_Error || (m_Error=regeCType); + // ??? point to nuls? + }else + m_ParsePointer+=2; + break; + case '=': // Equivalence class + m_ParsePointer+=2; + if(m_ParsePointer >= m_Pattern.GetLength()){ + m_Error || (m_Error=regeBracket); + // ??? point to nuls? + } + c = m_Pattern[m_ParsePointer]; + if(c== '-' || c==']'){ + m_Error || (m_Error=regeCollate); + // ??? point to nuls? + } + ParseBracketEClass(cset); + if((m_ParsePointer+1)>=m_Pattern.GetLength() || (m_Pattern.Mid(m_ParsePointer,2).Compare("=]"))){ + m_Error || (m_Error=regeCollate); + // ??? point to nuls? + }else + m_ParsePointer+=2; + break; + default: // Symbol, character or range + { + UCHAR start, finish; + start = ParseBracketSymbol(); + if((m_ParsePointer((BYTE)finish)){ + m_Error || (m_Error=regeRange); + // ??? point to nuls? + } + for(int tmp=start;tmp<=(BYTE)finish;tmp++) + cset.Add(tmp); + } + break; + } +} + +void CRegEx::ParseBracketCClass(CSet& cset) +{ +static struct { + char *className; + char *classChars; +} cc[] = { + {"alnum","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, + {"alpha","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"}, + {"blank"," \t"}, + {"cntrl","\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177"}, + {"digit","0123456789"}, + {"graph","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"}, + {"lower","abcdefghijklmnopqrstuvwxyz"}, + {"print","ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ "}, + {"punct","!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"}, + {"space","\t\n\v\f\r "}, + {"upper","ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, + {"xdigit","0123456789ABCDEFabcdef"} +}; +CString cclass; +UCHAR c; + while(m_ParsePointer < m_Pattern.GetLength() && isalpha(c=m_Pattern[m_ParsePointer])){ + cclass+=c; + m_ParsePointer++; + } +char *classChars = NULL; + for(int tmp=0;tmp<(sizeof(cc)/sizeof(cc[0]));tmp++){ + if(!cclass.CompareNoCase(cc[tmp].className)){ + classChars=cc[tmp].classChars; + break; + } + } + if(!classChars){ + m_Error || (m_Error=regeCType); + // ??? point to nuls? + return; + } + while(*classChars) + cset.Add(*(classChars++)); + // --- multis +} + +void CRegEx::ParseBracketEClass(CSet& cset) +{ + cset.Add(ParseBracketCollatingElement('='));; +} + +UCHAR CRegEx::ParseBracketCollatingElement(UCHAR term) +{ +static struct { + char *entityName; + char entity; +} cc[] = { {"NUL",'\0'},{"SOH",'\001'},{"STX",'\002'},{"ETX",'\003'},{"EOT",'\004'},{"ENQ",'\005'},{"ACK",'\006'},{"BEL",'\007'},{"alert",'\007'},{"BS",'\010'},{"backspace",'\b'},{"HT",'\011'},{"tab",'\t'},{"LF",'\012'},{"newline",'\n'},{"VT",'\013'},{"vertical-tab",'\v'},{"FF",'\014'},{"form-feed",'\f'},{"CR",'\015'},{"carriage-return",'\r'},{"SO",'\016'},{"SI",'\017'},{"DLE",'\020'},{"DC1",'\021'},{"DC2",'\022'},{"DC3",'\023'},{"DC4",'\024'},{"NAK",'\025'},{"SYN",'\026'},{"ETB",'\027'},{"CAN",'\030'},{"EM",'\031'},{"SUB",'\032'},{"ESC",'\033'},{"IS4",'\034'},{"FS",'\034'},{"IS3",'\035'},{"GS",'\035'},{"IS2",'\036'},{"RS",'\036'},{"IS1",'\037'},{"US",'\037'},{"space",' '},{"exclamation-mark",'!'},{"quotation-mark",'"'},{"number-sign",'#'},{"dollar-sign",'$'},{"percent-sign",'%'},{"ampersand",'&'},{"apostrophe",'\''},{"left-parenthesis",'('},{"right-parenthesis",')'},{"asterisk",'*'},{"plus-sign",'+'},{"comma",','},{"hyphen",'-'},{"hyphen-minus",'-'},{"period",'.'},{"full-stop",'.'},{"slash",'/'},{"solidus",'/'},{"zero",'0'},{"one",'1'},{"two",'2'},{"three",'3'},{"four",'4'},{"five",'5'},{"six",'6'},{"seven",'7'},{"eight",'8'},{"nine",'9'},{"colon",':'},{"semicolon",';'},{"less-than-sign",'<'},{"equals-sign",'='},{"greater-than-sign",'>'},{"question-mark",'?'},{"commercial-at",'@'},{"left-square-bracket",'['},{"backslash",'\\'},{"reverse-solidus",'\\'},{"right-square-bracket",']'},{"circumflex",'^'},{"circumflex-accent",'^'},{"underscore",'_'},{"low-line",'_'},{"grave-accent",'`'},{"left-brace",'{'},{"left-curly-bracket",'{'},{"vertical-line",'|'},{"right-brace",'}'},{"right-curly-bracket",'}'},{"tilde",'~'},{"DEL",'\177'} }; +CString seeTwo; + seeTwo=term; + seeTwo+=']'; +CString entityName; + while(m_ParsePointer=m_Pattern.GetLength()){ + m_Error || (m_Error=regeBracket); + // ??? point to nuls? + return 0; + } + for(int tmp=0;tmp<(sizeof(cc)/sizeof(cc[0]));tmp++) + if(!entityName.CompareNoCase(cc[tmp].entityName)) + return cc[tmp].entity; + if(entityName.GetLength()==1) + return entityName[0]; + m_Error || (m_Error=regeCollate); + // ??? point to nuls? + return 0; +} + +UCHAR CRegEx::ParseBracketSymbol() +{ + if(m_ParsePointer>=m_Pattern.GetLength()){ + m_Error || (m_Error=regeBracket); + // ??? point to nuls? + } + if((m_ParsePointer+1)mustLength){ + mustStart=seqStart; + mustLength=seqLength; + } + seqLength=0; + break; + } + } // Hmm.. originally it's meant to be do while not opEnd.. + if(!mustLength) + return; + // Turn into string, but, wait, personally I'm sure it could be put in the main loop.. or maybe not.. + for(tmp=0;tmprv) + rv = nest; + nest--; + break; + } + } // Again, originally we were supposed to scan till opEnd.. + if(nest) + m_iFlags|=iflagsBad; // Could this be an ASSERTion? + return rv; +} + +void CRegEx::ParseLiteral() +{ + if(!m_Pattern.GetLength()){ + m_Error || (m_Error=regeEmpty); + // ??? point to nuls? + } + while(m_ParsePointer < m_Pattern.GetLength()) + EmitOrdinary(m_Pattern[m_ParsePointer++]); +} + +void CRegEx::ParseBRE(int stopa,int stopb) +{ +int start = m_Strip.GetSize(); +BOOL first=TRUE; +BOOL wasDollar=FALSE; + if(m_ParsePointer=m_Pattern.GetLength()){ + m_Error || (m_Error=regeEscape); + // ??? point to nuls + }else + c = 0x100|m_Pattern[m_ParsePointer++]; + } + switch(c){ + case '.': + if(m_Flags®NewLine) + EmitNonNewLineAny(); + else + m_Error || m_Strip.Add(CSop(CSop::opAny,0)); + break; + case '[': + ParseBracket(); + break; + case 0x100|'{': + m_Error || (m_Error=regeBadRepeat); + // ??? point to nuls? + break; + case 0x100|'(': + m_Subexps++; + subno=m_Subexps; + m_ParseParens.SetAtGrow(m_Subexps,CParenthesis(m_Strip.GetSize())); + m_Error || m_Strip.Add(CSop(CSop::opLeftParen,subno)); + if(m_ParsePointercount2){ + m_Error || (m_Error=regeBadBrace); + // ??? poin to nuls? + } + }else // Single number with comma + count2=256; + }else // Single number + count2=count; + EmitRepeat(pos,count,count2); + if((m_ParsePointer+1)>=m_Pattern.GetLength() || m_Pattern.Mid(m_ParsePointer,2).Compare("\\}")){ + while(m_ParsePointer=m_Pattern.GetLength()){ + m_Error || (m_Error=regeBrace); + // ??? point to nuls? + } + m_Error || (m_Error=regeBadBrace); + }else + m_ParsePointer+=2; + }else if(c=='$') + return TRUE; + return FALSE; +} + +CRegEx::CRegEx() +{ + m_bCompiled=FALSE; +} + +LPCTSTR CRegEx::MatchFast(LPCTSTR begin) +{ + MatchStatesClear(CSop::stCurrent); + m_Strip[1].m_MatchData|=CSop::stCurrent; +int stripLen = m_Strip.GetSize(); + MatchStep(1,stripLen-1,CSop::stCurrent,charNothing,CSop::stCurrent); + MatchStatesCopy(CSop::stFresh,CSop::stCurrent); +LPCTSTR coldp = NULL; +LPCTSTR p = begin; +int c = (begin==m_mBegin)?charOut:((int)(BYTE)m_mPointer[-1]); + for(;;){ + // next character.. + int lastc = c; + c = (p==m_mEnd)?charOut:(int)*(BYTE*)p; + if(MatchStatesEqual(CSop::stCurrent,CSop::stFresh)) + coldp=p; + // Is there an EOL and/or BOL between lastc and c? - they ask.. + int flagc=0; + int i = 0; + if((lastc=='\n' && m_Flags®NewLine) || (lastc==charOut && !(m_mFlags®NotBOL))){ + flagc=charBOL; + i=m_BOLs; + } + if((c=='\n' && m_Flags®NewLine) || (c==charOut && !(m_mFlags®NotEOL))){ + flagc=(flagc==charBOL)?charBOLEOL:charEOL; + i+=m_EOLs; + } + if(i){ + for(;i>0;i--) + MatchStep(1,stripLen-1,CSop::stCurrent,flagc,CSop::stCurrent); + } + // What about a word boundary? - they wonder.. + if((flagc==charBOL || (lastc!=charOut && !isWordableChar(c))) && (c!=charOut && isWordableChar(c))) + flagc = charBOW; + if((lastc!=charOut && isWordableChar(lastc)) && (flagc==charEOL || (c!=charOut && !isWordableChar(c)))) + flagc = charEOW; + if(flagc==charBOW || flagc==charEOW){ + MatchStep(1,stripLen-1,CSop::stCurrent,flagc,CSop::stCurrent); + } + // Are we done? Now WE wonder.. + if((m_Strip[stripLen-1].m_MatchData&CSop::stCurrent) || p==m_mEnd) + break; // They insist I need to note break out.. Okay, I do.. + // Nope, we're not done. We have to face this character.. + MatchStatesCopy(CSop::stTemp,CSop::stCurrent); + MatchStatesCopy(CSop::stCurrent,CSop::stFresh); + ASSERT(c!=charOut); + MatchStep(1,stripLen-1,CSop::stTemp,c,CSop::stCurrent); + p++; + } + ASSERT(coldp); + m_cOldP=coldp; // *** I believe this variable can be changed 'in-place' + if(m_Strip[stripLen-1].m_MatchData&CSop::stCurrent) + return &p[1]; + else + return NULL; +} + +void CRegEx::MatchStatesClear(BYTE mask) +{ +int stripLen = m_Strip.GetSize(); + for(int tmp=0;tmp0;i--) + MatchStep(from,to,CSop::stCurrent,flagc,CSop::stCurrent); + } + // Now we wonder about word boundaries.. + if((flagc==charBOL || (lastc!=charOut && !isWordableChar(lastc))) && (c!=charOut && isWordableChar(c))) + flagc=charBOW; + if((lastc!=charOut && isWordableChar(lastc)) && (flagc==charEOL || (c!=charOut && !isWordableChar(c)))) + flagc=charEOW; + if(flagc==charBOW || flagc==charEOW){ + MatchStep(from,to,CSop::stCurrent,flagc,CSop::stCurrent); + } + // Are we done we all wonder?? + if(m_Strip[to].m_MatchData&CSop::stCurrent) + mp=p; + if(MatchStatesEqual(CSop::stCurrent,CSop::stEmpty) || p==end) + break; // Again, we're obliged to note break out. We do. + // Sucks.. we have to face this character.. + MatchStatesCopy(CSop::stTemp,CSop::stCurrent); + MatchStatesCopy(CSop::stCurrent,CSop::stEmpty); + ASSERT(c!=charOut); + MatchStep(from,to,CSop::stTemp,c,CSop::stCurrent); + MatchStep(from,to,CSop::stCurrent,charNothing,CSop::stCurrent); + p++; + } + return mp; +} + +LPCTSTR CRegEx::MatchDissect(LPCTSTR begin,LPCTSTR end,int from,int to) +{ +LPCTSTR sp = begin, dp; +LPCTSTR stp, rest, tail, ssp, oldssp, sep; +int ssub, esub; +int es; +int i; + for(int ss=from;ss=sp); // It did work.. It should've.. + } + ssub=ss+1; + esub=es-1; + // Did innards match? + if(MatchSlow(sp,rest,ssub,esub)){ + dp = MatchDissect(sp,rest,ssub,esub); + ASSERT(dp==rest); + }else // nope.. + ASSERT(sp==rest); + sp = rest; + break; + case CSop::opPlus0: + stp=end; + for(;;){ + // How long could this one be?? + rest = MatchSlow(sp,stp,ss,es); + ASSERT(rest); // It did.. It should've.. + // Could the rest match the rest? + tail = MatchSlow(rest,end,es,to); + if(tail==end) + break; // yup. + // nope.. + stp=rest-1; + ASSERT(stp>=sp); // It should've worked, we believe.. + } + ssub=ss+1; + esub=es-1; + ssp=sp; + oldssp=ssp; + for(;;){ // Find last match of innards.. + sep = MatchSlow(ssp,rest,ssub,esub); + if((!sep) || sep==ssp) + break; // Failed or matched nothin' + oldssp=ssp; + ssp=sep; + } + if(!sep){ + // Last successfull.. + sep=ssp; + ssp=oldssp; + } + ASSERT(sep=rest); // Must exhaust substring they say.. + VERIFY(MatchSlow(ssp,sep,ssub,esub)==rest); // Assert or verify - that is the question.. + dp = MatchDissect(ssp,sep,ssub,esub); + ASSERT(dp==sep); + sp=rest; + break; + case CSop::opChoice0: + stp = end; + for(;;){ + // how long.. + rest = MatchSlow(sp,stp,ss,es); + ASSERT(rest); + // Could it.. + tail = MatchSlow(rest,end,es,to); + if(tail==end) + break; // y + // n + stp = rest-1; + ASSERT(stp>=sp); + } + ssub=ss+1; + esub=ss+m_Strip[ss].m_Operand-1; + ASSERT(m_Strip[esub].m_Operator==CSop::opOr0); + for(;;){ // Find first matching branch.. + if(MatchSlow(sp,rest,ssub,esub)==rest) + break; + // this one missed, try next.. + ASSERT(m_Strip[esub].m_Operator==CSop::opOr0); + esub++; + ASSERT(m_Strip[esub].m_Operator==CSop::opOr1); + ssub=esub+1; + esub+=m_Strip[esub].m_Operand; + if(m_Strip[esub].m_Operator==CSop::opOr1) + esub--; + else + ASSERT(m_Strip[esub].m_Operator==CSop::opChoice1); + } + dp = MatchDissect(sp,rest,ssub,esub); + ASSERT(dp==rest); + sp=rest; + break; + case CSop::opPlus1: + case CSop::opQuest1: + case CSop::opOr0: + case CSop::opOr1: + case CSop::opChoice1: + ASSERT(FALSE); + break; + case CSop::opLeftParen: + i = m_Strip[ss].m_Operand; + ASSERT(0m_mBegin && !isWordableChar(*(sp-1)))) && (spm_mBegin && isWordableChar(*(sp-1))))) + return NULL; + break; + case CSop::opQuest1: + break; + case CSop::opOr0: // Matches null, but needs to skip + ss++; + s = m_Strip[ss]; + do{ + ASSERT(s.m_Operator==CSop::opOr1); + ss+=s.m_Operand; + }while((s=m_Strip[ss]).m_Operator!=CSop::opChoice1); + // Now we should note that ss++ gets us past the Choice1.. + break; + default: + // Have to make a choice.. + hard=TRUE; + break; + } + } + if(!hard){ // That was it.. + if(sp!=end) + return NULL; + return sp; + } + ss--; // Adjust for ther for's final increment.. + // Hard stuff.. is going on and on.. +CSop s = m_Strip[ss]; +int i, len, offsave; +int ssub,esub; +LPCTSTR ssp, dp; + switch(s.m_Operator){ + case CSop::opBackRef0: // The vilest depths they say.. If I only knew what the 'viles' stands for.. + i = s.m_Operand; + ASSERT(0=0); + len = m_Matches[i].GetLength(); + ASSERT((end-m_mBegin)>=len); + if(sp>end-len) + return NULL; // Not enough left to match.. + ssp = m_mBegin+m_Matches[i].m_Begin; + if(memcmp(sp,ssp,len)) + return NULL; + while(m_Strip[ss]!=CSop(CSop::opBackRef1,i)) + ss++; + return MatchBackRef(sp+len,end,ss+1,to,level-1); + break; + case CSop::opQuest0: // to null or not they wonder.. + dp = MatchBackRef(sp,end,ss+1,to,level); + if(dp) + return dp; // not.. + return MatchBackRef(sp,end,ss+s.m_Operand+1,to,level-1); + break; + case CSop::opPlus0: + ASSERT(m_mLastPos.GetSize()); + ASSERT(level+1 <= m_Pluses); + m_mLastPos[level+1]=sp; + return MatchBackRef(sp,end,ss+1,to,level+1); + break; + case CSop::opPlus1: + if(sp == m_mLastPos[level]) // Last pass matched null + return MatchBackRef(sp,end,ss+1,to,level-1); + // Try another pass.. + m_mLastPos[level]=sp; + dp = MatchBackRef(sp,end,ss-s.m_Operand+1,to,level); + if(dp) + return dp; + return MatchBackRef(sp,end,ss+1,to,level-1); + break; + case CSop::opChoice0: // find the right one, ifany + ssub = ss+1; + esub = ss+s.m_Operand-1; + ASSERT(m_Strip[esub].m_Operator==CSop::opOr0); + for(;;){ // Find first matching branch. + dp = MatchBackRef(sp,end,ssub,esub,level); + if(dp) + return dp; + // This one missed, try next one.. + if(m_Strip[esub].m_Operator==CSop::opChoice1) + return NULL; // There is none.. + esub++; + ASSERT(m_Strip[esub].m_Operator==CSop::opOr1); + ssub=esub+1; + esub+=m_Strip[esub].m_Operand; + if(m_Strip[esub].m_Operator==CSop::opOr1) + esub--; + else + ASSERT(m_Strip[esub].m_Operator==CSop::opChoice1); + } + break; + case CSop::opLeftParen: // Must undo assignment if rest fails.. + i = s.m_Operand; + ASSERT(0= m_Matches.GetSize()) + return rv; + if(m_Matches[match].m_Begin<0 || m_Matches[match].m_End<0) + return rv; + ASSERT(m_Matches[match].m_Begin CMatchBox; + enum { + matchMatch = 0, + matchPreMatch = -1, + matchPostMatch = -2 + }; + CMatchBox m_Matches; + enum { + charOut = 256, + charBOL, charEOL, charBOLEOL, charNothing, charBOW, charEOW, + charMaxCode = charEOW, + charNNChars = (charMaxCode-255) + }; + int m_mFlags; + enum { + regeSuccess = 0, + regeNoMatch = 1, regeBadPattern, regeCollate, regeCType, regeEscape, regeSubReg, regeBracket, + regeParen, regeBrace, regeBadBrace, regeRange, regeSpace, regeBadRepeat, regeEmpty, regeAssert, + regeInvArg + }; + int m_Error; + CRegEx(); + BOOL m_bCompiled; + CString m_Pattern; + BOOL m_bBackRefs; + int m_Pluses; + CString m_Must; + BYTE m_Category[CHAR_MAX-CHAR_MIN+1]; + int m_Categories; + int m_EOLs; + int m_BOLs; + int m_iFlags; + int m_Subexps; + struct CSop { + void Dump(CDumpContext& dc); + CSop() {} + CSop(BYTE op,DWORD opnd=0) : m_Operator(op), m_Operand(opnd) {} + BOOL operator==(CSop& other) {return m_Operator==other.m_Operator && m_Operand==other.m_Operand;} + BOOL operator!=(CSop& other) { return !((*this)==other);} + enum { + opEnd = 1, opChar, opBOL, opEOL, opAny, opAnyOf, opBackRef0, opBackRef1, + opPlus0, opPlus1, opQuest0, opQuest1, opLeftParen, opRightParen, opChoice0, + opOr0, opOr1, opChoice1, opBOW, opEOW + }; + BYTE m_Operator; + DWORD m_Operand; + enum { + stCurrent = 1, stFresh = 2, stTemp = 4, stEmpty = 8 + }; + BYTE m_MatchData; + }; + typedef CArray CStrip; + CStrip m_Strip; + int m_Flags; + struct CSet { + CSet() : m_Hash(0) { memset(m_Set,0,sizeof(m_Set)); } + CSet(CSet& src) { (*this)=src; } + CSet& operator=(CSet& src) { memmove(this,&src,sizeof(*this)); return *this; } + BOOL operator==(CSet& other) { if(m_Hash!=other.m_Hash)return FALSE;return !memcmp(m_Set,other.m_Set,sizeof(m_Set)); } + enum { + size = (CHAR_MAX-CHAR_MIN+1) + }; + BOOL m_Set[size]; + BYTE m_Hash; + public: + UCHAR GetOnly(); + void Sub(UCHAR c); + BOOL IsIn(UCHAR c); + void Add(UCHAR c); + }; + typedef CArray CSets; + CSets m_Sets; + enum { + // Compile flags + regBasic = 0, regExtended = 1, + regIgnoreCase = 2, + regNoSubExpressions = 4, // Also works for matching. + regNewLine = 16, + regLiteral = 32, + // Match Flags + regNotBOL = 1, + regNotEOL = 2, + regOneMatch=64, + regBackRefs=128, + // iFlags + iflagsUseBOL=1, iflagsUseEOL=2, iflagsBad=4 + }; + CString Replace(LPCTSTR src,LPCTSTR rep,int flags=0); + BOOL Match(LPCTSTR src,int flags=0); + BOOL Compile(LPCTSTR regex,int flags=0); +private: +#ifdef _DEBUG + void DumpStrip(CDumpContext& dc); +#endif + LPCTSTR MatchBackRef(LPCTSTR begin,LPCTSTR end,int from,int to,int level); + typedef CArray CStrPtrArray; + CStrPtrArray m_mLastPos; + LPCTSTR MatchDissect(LPCTSTR begin,LPCTSTR end,int from,int to); + LPCTSTR MatchSlow(LPCTSTR begin,LPCTSTR end,int from,int to); + LPCTSTR m_cOldP; + BOOL MatchStatesEqual(BYTE m1,BYTE m2); + LPCTSTR m_mBegin; + void MatchStatesCopy(BYTE dst,BYTE src); + void MatchStep(int from,int to,BYTE maskBefore,int charCode,BYTE maskAfter); + void MatchStatesClear(BYTE mask); + LPCTSTR MatchFast(LPCTSTR begin); + LPCTSTR m_mEnd; + LPCTSTR m_mPointer; + BOOL ParseBREexp(BOOL ordinaryStar); + void ParseBRE(int stopa=0,int stopb=0); + void ParseLiteral(); + int CountPluses(); + void FigureMust(); + BOOL IsInSameSets(UCHAR c1,UCHAR c2); + BOOL IsInSets(UCHAR c); + void Categorize(); + int StripDuplicate(int from,int to); + void EmitRepeat(int pos,int from,int to); + UCHAR ParseBracketSymbol(); + UCHAR ParseBracketCollatingElement(UCHAR term); + void ParseBracketEClass(CSet& cset); + void ParseBracketCClass(CSet& cset); + void ParseBracketTerm(CSet& cset); + int StoreSet(CSet& cset); + void ParseBracket(); + int ParseCount(); + void EmitNonNewLineAny(); + void EmitOrdinary(UCHAR c); + void StripInsert(int pos,CSop& sop); + void ParseEREexp(); + void ParseERE(int stop=0); + struct CParenthesis { + long m_Begin; + long m_End; + CParenthesis(long b=0,long e=0) : m_Begin(b), m_End(e) {} + }; + typedef CArray CParens; + CParens m_ParseParens; + int m_ParsePointer; +}; +#ifdef _DEBUG +inline CDumpContext& operator<<(CDumpContext& dc, CRegEx::CSop& sop) { sop.Dump(dc); return dc; } +#endif + +#endif // __REGEX_H \ No newline at end of file diff --git a/shared-code/SNMPExtDll.h b/shared-code/SNMPExtDll.h new file mode 100644 index 0000000..14c920d --- a/dev/null +++ b/shared-code/SNMPExtDll.h @@ -0,0 +1,252 @@ +#ifndef __SNMPEXTDLL_H +#define __SNMPEXTDLL_H + +#include "snmpeer.h" + +#include + +namespace Klever { + +class CSNMPExtDLL : public CSNMPeer { +public: + HINSTANCE m_hInstance; + HANDLE m_hEvent; + AsnObjectIdentifier m_OID; + BOOL (SNMP_FUNC_TYPE *m_extInit)(DWORD dw,HANDLE h,AsnObjectIdentifier* aoid); + BOOL (SNMP_FUNC_TYPE *m_extQuery)(BYTE b,RFC1157VarBindList* rvbl,AsnInteger* ai1,AsnInteger* ai2); + BOOL (SNMP_FUNC_TYPE *m_extTrap)(AsnObjectIdentifier*,AsnNetworkAddress*,AsnInteger*,AsnInteger*,AsnTimeticks*,RFC1157VarBindList*); + + HINSTANCE m_hSNMPAPI; + void (SNMP_FUNC_TYPE *m_snmpOIDFree)(AsnObjectIdentifier*); + LPVOID (SNMP_FUNC_TYPE *m_snmpAlloc)(UINT); + void (SNMP_FUNC_TYPE *m_snmpFree)(LPVOID); + void (SNMP_FUNC_TYPE *m_snmpVBLFree)(RFC1157VarBindList* vbl); + void InitSNMP() { + m_hSNMPAPI = ::LoadLibraryEx("SNMPAPI",NULL,0); + if(!m_hSNMPAPI) + return; + *(FARPROC*)&m_snmpOIDFree = ::GetProcAddress(m_hSNMPAPI,"SnmpUtilOidFree"); + *(FARPROC*)&m_snmpAlloc = ::GetProcAddress(m_hSNMPAPI,"SnmpUtilMemAlloc"); + *(FARPROC*)&m_snmpFree = ::GetProcAddress(m_hSNMPAPI,"SnmpUtilMemFree"); + *(FARPROC*)&m_snmpVBLFree = ::GetProcAddress(m_hSNMPAPI,"SnmpUtilVarBindListFree"); + if( + (m_snmpFree && !m_snmpAlloc) || + (m_snmpAlloc && !m_snmpFree) + ) + DeinitSNMP(); + } + void DeinitSNMP() { + if(!m_hSNMPAPI) + return; + ::FreeLibrary(m_hSNMPAPI); + m_hSNMPAPI=NULL; + } + void SNMPFreeOID(AsnObjectIdentifier* oid) { + if(m_hSNMPAPI && m_snmpOIDFree) + (*m_snmpOIDFree)(oid); + else + ::GlobalFree((HGLOBAL)oid->ids); + } + LPVOID SNMPAlloc(UINT size) { + if(m_hSNMPAPI && m_snmpAlloc) + return (*m_snmpAlloc)(size); + else + return ::GlobalAlloc(GMEM_FIXED,size); + } + void SNMPFree(LPVOID addr) { + if(m_hSNMPAPI && m_snmpFree) + (*m_snmpFree)(addr); + else + :: GlobalFree((HGLOBAL)addr); + } + void SNMPFreeVBL(RFC1157VarBindList& vbl) { + if(m_hSNMPAPI && m_snmpVBLFree) + (*m_snmpVBLFree)(&vbl); + else{ + for(UINT tmp=0;tmpsizeof(i)) + return FALSE; + i.s_addr=0; + memmove(&i,ip.stream,ip.length); + ou.Set(i); + return TRUE; + } + + + CSNMPExtDLL(LPCTSTR dllName) : m_hInstance(NULL) { InitSNMP(); Init(dllName); } + ~CSNMPExtDLL() { Deinit(); DeinitSNMP(); } + + BOOL Init(LPCTSTR dllName) { + Deinit(); + m_hInstance = ::LoadLibraryEx(dllName,NULL,0); + if(!m_hInstance) + return FALSE; + *(FARPROC*)&m_extInit = ::GetProcAddress(m_hInstance,"SnmpExtensionInit"); + *(FARPROC*)&m_extQuery = ::GetProcAddress(m_hInstance,"SnmpExtensionQuery"); + *(FARPROC*)&m_extTrap = ::GetProcAddress(m_hInstance,"SnmpExtensionTrap"); + if(!(m_extInit && m_extQuery && m_extTrap)){ + Deinit(); + return FALSE; + } + if(!((*m_extInit)(GetCurrentTime(),&m_hEvent,&m_OID))){ + Deinit(); + return FALSE; + } + return TRUE; + } + void Deinit() { + if(!m_hInstance) + return; + ::FreeLibrary(m_hInstance); + } + virtual BOOL Request(BYTE type,CSNMPVarBindList& in,CSNMPVarBindList& ou) { + RFC1157VarBindList vbl; + SNMPBuildVBL(vbl,in); + AsnInteger errorStatus, errorIndex; + (*m_extQuery)(type,&vbl,&errorStatus,&errorIndex); + ou.RemoveAll(); + SNMPParseVBL(vbl,ou); + SNMPFreeVBL(vbl); + return TRUE; + } +}; + +}; + +#endif // __SNMPEXTDLL_H diff --git a/shared-code/SNMPOIDs.h b/shared-code/SNMPOIDs.h new file mode 100644 index 0000000..68ee659 --- a/dev/null +++ b/shared-code/SNMPOIDs.h @@ -0,0 +1,221 @@ +#ifndef __SNMPOIDS_H +#define __SNMPOIDS_H + +#define DEFINE_OID(name,oid) static UINT name[] = oid + +// MIB-II OIDs + +#define OIDccitt {0} +#define OIDnull {0,0} +#define OIDiso {1} +#define OIDorg {1,3} +#define OIDdod {1,3,6} +#define OIDinternet {1,3,6,1} +#define OIDdirectory {1,3,6,1,1} +#define OIDmgmt {1,3,6,1,2} +#define OIDmib_2 {1,3,6,1,2,1} +#define OIDsystem {1,3,6,1,2,1,1} +#define OIDsysDescr {1,3,6,1,2,1,1,1} +#define OIDsysObjectID {1,3,6,1,2,1,1,2} +#define OIDsysUpTime {1,3,6,1,2,1,1,3} +#define OIDsysContact {1,3,6,1,2,1,1,4} +#define OIDsysName {1,3,6,1,2,1,1,5} +#define OIDsysLocation {1,3,6,1,2,1,1,6} +#define OIDsysServices {1,3,6,1,2,1,1,7} +#define OIDtransmission {1,3,6,1,2,1,10} +#define OIDsnmp {1,3,6,1,2,1,11} +#define OIDsnmpInPkts {1,3,6,1,2,1,11,1} +#define OIDsnmpInBadValues {1,3,6,1,2,1,11,10} +#define OIDsnmpInReadOnlys {1,3,6,1,2,1,11,11} +#define OIDsnmpInGenErrs {1,3,6,1,2,1,11,12} +#define OIDsnmpInTotalReqVars {1,3,6,1,2,1,11,13} +#define OIDsnmpInTotalSetVars {1,3,6,1,2,1,11,14} +#define OIDsnmpInGetRequests {1,3,6,1,2,1,11,15} +#define OIDsnmpInGetNexts {1,3,6,1,2,1,11,16} +#define OIDsnmpInSetRequests {1,3,6,1,2,1,11,17} +#define OIDsnmpInGetResponses {1,3,6,1,2,1,11,18} +#define OIDsnmpInTraps {1,3,6,1,2,1,11,19} +#define OIDsnmpOutPkts {1,3,6,1,2,1,11,2} +#define OIDsnmpOutTooBigs {1,3,6,1,2,1,11,20} +#define OIDsnmpOutNoSuchNames {1,3,6,1,2,1,11,21} +#define OIDsnmpOutBadValues {1,3,6,1,2,1,11,22} +#define OIDsnmpOutGenErrs {1,3,6,1,2,1,11,24} +#define OIDsnmpOutGetRequests {1,3,6,1,2,1,11,25} +#define OIDsnmpOutGetNexts {1,3,6,1,2,1,11,26} +#define OIDsnmpOutSetRequests {1,3,6,1,2,1,11,27} +#define OIDsnmpOutGetResponses {1,3,6,1,2,1,11,28} +#define OIDsnmpOutTraps {1,3,6,1,2,1,11,29} +#define OIDsnmpInBadVersions {1,3,6,1,2,1,11,3} +#define OIDsnmpEnableAuthenTraps {1,3,6,1,2,1,11,30} +#define OIDsnmpInBadCommunityNames {1,3,6,1,2,1,11,4} +#define OIDsnmpInBadCommunityUses {1,3,6,1,2,1,11,5} +#define OIDsnmpInASNParseErrs {1,3,6,1,2,1,11,6} +#define OIDsnmpInTooBigs {1,3,6,1,2,1,11,8} +#define OIDsnmpInNoSuchNames {1,3,6,1,2,1,11,9} +#define OIDinterfaces {1,3,6,1,2,1,2} +#define OIDifNumber {1,3,6,1,2,1,2,1} +#define OIDifTable {1,3,6,1,2,1,2,2} +#define OIDifEntry {1,3,6,1,2,1,2,2,1} +#define OIDifIndex {1,3,6,1,2,1,2,2,1,1} +#define OIDifInOctets {1,3,6,1,2,1,2,2,1,10} +#define OIDifInUcastPkts {1,3,6,1,2,1,2,2,1,11} +#define OIDifInNUcastPkts {1,3,6,1,2,1,2,2,1,12} +#define OIDifInDiscards {1,3,6,1,2,1,2,2,1,13} +#define OIDifInErrors {1,3,6,1,2,1,2,2,1,14} +#define OIDifInUnknownProtos {1,3,6,1,2,1,2,2,1,15} +#define OIDifOutOctets {1,3,6,1,2,1,2,2,1,16} +#define OIDifOutUcastPkts {1,3,6,1,2,1,2,2,1,17} +#define OIDifOutNUcastPkts {1,3,6,1,2,1,2,2,1,18} +#define OIDifOutDiscards {1,3,6,1,2,1,2,2,1,19} +#define OIDifDescr {1,3,6,1,2,1,2,2,1,2} +#define OIDifOutErrors {1,3,6,1,2,1,2,2,1,20} +#define OIDifOutQLen {1,3,6,1,2,1,2,2,1,21} +#define OIDifSpecific {1,3,6,1,2,1,2,2,1,22} +#define OIDifType {1,3,6,1,2,1,2,2,1,3} +#define OIDifMtu {1,3,6,1,2,1,2,2,1,4} +#define OIDifSpeed {1,3,6,1,2,1,2,2,1,5} +#define OIDifPhysAddress {1,3,6,1,2,1,2,2,1,6} +#define OIDifAdminStatus {1,3,6,1,2,1,2,2,1,7} +#define OIDifOperStatus {1,3,6,1,2,1,2,2,1,8} +#define OIDifLastChange {1,3,6,1,2,1,2,2,1,9} +#define OIDat {1,3,6,1,2,1,3} +#define OIDatTable {1,3,6,1,2,1,3,1} +#define OIDatEntry {1,3,6,1,2,1,3,1,1} +#define OIDatIfIndex {1,3,6,1,2,1,3,1,1,1} +#define OIDatPhysAddress {1,3,6,1,2,1,3,1,1,2} +#define OIDatNetAddress {1,3,6,1,2,1,3,1,1,3} +#define OIDip {1,3,6,1,2,1,4} +#define OIDipForwarding {1,3,6,1,2,1,4,1} +#define OIDipOutRequests {1,3,6,1,2,1,4,10} +#define OIDipOutDiscards {1,3,6,1,2,1,4,11} +#define OIDipOutNoRoutes {1,3,6,1,2,1,4,12} +#define OIDipReasmTimeout {1,3,6,1,2,1,4,13} +#define OIDipReasmReqds {1,3,6,1,2,1,4,14} +#define OIDipReasmOKs {1,3,6,1,2,1,4,15} +#define OIDipReasmFails {1,3,6,1,2,1,4,16} +#define OIDipFragOKs {1,3,6,1,2,1,4,17} +#define OIDipFragFails {1,3,6,1,2,1,4,18} +#define OIDipFragCreates {1,3,6,1,2,1,4,19} +#define OIDipDefaultTTL {1,3,6,1,2,1,4,2} +#define OIDipAddrTable {1,3,6,1,2,1,4,20} +#define OIDipAddrEntry {1,3,6,1,2,1,4,20,1} +#define OIDipAdEntAddr {1,3,6,1,2,1,4,20,1,1} +#define OIDipAdEntIfIndex {1,3,6,1,2,1,4,20,1,2} +#define OIDipAdEntNetMask {1,3,6,1,2,1,4,20,1,3} +#define OIDipAdEntBcastAddr {1,3,6,1,2,1,4,20,1,4} +#define OIDipAdEntReasmMaxSize {1,3,6,1,2,1,4,20,1,5} +#define OIDipRouteTable {1,3,6,1,2,1,4,21} +#define OIDipRouteEntry {1,3,6,1,2,1,4,21,1} +#define OIDipRouteDest {1,3,6,1,2,1,4,21,1,1} +#define OIDipRouteAge {1,3,6,1,2,1,4,21,1,10} +#define OIDipRouteMask {1,3,6,1,2,1,4,21,1,11} +#define OIDipRouteMetric5 {1,3,6,1,2,1,4,21,1,12} +#define OIDipRouteInfo {1,3,6,1,2,1,4,21,1,13} +#define OIDipRouteIfIndex {1,3,6,1,2,1,4,21,1,2} +#define OIDipRouteMetric1 {1,3,6,1,2,1,4,21,1,3} +#define OIDipRouteMetric2 {1,3,6,1,2,1,4,21,1,4} +#define OIDipRouteMetric3 {1,3,6,1,2,1,4,21,1,5} +#define OIDipRouteMetric4 {1,3,6,1,2,1,4,21,1,6} +#define OIDipRouteNextHop {1,3,6,1,2,1,4,21,1,7} +#define OIDipRouteType {1,3,6,1,2,1,4,21,1,8} +#define OIDipRouteProto {1,3,6,1,2,1,4,21,1,9} +#define OIDipNetToMediaTable {1,3,6,1,2,1,4,22} +#define OIDipNetToMediaEntry {1,3,6,1,2,1,4,22,1} +#define OIDipNetToMediaIfIndex {1,3,6,1,2,1,4,22,1,1} +#define OIDipNetToMediaPhysAddress {1,3,6,1,2,1,4,22,1,2} +#define OIDipNetToMediaNetAddress {1,3,6,1,2,1,4,22,1,3} +#define OIDipNetToMediaType {1,3,6,1,2,1,4,22,1,4} +#define OIDipRoutingDiscards {1,3,6,1,2,1,4,23} +#define OIDipInReceives {1,3,6,1,2,1,4,3} +#define OIDipInHdrErrors {1,3,6,1,2,1,4,4} +#define OIDipInAddrErrors {1,3,6,1,2,1,4,5} +#define OIDipForwDatagrams {1,3,6,1,2,1,4,6} +#define OIDipInUnknownProtos {1,3,6,1,2,1,4,7} +#define OIDipInDiscards {1,3,6,1,2,1,4,8} +#define OIDipInDelivers {1,3,6,1,2,1,4,9} +#define OIDicmp {1,3,6,1,2,1,5} +#define OIDicmpInMsgs {1,3,6,1,2,1,5,1} +#define OIDicmpInTimestamps {1,3,6,1,2,1,5,10} +#define OIDicmpInTimestampReps {1,3,6,1,2,1,5,11} +#define OIDicmpInAddrMasks {1,3,6,1,2,1,5,12} +#define OIDicmpInAddrMaskReps {1,3,6,1,2,1,5,13} +#define OIDicmpOutMsgs {1,3,6,1,2,1,5,14} +#define OIDicmpOutErrors {1,3,6,1,2,1,5,15} +#define OIDicmpOutDestUnreachs {1,3,6,1,2,1,5,16} +#define OIDicmpOutTimeExcds {1,3,6,1,2,1,5,17} +#define OIDicmpOutParmProbs {1,3,6,1,2,1,5,18} +#define OIDicmpOutSrcQuenchs {1,3,6,1,2,1,5,19} +#define OIDicmpInErrors {1,3,6,1,2,1,5,2} +#define OIDicmpOutRedirects {1,3,6,1,2,1,5,20} +#define OIDicmpOutEchos {1,3,6,1,2,1,5,21} +#define OIDicmpOutEchoReps {1,3,6,1,2,1,5,22} +#define OIDicmpOutTimestamps {1,3,6,1,2,1,5,23} +#define OIDicmpOutTimestampReps {1,3,6,1,2,1,5,24} +#define OIDicmpOutAddrMasks {1,3,6,1,2,1,5,25} +#define OIDicmpOutAddrMaskReps {1,3,6,1,2,1,5,26} +#define OIDicmpInDestUnreachs {1,3,6,1,2,1,5,3} +#define OIDicmpInTimeExcds {1,3,6,1,2,1,5,4} +#define OIDicmpInParmProbs {1,3,6,1,2,1,5,5} +#define OIDicmpInSrcQuenchs {1,3,6,1,2,1,5,6} +#define OIDicmpInRedirects {1,3,6,1,2,1,5,7} +#define OIDicmpInEchos {1,3,6,1,2,1,5,8} +#define OIDicmpInEchoReps {1,3,6,1,2,1,5,9} +#define OIDtcp {1,3,6,1,2,1,6} +#define OIDtcpRtoAlgorithm {1,3,6,1,2,1,6,1} +#define OIDtcpInSegs {1,3,6,1,2,1,6,10} +#define OIDtcpOutSegs {1,3,6,1,2,1,6,11} +#define OIDtcpRetransSegs {1,3,6,1,2,1,6,12} +#define OIDtcpConnTable {1,3,6,1,2,1,6,13} +#define OIDtcpConnEntry {1,3,6,1,2,1,6,13,1} +#define OIDtcpConnState {1,3,6,1,2,1,6,13,1,1} +#define OIDtcpConnLocalAddress {1,3,6,1,2,1,6,13,1,2} +#define OIDtcpConnLocalPort {1,3,6,1,2,1,6,13,1,3} +#define OIDtcpConnRemAddress {1,3,6,1,2,1,6,13,1,4} +#define OIDtcpConnRemPort {1,3,6,1,2,1,6,13,1,5} +#define OIDtcpInErrs {1,3,6,1,2,1,6,14} +#define OIDtcpOutRsts {1,3,6,1,2,1,6,15} +#define OIDtcpRtoMin {1,3,6,1,2,1,6,2} +#define OIDtcpRtoMax {1,3,6,1,2,1,6,3} +#define OIDtcpMaxConn {1,3,6,1,2,1,6,4} +#define OIDtcpActiveOpens {1,3,6,1,2,1,6,5} +#define OIDtcpPassiveOpens {1,3,6,1,2,1,6,6} +#define OIDtcpAttemptFails {1,3,6,1,2,1,6,7} +#define OIDtcpEstabResets {1,3,6,1,2,1,6,8} +#define OIDtcpCurrEstab {1,3,6,1,2,1,6,9} +#define OIDudp {1,3,6,1,2,1,7} +#define OIDudpInDatagrams {1,3,6,1,2,1,7,1} +#define OIDudpNoPorts {1,3,6,1,2,1,7,2} +#define OIDudpInErrors {1,3,6,1,2,1,7,3} +#define OIDudpOutDatagrams {1,3,6,1,2,1,7,4} +#define OIDudpTable {1,3,6,1,2,1,7,5} +#define OIDudpEntry {1,3,6,1,2,1,7,5,1} +#define OIDudpLocalAddress {1,3,6,1,2,1,7,5,1,1} +#define OIDudpLocalPort {1,3,6,1,2,1,7,5,1,2} +#define OIDegp {1,3,6,1,2,1,8} +#define OIDegpInMsgs {1,3,6,1,2,1,8,1} +#define OIDegpInErrors {1,3,6,1,2,1,8,2} +#define OIDegpOutMsgs {1,3,6,1,2,1,8,3} +#define OIDegpOutErrors {1,3,6,1,2,1,8,4} +#define OIDegpNeighTable {1,3,6,1,2,1,8,5} +#define OIDegpNeighEntry {1,3,6,1,2,1,8,5,1} +#define OIDegpNeighState {1,3,6,1,2,1,8,5,1,1} +#define OIDegpNeighStateUps {1,3,6,1,2,1,8,5,1,10} +#define OIDegpNeighStateDowns {1,3,6,1,2,1,8,5,1,11} +#define OIDegpNeighIntervalHello {1,3,6,1,2,1,8,5,1,12} +#define OIDegpNeighIntervalPoll {1,3,6,1,2,1,8,5,1,13} +#define OIDegpNeighMode {1,3,6,1,2,1,8,5,1,14} +#define OIDegpNeighEventTrigger {1,3,6,1,2,1,8,5,1,15} +#define OIDegpNeighAddr {1,3,6,1,2,1,8,5,1,2} +#define OIDegpNeighAs {1,3,6,1,2,1,8,5,1,3} +#define OIDegpNeighInMsgs {1,3,6,1,2,1,8,5,1,4} +#define OIDegpNeighInErrs {1,3,6,1,2,1,8,5,1,5} +#define OIDegpNeighOutMsgs {1,3,6,1,2,1,8,5,1,6} +#define OIDegpNeighOutErrs {1,3,6,1,2,1,8,5,1,7} +#define OIDegpNeighInErrMsgs {1,3,6,1,2,1,8,5,1,8} +#define OIDegpNeighOutErrMsgs {1,3,6,1,2,1,8,5,1,9} +#define OIDegpAs {1,3,6,1,2,1,8,6} +#define OIDexperimental {1,3,6,1,3} +#define OIDprivate {1,3,6,1,4} +#define OIDenterprises {1,3,6,1,4,1} + +#endif // __SNMPOIDS_H \ No newline at end of file diff --git a/shared-code/SNMPeer.h b/shared-code/SNMPeer.h new file mode 100644 index 0000000..68f2efe --- a/dev/null +++ b/shared-code/SNMPeer.h @@ -0,0 +1,286 @@ +#ifndef __SNMPEER_H +#define __SNMPEER_H + +namespace Klever { + +class CASNAny { +public: + enum { + asnCls = 0xC0, + asnClsUniversal = 0x00, + asnClsApplication = 0x40, + asnClsContextSpecific = 0x80, + asnClsPrivate = 0xC0, + asnConstructed = 0x20, + asnPrimitive = 0x00, + asnTag = 0x1F, + // ASN.1 Primitive Tags + asnTagInteger = 0x02, + asnTagOctetString = 0x04, + asnTagNull = 0x05, + asnTagOID = 0x06, + // ASN.1 Constructed Tags + asnTagSequence = 0x10, + // RFC1155 Primitive Tags + asnTagIP = 0x00, + asnTagCounter = 0x01, + asnTagGauge = 0x02, + asnTagTicks = 0x03, + asnTagOpaque = 0x04, + // RFC1213 alias + asnTagDispString = 0x04, // (ASN.1 Octet string) + // RFC1157 Constructed Tags + asnTagGetRequest = 0x00, + asnTagGetNextRequest = 0x01, + asnTagGetResponse = 0x02, + asnTagSetRequest = 0x03, + asnTagTrap = 0x04 + }; + enum { + typeASNInteger = (asnClsUniversal|asnPrimitive|asnTagInteger), + typeASNOctetString = (asnClsUniversal|asnPrimitive|asnTagOctetString), + typeASNNull = (asnClsUniversal|asnPrimitive|asnTagNull), + typeASNOID = (asnClsUniversal|asnPrimitive|asnTagOID), + + typeASNSequence = (asnClsUniversal|asnConstructed|asnTagSequence), + typeASNSequenceOf = (asnClsUniversal|asnConstructed|asnTagSequence), + + typeASNIP = (asnClsApplication|asnPrimitive|asnTagIP), + typeASNCounter = (asnClsApplication|asnPrimitive|asnTagCounter), + typeASNGauge = (asnClsApplication|asnPrimitive|asnTagGauge), + typeASNTicks = (asnClsApplication|asnPrimitive|asnTagTicks), + typeASNOpaque = (asnClsApplication|asnPrimitive|asnTagOpaque), + typeASNDispString = (asnClsUniversal|asnPrimitive|asnTagOctetString), + + typeASNGetRequest = (asnClsContextSpecific|asnConstructed|asnTagGetRequest), + typeASNGetNextRequest = (asnClsContextSpecific|asnConstructed|asnTagGetNextRequest), + typeASNGetResponse = (asnClsContextSpecific|asnConstructed|asnTagGetResponse), + typeASNSetRequest = (asnClsContextSpecific|asnConstructed|asnTagSetRequest), + typeASNTrap = (asnClsContextSpecific|asnConstructed|asnTagTrap) + }; + + typedef LONG asnInteger; + typedef LARGE_INTEGER asnInteger64; + typedef DWORD asnCounter; + typedef ULARGE_INTEGER asnCounter64; + typedef DWORD asnGauge; + typedef ULARGE_INTEGER asnGauge64; + typedef DWORD asnTicks; + typedef ULARGE_INTEGER asnTicks64; + struct asnDynamic { + UINT size; + LPBYTE data; + BOOL Allocate(UINT size) { + BOOL rv = Free(); + if(size) + rv=rv&&(data=new BYTE[size]); + if(rv) + asnDynamic::size=size; + return rv; + } + BOOL Set(LPBYTE data,UINT size) { + BOOL rv = Allocate(size); + if(rv && size) + memmove(asnDynamic::data,data,size); + return rv; + } + BOOL Free() { + if(!size) + return TRUE; + delete data; + size=0; + data=0; + return TRUE; + } + void Clean() { + size=0; + data=0; + } + BOOL Copy(asnDynamic& src) { + BOOL rv = Free(); + if(rv){ + if(src.size) + rv=rv&&(data = new BYTE[src.size]); + if(rv){ + if(size=src.size) + memmove(data,src.data,size); + } + } + return rv; + } + }; + typedef asnDynamic asnOctetString; + typedef asnDynamic asnOID; + typedef in_addr asnIP; + typedef asnDynamic asnSequence; + + BYTE type; + enum _storeType { + storeDynamic, + storeStatic + } storeType; + union { + asnInteger number; + asnInteger64 number64; + asnOctetString string; + asnOID oid; + asnSequence sequence; + asnIP ip; + asnCounter counter; + asnCounter64 counter64; + asnGauge gauge; + asnGauge64 gauge64; + asnTicks ticks; + asnTicks64 ticks64; + asnDynamic data; + } value; + + CASNAny() : type(typeASNNull), storeType(storeStatic) { value.data.Clean(); } + CASNAny(CASNAny& src) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Copy(src); } + CASNAny(BYTE type) : type(type), storeType(storeStatic) { value.data.Clean(); } + CASNAny(BYTE type,LONG number) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,number); } + CASNAny(BYTE type,LONGLONG number) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,number); } + CASNAny(BYTE type,LPCTSTR string) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,string); } + CASNAny(BYTE type,LPBYTE data,UINT length) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,data,length); } + CASNAny(BYTE type,UINT* data,UINT size) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(type,(LPBYTE)data,size); } + CASNAny(in_addr& ip) : type(typeASNNull), storeType(storeStatic) { value.data.Clean();Set(ip); } + ~CASNAny() { Free(); } + + BOOL Set(BYTE type) { + BOOL rv = Free(); + CASNAny::type=type; + return rv; + } + BOOL Set(BYTE type,LONG number) { + BOOL rv = Free(); + CASNAny::type=type; + value.number=number; + storeType=storeStatic; + return rv; + } + BOOL Set(BYTE type,LONGLONG number) { + BOOL rv = Free(); + CASNAny::type=type; + value.number64.QuadPart = number; + storeType=storeStatic; + return rv; + } + BOOL Set(BYTE type,LPCTSTR string) { + BOOL rv = Free(); + CASNAny::type=type; + rv=rv&&value.string.Set((LPBYTE)string,strlen(string)+1); + if(rv){ + value.string.size--; + storeType=storeDynamic; + } + return rv; + } + BOOL Set(BYTE type,LPBYTE data,UINT length) { + BOOL rv = Free(); + CASNAny::type=type; + rv=rv&&value.data.Set(data,length); + if(rv) + storeType=storeDynamic; + return rv; + } + BOOL Set(in_addr& ip) { + BOOL rv = Free(); + memmove(&value.ip,&ip,sizeof(value.ip)); + type=typeASNIP; + storeType=storeStatic; + return rv; + } + BOOL Free() { + if(storeType==storeDynamic) + value.data.Free(); + else{ + memset(&value,0,sizeof(value)); + value.data.Clean(); + } + storeType=storeStatic; + type=typeASNNull; + return TRUE; + } + BOOL Copy(CASNAny& src) { + BOOL rv = Free(); + if(src.storeType==storeDynamic){ + rv=rv&&value.data.Copy(src.value.data); + if(rv){ + type=src.type; + storeType=src.storeType; + } + }else{ + memmove(this,&src,sizeof(*this)); + } + return rv; + } + CASNAny& operator=(CASNAny& src) { + VERIFY(Copy(src)); + return *this; + } + + // High Level + CString GetString() { + ASSERT(storeType==storeDynamic); + CString rv; + LPTSTR b = rv.GetBuffer(value.data.size+1); + ASSERT(b); + b[value.data.size]=0; + memmove(b,value.data.data,value.data.size); + rv.ReleaseBuffer(); + return rv; + } +}; + + +class CSNMPVarBind { +public: + CASNAny name; + CASNAny value; + + CSNMPVarBind() {} + CSNMPVarBind(CASNAny& name,CASNAny& value) : name(name), value(value) {} + CSNMPVarBind(CASNAny& name) : name(name) {} + CSNMPVarBind(CSNMPVarBind& src) { Copy(src); } + BOOL Copy(CSNMPVarBind& src) { + name.Copy(src.name); + value.Copy(src.value); + return TRUE; + } + CSNMPVarBind& operator=(CSNMPVarBind& src) { + Copy(src); + return *this; + } + // High level + BOOL IsName(UINT* prefix,UINT prefixSize,BOOL bExact=FALSE) { + if(name.type!=CASNAny::typeASNOID) + return FALSE; + if(name.value.oid.size { +public: + CSNMPVarBind* GetVarBind(UINT* prefix,UINT prefixSize,BOOL bExact=FALSE) { + POSITION p = GetHeadPosition(); + while(p){ + CSNMPVarBind& vb = GetNext(p); + if(vb.IsName(prefix,prefixSize,bExact)) + return &vb; + } + return NULL; + } +}; + +class CSNMPeer { +public: + virtual BOOL Request(BYTE type,CSNMPVarBindList& in,CSNMPVarBindList& ou) = 0; +}; + +}; + +#endif // __SNMPEER_H diff --git a/shared-code/install.h b/shared-code/install.h new file mode 100644 index 0000000..8c55ca9 --- a/dev/null +++ b/shared-code/install.h @@ -0,0 +1,370 @@ +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN +#define WIN32_EXTRALEAN +#include +#include +#include +#include +#include +#include + +extern "C" WINSHELLAPI void WINAPI SHFree( LPVOID); + +template class Smart { +public: + T *pT; + + Smart() : pT(NULL) {} + Smart(int cb) : pT(new T[cb]) {} + Smart(T* p) : pT(p) {} + ~Smart() { if(pT)delete pT; } + + Smart& operator=(T* p) { if(pT)delete pT; pT=p; return *this; } + operator T* () { return pT; } + +// T& operator[](int ndx) { return pT[ndx]; } + + T* Detach() { T* rv = pT; pT=NULL; return rv; } +}; +typedef Smart STRING; + +#define APPEND_SLASH(str) if((str)[strlen(str)-1]!='\\')strcat(str,"\\") + +HINSTANCE theInstance; + +LPSTR strFETCH_REG_KEY(HKEY hRoot,LPCSTR subKey,LPCSTR val) +{ +HKEY hkey; + if(RegOpenKeyEx(hRoot,subKey,0,KEY_QUERY_VALUE,&hkey)!=ERROR_SUCCESS) + return NULL; +DWORD kType,cb=0; +STRING rv; + if(RegQueryValueEx(hkey,val,NULL,&kType,NULL,&cb)==ERROR_SUCCESS && kType==REG_SZ){ + rv= new char[cb]; + _ASSERT(rv!=NULL); + if(RegQueryValueEx(hkey,val,NULL,&kType,(LPBYTE)(LPSTR)rv,&cb)!=ERROR_SUCCESS) + rv=NULL; + } + RegCloseKey(hkey); + return rv.Detach(); +} + +BOOL strSET_REG_KEY(HKEY hRoot,LPCSTR subKey,LPCSTR valName,LPCSTR val) +{ +HKEY hkey; +DWORD dw; + if(RegCreateKeyEx(hRoot,subKey,0,REG_NONE,REG_OPTION_NON_VOLATILE,KEY_READ|KEY_WRITE,NULL,&hkey,&dw)!=ERROR_SUCCESS) + return FALSE; +BOOL rv = (RegSetValueEx(hkey,valName,0,REG_SZ,(LPBYTE)val,strlen(val)+1)==ERROR_SUCCESS); + RegCloseKey(hkey); + return rv; +} + +void MAKE_PATH(LPCSTR path) +{ +STRING tmp(strlen(path)+1); +LPCSTR t0=path; +LPSTR t1=tmp; + while(*t0){ + if((*t0)=='\\'){ + *t1=0; + CreateDirectory(tmp,NULL); + } + *(t1++)=*(t0++); + } + *t1=0; + CreateDirectory(tmp,NULL); +} + +BOOL ADDMENU(LPCSTR menu,LPCSTR item,LPCSTR path,LPCSTR program) +{ +STRING stm = strFETCH_REG_KEY(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders","Programs"); + if(!stm) + return FALSE; +int pil = 1+strlen(path)+1+strlen(program)+1+1; +STRING pi(pil); + strcpy(pi,path); + APPEND_SLASH(pi); + strcat(pi,program); +int ipl = strlen(stm)+1+strlen(menu)+1+strlen(item)+4+1; +STRING ip(ipl); + memmove(ip,stm,strlen(stm)+1); + APPEND_SLASH(ip); + strcat(ip,menu); + MAKE_PATH(ip); + APPEND_SLASH(ip); + strcat(ip,item); + strcat(ip,".lnk"); +IShellLink* sl = NULL; +IPersistFile* pf = NULL; +BOOL rv = FALSE; + do{ + HRESULT hrv = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(LPVOID*)&sl); + if(!SUCCEEDED(hrv)) + break; + sl->SetDescription(item); + sl->SetPath(pi); + hrv = sl->QueryInterface(IID_IPersistFile,(LPVOID*)&pf); + if(!SUCCEEDED(hrv)) + break; + WORD wsz[MAX_PATH]; + MultiByteToWideChar(CP_ACP,0,ip,-1,wsz,MAX_PATH); + hrv = pf->Save(wsz,TRUE); + if(SUCCEEDED(hrv)) + rv=TRUE; + }while(FALSE); + if(pf) + pf->Release(); + if(sl) + sl->Release(); + return rv; +} + +FILE* CREATE_INF_FILE(LPCSTR path,LPCSTR file) +{ +STRING fn(strlen(path)+1+strlen(file)+1); + strcpy(fn,path); + APPEND_SLASH(fn); + strcat(fn,file); + return fopen(fn,"wt"); +} + +BOOL INSTALLFILE(LPCSTR res,LPCSTR path,LPCSTR file) +{ +STRING temp(MAX_PATH); + if(!GetTempPath(MAX_PATH,temp)) return FALSE; +STRING tf(MAX_PATH); + if(!GetTempFileName(temp,"KGI",0,tf)) return FALSE; +HRSRC hrsrc = FindResource(NULL,res,MAKEINTRESOURCE(RT_RCDATA)); + if(!hrsrc) return FALSE; +DWORD sor = SizeofResource(NULL,hrsrc); + if(!sor) return FALSE; +HGLOBAL hglobal = LoadResource(NULL,hrsrc); + if(!hglobal) return FALSE; +LPVOID lpv = LockResource(hglobal); + if(!lpv) return FALSE; +HANDLE hf = CreateFile(tf,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY,NULL); + if(!hf) return FALSE; +DWORD written = 0; + if(!WriteFile(hf,lpv,sor,&written,NULL) || written!=sor){ + CloseHandle(hf); + return FALSE; + } + CloseHandle(hf); +STRING toKill(strlen(tf)+1); + strcpy(toKill,tf); + for(int tmp=strlen(tf)-1;tmp>0 && ((tf[tmp])!='\\');tmp--); + if(tf[tmp]=='\\') + tf[tmp++]=0; +STRING nothing(_MAX_PATH); +UINT nothingLength=_MAX_PATH; + if(VerInstallFile(0,&tf[tmp],(LPSTR)file,tf,(LPSTR)path,NULL,nothing,¬hingLength)){ + DeleteFile(toKill); + return FALSE; + } + DeleteFile(toKill); + return TRUE; +} + +LPCSTR pdTitle, pdPrompt; +char pdPath[_MAX_PATH]; +BOOL CALLBACK pathDlgProc(HWND hwnd,UINT uMsg,WPARAM wP,LPARAM lP) +{ + switch(uMsg){ + case WM_INITDIALOG: + SetWindowText(hwnd,pdTitle); + SetDlgItemText(hwnd,IDC_PROMPT,pdPrompt); + SetDlgItemText(hwnd,IDC_PATH,pdPath); + SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); + return 1; + case WM_COMMAND: + switch(LOWORD(wP)){ // ID + case IDC_BROWSE: + switch(HIWORD(wP)){ + case BN_CLICKED: + { + BROWSEINFO bi; + memset(&bi,0,sizeof(bi)); + bi.hwndOwner=hwnd; + bi.pszDisplayName=pdPath; + bi.lpszTitle="Select Folder.."; + bi.ulFlags=BIF_RETURNONLYFSDIRS; + LPITEMIDLIST lpidl=SHBrowseForFolder(&bi); + if(lpidl){ + SHGetPathFromIDList(lpidl,pdPath); + SHFree(lpidl); + SetDlgItemText(hwnd,IDC_PATH,pdPath); + } + } + return 1; + } + break; + case IDOK: + switch(HIWORD(wP)){ + case BN_CLICKED: + if(GetDlgItemText(hwnd,IDC_PATH,pdPath,sizeof(pdPath))) + EndDialog(hwnd,IDOK); + else + // *** Error message + EndDialog(hwnd,IDCANCEL); + return 1; + } + break; + case IDCANCEL: + switch(HIWORD(wP)){ + case BN_CLICKED: + EndDialog(hwnd,IDCANCEL); + return 1; + } + break; + }; + break; + } + return 0; +} + +LPSTR REQUESTPATH(LPCSTR title,LPCSTR prompt,LPCSTR defPath) +{ + pdTitle=title;pdPrompt=prompt; + strcpy(pdPath,defPath); + if(DialogBox(NULL,MAKEINTRESOURCE(IDD_PATH),NULL/*Parent*/,(DLGPROC)&pathDlgProc)!=IDOK) + return NULL; +STRING rv(strlen(pdPath)+1); + strcpy(rv,pdPath); + return rv.Detach(); +} + +HKEY uninstallKey(LPCSTR regKey) { + STRING rk(100+strlen(regKey)+1); + sprintf(rk,"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s",regKey); + HKEY rv = NULL; + DWORD dw; + if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,rk,0,REG_NONE,REG_OPTION_NON_VOLATILE,KEY_READ|KEY_WRITE,NULL,&rv,&dw)!=ERROR_SUCCESS) + return NULL; + return rv; +} + +BOOL REG_UNINSTALL_COMMAND(LPCSTR regKey,LPCSTR dName,LPCSTR iPath,LPCSTR iFile,LPCSTR iSection) +{ + HKEY hKey = uninstallKey(regKey); + if(!hKey) + return FALSE; + BOOL rv=FALSE; + do{ + if(RegSetValueEx(hKey,"DisplayName",0,REG_SZ,(LPBYTE)dName,strlen(dName)+1)!=ERROR_SUCCESS) + break; + STRING us(50+strlen(iPath)+1+strlen(iFile)+strlen(iSection)+1); + strcpy(us,"RunDll32 setupapi.dll,InstallHinfSection "); + strcat(us,iSection); + strcat(us," 132 "); + strcat(us,iPath); + APPEND_SLASH(us); + strcat(us,iFile); + if(RegSetValueEx(hKey,"UninstallString",0,REG_SZ,(LPBYTE)(LPCSTR)us,strlen(us)+1)!=ERROR_SUCCESS) + break; + rv=TRUE; + }while(FALSE); + RegCloseKey(hKey); + return rv; +} +BOOL REG_UNINSTALL_ICON(LPCSTR regKey,LPCSTR path,LPCSTR file,int n) { + HKEY hKey = uninstallKey(regKey); + if(!hKey) + return FALSE; + STRING uis(strlen(path)+1+strlen(file)+7); + strcpy(uis,path); + APPEND_SLASH(uis); + strcat(uis,file); + char tmp[8]; + sprintf(tmp,";%d",n); + strcat(uis,tmp); + BOOL rv = TRUE; + if(RegSetValueEx(hKey,"DisplayIcon",0,REG_SZ,(LPBYTE)(LPCSTR)uis,strlen(uis)+1)!=ERROR_SUCCESS) + rv = FALSE; + RegCloseKey(hKey); + return rv; +} +BOOL REG_UNINSTALL_COMMENT(LPCSTR regKey,LPCSTR comment) { + HKEY hKey = uninstallKey(regKey); + if(!hKey) + return FALSE; + BOOL rv = TRUE; + if(RegSetValueEx(hKey,"lComment",0,REG_SZ,(LPBYTE)comment,strlen(comment)+1)!=ERROR_SUCCESS) + rv = FALSE; + RegCloseKey(hKey); + return rv; +} +BOOL REG_UNINSTALL_VERSION(LPCSTR regKey,LPCSTR version) { + HKEY hKey = uninstallKey(regKey); + if(!hKey) + return FALSE; + BOOL rv = TRUE; + if(RegSetValueEx(hKey,"DisplayVersion",0,REG_SZ,(LPBYTE)version,strlen(version)+1)!=ERROR_SUCCESS) + rv = FALSE; + RegCloseKey(hKey); + return rv; +} +BOOL REG_UNINSTALL_LOCATION(LPCSTR regKey,LPCSTR location) { + HKEY hKey = uninstallKey(regKey); + if(!hKey) + return FALSE; + BOOL rv = TRUE; + if(RegSetValueEx(hKey,"InstallLocation",0,REG_SZ,(LPBYTE)location,strlen(location)+1)!=ERROR_SUCCESS) + rv = FALSE; + RegCloseKey(hKey); + return rv; +} +BOOL REG_UNINSTALL_PUBLISHER(LPCSTR regKey,LPCSTR publisher) { + HKEY hKey = uninstallKey(regKey); + if(!hKey) + return FALSE; + BOOL rv = TRUE; + if(RegSetValueEx(hKey,"Publisher",0,REG_SZ,(LPBYTE)publisher,strlen(publisher)+1)!=ERROR_SUCCESS) + rv = FALSE; + RegCloseKey(hKey); + return rv; +} +BOOL REG_UNINSTALL_URLS(LPCSTR regKey,LPCSTR about,LPCSTR update) { + HKEY hKey = uninstallKey(regKey); + if(!hKey) + return FALSE; + BOOL rv = TRUE; + if(RegSetValueEx(hKey,"URLInfoAbout",0,REG_SZ,(LPBYTE)about,strlen(about)+1)!=ERROR_SUCCESS) + rv = FALSE; + if(RegSetValueEx(hKey,"URLUpdateInfo",0,REG_SZ,(LPBYTE)update,strlen(update)+1)!=ERROR_SUCCESS) + rv = FALSE; + RegCloseKey(hKey); + return rv; +} + +#define INF_FILE_HEADER(i) fprintf(i,"[Version]\nSignature=\"$CHICAGO$\"\n\n") +#define INF_FILE_SECTION(i,s) fprintf(i,"\n[%s]\n",s) +#define INF_UNINSTALL_REG(i,p) fprintf(i,"HKLM,Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s\nHKLM,Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s,DisplayName\nHKLM,Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s,UninstallString\n",p,p,p) +#define INF_MENU_GROUP(i,n,m) fprintf(i,"setup.ini, progman.groups,,\"group%d=%s\"\n",n,m) +#define INF_MENU_ITEM(i,n,m) fprintf(i,"setup.ini, group%d,, \"\"\"%s\"\"\"\n",n,m); +#define INF_REMOVE_ROOT(i,g,r) fprintf(i,"HKLM,Software\\Microsoft\\Windows\\CurrentVersion\\DeleteFiles\\%s,,,\"%s\"\n",g,r) +#define INF_REMOVE_FILE(i,g,f) fprintf(i,"HKLM,Software\\Microsoft\\Windows\\CurrentVersion\\DeleteFiles\\%s,%s,,\"%s\"\n",g,f,f) +#define INF_REMOVE_HELP_FILE(i,g,f) {INF_REMOVE_FILE(i,g,f".hlp");INF_REMOVE_FILE(i,g,f".cnt");INF_REMOVE_FILE(i,g,f".GID");INF_REMOVE_FILE(i,g,f".FTS");} + +LPSTR GET_SHORT_PATH(LPCSTR path) +{ +char tmp; +DWORD len = GetShortPathName(path,&tmp,1); + if(!len) + return NULL; +STRING rv(len+1); + if(!GetShortPathName(path,rv,len+1)) + return NULL; + return rv.Detach(); +} + +BOOL Install(void); + +int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR,int) +{ + theInstance=hInstance; + CoInitialize(NULL); + Install(); + CoUninitialize(); + return 0; +} diff --git a/shared-code/ip_icmp.h b/shared-code/ip_icmp.h new file mode 100644 index 0000000..acaf7e9 --- a/dev/null +++ b/shared-code/ip_icmp.h @@ -0,0 +1,91 @@ +#ifndef IP_ICMPHEADER + +#define IP_ICMPHEADER + +struct icmp { + BYTE icmp_type; + BYTE icmp_code; + WORD icmp_cksum; + WORD icmp_id; + WORD icmp_seq; + char icmp_data[1]; +}; + +#define SIZE_ICMP_HDR 8 +#define SIZE_TIME_DATA 8 + +struct ip { + BYTE ip_hl:4, /* header length */ + ip_v:4; /* version */ + BYTE ip_tos; /* type of service */ + short ip_len; /* total length */ + u_short ip_id; /* identification */ + short ip_off; /* fragment offset field */ + BYTE ip_ttl; /* time to live */ + BYTE ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +}; + +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ + +#define ICMP_MAXTYPE 18 + +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + +#define STNORM 0 + +/* Definition of the lowest telnet byte following an IAC byte */ +#define LOW_TEL_OPT 236 + +#define TEL_EOF 236 +#define SUSP 237 +#define ABORT 238 + +#define SE 240 +#define NOP 241 +#define DM 242 +#define BREAK 243 +#define IP 244 +#define AO 245 +#define AYT 246 +#define EC 247 +#define EL 248 +#define GOAHEAD 249 +#define SB 250 +#define WILL 251 +#define WONT 252 +#define DO 253 +#define DONT 254 +#define IAC 255 + +#endif + diff --git a/shared-code/kHelpers.h b/shared-code/kHelpers.h new file mode 100644 index 0000000..209c6b0 --- a/dev/null +++ b/shared-code/kHelpers.h @@ -0,0 +1,159 @@ +#ifndef __KHELPERS_H +#define __KHELPERS_H + +#include + +extern "C" WINSHELLAPI void WINAPI SHFree( LPVOID); + +namespace Klever { + + inline BOOL BrowseForFolder(CString& folder,LPCTSTR title=NULL,CWnd* pParent=NULL) { + BROWSEINFO bi; + memset(&bi,0,sizeof(bi)); + if(pParent) + bi.hwndOwner=pParent->GetSafeHwnd(); + CString rv; + bi.pszDisplayName=rv.GetBuffer(MAX_PATH); + bi.lpszTitle=title; + bi.ulFlags=BIF_RETURNONLYFSDIRS; + LPITEMIDLIST lpidl = SHBrowseForFolder(&bi); + if(lpidl){ + SHGetPathFromIDList(lpidl,bi.pszDisplayName); + SHFree(lpidl); + rv.ReleaseBuffer(); + folder=rv; + return TRUE; + } + rv.ReleaseBuffer(); + return FALSE; + } + inline BOOL BrowseForFolder(CString& folder,UINT idTitle,CWnd* pParent=NULL) { + CString title; + VERIFY(title.LoadString(idTitle)); + return BrowseForFolder(folder,title,pParent); + } + inline CString GluePathAndFile(LPCTSTR path,LPCTSTR file) { + CString rv = path; + while((!rv.IsEmpty()) && rv[rv.GetLength()-1]=='\\') + rv=rv.Left(rv.GetLength()-1); + rv+='\\'; + while(*file && *file=='\\') + file++; + rv+=file; + return rv; + } + inline UINT TokenizeString(CStringList& rv,LPCTSTR string,LPCTSTR delimiter) { + CString s = string; + int found; + int delength = strlen(delimiter); + int rvc = 0; + while((found=s.Find(delimiter))>=0){ + rv.AddTail(s.Left(found)); + rvc++; + s=s.Mid(found+delength); + } + if(!s.IsEmpty()){ + rv.AddTail(s); + rvc++; + } + return rvc; + } + inline BOOL LogRecord(LPCTSTR logFile,LPCTSTR logRecord) { + try{ + CFile f(logFile,CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::shareDenyWrite); + f.SeekToEnd(); + CString s = CTime::GetCurrentTime().Format("[%c] ")+logRecord+"\r\n"; + f.Write((LPCTSTR)s,s.GetLength()); + }catch(CException* e){ + e->Delete(); + return FALSE; + } + return TRUE; + } + inline BOOL ReadString(CFile* file,CString& rv) { + rv.Empty(); + int nBuffer = 256; + TCHAR* ch = rv.GetBuffer(nBuffer); + int nPos = 0; + BOOL bRV = FALSE; + for(;;){ + TCHAR c; + try{ + if(file->Read(&c,sizeof(c))!=sizeof(c)) + break; + bRV=TRUE; + }catch(CException* e){ + e->Delete(); + TRACE0("Exception in ReadString\n"); + return FALSE; + } + if(nPos>=(nBuffer-1)){ + rv.ReleaseBuffer(); + ch = rv.GetBuffer(nBuffer=nBuffer+256); + ASSERT(ch); + } + if(c=='\n') + break; + ch[nPos++]=c; + } + ch[nPos]=0; + for(;;){ + nPos--; + if(nPos<0) + break; + if(ch[nPos]!='\r') + break; + ch[nPos]=0; + } + rv.ReleaseBuffer(); + rv.FreeExtra(); + return bRV; + } + + inline int LoadStringList(CStringList& list,LPCTSTR section) { + CString n; + list.RemoveAll(); + CWinApp* app = AfxGetApp(); + ASSERT(app); + for(int tmp=0;;tmp++){ + n.Format("%d",tmp); + CString str = app->GetProfileString(section,n,NULL); + if(str.IsEmpty()) + break; + list.AddTail(str); + } + return tmp; + } + inline int SaveStringList(CStringList& list,LPCTSTR section) { + CString n; + CWinApp* app = AfxGetApp(); + ASSERT(app); + POSITION p = list.GetHeadPosition(); + for(int tmp=0;p;tmp++){ + n.Format("%d",tmp); + app->WriteProfileString(section,n,list.GetNext(p)); + } + n.Format("%d",tmp); + app->WriteProfileString(section,n,NULL); + return tmp; + } + + inline BOOL WriteProfileString(LPCTSTR section,LPCTSTR entry,LPCTSTR str) { + CWinApp* app = AfxGetApp(); + return app->WriteProfileBinary(section,entry,(LPBYTE)str,strlen(str)+1); + } + inline CString GetProfileString(LPCTSTR section,LPCTSTR entry,LPCTSTR defval) { + CWinApp* app = AfxGetApp(); + LPBYTE pData; + UINT nCount; + CString rv = defval; + if(app->GetProfileBinary(section,entry,&pData,&nCount)){ + rv = (LPCTSTR)pData; + delete pData; + } + return rv; + } + +}; + +#endif // __KHELPERS_H diff --git a/shared-code/kICMP.cpp b/shared-code/kICMP.cpp new file mode 100644 index 0000000..09a8f94 --- a/dev/null +++ b/shared-code/kICMP.cpp @@ -0,0 +1,300 @@ +#include "../stdafx.h" +#include "kICMP.h" + +CICMP::_mechanismus CICMP::m_mechanismus = CICMP::_icmpUndetermined; + +BOOL CICMPDll::Initialize() +{ + if(m_hICMP!=INVALID_HANDLE_VALUE || m_hICMPDLL) + Deinitialize(); + m_hICMPDLL = ::LoadLibraryEx("ICMP",NULL,0); + if(!m_hICMPDLL) + return FALSE; + *(FARPROC*)&m_icmpCF = ::GetProcAddress(m_hICMPDLL,"IcmpCreateFile"); + *(FARPROC*)&m_icmpSE = ::GetProcAddress(m_hICMPDLL,"IcmpSendEcho"); + *(FARPROC*)&m_icmpCH = ::GetProcAddress(m_hICMPDLL,"IcmpCloseHandle"); + if(!(m_icmpCF && m_icmpSE && m_icmpCH)){ + Deinitialize(); return FALSE; + } + m_hICMP = (*m_icmpCF)(); + if(m_hICMP==INVALID_HANDLE_VALUE){ + Deinitialize(); return FALSE; + } + TRACE0("ICMP-DLL Initialized\n"); + return TRUE; +} +void CICMPDll::Deinitialize() +{ + if(m_hICMPDLL){ + if(m_hICMP!=INVALID_HANDLE_VALUE && m_icmpCH) + (*m_icmpCH)(m_hICMP); + ::FreeLibrary(m_hICMPDLL); m_hICMPDLL = NULL; + m_icmpCF = NULL; + m_icmpSE = NULL; + m_icmpCH = NULL; + } + m_hICMP=INVALID_HANDLE_VALUE; + if(m_sizeOut && m_bsOut){ + delete m_bsOut; + m_bsOut = NULL; m_sizeOut = 0; + } + if(m_sizeIn && m_bsIn){ + delete m_bsIn; + m_bsIn = NULL; m_sizeIn = 0; + } +} + +LONG CICMPDll::Ping(const in_addr host,const UINT packetSize, + const UINT timeOut,LPINT pStatus) +{ + if(!(m_hICMP && m_hICMPDLL && m_icmpSE)){ + if(pStatus) + (*pStatus) = icmpNotInitialized; + return -1; + } + VERIFY(AdjustBuffers(packetSize)); +IPINFO ipi; + memset(&ipi,0,sizeof(ipi)); + ipi.Ttl = 30; + for(UINT tmp=0;tmpStatus = 0xFFFFFFFFl; + if((*m_icmpSE)(m_hICMP,host.s_addr,m_bsOut,packetSize, + &ipi,pRep,m_sizeIn,timeOut)) + TRACE0("ICMP-SendEcho succeeded\n"); + else + TRACE0("ICMP-SendEcho failed\n"); +LONG lrv = -1; +INT rv = ipUnknown; + switch(pRep->Status){ + case IP_SUCCESS: + lrv = pRep->RTTime; rv = ipSuccess; + break; + case IP_BUF_TOO_SMALL: rv = ipBuffTooSmall; break; + case IP_DEST_NET_UNREACHABLE: rv = ipDestNetUnreachable; break; + case IP_DEST_HOST_UNREACHABLE: rv = ipDestHostUnreachable; break; + case IP_DEST_PROT_UNREACHABLE: rv = ipDestProtUnreachable; break; + case IP_DEST_PORT_UNREACHABLE: rv = ipDestPortUnreachable; break; + case IP_NO_RESOURCES: rv = ipNoResources; break; + case IP_BAD_OPTION: rv = ipBadOption; break; + case IP_HW_ERROR: rv = ipHWError; break; + case IP_PACKET_TOO_BIG: rv = ipPacketTooBig; break; + case IP_REQ_TIMED_OUT: rv = ipTimeOut; break; + case IP_BAD_REQ: rv = ipBadRequest; break; + case IP_BAD_ROUTE: rv = ipBadRoute; break; + case IP_TTL_EXPIRED_TRANSIT: rv = ipTTLExpiredInTransit; break; + case IP_TTL_EXPIRED_REASSEM: rv = ipTTLExpiredInReasm; break; + case IP_PARAM_PROBLEM: rv = ipParamProblem; break; + case IP_SOURCE_QUENCH: rv = ipSourceQuench; break; + case IP_OPTION_TOO_BIG: rv = ipOptionTooBig; break; + case IP_BAD_DESTINATION: rv = ipBadDest; break; + } + if(pStatus) + (*pStatus)=rv; + return lrv; +} + +BOOL CICMPDll::AdjustBuffers(UINT packetSize) +{ + if(!packetSize) + packetSize=1; + if(packetSize>m_sizeOut){ + if(m_sizeOut && m_bsOut) + delete m_bsOut; + m_bsOut = new BYTE[m_sizeOut=packetSize]; + if(!m_bsOut) + return FALSE; + } +UINT sin = sizeof(ICMPECHO)+SIZE_ICMP_HDR+packetSize; + if(sin>m_sizeIn){ + if(m_sizeIn && m_bsIn) + delete m_bsIn; + m_bsIn = new BYTE[m_sizeIn=sin]; + if(!m_bsIn) + return FALSE; + } + return TRUE; +} + + +WORD CICMPWS::m_icmpSeq = 0; + +BOOL CICMPWS::Initialize() +{ + if(m_socket!=INVALID_SOCKET) + Deinitialize(); + m_socket = socket(AF_INET,SOCK_RAW,1/*ICMP*/); + if(m_socket==INVALID_SOCKET) + return FALSE; + TRACE0("ICMP-WS Initialized\n"); + return TRUE; +} +void CICMPWS::Deinitialize() +{ + if(m_socket!=INVALID_SOCKET){ + closesocket(m_socket); + m_socket=INVALID_SOCKET; + } + if(m_sizeOut && m_bsOut){ + delete m_bsOut; + m_bsOut = NULL; m_sizeOut = 0; + } + if(m_sizeIn && m_bsIn){ + delete m_bsIn; + m_bsIn = NULL; m_sizeIn = 0; + } +} +LONG CICMPWS::Ping(const in_addr host,const UINT packetSize, + const UINT timeOut,LPINT pStatus) +{ + if(m_socket==INVALID_SOCKET){ + if(pStatus) + (*pStatus)=icmpNotInitialized; + } + VERIFY(AdjustBuffers(packetSize)); +icmp* pPacket = (icmp*)m_bsOut; + memset(pPacket,0,m_sizeOut); + pPacket->icmp_type = ICMP_ECHO; + pPacket->icmp_seq = m_icmpSeq++; + pPacket->icmp_id = (WORD)(::GetCurrentThreadId()&0xFFFF); + for(UINT tmp=0;tmpicmp_data[tmp]=tmp&0xFF; + pPacket->icmp_cksum = cksum(pPacket,SIZE_ICMP_HDR+packetSize); +sockaddr_in to; + memset(&to,0,sizeof(to)); + to.sin_addr.s_addr = host.s_addr; + to.sin_family = AF_INET; + if(sendto(m_socket,(char*)pPacket,SIZE_ICMP_HDR+packetSize,0, + (SOCKADDR*)&to,sizeof(to)) != (int)(SIZE_ICMP_HDR+packetSize)){ + TRACE1("sendto: %lu\n",WSAGetLastError()); + if(pStatus) + (*pStatus)=icmpSocketError; + return -1; + } +DWORD sentTime = ::GetTickCount(); +sockaddr_in from; + memset(&from,0,sizeof(from)); + from.sin_family=AF_INET; + from.sin_addr.s_addr=INADDR_ANY; +fd_set fds; + FD_ZERO(&fds); + FD_SET(m_socket,&fds); +long lrv = -1; +INT rv = ipTimeOut; + for(;;){ + DWORD ct = ::GetTickCount(); + if((ct-sentTime)>=timeOut){ + TRACE0("Timeout\n"); + break; + } + timeval tv = { + (timeOut-ct+sentTime)/1000, + (timeOut-ct+sentTime)%1000 + }; // tv_sec, tv_usec (secs,microsecs) + if(!select(m_socket,&fds,NULL,NULL,&tv)){ + TRACE1("select: %d\n",WSAGetLastError()); + break; + } + DWORD rtime = ::GetTickCount(); + ASSERT(FD_ISSET(m_socket,&fds)); + int fl = sizeof(from); + int rb = recvfrom(m_socket,(char*)m_bsIn,m_sizeIn,0,(SOCKADDR*)&from,&fl); + ip* pIP = (ip*)m_bsIn; + icmp* pICMP = (icmp*)&m_bsIn[sizeof(ip)]; + if(pICMP->icmp_id!=pPacket->icmp_id) + continue; + if(pICMP->icmp_seq!=pPacket->icmp_seq) + continue; + if(from.sin_addr.s_addr!=host.s_addr) + continue; + if(pICMP->icmp_type==ICMP_ECHOREPLY){ + lrv=rtime-sentTime; + rv=ipSuccess; + break; + } + rv = ipUnknown; // *** + break; + } + if(pStatus) + (*pStatus)=rv; + return lrv; +} + +BOOL CICMPWS::AdjustBuffers(UINT packetSize) +{ + if(!packetSize) + packetSize=0; +UINT osize = packetSize+SIZE_ICMP_HDR; + if(m_sizeOut0){ + if(count>1){ + lSum+=*(pData++); + count-=2; + }else{ + lSum+=((WORD)*(BYTE*)pData)&0xFF; + count--; + } + } + lSum = (lSum&0xFFFF)+(lSum>>16); + lSum += (lSum>>16); + return (~lSum)&0xFFFF; +} + +CICMP* CICMP::CreateICMP() +{ + if(m_mechanismus==_icmpUndetermined) + GuessMechanismus(); + switch(m_mechanismus){ + case _icmpWinsock: + return new CICMPWS; + break; + case _icmpDLL: + return new CICMPDll; + break; + } + return NULL; +} + +void CICMP::GuessMechanismus() +{ + m_mechanismus=_icmpUndetermined; +SOCKET testSocket = socket(AF_INET,SOCK_RAW,1); + if(testSocket!=INVALID_SOCKET){ + closesocket(testSocket); + m_mechanismus=_icmpWinsock; + }else{ + HINSTANCE hICMP = ::LoadLibraryEx("ICMP",NULL,0); + if(!hICMP) + return; + BOOL isThere = ( + ::GetProcAddress(hICMP,"IcmpCreateFile") + && ::GetProcAddress(hICMP,"IcmpSendEcho") + && ::GetProcAddress(hICMP,"IcmpCloseHandle") + ); + ::FreeLibrary(hICMP); + if(isThere) + m_mechanismus=_icmpDLL; + } +} \ No newline at end of file diff --git a/shared-code/kICMP.h b/shared-code/kICMP.h new file mode 100644 index 0000000..7a5ceaa --- a/dev/null +++ b/shared-code/kICMP.h @@ -0,0 +1,80 @@ +#ifndef __KICMP_H +#define __KICMP_H + +class CICMP { + enum _mechanismus { + _icmpUndetermined = -1, + _icmpWinsock = 0, _icmpDLL + }; +static _mechanismus m_mechanismus; +static void GuessMechanismus(); +public: +static + CICMP* CreateICMP(); + + enum { + ipSuccess = 0, + ipBuffTooSmall, ipDestNetUnreachable, ipDestHostUnreachable, + ipDestProtUnreachable, ipDestPortUnreachable, ipNoResources, + ipBadOption, ipHWError, ipPacketTooBig, ipTimeOut, ipBadRequest, + ipBadRoute, ipTTLExpiredInTransit, ipTTLExpiredInReasm, + ipParamProblem, ipSourceQuench, ipOptionTooBig, ipBadDest, + ipUnknown = -1, + icmpNotInitialized = -2, + icmpSocketError = -3 + }; + + virtual BOOL Initialize() = 0; + virtual void Deinitialize() = 0; + + virtual LONG Ping(const in_addr host,const UINT packetSize=0, + const UINT timeOut=10000,LPINT pStatus=NULL) = 0; +}; + +class CICMPDll : public CICMP { + HANDLE (WINAPI *m_icmpCF)(VOID); + BOOL (WINAPI *m_icmpSE)(HANDLE,ULONG,LPVOID,WORD, + PIPINFO,LPVOID,DWORD,DWORD); + BOOL (WINAPI *m_icmpCH)(HANDLE); +public: + HINSTANCE m_hICMPDLL; + HANDLE m_hICMP; + LPBYTE m_bsIn, m_bsOut; + UINT m_sizeIn, m_sizeOut; + + CICMPDll() : m_hICMP(INVALID_HANDLE_VALUE), m_hICMPDLL(NULL), + m_bsIn(NULL), m_bsOut(NULL), m_sizeIn(0), m_sizeOut(0) {} + virtual ~CICMPDll() { Deinitialize(); } + + virtual BOOL Initialize(); + virtual void Deinitialize(); + + virtual LONG Ping(const in_addr host,const UINT packetSize=0, + const UINT timeOut=10000,LPINT pStatus=NULL); + + BOOL AdjustBuffers(UINT packetSize=0); +}; + +class CICMPWS : public CICMP { +static + WORD m_icmpSeq; +public: + SOCKET m_socket; + LPBYTE m_bsIn, m_bsOut; + UINT m_sizeIn, m_sizeOut; + + CICMPWS() : m_socket(INVALID_SOCKET), m_bsIn(NULL), m_bsOut(NULL), + m_sizeIn(0), m_sizeOut(0) {} + virtual ~CICMPWS() { Deinitialize(); } + + virtual BOOL Initialize(); + virtual void Deinitialize(); + + virtual LONG Ping(const in_addr host,const UINT packetSize=0, + const UINT timeOut=10000,LPINT pStatus=NULL); + + BOOL AdjustBuffers(UINT packetSize=0); + WORD cksum(LPVOID data,int count); +}; + +#endif // __KICMP_H \ No newline at end of file diff --git a/shared-code/kinhelp.xsl b/shared-code/kinhelp.xsl new file mode 100644 index 0000000..0bb384a --- a/dev/null +++ b/shared-code/kinhelp.xsl @@ -0,0 +1,250 @@ + + + + + + + {\rtf1\ansi + @{\footnote + THIS FILE WAS AUTOMATICALLY GENERATED FROM XML DOCUMENT. + DO NOT MODIFY THIS FILE DIRECTLY. EDIT XML DOCUMENT INSTEAD + } + + + + } + + + + \pard\plain + + \keepn + + + #{\footnote + + } + + + ${\footnote + + } + + + K{\footnote + + } + + + \page + + + + {#{\footnote + + }} + + + + + + + + + + + + + {\uldb + + }{\v %!ExecFile(" + + ")} + + + {\uldb + + }{\v + + } + + + Warining: Unqualified hyper-reference. Using as help-internal + {\uldb + + }{\v + + } + + + + + + + + \pard + + { \f1\fs18\b\sb120 + + } + + + + \par\sa120\sb120\qj + + \pard + + \f1\fs18\sb120 + + + + + \par\sa120\sb120\qj\f1\fs16 + + + + + \par\sa120\sb120\qr\f1\fs16 + + + + + \{bmct + + \} + + + + \par\pard\plain\f1\fs24\qc\cf2\b + + - + + + + + \par\pard\plain\fi0\li0\f1\fs18 \bullet + + + + + {\b + + } + + + {\i + + } + + + {\ul + + } + + + {\strike + + } + + + + + + + + {\b } + + + + {\b + + } + + + + + + + + + {\b\cf6 } + + + + {\b\cf6 + + } + + + + + {\i + + } + + + + + + + + + + + { + \par\pard\plain\sb360\sa120 \f1\fs16 Copyright (c) + + {\uldb\cf0 Klever Group (http://www.klever.net/)}{\v %!ExecFile("http://www.klever.net/")} + \par\qj\sb120\sa120 + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + \par The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + \par \sa360 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + } + + + \par \sa0\sb120\ql \f1\fs16 Author: {\b\uldb\cf11 Michael Krelin ({\i hacker@klever.net})}{\v %!ExecFile("mailto:hacker@klever.net")} + \par \sa0\sb0 Fan mail send to {\i\uldb gefilte@klever.net}{\v %!ExecFile("mailto:gefilte@klever.net")} + + + + \pard + + \pard + + + + + \par \fi0\li \bullet + + + + + + + + + + + {\colortbl; + \red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0; + \red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255; + \red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128; + \red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;} + + + + {\fonttbl + {\f0\froman Times New Roman;} + {\f1\fswiss Arial;} + {\f3\froman Symbol;} + } + + + diff --git a/shared-code/ms_icmp.h b/shared-code/ms_icmp.h new file mode 100644 index 0000000..32d97f5 --- a/dev/null +++ b/shared-code/ms_icmp.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------ +* Filename: MS_ICMP.H +* +* Description: Prototypes of Microsoft's ICMP.DLL functions for +* access to Internet Control Message Protocol (their stacks do +* not support the standard Berkeley Sockets raw socket API). +* Use this to do "ping" or "traceroute," although beware that +* Microsoft discourages its use. +*/ + + +/* Note 2: For the most part, you can refer to RFC 791 for detials on +* how to fill in values for the IP option information structure. */ +typedef struct ip_option_information { + u_char Ttl; /* Time To Live (used for traceroute) */ + u_char Tos; /* Type Of Service (usually 0) */ + u_char Flags; /* IP header flags (usually 0) */ + u_char OptionsSize; /* Size of options data (usually 0, max 40) */ + u_char FAR *OptionsData;/* Options data buffer */ +} IPINFO, *PIPINFO, FAR *LPIPINFO; + +/* Note 1: The Reply Buffer will have an array of ICMP_ECHO_REPLY +* structures, followed by options and the data in ICMP echo reply +* datagram received. You must have room for at least one ICMP +* echo reply structure, plus 8 bytes for an ICMP header. */ +typedef struct icmp_echo_reply { + u_long Address; /* source address */ + u_long Status; /* IP status value (see below) */ + u_long RTTime; /* Round Trip Time in milliseconds */ + u_short DataSize; /* reply data size */ + u_short Reserved; /* */ + void FAR *Data; /* reply data buffer */ + typedef struct ip_option_information Options; /* reply options */ +} ICMPECHO, *PICMPECHO, FAR *LPICMPECHO; + +#define IP_STATUS_BASE 11000 +#define IP_SUCCESS 0 +#define IP_BUF_TOO_SMALL (IP_STATUS_BASE + 1) +#define IP_DEST_NET_UNREACHABLE (IP_STATUS_BASE + 2) +#define IP_DEST_HOST_UNREACHABLE (IP_STATUS_BASE + 3) +#define IP_DEST_PROT_UNREACHABLE (IP_STATUS_BASE + 4) +#define IP_DEST_PORT_UNREACHABLE (IP_STATUS_BASE + 5) +#define IP_NO_RESOURCES (IP_STATUS_BASE + 6) +#define IP_BAD_OPTION (IP_STATUS_BASE + 7) +#define IP_HW_ERROR (IP_STATUS_BASE + 8) +#define IP_PACKET_TOO_BIG (IP_STATUS_BASE + 9) +#define IP_REQ_TIMED_OUT (IP_STATUS_BASE + 10) +#define IP_BAD_REQ (IP_STATUS_BASE + 11) +#define IP_BAD_ROUTE (IP_STATUS_BASE + 12) +#define IP_TTL_EXPIRED_TRANSIT (IP_STATUS_BASE + 13) +#define IP_TTL_EXPIRED_REASSEM (IP_STATUS_BASE + 14) +#define IP_PARAM_PROBLEM (IP_STATUS_BASE + 15) +#define IP_SOURCE_QUENCH (IP_STATUS_BASE + 16) +#define IP_OPTION_TOO_BIG (IP_STATUS_BASE + 17) +#define IP_BAD_DESTINATION (IP_STATUS_BASE + 18) +#define IP_ADDR_DELETED (IP_STATUS_BASE + 19) +#define IP_SPEC_MTU_CHANGE (IP_STATUS_BASE + 20) +#define IP_MTU_CHANGE (IP_STATUS_BASE + 21) +#define IP_UNLOAD (IP_STATUS_BASE + 22) +#define IP_GENERAL_FAILURE (IP_STATUS_BASE + 50) +#define MAX_IP_STATUS IP_GENERAL_FAILURE +#define IP_PENDING (IP_STATUS_BASE + 255) + + +HANDLE WINAPI PASCAL IcmpCreateFile(VOID); /* INVALID_HANDLE_VALUE on error */ +BOOL WINAPI PASCAL IcmpCloseHandle(HANDLE IcmpHandle); /* FALSE on error */ +DWORD WINAPI PASCAL IcmpSendEcho( + HANDLE IcmpHandle, /* handle returned from IcmpCreateFile() */ + u_long DestAddress, /* destination IP address (in network order) */ + LPVOID RequestData, /* pointer to buffer to send */ + WORD RequestSize, /* length of data in buffer */ + LPIPINFO RequestOptns, /* see Note 2 below */ + LPVOID ReplyBuffer, /* see Note 1 below */ + DWORD ReplySize, /* length of reply (must allow at least 1 reply) */ + DWORD Timeout /* time in milliseconds to wait for reply */ +); + diff --git a/shared-data/browse-icon.ico b/shared-data/browse-icon.ico new file mode 100644 index 0000000..d2d1b3c --- a/dev/null +++ b/shared-data/browse-icon.ico Binary files differ diff --git a/shared-data/install-icon.ico b/shared-data/install-icon.ico new file mode 100644 index 0000000..23e86a6 --- a/dev/null +++ b/shared-data/install-icon.ico Binary files differ diff --git a/shared-data/klever-background.bmp b/shared-data/klever-background.bmp new file mode 100644 index 0000000..e4d87ec --- a/dev/null +++ b/shared-data/klever-background.bmp Binary files differ diff --git a/shared-data/play-icon.ico b/shared-data/play-icon.ico new file mode 100644 index 0000000..3d2a11e --- a/dev/null +++ b/shared-data/play-icon.ico Binary files differ diff --git a/status.cpp b/status.cpp new file mode 100644 index 0000000..3338590 --- a/dev/null +++ b/status.cpp @@ -0,0 +1,30 @@ + +enum _STSB { + stsbSend = 1, + stsbIs = 0 +}; + +BOOL statusOnDo() +{ + TRACE0("DO STATUS\n"); + return TRUE; +} +BOOL statusOnWill() +{ + TRACE0("WILL STATUS\n"); + return TRUE; +} +BOOL statusOnSB(LPBYTE data,UINT size) +{ + if(!size) + return FALSE; + switch(data[0]){ + case stsbSend: + TRACE0("SB STATUS SEND\n"); + break; + case stsbIs: + TRACE0("SB STATUS IS\n"); + break; + } + return TRUE; +} \ No newline at end of file diff --git a/terminal.cpp b/terminal.cpp new file mode 100644 index 0000000..f60ce8b --- a/dev/null +++ b/terminal.cpp @@ -0,0 +1,147 @@ +extern int TTTermType; +class CTTY; +struct _tType { + LPCTSTR m_Name; + CTTY* m_Termcap; +}; +extern _tType TTypes[]; + +BOOL TerminalUpdateTitle(); + +#include "TTY.cpp" +#include "VT100.cpp" + +enum _TTSB { + ttsbSend = 1, + ttsbIs = 0 +}; + +_tType TTypes[] = { + {"VT102",&TT_VT100}, + {"DEC-VT102",&TT_VT100}, + {"VT100",&TT_VT100}, + {"DEC-VT100",&TT_VT100}, + {"ANSI",&TT_VT100}, + {"TTY",&TT_TTY}, + {"UNKNOWN",&TT_TTY}, + {"DUMB",&TT_TTY} +}; +int TType = -1; +CTTY* TTTerm = NULL; +int TTTermType = -1; + +BOOL TerminalPullType(LPCTSTR ttype,LPCTSTR newName=NULL) +{ + for(int tmp=0;tmp<(sizeof(TTypes)/sizeof(*TTypes));tmp++){ + if(!stricmp(ttype,TTypes[tmp].m_Name)){ + if(tmp){ + _tType t; + memmove(&t,&TTypes[tmp],sizeof(t)); + memmove(&TTypes[1],&TTypes[0],sizeof(*TTypes)*tmp); + memmove(&TTypes[0],&t,sizeof(TTypes[0])); + } + if(newName) + TTypes[0].m_Name=newName; + return TRUE; + } + } + return FALSE; +} +BOOL TerminalPrintTypes() +{ + for(int tmp=0;tmp<(sizeof(TTypes)/sizeof(*TTypes));tmp++) + printf(" %s",TTypes[tmp].m_Name); + return TRUE; +} + +BOOL TerminalUpdateTitle() +{ +CHAR consoleTitle[1024]; + sprintf(consoleTitle,DAMN_KIN_NAME " %s:%s - %s",remoteHost,remoteProt,TTTerm->GetTitle()); + return SetConsoleTitle(consoleTitle); +} + +BOOL SelectTermType(int tt) +{ + if(tt<0) + tt=0; + if(tt>=(sizeof(TTypes)/sizeof(*TTypes))) + tt = sizeof(TTypes)/sizeof(*TTypes)-1; + TTTerm = TTypes[tt].m_Termcap; + TTTermType=tt; + VERIFY(TTTerm->Init()); + return TerminalUpdateTitle(); +} +BOOL TerminalOut(BYTE c) +{ + ASSERT(TTTerm); + return TTTerm->Output(c); +} +BOOL TerminalIn(KEY_EVENT_RECORD k) +{ + ASSERT(TTTerm); + if(k.uChar.AsciiChar){ // Maybe fall for V-Processing if ENHANCED_KEY + // Workaround for ENTER's \r/\n dilemma.. *********** + // Maybe should be moved to termtype-dependant code + CHAR c = k.uChar.AsciiChar; + if(k.wVirtualKeyCode==VK_RETURN){ + if(c=='\r') + return TTTerm->Input('\r') && TTTerm->Input('\n'); + else if(c=='\n') + return TTTerm->Input('\n'); + } + return TTTerm->Input(c); + }else + return TTTerm->VInput(k.wVirtualKeyCode,k.dwControlKeyState); +} +BOOL TerminalIn(LPCTSTR str) +{ + ASSERT(TTTerm); + while(*str) + TTTerm->Input(*(str++)); + return TRUE; +} +BOOL TerminalPreO() +{ + ASSERT(TTTerm); + return TTTerm->PreOutput(); +} +BOOL TerminalPostO() +{ + ASSERT(TTTerm); + return TTTerm->PostOutput(); +} + +BOOL terminaltypeOnInit() +{ + VERIFY(SetConsoleMode(hConsoleInput,0)); + TType = -1; + return SelectTermType(0); +} +BOOL terminaltypeOnDo() +{ + TRACE0("DO TERMINAL-TYPE\n"); + return TRUE; +} +BOOL terminaltypeOnSB(LPBYTE data,UINT size) +{ + if(!size) + return FALSE; + if(data[0]!=ttsbSend) + return FALSE; + TRACE0("SB TERMINAL-TYPE SEND\n"); + TType++; + if(TType>(sizeof(TTypes)/sizeof(*TTypes))) + TType=0; +int tt = TType; + if(tt>=(sizeof(TTypes)/sizeof(*TTypes))) + tt = sizeof(TTypes)/sizeof(*TTypes)-1; + VERIFY(SelectTermType(tt)); +int ds = strlen(TTypes[tt].m_Name)+1; +LPBYTE lpb = new BYTE[ds]; + lpb[0] = ttsbIs; + memmove(&lpb[1],TTypes[tt].m_Name,ds-1); + VERIFY(SubNegotiate(toTerminalType,lpb,ds)); + delete lpb; + return TRUE; +} -- cgit v0.9.0.2