Added windows/wintel directory for the windows telnet program
authorKeith Vetter <keithv@fusion.com>
Tue, 28 Mar 1995 04:51:52 +0000 (04:51 +0000)
committerKeith Vetter <keithv@fusion.com>
Tue, 28 Mar 1995 04:51:52 +0000 (04:51 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5278 dc483132-0cff-0310-8789-dd5450dbe970

25 files changed:
src/windows/wintel/auth.c [new file with mode: 0644]
src/windows/wintel/auth.h [new file with mode: 0644]
src/windows/wintel/changelo [new file with mode: 0644]
src/windows/wintel/dialog.h [new file with mode: 0644]
src/windows/wintel/edit.c [new file with mode: 0644]
src/windows/wintel/emul.c [new file with mode: 0644]
src/windows/wintel/font.c [new file with mode: 0644]
src/windows/wintel/ini.h [new file with mode: 0644]
src/windows/wintel/intern.c [new file with mode: 0644]
src/windows/wintel/k5stream.c [new file with mode: 0644]
src/windows/wintel/k5stream.h [new file with mode: 0644]
src/windows/wintel/makefile [new file with mode: 0644]
src/windows/wintel/ncsa.ico [new file with mode: 0644]
src/windows/wintel/negotiat.c [new file with mode: 0644]
src/windows/wintel/screen.c [new file with mode: 0644]
src/windows/wintel/screen.h [new file with mode: 0644]
src/windows/wintel/struct.h [new file with mode: 0644]
src/windows/wintel/telnet.c [new file with mode: 0644]
src/windows/wintel/telnet.def [new file with mode: 0644]
src/windows/wintel/telnet.dlg [new file with mode: 0644]
src/windows/wintel/telnet.h [new file with mode: 0644]
src/windows/wintel/telnet.rc [new file with mode: 0644]
src/windows/wintel/telopts.h [new file with mode: 0644]
src/windows/wintel/terminal.ico [new file with mode: 0644]
src/windows/wintel/wt-proto.h [new file with mode: 0644]

diff --git a/src/windows/wintel/auth.c b/src/windows/wintel/auth.c
new file mode 100644 (file)
index 0000000..f3956ac
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * Implements Kerberos 4 authentication
+ */
+
+#include <time.h>
+#include <string.h>
+#ifdef KRB4
+    #include "kerberos.h"
+#endif
+#include "telnet.h"
+#include "telopts.h"
+
+#ifdef KRB5
+    #include "krb5.h"
+    #include "des_int.h"
+    #include "com_err.h"
+    #include "los-proto.h"
+#endif
+
+/*
+ * Contants
+ */
+       #define IS                                              0
+       #define SEND                                    1
+       #define REPLY                                   2
+       #define NAME                                    3
+
+       #define AUTH_NULL                               0
+       #define KERBEROS_V4                             1
+       #define KERBEROS_V5                             2
+       #define SPX                                             3
+       #define RSA                             6
+       #define LOKI                       10
+
+       #define AUTH                                    0
+       #define K4_REJECT                               1
+       #define K4_ACCEPT                               2
+       #define K4_CHALLENGE                    3
+       #define K4_RESPONSE                             4
+
+       #define K5_REJECT                               1
+       #define K5_ACCEPT                               2
+       #define K5_RESPONSE                             3
+
+       #define AUTH_WHO_MASK               1
+       #define AUTH_CLIENT_TO_SERVER   0
+       #define AUTH_SERVER_TO_CLIENT   1
+
+       #define AUTH_HOW_MASK               2
+       #define AUTH_HOW_ONE_WAY        0
+       #define AUTH_HOW_MUTUAL         2
+
+    #ifndef KSUCCESS
+        #define KSUCCESS    0
+        #define KFAILURE    255
+    #endif
+/*
+ * Globals
+ */
+    #ifdef KRB4
+       static CREDENTIALS cred;
+       #define KRB_SERVICE_NAME    "rcmd"
+        #define KERBEROS_VERSION    KERBEROS_V4
+    #endif
+    #ifdef KRB5
+        static krb5_data auth;
+       static int auth_how;
+        #define KRB_SERVICE_NAME    "host"
+        #define KERBEROS_VERSION    KERBEROS_V5
+    #endif
+
+       BOOL encrypt_enable;
+
+/*+
+ * Function: Enable or disable the encryption process.
+ *
+ * Parameters:
+ *     enable - TRUE to enable, FALSE to disable.
+ */
+static void auth_encrypt_enable(
+       BOOL enable)
+{
+       encrypt_enable = enable;
+
+} /* auth_encrypt_enable */
+
+
+/*+
+ * Function: Abort the authentication process
+ *
+ * Parameters:
+ *     ks - kstream to send abort message to.
+ */
+static void auth_abort(
+       kstream ks,
+       char *errmsg,
+       long r)
+{
+    char buf[9];
+
+       wsprintf(buf, "%c%c%c%c%c%c%c%c", IAC, SB, AUTHENTICATION, IS, AUTH_NULL, AUTH_NULL, IAC, SE);
+       TelnetSend(ks, (LPSTR)buf, 8, 0);
+
+       if (errmsg != NULL) {
+               strcpy(strTmp, errmsg);
+
+               if (r != KSUCCESS) {
+                       strcat(strTmp, "\n");
+            #ifdef KRB4
+                lstrcat(strTmp, krb_get_err_text(r));
+            #endif
+            #ifdef KRB5
+                lstrcat (strTmp, error_message(r));
+            #endif
+               }
+
+               MessageBox(HWND_DESKTOP, strTmp, "Kerberos authentication failed!", MB_OK | MB_ICONEXCLAMATION);
+       }
+
+} /* auth_abort */
+
+
+/*+
+ * Function: Copy data to buffer, doubling IAC character if present.
+ *
+ * Parameters:
+ *     kstream - kstream to send abort message to.
+ */
+static int copy_for_net(
+       unsigned char *to,
+       unsigned char *from,
+       int c)
+{
+       int n;
+
+       n = c;
+
+       while (c-- > 0) {
+               if ((*to++ = *from++) == IAC) {
+                       n++;
+                       *to++ = IAC;
+               }
+       }
+
+       return n;
+
+} /* copy_for_net */
+
+
+/*+
+ * Function: Parse authentication send command
+ *
+ * Parameters:
+ *     ks - kstream to send abort message to.
+ *
+ *  parsedat - the sub-command data.
+ *
+ *     end_sub - index of the character in the 'parsedat' array which
+ *             is the last byte in a sub-negotiation
+ *
+ * Returns: Kerberos error code.
+ */
+static int auth_send(
+       kstream ks,
+       unsigned char *parsedat,
+       int end_sub)
+{
+    char buf[512];
+       char *pname;
+    int plen;
+       int r;
+       int i;
+    #ifdef KRB4
+       KTEXT_ST auth;
+           char instance[INST_SZ];
+       char *realm;
+    #endif /* KRB4 */
+    #ifdef KRB5
+        extern int kerberos5_send (int how);
+    #endif /* KRB5 */
+
+       auth_how = -1;
+
+       for (i = 2; i+1 <= end_sub; i += 2) {
+               if (parsedat[i] == KERBEROS_VERSION)
+                       if ((parsedat[i+1] & AUTH_WHO_MASK) == AUTH_CLIENT_TO_SERVER) {
+                               auth_how = parsedat[i+1] & AUTH_HOW_MASK;
+                               break;
+                       }
+       }
+
+       if (auth_how == -1) {
+               auth_abort(ks, NULL, 0);
+               return KFAILURE;
+       }
+
+    #ifdef KRB4
+       memset(instance, 0, sizeof(instance));
+
+       if (realm = krb_get_phost(szHostName))
+               lstrcpy(instance, realm);
+
+       realm = krb_realmofhost(szHostName);
+
+       if (!realm) {
+               strcpy(buf, "Can't find realm for host \"");
+               strcat(buf, szHostName);
+               strcat(buf, "\"");
+               auth_abort(ks, buf, 0);
+               return KFAILURE;
+       }
+
+       r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0);
+
+       if (r == 0)
+               r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred);
+
+       if (r) {
+               strcpy(buf, "Can't get \"");
+               strcat(buf, KRB_SERVICE_NAME);
+               if (instance[0] != 0) {
+                       strcat(buf, ".");
+                       lstrcat(buf, instance);
+               }
+               strcat(buf, "@");
+               lstrcat(buf, realm);
+               strcat(buf, "\" ticket");
+               auth_abort(ks, buf, r);
+               return r;
+       }
+
+        if (szUserName[0])
+            pname = szUserName;
+        else
+            pname = cred.pname;
+        plen = strlen (szUserName);
+
+    #endif /* KRB4 */
+    
+    #ifdef KRB5
+        r = kerberos5_send (auth_how);
+        if (! r)
+            return KFAILURE;
+
+        plen = strlen (szUserName);             /* Set in kerberos_5 if needed */
+        pname = szUserName;
+
+    #endif /* KRB5 */
+
+       wsprintf(buf, "%c%c%c%c", IAC, SB, AUTHENTICATION, NAME);
+       memcpy (&buf[4], pname, plen);
+       wsprintf(&buf[plen + 4], "%c%c", IAC, SE);
+       TelnetSend(ks, (LPSTR)buf, lstrlen(pname)+6, 0);
+
+       wsprintf(buf, "%c%c%c%c%c%c%c", IAC, SB, AUTHENTICATION, IS,
+               KERBEROS_VERSION, auth_how | AUTH_CLIENT_TO_SERVER, AUTH);
+
+    #if KRB4
+       auth.length = copy_for_net(&buf[7], auth.dat, auth.length);
+    #endif /* KRB4 */
+    #if KRB5
+       auth.length = copy_for_net(&buf[7], auth.data, auth.length);
+    #endif /* KRB5 */
+
+       wsprintf(&buf[auth.length+7], "%c%c", IAC, SE);
+
+       TelnetSend(ks, (LPSTR)buf, auth.length+9, 0);
+
+       return KSUCCESS;
+
+}      /* auth_send */
+
+/*+
+ * Function: Parse authentication reply command
+ *
+ * Parameters:
+ *     ks - kstream to send abort message to.
+ *
+ *  parsedat - the sub-command data.
+ *
+ *     end_sub - index of the character in the 'parsedat' array which
+ *             is the last byte in a sub-negotiation
+ *
+ * Returns: Kerberos error code.
+ */
+#ifdef KRB5
+static int auth_reply(
+       kstream ks,
+       unsigned char *parsedat,
+       int end_sub)
+{
+    extern int kerberos5_reply (int how, unsigned char *data, int cnt);
+    int n;
+
+    n = kerberos5_reply (0, parsedat, end_sub);
+
+    return n;
+}
+#endif  /* KRB5 */
+#ifdef KRB4
+static int auth_reply(
+       kstream ks,
+       unsigned char *parsedat,
+       int end_sub)
+{
+       time_t t;
+       int x;
+    char buf[512];
+       int i;
+    des_cblock session_key;
+    des_key_schedule sched;
+    static des_cblock challenge;
+
+       if (end_sub < 4)
+               return KFAILURE;
+               
+       if (parsedat[2] != KERBEROS_V4)
+               return KFAILURE;
+
+       if (parsedat[4] == K4_REJECT) {
+               buf[0] = 0;
+
+               for (i = 5; i <= end_sub; i++) {
+                       if (parsedat[i] == IAC)
+                               break;
+                       buf[i-5] = parsedat[i];
+                       buf[i-4] = 0;
+               }
+
+               if (!buf[0])
+                       strcpy(buf, "Authentication rejected by remote machine!");
+               MessageBox(HWND_DESKTOP, buf, NULL, MB_OK | MB_ICONEXCLAMATION);
+
+               return KFAILURE;
+       }
+
+       if (parsedat[4] == K4_ACCEPT) {
+               if ((parsedat[3] & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY)
+                       return KSUCCESS;
+
+               if ((parsedat[3] & AUTH_HOW_MASK) != AUTH_HOW_MUTUAL)
+                       return KFAILURE;
+
+        des_key_sched(cred.session, sched);
+
+               t = time(NULL);
+               memcpy(challenge, &t, 4);
+               memcpy(&challenge[4], &t, 4);
+        des_ecb_encrypt(&challenge, &session_key, sched, 1);
+
+               /*
+               * Increment the challenge by 1, and encrypt it for
+               * later comparison.
+               */
+               for (i = 7; i >= 0; --i) {
+                       x = (unsigned int)challenge[i] + 1;
+                       challenge[i] = x;       /* ignore overflow */
+                       if (x < 256)            /* if no overflow, all done */
+                               break;
+               }
+
+        des_ecb_encrypt(&challenge, &challenge, sched, 1);
+
+               wsprintf(buf, "%c%c%c%c%c%c%c", IAC, SB, AUTHENTICATION, IS,
+                       KERBEROS_V4, AUTH_CLIENT_TO_SERVER|AUTH_HOW_MUTUAL, K4_CHALLENGE);
+               memcpy(&buf[7], session_key, 8);
+               wsprintf(&buf[15], "%c%c", IAC, SE);
+               TelnetSend(ks, (LPSTR)buf, 17, 0);
+
+               return KSUCCESS;
+       }
+
+       if (parsedat[4] == K4_RESPONSE) {
+               if (end_sub < 12)
+                       return KFAILURE;
+
+               if (memcmp(&parsedat[5], challenge, sizeof(challenge)) != 0) {
+               MessageBox(HWND_DESKTOP, "Remote machine is being impersonated!",
+                          NULL, MB_OK | MB_ICONEXCLAMATION);
+
+                       return KFAILURE;
+               }
+
+               return KSUCCESS;
+       }
+       
+       return KFAILURE;
+
+} /* auth_reply */
+
+#endif /* KRB4 */
+/*+
+ * Function: Parse the athorization sub-options and reply.
+ *
+ * Parameters:
+ *     ks - kstream to send abort message to.
+ *
+ *     parsedat - sub-option string to parse.
+ *
+ *     end_sub - last charcter position in parsedat.
+ */
+void auth_parse(
+       kstream ks,
+       unsigned char *parsedat,
+       int end_sub)
+{
+       if (parsedat[1] == SEND)
+               auth_send(ks, parsedat, end_sub);
+
+       if (parsedat[1] == REPLY)
+               auth_reply(ks, parsedat, end_sub);
+
+} /* auth_parse */
+
+
+/*+
+ * Function: Initialization routine called kstream encryption system.
+ *
+ * Parameters:
+ *     str - kstream to send abort message to.
+ *
+ *  data - user data.
+ */
+int INTERFACE auth_init(
+       kstream str,
+       kstream_ptr data)
+{
+       return 0;
+
+} /* auth_init */
+
+
+/*+
+ * Function: Destroy routine called kstream encryption system.
+ *
+ * Parameters:
+ *     str - kstream to send abort message to.
+ *
+ *  data - user data.
+ */
+void INTERFACE auth_destroy(
+       kstream str)
+{
+} /* auth_destroy */
+
+
+/*+
+ * Function: Callback to encrypt a block of characters
+ *
+ * Parameters:
+ *     out - return as pointer to converted buffer.
+ *
+ *  in - the buffer to convert
+ *
+ *  str - the stream being encrypted
+ *
+ * Returns: number of characters converted.
+ */
+int INTERFACE auth_encrypt(
+       struct kstream_data_block *out,
+       struct kstream_data_block *in,
+       kstream str)
+{
+       out->ptr = in->ptr;
+
+       out->length = in->length;
+
+       return(out->length);
+
+} /* auth_encrypt */
+
+
+/*+
+ * Function: Callback to decrypt a block of characters
+ *
+ * Parameters:
+ *     out - return as pointer to converted buffer.
+ *
+ *  in - the buffer to convert
+ *
+ *  str - the stream being encrypted
+ *
+ * Returns: number of characters converted.
+ */
+int INTERFACE auth_decrypt(
+       struct kstream_data_block *out,
+       struct kstream_data_block *in,
+       kstream str)
+{
+       out->ptr = in->ptr;
+
+       out->length = in->length;
+
+       return(out->length);
+
+} /* auth_decrypt */
+
+/*+*/
+#ifdef KRB5
+
+/*
+** 
+** Code lifted from telnet sample code in the appl directory.
+** 
+*/
+
+krb5_auth_context *auth_context;
+krb5_flags krb5_kdc_default_options = KDC_OPT_RENEWABLE_OK;
+
+/* 0 on failure, 1 on success */
+int 
+kerberos5_send (int how)
+{
+       krb5_error_code r;
+       krb5_ccache ccache;
+    krb5_creds cred;
+       krb5_creds * new_cred;
+       extern krb5_flags krb5_kdc_default_options;
+       krb5_flags ap_opts;
+    int len;
+
+       if (r = krb5_cc_default(k5_context, &ccache)) {
+        com_err (NULL, r, "while authorizing.");
+               return(0);
+       }
+
+       memset((char *)&cred, 0, sizeof(cred));
+       if (r = krb5_sname_to_principal(k5_context, szHostName, KRB_SERVICE_NAME,
+            KRB5_NT_SRV_HST, &cred.server)) {
+        com_err (NULL, r, "while authorizing.");
+        return(0);
+    }
+
+       if (r = krb5_cc_get_principal(k5_context, ccache, &cred.client)) {
+        com_err (NULL, r, "while authorizing.");
+        krb5_free_cred_contents(k5_context, &cred);
+               return(0);
+       }
+    if (szUserName[0] == '\0') {                /* Get user name now */
+        len  = krb5_princ_component(k5_context, cred.client, 0)->length;
+        memcpy (szUserName,
+            krb5_princ_component(k5_context, cred.client, 0)->data,
+            len);
+        szUserName[len] = '\0';
+    }
+
+
+       if (r = krb5_get_credentials(k5_context, krb5_kdc_default_options,
+                                    ccache, &cred, &new_cred)) {
+        com_err (NULL, r, "while authorizing.");
+               krb5_free_cred_contents(k5_context, &cred);
+               return(0);
+       }
+
+    ap_opts = 0;
+       if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
+           ap_opts = AP_OPTS_MUTUAL_REQUIRED;
+
+       r = krb5_mk_req_extended(k5_context, &auth_context, ap_opts,
+                                NULL, new_cred, &auth);
+
+       krb5_free_cred_contents(k5_context, &cred);
+       krb5_free_creds(k5_context, new_cred);
+
+       if (r) {
+        com_err (NULL, r, "while authorizing.");
+               return(0);
+       }
+
+       return(1);
+}
+/*+*/
+int
+kerberos5_reply (int how, unsigned char *data, int cnt) {
+    static int mutual_complete = 0;
+
+    data += 4;                                  /* Point to status byte */
+
+       switch (*data++) {
+       case K5_REJECT:
+        if (cnt > 0)
+            wsprintf (strTmp,
+                "Kerberos V5 refuses authentication because %.*s",
+                cnt, data);
+               else
+                       wsprintf (strTmp, "Kerberos V5 refuses authentication");
+        MessageBox (HWND_DESKTOP, strTmp, "", MB_OK | MB_ICONEXCLAMATION);
+
+               return KFAILURE;
+
+       case K5_ACCEPT:
+               if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && !mutual_complete) {
+                   wsprintf(strTmp, "Kerberos V5 accepted you, " 
+              "but didn't provide mutual authentication");
+            MessageBox (HWND_DESKTOP, strTmp, "", MB_OK | MB_ICONEXCLAMATION);
+                   return KSUCCESS;
+               }
+
+        return KSUCCESS;
+               break;
+
+       case K5_RESPONSE:
+               if ((how & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
+                   /* the rest of the reply should contain a krb_ap_rep */
+                   krb5_ap_rep_enc_part *reply;
+                   krb5_data inbuf;
+                   krb5_error_code r;
+
+                   inbuf.length = cnt;
+                   inbuf.data = (char *)data;
+
+                   if (r = krb5_rd_rep (k5_context, auth_context, &inbuf, &reply)) {
+                com_err (NULL, r, "while authorizing.");
+                return KFAILURE;
+                   }
+                   krb5_free_ap_rep_enc_part(k5_context, reply);
+
+                   mutual_complete = 1;
+               }
+               return KSUCCESS;
+
+       default:
+               return KSUCCESS;                        // Unknown code
+       }
+}
+#endif /* KRB5 */
diff --git a/src/windows/wintel/auth.h b/src/windows/wintel/auth.h
new file mode 100644 (file)
index 0000000..ddc8b21
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Implements Kerberos 4 authentication and ecryption
+ */
+
+void auth_parse(
+       kstream ks,
+       unsigned char *parsedat,
+       int end_sub);
+
+int INTERFACE auth_init(
+       kstream str,
+       kstream_ptr data);
+
+void INTERFACE auth_destroy(
+       kstream str);
+
+int INTERFACE auth_encrypt(
+       struct kstream_data_block *out,
+       struct kstream_data_block *in,
+       kstream str);
+
+int INTERFACE auth_decrypt(
+       struct kstream_data_block *out,
+       struct kstream_data_block *in,
+       kstream str);
diff --git a/src/windows/wintel/changelo b/src/windows/wintel/changelo
new file mode 100644 (file)
index 0000000..9364c5f
--- /dev/null
@@ -0,0 +1,8 @@
+Mon Mar 27 20:18:41 1995 Keith Vetter (keithv@fusion.com)
+
+       * Initial release based upon the K4 version. 
+        * K4 streams layer is replaced with no-ops in k5stream.c
+        * only one-way authentication tested since a telnet daemon which
+           does mutual is not available.
+        * connect port is hard-wired to 13131 for now since that is the
+           port of the only available K5 telnet daemon (tsx-11.mit.edu)
diff --git a/src/windows/wintel/dialog.h b/src/windows/wintel/dialog.h
new file mode 100644 (file)
index 0000000..da4790f
--- /dev/null
@@ -0,0 +1,31 @@
+#define IDM_ABOUT 100
+#define IDM_SHOWCONSOLE 700
+
+#define IDM_OPENTELNETDLG           200
+#define TEL_CONNECT_NAME            201
+#define TEL_USEDEFAULTS             202
+#define TEL_MANUALCONFIGURE         203
+#define TEL_OK                      204
+#define TEL_CANCEL                  206
+#define CON_SESSIONNAME             302
+#define CON_WINDOWTITLE             304
+#define CON_COLUMNS132              305
+#define CON_COLUMNS80               306
+#define CON_BACKSPACE               307
+#define CON_DELETE                  308
+#define CON_CRLF                    309
+#define CON_CRNUL                   310
+#define CON_BUFFERS                 311
+#define CON_SENDS                   312
+#define CON_OK                      320
+#define CON_USEDEFAULTS             321
+#define CONFIGDLG                   300
+#define CON_SCRLBCK                 317
+#define CON_NUMLINES                318
+#define PRINTQUEUE                  400
+#define IDM_PRINTQUEUE              500
+#define TEL_PUSH1                   601
+#define TEL_PUSH2                   602
+#define TEL_PUSH3                   603
+#define TEL_PUSH4                   604
+#define TEL_PUSH5                   605
diff --git a/src/windows/wintel/edit.c b/src/windows/wintel/edit.c
new file mode 100644 (file)
index 0000000..16ac28c
--- /dev/null
@@ -0,0 +1,419 @@
+#include <windows.h>
+#include <commdlg.h>
+#include <ctype.h>
+#include "screen.h"
+
+char *cInvertedArray;
+int bMouseDown=FALSE;
+int iLocStart,iLocEnd,bSelection;
+
+void Edit_LbuttonDown(HWND hWnd,LPARAM lParam) {
+    SCREEN *fpScr;
+    HGLOBAL hgScr;
+    HMENU hMenu;
+    int iTmp,iXlocStart,iYlocStart;
+    HDC hDC;
+    
+    hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+    if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+    fpScr=(SCREEN *)GlobalLock(hgScr);
+    if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+    
+    hDC=GetDC(hWnd);
+    for (iTmp=0; iTmp < fpScr->width*fpScr->height; iTmp++) {        
+        if (cInvertedArray[iTmp]) {
+            PatBlt(hDC,(iTmp%fpScr->width)*fpScr->cxChar,(int)(iTmp/fpScr->width)*fpScr->cyChar,
+                fpScr->cxChar,fpScr->cyChar,DSTINVERT);                
+            cInvertedArray[iTmp]=0;                    
+        }    
+    }
+    bSelection=FALSE;
+    hMenu=GetMenu(hWnd);
+    EnableMenuItem(hMenu,IDM_COPY,MF_GRAYED);
+    ReleaseDC(hWnd,hDC);
+    iXlocStart=(int)LOWORD(lParam)/fpScr->cxChar;
+       if (iXlocStart >= fpScr->width)
+               iXlocStart = fpScr->width - 1;
+    iYlocStart=(int)HIWORD(lParam)/fpScr->cyChar;
+       if (iYlocStart >= fpScr->height)
+               iYlocStart = fpScr->height - 1;
+    iLocStart=iXlocStart+(iYlocStart*fpScr->width);
+    bMouseDown=TRUE;
+    GlobalUnlock(hgScr);
+}
+
+void Edit_LbuttonUp(HWND hWnd, LPARAM lParam) {
+    SCREEN *fpScr;
+    HGLOBAL hgScr;
+    int iTmp,iTmp2;
+    HMENU hMenu;
+    
+    bMouseDown=FALSE;
+    if (bSelection) return;
+    bSelection=TRUE;
+    hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+    if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+    fpScr=(SCREEN *)GlobalLock(hgScr);
+    if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");        
+    iTmp=(int)LOWORD(lParam)/fpScr->cxChar;
+       if (iTmp >= fpScr->width)
+               iTmp = fpScr->width - 1;
+    iTmp2=(int)HIWORD(lParam)/fpScr->cyChar;
+       if (iTmp2 >= fpScr->height)
+               iTmp2 = fpScr->height - 1;
+    GlobalUnlock(hgScr);
+    iLocEnd=iTmp+(iTmp2*fpScr->width);
+    if (iLocEnd==iLocStart) {
+        bSelection=FALSE;
+    } else {
+        hMenu=GetMenu(hWnd);
+        EnableMenuItem(hMenu,IDM_COPY,MF_ENABLED);
+    }    
+}    
+    
+void Edit_MouseMove(HWND hWnd, LPARAM lParam){
+    SCREEN *fpScr;
+    HGLOBAL hgScr;
+    int iTmp,iTmp2,iXlocCurr,iYlocCurr,iLocCurr,iX,iX2,iY,iY2;
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    HDC hDC;
+    
+    hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+    if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+    fpScr=(SCREEN *)GlobalLock(hgScr);
+    if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+    hDC = GetDC(hWnd);
+    iXlocCurr=(int)LOWORD(lParam)/fpScr->cxChar;
+       if (iXlocCurr >= fpScr->width)
+               iXlocCurr = fpScr->width - 1;
+    iYlocCurr=(int)HIWORD(lParam)/fpScr->cyChar;
+       if (iYlocCurr >= fpScr->height)
+               iYlocCurr = fpScr->height - 1;
+    iLocCurr=iXlocCurr+(iYlocCurr*fpScr->width);
+    if (iLocCurr > iLocStart) {    
+        for (iTmp=0; iTmp < iLocStart; iTmp++) {        
+            if (cInvertedArray[iTmp]) {
+                PatBlt(hDC,(iTmp%fpScr->width)*fpScr->cxChar,(int)(iTmp/fpScr->width)*fpScr->cyChar,
+                    fpScr->cxChar,fpScr->cyChar,DSTINVERT);                
+                cInvertedArray[iTmp]=0;                    
+            }    
+        }
+        iX=(iLocStart%fpScr->width);
+        iY=(int)(iLocStart/fpScr->width);
+        iX2=(iLocCurr%fpScr->width);
+        iY2=(int)(iLocCurr/fpScr->width);
+        if (iY==iY2) {
+            hgScrLine=GetScreenLineFromY(fpScr,iY);
+            fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+            for (iTmp2= iX; iTmp2 < iX2; iTmp2++) {
+                if ((!cInvertedArray[iTmp2+(fpScr->width*iY)])&& fpScrLine->text[iTmp2]) {
+                    PatBlt(hDC,(iTmp2)*fpScr->cxChar,iY*fpScr->cyChar,
+                        fpScr->cxChar,fpScr->cyChar,DSTINVERT);
+                    cInvertedArray[iTmp2+(fpScr->width*iY)]=fpScrLine->text[iTmp2];
+                }    
+            }    
+            LINE_MEM_UNLOCK(hgScrLine);
+        }            
+        else {
+            hgScrLine=GetScreenLineFromY(fpScr,iY);
+            fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+            for (iTmp2= iX; iTmp2 < fpScr->width; iTmp2++) {
+                if ((!cInvertedArray[iTmp2+(fpScr->width*iY)])&& fpScrLine->text[iTmp2]) {
+                    PatBlt(hDC,(iTmp2)*fpScr->cxChar,iY*fpScr->cyChar,
+                        fpScr->cxChar,fpScr->cyChar,DSTINVERT);
+                    cInvertedArray[iTmp2+(fpScr->width*iY)]=fpScrLine->text[iTmp2];
+                }    
+            }                
+            for (iTmp=iY+1; iTmp < iY2; iTmp++) {
+                hgScrLine=GetScreenLineFromY(fpScr,iTmp);
+                fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+                for (iTmp2= 0; iTmp2 < fpScr->width; iTmp2++) {
+                    if ((!cInvertedArray[iTmp2+(fpScr->width*iTmp)])&& fpScrLine->text[iTmp2]) {
+                        PatBlt(hDC,(iTmp2)*fpScr->cxChar,iTmp*fpScr->cyChar,
+                            fpScr->cxChar,fpScr->cyChar,DSTINVERT);
+                        cInvertedArray[iTmp2+(fpScr->width*iTmp)]=fpScrLine->text[iTmp2];
+                    }    
+                }    
+                LINE_MEM_UNLOCK(hgScrLine);
+            }
+            if (!(iY2==iY)) {
+                hgScrLine=GetScreenLineFromY(fpScr,iY2);
+                fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+                for (iTmp2= 0; iTmp2 < iX2; iTmp2++) {
+                    if ((!cInvertedArray[iTmp2+(fpScr->width*iY2)])&& fpScrLine->text[iTmp2]) {
+                        PatBlt(hDC,(iTmp2)*fpScr->cxChar,iY2*fpScr->cyChar,
+                            fpScr->cxChar,fpScr->cyChar,DSTINVERT);
+                        cInvertedArray[iTmp2+(fpScr->width*iY2)]=fpScrLine->text[iTmp2];
+                    }    
+                }    
+                LINE_MEM_UNLOCK(hgScrLine);                
+            }                
+
+        }    
+        for (iTmp=iLocCurr; iTmp < fpScr->width*fpScr->height; iTmp++) {        
+            if (cInvertedArray[iTmp]) {
+                PatBlt(hDC,(iTmp%fpScr->width)*fpScr->cxChar,(int)(iTmp/fpScr->width)*fpScr->cyChar,
+                    fpScr->cxChar,fpScr->cyChar,DSTINVERT);                
+                cInvertedArray[iTmp]=0;                    
+            }    
+        }
+    } else { /* going backwards */
+        for (iTmp=0; iTmp < iLocCurr; iTmp++) {        
+            if (cInvertedArray[iTmp]) {
+                PatBlt(hDC,(iTmp%fpScr->width)*fpScr->cxChar,(int)(iTmp/fpScr->width)*fpScr->cyChar,
+                    fpScr->cxChar,fpScr->cyChar,DSTINVERT);                
+                cInvertedArray[iTmp]=0;                    
+            }    
+        }
+        iX=(iLocCurr%fpScr->width);
+        iY=(int)(iLocCurr/fpScr->width);
+        iX2=(iLocStart%fpScr->width);
+        iY2=(int)(iLocStart/fpScr->width);
+        if (iY==iY2) {
+            hgScrLine=GetScreenLineFromY(fpScr,iY);
+            fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+            for (iTmp2= iX; iTmp2 < iX2; iTmp2++) {
+                if ((!cInvertedArray[iTmp2+(fpScr->width*iY)])&& fpScrLine->text[iTmp2]) {
+                    PatBlt(hDC,(iTmp2)*fpScr->cxChar,iY*fpScr->cyChar,
+                        fpScr->cxChar,fpScr->cyChar,DSTINVERT);
+                    cInvertedArray[iTmp2+(fpScr->width*iY)]=fpScrLine->text[iTmp2];
+                }    
+            }    
+            LINE_MEM_UNLOCK(hgScrLine);
+        }            
+        else {
+            hgScrLine=GetScreenLineFromY(fpScr,iY);
+            fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+            for (iTmp2= iX; iTmp2 < fpScr->width; iTmp2++) {
+                if ((!cInvertedArray[iTmp2+(fpScr->width*iY)])&& fpScrLine->text[iTmp2]) {
+                    PatBlt(hDC,(iTmp2)*fpScr->cxChar,iY*fpScr->cyChar,
+                        fpScr->cxChar,fpScr->cyChar,DSTINVERT);
+                    cInvertedArray[iTmp2+(fpScr->width*iY)]=fpScrLine->text[iTmp2];
+                }    
+            }                
+            for (iTmp=iY+1; iTmp < iY2; iTmp++) {
+                hgScrLine=GetScreenLineFromY(fpScr,iTmp);
+                fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+                for (iTmp2= 0; iTmp2 < fpScr->width; iTmp2++) {
+                    if ((!cInvertedArray[iTmp2+(fpScr->width*iTmp)])&& fpScrLine->text[iTmp2]) {
+                        PatBlt(hDC,(iTmp2)*fpScr->cxChar,iTmp*fpScr->cyChar,
+                            fpScr->cxChar,fpScr->cyChar,DSTINVERT);
+                        cInvertedArray[iTmp2+(fpScr->width*iTmp)]=fpScrLine->text[iTmp2];
+                    }    
+                }    
+                LINE_MEM_UNLOCK(hgScrLine);
+            }
+            if (!(iY2==iY)) {
+                hgScrLine=GetScreenLineFromY(fpScr,iY2);
+                fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+                for (iTmp2= 0; iTmp2 < iX2; iTmp2++) {
+                    if ((!cInvertedArray[iTmp2+(fpScr->width*iY2)])&& fpScrLine->text[iTmp2]) {
+                        PatBlt(hDC,(iTmp2)*fpScr->cxChar,iY2*fpScr->cyChar,
+                            fpScr->cxChar,fpScr->cyChar,DSTINVERT);
+                        cInvertedArray[iTmp2+(fpScr->width*iY2)]=fpScrLine->text[iTmp2];
+                    }    
+                }    
+                LINE_MEM_UNLOCK(hgScrLine);                
+            }                
+
+        }    
+        for (iTmp=iLocStart; iTmp < fpScr->width*fpScr->height; iTmp++) {        
+            if (cInvertedArray[iTmp]) {
+                PatBlt(hDC,(iTmp%fpScr->width)*fpScr->cxChar,(int)(iTmp/fpScr->width)*fpScr->cyChar,
+                    fpScr->cxChar,fpScr->cyChar,DSTINVERT);                
+                cInvertedArray[iTmp]=0;                    
+            }    
+        }
+        
+    }            
+    ReleaseDC(hWnd,hDC);
+    GlobalUnlock(hgScr);
+}
+
+void Edit_ClearSelection(SCREEN *fpScr) {
+    int iTmp;
+    HDC hDC;
+    HMENU hMenu;
+
+    hDC=GetDC(fpScr->hWnd);
+    for (iTmp=0; iTmp < fpScr->width*fpScr->height; iTmp++) {        
+        if (cInvertedArray[iTmp]) {
+            PatBlt(hDC,(iTmp%fpScr->width)*fpScr->cxChar,(int)(iTmp/fpScr->width)*fpScr->cyChar,
+                fpScr->cxChar,fpScr->cyChar,DSTINVERT);                
+            cInvertedArray[iTmp]=0;                    
+        }    
+    }
+    bSelection=FALSE;
+    hMenu=GetMenu(fpScr->hWnd);
+    EnableMenuItem(hMenu,IDM_COPY,MF_GRAYED);    
+    ReleaseDC(fpScr->hWnd,hDC);
+}    
+
+void Edit_Copy(HWND hWnd) {
+    int iTmp,iIdx;
+    HGLOBAL hCutBuffer;
+    LPSTR lpCutBuffer;
+    SCREEN *fpScr;
+    HGLOBAL hgScr;
+    
+    hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+    if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+    fpScr=(SCREEN *)GlobalLock(hgScr);
+
+    hCutBuffer= GlobalAlloc(GHND,(DWORD)(fpScr->width*fpScr->height+1));
+    lpCutBuffer= GlobalLock(hCutBuffer);
+
+    if (iLocStart > iLocEnd) { /* swap variables */
+        iTmp=iLocStart;
+        iLocStart=iLocEnd;
+        iLocEnd=iLocStart;
+    }        
+    iTmp=iLocStart;
+    iIdx=0;
+    while (iTmp < iLocEnd) {
+        if (!cInvertedArray[iTmp]) {
+            lpCutBuffer[iIdx++]='\r';
+            lpCutBuffer[iIdx++]='\n';
+            iTmp= (((int)(iTmp/fpScr->width))+1)*fpScr->width;            
+            continue;
+        }
+        lpCutBuffer[iIdx++]=cInvertedArray[iTmp++];
+    }
+    lpCutBuffer[iIdx]=0;
+    GlobalUnlock(hCutBuffer);
+    OpenClipboard(hWnd);
+    EmptyClipboard();
+    SetClipboardData(CF_TEXT,hCutBuffer);
+    CloseClipboard();
+}
+
+void Edit_Paste(HWND hWnd) {
+    HGLOBAL hClipMemory;
+    static HGLOBAL hMyClipBuffer;
+    LPSTR lpClipMemory,lpMyClipBuffer;
+    HGLOBAL hgScr;
+       SCREEN *fpScr;                              
+    
+    if (hMyClipBuffer) GlobalFree(hMyClipBuffer);
+    OpenClipboard(hWnd);
+    hClipMemory = GetClipboardData(CF_TEXT);
+    hMyClipBuffer = GlobalAlloc(GHND,GlobalSize(hClipMemory));
+    lpMyClipBuffer= GlobalLock(hMyClipBuffer);
+    lpClipMemory= GlobalLock(hClipMemory);
+    
+    hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+    if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+       fpScr=(SCREEN *)GlobalLock(hgScr);
+    if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+
+    lstrcpy(lpMyClipBuffer,lpClipMemory);
+//    OutputDebugString(lpMyClipBuffer);
+    PostMessage(fpScr->hwndTel,WM_MYSCREENBLOCK,(WPARAM)hMyClipBuffer,
+                    (HSCREEN)hgScr);                
+    CloseClipboard();                    
+    GlobalUnlock(hClipMemory);
+    GlobalUnlock(hMyClipBuffer);    
+}
+
+void Edit_LbuttonDblclk(HWND hWnd,LPARAM lParam) {
+    HDC hDC;
+    SCREEN *fpScr;
+    HGLOBAL hgScr;
+    int iTmp,iTmp2,iXlocStart,iYloc;
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+        
+    hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+    if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+    fpScr=(SCREEN *)GlobalLock(hgScr);
+    if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+    
+    hDC=GetDC(hWnd);
+    for (iTmp=0; iTmp < fpScr->width*fpScr->height; iTmp++) {        
+        if (cInvertedArray[iTmp]) {
+            PatBlt(hDC,(iTmp%fpScr->width)*fpScr->cxChar,(int)(iTmp/fpScr->width)*fpScr->cyChar,
+                fpScr->cxChar,fpScr->cyChar,DSTINVERT);                
+            cInvertedArray[iTmp]=0;                    
+        }    
+    }
+    bSelection=FALSE;
+    iXlocStart=(int)LOWORD(lParam)/fpScr->cxChar;
+       if (iXlocStart >= fpScr->width)
+               iXlocStart = fpScr->width - 1;
+    iYloc=(int)HIWORD(lParam)/fpScr->cyChar;
+       if (iYloc >= fpScr->height)
+               iYloc = fpScr->height - 1;
+    iLocStart=iXlocStart+(iYloc*fpScr->width);
+    
+    hgScrLine=GetScreenLineFromY(fpScr,iYloc);
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+    
+    iTmp=iXlocStart;
+    while (isalnum((int)fpScrLine->text[iTmp])) {
+        PatBlt(hDC,iTmp*fpScr->cxChar,iYloc*fpScr->cyChar,
+             fpScr->cxChar,fpScr->cyChar,DSTINVERT);                    
+        cInvertedArray[iTmp+(iYloc*fpScr->width)]=fpScrLine->text[iTmp];
+        iTmp++;
+    }
+    iTmp2=iXlocStart-1;
+    while (isalnum((int)fpScrLine->text[iTmp2])) {
+        PatBlt(hDC,iTmp2*fpScr->cxChar,iYloc*fpScr->cyChar,
+             fpScr->cxChar,fpScr->cyChar,DSTINVERT);                        
+        cInvertedArray[iTmp2+(iYloc*fpScr->width)]=fpScrLine->text[iTmp2];
+        iTmp2--;
+    }    
+    iLocStart=(iTmp2+1)+(iYloc*fpScr->width);
+    iLocEnd=(iTmp)+(iYloc*fpScr->width);        
+
+    bSelection=TRUE;
+    ReleaseDC(hWnd,hDC);
+    LINE_MEM_UNLOCK(hgScrLine);        
+    GlobalUnlock(hgScr);
+}
+
+void Edit_TripleClick(HWND hWnd,LPARAM lParam) {
+    HDC hDC;
+    SCREEN *fpScr;
+    HGLOBAL hgScr;
+    int iTmp,iYloc;
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+        
+//    OutputDebugString("Triple Click \r\n");
+    hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+    if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+    fpScr=(SCREEN *)GlobalLock(hgScr);
+    if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+    
+    hDC=GetDC(hWnd);
+    for (iTmp=0; iTmp < fpScr->width*fpScr->height; iTmp++) {        
+        if (cInvertedArray[iTmp]) {
+            PatBlt(hDC,(iTmp%fpScr->width)*fpScr->cxChar,(int)(iTmp/fpScr->width)*fpScr->cyChar,
+                fpScr->cxChar,fpScr->cyChar,DSTINVERT);                
+            cInvertedArray[iTmp]=0;                    
+        }    
+    }
+    bSelection=FALSE;
+    iYloc=(int)HIWORD(lParam)/fpScr->cyChar;
+       if (iYloc >= fpScr->height)
+               iYloc = fpScr->height - 1;
+    iLocStart=(iYloc*fpScr->width);
+    
+    hgScrLine=GetScreenLineFromY(fpScr,iYloc);
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+    
+    for (iTmp=0; iTmp<fpScr->width; iTmp++) {
+        if (fpScrLine->text[iTmp]) {
+            PatBlt(hDC,iTmp*fpScr->cxChar,iYloc*fpScr->cyChar,
+                 fpScr->cxChar,fpScr->cyChar,DSTINVERT);                    
+            cInvertedArray[iTmp+(iYloc*fpScr->width)]=fpScrLine->text[iTmp];
+        } else break;    
+    }
+    iLocEnd=(iTmp+(iYloc*fpScr->width));
+
+    bSelection=TRUE;
+    ReleaseDC(hWnd,hDC);
+    LINE_MEM_UNLOCK(hgScrLine);        
+    GlobalUnlock(hgScr);
+}
diff --git a/src/windows/wintel/emul.c b/src/windows/wintel/emul.c
new file mode 100644 (file)
index 0000000..027089e
--- /dev/null
@@ -0,0 +1,815 @@
+#include "windows.h"
+#include "screen.h"
+
+/**********************************************************************
+*  Function :   ScreenEmChar
+*  Purpose  :   Send a character to the virtual screen with no translantion
+*  Parameters   :
+            fpScr - pointer top screen
+*           c - character to send to the virtual screen
+*  Returns  :   none
+*  Calls    :
+*  Called by    :   ScreenEm()
+**********************************************************************/
+static int ScreenEmChar(SCREEN *fpScr,unsigned char c)
+{
+    int sx;
+    int insert,
+        ocount,
+        attrib,
+        extra,
+        offend;
+    char *acurrent,         /* pointer to the attributes for characters drawn */
+        *current,           /* pointer to the place to put characters */
+        *start;
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+
+    hgScrLine=GetScreenLineFromY(fpScr,fpScr->y);
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+    if (fpScrLine==NULL) return (-1);
+
+    current=start=&fpScrLine->text[fpScr->x];
+    acurrent=&fpScrLine->attrib[fpScr->x];
+
+    attrib=fpScr->attrib;
+    insert=fpScr->IRM;          /* boolean */
+    ocount=fpScr->x;
+    offend=0;
+    extra=0;
+    sx=fpScr->x;
+    if(fpScr->x>fpScr->width) {
+        if(fpScr->DECAWM) {  /* check for line wrapping on */
+            fpScr->x=0;
+            ScreenIndex(fpScr);
+        } /* end if */
+        else                /* no line wrapping */
+            fpScr->x=fpScr->width;
+        current=start=&fpScrLine->text[fpScr->x];
+        acurrent=&fpScrLine->attrib[fpScr->x];
+        ocount=fpScr->x;
+        sx=fpScr->x;
+    } /* end if */
+    if(insert)
+        ScreenInsChar(fpScr,1);
+    *current=c;
+    *acurrent=(char)attrib;
+    if(fpScr->x<fpScr->width) {
+        acurrent++;
+        current++;
+        fpScr->x++;
+    } /* end if */
+    else {
+        if(fpScr->DECAWM) {
+            fpScr->x++;
+            offend=1;
+        } /* end if */
+        else {
+            fpScr->x=fpScr->width;
+            extra=1;
+        } /* end else */
+    } /* end else */
+    if(insert)
+        ScreenInsString(fpScr,fpScr->x-ocount+offend+extra,start);        /* actually just decides which RS to use */
+    else
+        ScreenDraw(fpScr,sx,fpScr->y,fpScr->attrib,fpScr->x-ocount+offend+extra,start);
+    LINE_MEM_UNLOCK(hgScrLine);        
+}   /* end ScreenEmChar() */
+
+void ScreenEm(LPSTR c,int len,HSCREEN hsScr)
+{
+    HSCREENLINE hgScrLine;
+    SCREEN *fpScr;
+    SCREENLINE *fpScrLine;    
+    int escflg;             /* vt100 escape level */
+    RECT rc;
+       unsigned int ic;
+       char stat[20];
+       int i;
+    
+    fpScr=(SCREEN *) GlobalLock(hsScr);
+    if (fpScr==NULL) {
+        OutputDebugString("Screen is hosed.\r\n");
+        return;
+    }
+
+    if (fpScr->screen_bottom != fpScr->buffer_bottom) {
+               ScreenUnscroll(fpScr);
+        InvalidateRect(fpScr->hWnd,NULL,TRUE);
+        SetScrollPos(fpScr->hWnd,SB_VERT,fpScr->numlines,TRUE);
+       }
+
+    ScreenCursorOff(fpScr);
+    escflg=fpScr->escflg;
+
+#ifdef UM
+/* @UM */
+    if(fpScr->localprint && (len>0)) {    /* see if printer needs anything */
+        pcount=send_localprint(c,len);
+        len-=pcount;
+        c+=pcount;
+      } /* end if */
+/* @UM */
+#endif
+
+    while(len>0) {
+        while((*c<32) && (escflg==0) && (len>0)) {      /* look at first character in the vt100 string, if it is a non-printable ascii code */
+            switch(*c) {
+            
+                case 0x1b:      /* ESC found (begin vt100 control sequence) */
+                    escflg++;
+                    break;
+
+                               case -1:                /* IAC from telnet session */
+                                       escflg=6;
+                                       break;
+
+#ifdef CISB
+                case 0x05:      /* CTRL-E found (answerback) */
+                    bp_ENQ();
+                    break;
+
+#endif
+                case 0x07:      /* CTRL-G found (bell) */
+                    ScreenBell(fpScr);
+                    break;
+
+                case 0x08:      /* CTRL-H found (backspace) */
+                    ScreenBackspace(fpScr);
+                    break;
+
+                case 0x09:          /* CTRL-I found (tab) */
+                    ScreenTab(fpScr);       /* Later change for versatile tabbing */
+                    break;
+
+                case 0x0a:          /* CTRL-J found (line feed) */
+                case 0x0b:          /* CTRL-K found (treat as line feed) */
+                case 0x0c:          /* CTRL-L found (treat as line feed) */
+                    ScreenIndex(fpScr);
+                    break;
+                case 0x0d:      /* CTRL-M found (carriage feed) */
+                    ScreenCarriageFeed(fpScr);
+                    break;
+
+#ifdef LATER
+                case 0x0e:      /* CTRL-N found (invoke Graphics (G1) character set) */
+                    if(fpScr->G1)
+                        fpScr->attrib=VSgraph(fpScr->attrib);
+                    else
+                        fpScr->attrib=VSnotgraph(fpScr->attrib);
+                    fpScr->charset=1;
+                    break;
+
+                case 0x0f:      /* CTRL-O found (invoke 'normal' (G0) character set) */
+                    if(fpScr->G0)
+                        fpScr->attrib=VSgraph(fpScr->attrib);
+                    else
+                        fpScr->attrib=VSnotgraph(fpScr->attrib);
+                    fpScr->charset=0;
+                    break;
+#endif
+#ifdef CISB
+                case 0x10:      /* CTRL-P found (undocumented in vt100) */
+                    bp_DLE( c, len);
+                    len=0;
+                    break;
+#endif
+
+#ifdef NOT_USED
+                case 0x11:      /* CTRL-Q found (XON) (unused presently) */
+                case 0x13:      /* CTRL-S found (XOFF) (unused presently) */
+                case 0x18:      /* CTRL-X found (CAN) (unused presently) */
+                case 0x1a:      /* CTRL-Z found (SUB) (unused presently) */
+                    break;
+#endif
+              } /* end switch */
+            c++;        /* advance to the next character in the string */
+            len--;      /* decrement the counter */
+          } /* end while */
+
+        if(escflg==0) {  /* check for normal character to print */
+            while((len>0) && (*c>=32)) {     /* print out printable ascii chars, if we haven't found an ESCAPE char */
+                int sx;
+                int insert,
+                    ocount,
+                    attrib,
+                    extra,
+                    offend;
+                char *acurrent,         /* pointer to the attributes for characters drawn */
+                    *current,           /* pointer to the place to put characters */
+                    *start;
+
+                hgScrLine=GetScreenLineFromY(fpScr,fpScr->y);
+                fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+                if (fpScrLine==NULL) return;
+
+                current=start=&fpScrLine->text[fpScr->x];
+                acurrent=&fpScrLine->attrib[fpScr->x];
+                attrib=fpScr->attrib;
+                insert=fpScr->IRM;          /* boolean */
+                ocount=fpScr->x;
+                offend=0;
+                extra=0;
+                sx=fpScr->x;
+                if(fpScr->x>fpScr->width) {
+                    if(fpScr->DECAWM) {  /* check for line wrapping on */
+                        fpScr->x=0;
+                        ScreenIndex(fpScr);
+                      } /* end if */
+                    else                /* no line wrapping */
+                        fpScr->x=fpScr->width;
+                    current=start=&fpScrLine->text[fpScr->x];
+                    acurrent=&fpScrLine->attrib[fpScr->x];
+                    ocount=fpScr->x;
+                    sx=fpScr->x;
+                } /* end if */
+                while((len>0) && (*c>=32) && (offend==0)) {
+                    if(insert)
+                        ScreenInsChar(fpScr,1);
+                    *current=*c;
+                    *acurrent=(char)attrib;
+                    c++;
+                    len--;
+                    if(fpScr->x<fpScr->width) {
+                        acurrent++;
+                        current++;
+                        fpScr->x++;
+                      } /* end if */
+                    else {
+                        if(fpScr->DECAWM) {
+                            fpScr->x++;
+                            offend=1;
+                          } /* end if */
+                        else {
+                            fpScr->x=fpScr->width;
+                            extra=1;
+                          } /* end else */
+                      } /* end else */
+                  } /* end while */
+                if (insert)
+                    ScreenInsString(fpScr,fpScr->x-ocount+offend+extra,start);        /* actually just decides which RS to use */
+                else 
+                    ScreenDraw(fpScr,sx,fpScr->y,fpScr->attrib,fpScr->x-ocount+offend+extra,start);
+              } /* end while */
+          } /* end if */
+          
+        while((len>0) && (escflg==1)) {     /* ESC character was found */
+            switch(*c) {
+                case 0x08:      /* CTRL-H found (backspace) */
+                    ScreenBackspace(fpScr);
+                    break;
+
+                case '[':               /* mostly cursor movement options, and DEC private stuff following */
+//                    OutputDebugString("[");
+                    ScreenApClear(fpScr);
+                    escflg=2;
+                    break;
+
+                case '#':               /* various screen adjustments */
+//                    OutputDebugString("#");
+                    escflg=3;
+                    break;
+
+                case '(':               /* G0 character set options */
+//                    OutputDebugString("(");
+                    escflg=4;
+                    break;
+
+                case ')':               /* G1 character set options */
+//                    OutputDebugString(")");
+                    escflg=5;
+                    break;
+
+                case '>':               /* keypad numeric mode (DECKPAM) */
+//                    OutputDebugString(">");
+                    fpScr->DECPAM=0;
+                    escflg=0;
+                    break;
+
+                case '=':               /* keypad application mode (DECKPAM) */
+//                    OutputDebugString("=");
+                    fpScr->DECPAM=1;
+                    escflg=0;
+                    break;
+
+                case '7':               /* save cursor (DECSC) */
+//                    OutputDebugString("7!");
+                    ScreenSaveCursor(fpScr);
+                    escflg=0;
+                    break;
+
+                case '8':               /* restore cursor (DECRC) */
+//                    OutputDebugString("8!");
+                    ScreenRestoreCursor(fpScr);
+                    escflg=0;
+                    break;
+#ifdef LATER
+                case 'c':               /* reset to initial state (RIS) */
+                    ScreenReset(fpScr);
+                    escflg=0;
+                    break;
+#endif
+                case 'D':               /* index (move down one line) (IND) */
+                    ScreenIndex(fpScr);
+                    escflg=0;
+                    break;
+
+                case 'E':               /*  next line (move down one line and to first column) (NEL) */
+//                    OutputDebugString("E!");
+                    fpScr->x=0;
+                    ScreenIndex(fpScr);
+                    escflg=0;
+                    break;
+
+                case 'H':               /* horizontal tab set (HTS) */
+//                    OutputDebugString("H!");
+                    fpScr->tabs[fpScr->x]='x';
+                    escflg=0;
+                    break;
+
+#ifdef CISB
+                case 'I':               /* undoumented in vt100 */
+                    bp_ESC_I();
+                    break;
+
+#endif
+
+                case 'M':               /* reverse index (move up one line) (RI) */
+//                    OutputDebugString("M!");
+                    ScreenRevIndex(fpScr);
+                    escflg=0;
+                    break;
+
+                case 'Z':               /* identify terminal (DECID) */
+                    OutputDebugString("Screen Send Ident- Not implemented! \r\n");
+//                    ScreenSendIdent(fpScr);
+
+                    escflg=0;
+                    break;
+
+                default:
+                    ScreenEmChar(fpScr,0x1b); /* put the ESC character into the Screen */
+                    ScreenEmChar(fpScr,*c);   /* put the next character into the Screen */
+                    escflg=0;
+                    break;
+
+              } /* end switch */
+            c++;
+            len--;
+          } /* end while */
+        while((escflg==2) && (len>0)) {     /* '[' handling */            
+            switch(*c) {
+                case 0x08:      /* backspace */
+                    ScreenBackspace(fpScr);
+                    break;
+
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':               /* numeric parameters */
+                    if(fpScr->parms[fpScr->parmptr]<0)
+                        fpScr->parms[fpScr->parmptr]=0;
+                    fpScr->parms[fpScr->parmptr]*=10;
+                    fpScr->parms[fpScr->parmptr]+=*c-'0';
+                    break;
+
+                case '?':               /* vt100 mode change */
+                    fpScr->parms[fpScr->parmptr++]=(-2);
+                    break;
+
+                case ';':               /* parameter divider */
+                    fpScr->parmptr++;
+                    break;
+
+                case 'A':               /* cursor up (CUU) */
+//                    OutputDebugString("A");
+                    rc.left=((fpScr->x)*(fpScr->cxChar));
+                    rc.right=(((fpScr->x)+1)*(fpScr->cxChar));
+                    rc.top=((fpScr->cyChar)*(fpScr->y));    
+                    rc.bottom=((fpScr->cyChar)*((fpScr->y)+1));
+                    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+//                    OutputDebugString("[2A]");
+                    if(fpScr->parms[0]<1)
+                        fpScr->y--;
+                    else
+                        fpScr->y-=fpScr->parms[0];
+                    if(fpScr->y<fpScr->top)
+                        fpScr->y=fpScr->top;
+                    ScreenRange(fpScr);
+                    escflg=0;
+                    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+                    break;
+
+                case 'B':               /* cursor down (CUD) */
+//                    OutputDebugString("B");
+                    rc.left=((fpScr->x)*(fpScr->cxChar));
+                    rc.right=(((fpScr->x)+1)*(fpScr->cxChar));
+                    rc.top=((fpScr->cyChar)*(fpScr->y));    
+                    rc.bottom=((fpScr->cyChar)*((fpScr->y)+1));
+                    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+//                    OutputDebugString("[2B]");
+                    if(fpScr->parms[0]<1)
+                        fpScr->y++;
+                    else
+                        fpScr->y+=fpScr->parms[0];
+                    if(fpScr->y>fpScr->bottom)
+                        fpScr->y=fpScr->bottom;
+                    ScreenRange(fpScr);
+                    escflg=0;
+                    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+                    break;
+
+                case 'C':               /* cursor forward (right) (CUF) */
+//                    OutputDebugString("C");
+                    rc.left=((fpScr->x)*(fpScr->cxChar));
+                    rc.right=(((fpScr->x)+1)*(fpScr->cxChar));
+                    rc.top=((fpScr->cyChar)*(fpScr->y));    
+                    rc.bottom=((fpScr->cyChar)*((fpScr->y)+1));
+                    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+//                    OutputDebugString("[2C]");
+                    if(fpScr->parms[0]<1)
+                        fpScr->x++;
+                    else
+                        fpScr->x+=fpScr->parms[0];
+                    ScreenRange(fpScr);
+                    if(fpScr->x>fpScr->width)
+                        fpScr->x=fpScr->width;
+                    escflg=0;
+                    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+                    break;
+
+                case 'D':               /* cursor backward (left) (CUB) */
+//                    OutputDebugString("D");
+                    rc.left=((fpScr->x)*(fpScr->cxChar));
+                    rc.right=(((fpScr->x)+1)*(fpScr->cxChar));
+                    rc.top=((fpScr->cyChar)*(fpScr->y));    
+                    rc.bottom=((fpScr->cyChar)*((fpScr->y)+1));
+                    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+//                    OutputDebugString("[2D]");
+                    if(fpScr->parms[0]<1)
+                        fpScr->x--;
+                    else
+                        fpScr->x-=fpScr->parms[0];
+                    ScreenRange(fpScr);
+                    escflg=0;
+                    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+                    break;
+
+                case 'f':               /* horizontal & vertical position (HVP) */
+                case 'H':               /* cursor position (CUP) */
+//                    OutputDebugString("fH");
+                    rc.left=((fpScr->x)*(fpScr->cxChar));
+                    rc.right=(((fpScr->x)+1)*(fpScr->cxChar));
+                    rc.top=((fpScr->cyChar)*(fpScr->y));    
+                    rc.bottom=((fpScr->cyChar)*((fpScr->y)+1));
+                    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+//                    OutputDebugString("[2H]");
+                    fpScr->x=fpScr->parms[1]-1;
+                    fpScr->y=fpScr->parms[0]-1;
+                    ScreenRange(fpScr);         /* make certain the cursor position is valid */
+                    escflg=0;
+                    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+                    break;
+
+                case 'J':               /* erase in display (ED) */
+//                    OutputDebugString("J");
+                    switch(fpScr->parms[0]) {
+                        case -1:
+                        case 0:     /* erase from active position to end of screen */
+                            ScreenEraseToEndOfScreen(fpScr);
+                            break;
+                        case 1:     /* erase from start of screen to active position */
+                            OutputDebugString("[Screen Erase to Position- Not Implemented!]\r\n");
+//                            ScreenEraseToPosition(fpScr);
+                            break;
+
+                        case 2:     /* erase whole screen */
+//                            OutputDebugString("2");
+                            ScreenEraseScreen(fpScr);
+                            break;
+
+                        default:
+                            break;
+                      } /* end switch */
+                    escflg=0;
+                    break;
+
+                case 'K':               /* erase in line (EL) */
+//                    OutputDebugString("K");
+                    switch(fpScr->parms[0]) {
+                        case -1:
+                        case 0:     /* erase to end of line */
+//                            OutputDebugString("0");
+                            ScreenEraseToEOL(fpScr);
+                            break;
+
+                        case 1:     /* erase to beginning of line */
+//                            OutputDebugString("1");
+                            ScreenEraseToBOL(fpScr);
+                            break;
+
+                        case 2:     /* erase whole line */
+//                            OutputDebugString("2");
+                            ScreenEraseLine(fpScr,-1);
+                            break;
+
+                        default:
+                            break;
+                      } /* end switch */
+                    escflg=0;
+                    break;
+
+                case 'L':               /* insert n lines preceding current line (IL) */
+//                    OutputDebugString("L");
+                    if(fpScr->parms[0]<1)
+                        fpScr->parms[0]=1;
+                    ScreenInsLines(fpScr,fpScr->parms[0],-1);
+                    escflg=0;
+                    break;
+
+                case 'M':               /* delete n lines from current position downward (DL) */
+//                    OutputDebugString("M");
+                    if(fpScr->parms[0]<1)
+                        fpScr->parms[0]=1;
+                    ScreenDelLines(fpScr,fpScr->parms[0],-1);
+                    escflg=0;
+                    break;
+
+                case 'P':               /* delete n chars from cursor to the left (DCH) */
+//                    OutputDebugString("P");
+                    if(fpScr->parms[0]<1)
+                        fpScr->parms[0]=1;
+                    ScreenDelChars(fpScr,fpScr->parms[0]);
+                    escflg=0;
+                    break;
+
+#ifdef NOT_NEEDED
+                case 'R':               /* receive cursor position status from host */
+                    break;
+#endif
+#ifdef LATER
+                case 'c':               /* device attributes (DA) */
+                    ScreenSendIdent();
+                    escflg=0;
+                    break;
+#endif
+                case 'g':               /* tabulation clear (TBC) */
+//                    OutputDebugString("g");
+                    if(fpScr->parms[0]==3)   /* clear all tabs */
+                        ScreenTabClear(fpScr);
+                    else
+                        if(fpScr->parms[0]<=0)   /* clear tab stop at active position */
+                            fpScr->tabs[fpScr->x]=' ';
+                    escflg=0;
+                    break;
+
+                case 'h':               /* set mode (SM) */
+//                    OutputDebugString("h");
+//                  ScreenSetOption(fpScr,1);
+                    escflg=0;
+                    break;
+
+
+                case 'i':               /* toggle printer */
+//                    if(fpScr->parms[fpScr->parmptr]==5)
+//                        fpScr->localprint=1;
+//                    else if(fpScr->parms[fpScr->parmptr]==4)
+//                        fpScr->localprint=0;
+                    escflg=0;
+                    break;
+
+                case 'l':               /* reset mode (RM) */
+//                    OutputDebugString("l");
+//                    ScreenSetOption(fpScr,0);
+                    escflg=0;
+                    break;
+
+                case 'm':               /* select graphics rendition (SGR) */
+//                    OutputDebugString("m");
+                    {
+                        int temp=0;
+
+                        while(temp<=fpScr->parmptr) {
+                            if(fpScr->parms[temp]<1)
+                                fpScr->attrib&=128;
+                            else
+                                fpScr->attrib|=(1<<(fpScr->parms[temp]-1));
+                            temp++;
+                          } /* end while */
+                      } /* end case */
+                    escflg=0;
+                    break;
+
+                case 'n':               /* device status report (DSR) */
+                    switch(fpScr->parms[0]) {
+#ifdef NOT_SUPPORTED
+                    case 0: /* response from vt100; ready, no malfunctions */
+                    case 3: /* response from vt100; malfunction, retry */
+#endif
+                    case 5: /* send status */
+                    case 6: /* send active position */
+                                               wsprintf(stat, "\033[%d;%dR", fpScr->y, fpScr->x);
+                                               for (i = 0; stat[i]; i++)
+                                                       SendMessage(fpScr->hwndTel,WM_MYSCREENCHAR,stat[i],hsScr);
+                        break;
+                    } /* end switch */
+                    escflg=0;
+                    break;
+
+                case 'q':               /* load LEDs (unsupported) (DECLL) */
+                    escflg=0;
+                    break;
+
+                case 'r':               /* set top & bottom margins (DECSTBM) */
+                    if(fpScr->parms[0]<0)
+                        fpScr->top=0;
+                    else
+                        fpScr->top=fpScr->parms[0]-1;
+                    if(fpScr->parms[1]<0)
+                        fpScr->bottom=fpScr->height-1;
+                    else
+                        fpScr->bottom=fpScr->parms[1]-1;
+                    if(fpScr->top<0)
+                        fpScr->top=0;
+                    if(fpScr->top>fpScr->height-1)
+                        fpScr->top=fpScr->height-1;
+                    if(fpScr->bottom<1)
+                        fpScr->bottom=fpScr->height;
+                    if(fpScr->bottom>=fpScr->height)
+                        fpScr->bottom=fpScr->height-1;
+                    if(fpScr->top>=fpScr->bottom) {   /* check for valid scrolling region */
+                        if(fpScr->bottom>=1)     /* assume the bottom value has precedence, unless it is as the top of the screen */
+                            fpScr->top=fpScr->bottom-1;
+                        else                /* totally psychotic case, bottom of screen set to the very top line, move the bottom to below the top */
+                            fpScr->bottom=fpScr->top+1;
+                      } /* end if */
+                    fpScr->x=0;
+                    fpScr->y=0;
+#ifdef NOT_SUPPORTED
+                    if (fpScr->DECORG)
+                        fpScr->y=fpScr->top;  /* origin mode relative */
+#endif
+                    escflg=0;
+                    break;
+
+#ifdef NOT_SUPPORTED
+                case 'x':                       /* request/report terminal parameters (DECREQTPARM/DECREPTPARM) */
+                case 'y':                       /* invoke confidence test (DECTST) */
+                    break;
+#endif
+                default:            /* Dag blasted strays... */
+                    escflg=0;
+                    break;
+
+              } /* end switch */
+            c++;
+            len--;
+
+#ifdef NOT
+/* @UM */
+            if(fpScr->localprint && (len>0)) {    /* see if printer needs anything */
+                pcount=send_localprint(c,len);
+                len-=pcount;
+                c+=pcount;
+              } /* end if */
+/* @UM */
+#endif
+          } /* end while */
+        while((escflg==3) && (len>0)) { /* #  Handling */
+            switch(*c) {
+                case 0x08:      /* backspace */
+                    ScreenBackspace(fpScr);
+                    break;
+
+#ifdef NOT_SUPPORTED
+                case '3':               /* top half of double line (DECDHL) */
+                case '4':               /* bottom half of double line (DECDHL) */
+                case '5':               /* single width line (DECSWL) */
+                case '6':               /* double width line (DECDWL) */
+                    break;
+#endif
+                case '8':               /* screen alignment display (DECALN) */
+                    ScreenAlign(fpScr);
+//                    OutputDebugString("8");
+                    escflg=0;
+                    break;
+                default:
+                    escflg=0;
+                    break;
+
+              } /* end switch */
+            c++;
+            len--;
+          } /* end while */
+        while((escflg==4) && (len>0)) { /* ( Handling (GO character set) */
+            switch(*c) {
+                case 0x08:      /* backspace */
+                    ScreenBackspace(fpScr);
+                    break;
+
+#ifdef LATER
+                case 'A':               /* united kingdom character set (unsupported) */
+                case 'B':               /* ASCII character set */
+                case '1':               /* choose standard graphics (same as ASCII) */
+                    fpScr->G0=0;
+                    if(!fpScr->charset)
+                        fpScr->attrib=ScreenNotGraph(fpScr->attrib);
+                    escflg=0;
+                    break;
+
+                case '0':               /* choose special graphics set */
+                case '2':               /* alternate character set (special graphics) */
+                    fpScr->G0=1;
+                    if(!fpScr->charset)
+                        fpScr->attrib=ScreenGraph(fpScr->attrib);
+                    escflg=0;
+                    break;
+#endif
+                default:
+                    escflg=0;
+                    break;
+              } /* end switch */
+            c++;
+            len--;
+          } /* end while */
+        while((escflg==5) && (len>0)) { /* ) Handling (G1 handling) */
+            switch(*c) {
+                case 0x08:      /* backspace */
+                    ScreenBackspace(fpScr);
+                    break;
+
+#ifdef LATER
+                case 'A':               /* united kingdom character set (unsupported) */
+                case 'B':               /* ASCII character set */
+                case '1':               /* choose standard graphics (same as ASCII) */
+                    fpScr->G1=0;
+                    if(fpScr->charset)
+                        fpScr->attrib=ScreenNotGraph(fpScr->attrib);
+                    escflg=0;
+                    break;
+
+                case '0':               /* choose special graphics set */
+                case '2':               /* alternate character set (special graphics) */
+                    fpScr->G1=1;
+                    if(fpScr->charset)
+                        fpScr->attrib=ScreenGraph(fpScr->attrib);
+                    escflg=0;
+                    break;
+#endif
+                default:
+                    escflg=0;
+                    break;
+              } /* end switch */
+            c++;
+            len--;
+          } /* end while */
+
+        while((escflg>=6) && (escflg<=10) && (len>0)) { /* Handling IAC */
+                       ic = (unsigned char) *c;
+                       switch (escflg) {
+
+                       case 6:     /* Handling IAC xx */
+                               if (ic == 255) /* if IAC */
+                                       escflg=0;
+                else if (ic == 250) /* if SB */
+                                       escflg=7;
+                               else
+                                       escflg=9;
+                               break;
+
+                       case 7:     /* Handling IAC SB xx */
+                               if (ic == 255) /* if IAC */
+                    escflg=8;
+                               break;
+
+                       case 8:     /* Handling IAC SB IAC xx */
+                               if (ic == 255) /* if IAC IAC */
+                   escflg=7;
+                               else if (ic == 240) /* if IAC SE */
+                   escflg=0;
+                               break;
+
+                       case 9:    /* IAC xx xx */
+                               escflg=0;
+                               break;
+                       }
+            c++;        /* advance to the next character in the string */
+            len--;      /* decrement the counter */
+               }
+
+        if((escflg>2 && escflg<6) && (len>0)) {
+            escflg=0;
+            c++;
+            len--;
+          } /* end if */
+      } /* end while */
+    fpScr->escflg=escflg;
+    ScreenCursorOn(fpScr);
+    GlobalUnlock(hsScr);
+}   /* end ScreenEm() */
diff --git a/src/windows/wintel/font.c b/src/windows/wintel/font.c
new file mode 100644 (file)
index 0000000..9bdb00e
--- /dev/null
@@ -0,0 +1,128 @@
+#include <windows.h>
+#include <commdlg.h>
+#include "screen.h"
+#include "ini.h"
+
+LOGFONT lf;
+HFONT hFont;
+char szStyle[LF_FACESIZE];
+
+void ProcessFontChange(HWND hWnd) {
+    static DWORD dwFontColor;  /* Color of font if one has been selected */
+    CHOOSEFONT cf;
+    HDC hDC;
+    SCREEN *fpScr;
+    HGLOBAL hgScr;
+    TEXTMETRIC tm;
+    char buf[16];
+        
+    hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+    if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+    fpScr=(SCREEN *)GlobalLock(hgScr);
+    if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+
+    cf.lStructSize = sizeof(cf);
+    cf.hwndOwner = hWnd;
+    cf.lpLogFont = (LPLOGFONT)&(fpScr->lf);
+    cf.lpszStyle = szStyle;
+    cf.Flags = CF_INITTOLOGFONTSTRUCT; // | CF_USESTYLE;
+    cf.Flags |= CF_SCREENFONTS;
+//    cf.Flags |= CF_ANSIONLY;
+    cf.Flags |= CF_FORCEFONTEXIST;
+    cf.Flags |= CF_FIXEDPITCHONLY;
+    cf.Flags |= CF_NOSIMULATIONS;
+    if (ChooseFont(&cf)) {
+      if (fpScr->ghSelectedFont) DeleteObject(fpScr->ghSelectedFont);
+
+      fpScr->ghSelectedFont = CreateFontIndirect((LPLOGFONT)&(fpScr->lf));
+      fpScr->lf.lfUnderline=TRUE;
+      fpScr->ghSelectedULFont= CreateFontIndirect((LPLOGFONT)&(fpScr->lf));
+      fpScr->lf.lfUnderline=FALSE;
+      hDC=GetDC(hWnd);
+      SelectObject(hDC,fpScr->ghSelectedFont);
+      GetTextMetrics(hDC,(LPTEXTMETRIC)&tm);
+
+      fpScr->cxChar = tm.tmAveCharWidth;
+      fpScr->cyChar = tm.tmHeight+ tm.tmExternalLeading;
+      ReleaseDC(hWnd,hDC);
+      SetWindowPos(hWnd,NULL,0,0, fpScr->cxChar * fpScr->width + 
+                    FRAME_WIDTH, fpScr->cyChar * fpScr->height +
+                    FRAME_HEIGHT, SWP_NOMOVE|SWP_NOZORDER);
+
+      dwFontColor=RGB(255, 255, 255);
+      InvalidateRect(hWnd, NULL, TRUE);
+    }
+
+    WritePrivateProfileString(INI_FONT,"FaceName",fpScr->lf.lfFaceName,TELNET_INI);
+    wsprintf(buf,"%d",(int)fpScr->lf.lfHeight);
+    WritePrivateProfileString(INI_FONT,"Height",buf,TELNET_INI);
+    wsprintf(buf,"%d",(int)fpScr->lf.lfWidth);
+    WritePrivateProfileString(INI_FONT,"Width",buf,TELNET_INI);
+    wsprintf(buf,"%d",(int)fpScr->lf.lfEscapement);
+    WritePrivateProfileString(INI_FONT,"Escapement",buf,TELNET_INI);
+    wsprintf(buf,"%d",(int)fpScr->lf.lfCharSet);
+    WritePrivateProfileString(INI_FONT,"CharSet",buf,TELNET_INI);
+    wsprintf(buf,"%d",(int)fpScr->lf.lfPitchAndFamily);
+    WritePrivateProfileString(INI_FONT,"PitchAndFamily",buf,TELNET_INI);
+    
+    GlobalUnlock(hgScr);
+    return;
+}
+
+void NEAR InitializeStruct(WORD wCommDlgType, LPSTR lpStruct, HWND hWnd)
+{
+   LPCHOOSEFONT        lpFontChunk;
+   
+   switch (wCommDlgType)
+      {      
+      case IDC_FONT:
+
+         lpFontChunk = (LPCHOOSEFONT)lpStruct;
+
+         lpFontChunk->lStructSize    = sizeof(CHOOSEFONT);
+         lpFontChunk->hwndOwner      = hWnd;
+
+//The hDC field will be initialized when we return--this avoids passing
+//the hDC in or getting the DC twice.
+//The LOGFONT field will also be initialized when we get back.
+//            lpFontChunk->hDC            = hDC;
+//            lpFontChunk->lpLogFont      = &lf;
+
+         lpFontChunk->Flags          = CF_SCREENFONTS | CF_FIXEDPITCHONLY |
+                                       CF_INITTOLOGFONTSTRUCT | CF_APPLY;
+         lpFontChunk->rgbColors      = RGB(0, 0, 255);
+         lpFontChunk->lCustData      = 0L;
+         lpFontChunk->lpfnHook       = NULL;
+         lpFontChunk->lpTemplateName = (LPSTR)NULL;
+         lpFontChunk->hInstance      = (HANDLE)NULL;
+         lpFontChunk->lpszStyle      = (LPSTR)NULL;
+         lpFontChunk->nFontType      = SCREEN_FONTTYPE;
+         lpFontChunk->nSizeMin       = 0;
+         lpFontChunk->nSizeMax       = 0;
+         break;
+      default:
+         break;
+      }
+   return;
+}
+
+LPSTR NEAR AllocAndLockMem(HANDLE *hChunk, WORD wSize) {
+   LPSTR lpChunk;
+
+   *hChunk = GlobalAlloc(GMEM_FIXED, wSize);
+   if (*hChunk) {
+       lpChunk = GlobalLock(*hChunk);
+       if (!lpChunk) {
+           GlobalFree(*hChunk);
+           ReportError(IDC_LOCKFAIL);
+           lpChunk=NULL;
+       }
+   } else {
+       ReportError(IDC_ALLOCFAIL);
+       lpChunk=NULL;
+   }
+   return(lpChunk);
+}
+
+
diff --git a/src/windows/wintel/ini.h b/src/windows/wintel/ini.h
new file mode 100644 (file)
index 0000000..d391c8a
--- /dev/null
@@ -0,0 +1,16 @@
+/* Defines INI file vocabulary */
+#define TELNET_INI "kerberos.ini"
+
+       #define INI_TELNET "Telnet"
+               #define INI_FONT "Font"
+               #define INI_WIDTH "Width"
+               #define INI_HEIGHT "Height"
+               #define INI_POSITION "Position"
+               #define INI_BACKSPACE "Backspace"
+                       #define INI_BACKSPACE_BS "BS"
+                       #define INI_BACKSPACE_DEL "DEL"
+
+       #define INI_HOSTS "Telnet Hosts"
+               #define INI_HOST "Host"
+               #define INI_HOST_BS "BS"
+               #define INI_HOST_DEL "DEL"
diff --git a/src/windows/wintel/intern.c b/src/windows/wintel/intern.c
new file mode 100644 (file)
index 0000000..d2ec5fc
--- /dev/null
@@ -0,0 +1,837 @@
+#include <windows.h>
+#include <string.h>
+#include "screen.h"
+#define ScreenClearAttrib 0
+
+HSCREENLINE GetScreenLineFromY(SCREEN *fpScr,int y)
+{
+    HSCREENLINE hgScrLine,hgScrLineTmp;
+    SCREENLINE *fpScrLine;
+    int idx;
+
+    hgScrLine=fpScr->screen_top;
+    for (idx=0; idx<fpScr->height; idx++) {
+        if (idx==y) return(hgScrLine);
+        fpScrLine=LINE_MEM_LOCK(hgScrLine);
+        if (fpScrLine==NULL) return (NULL);    
+        hgScrLineTmp=fpScrLine->next;        
+        LINE_MEM_UNLOCK(hgScrLine);
+        hgScrLine=hgScrLineTmp;
+    }
+    return(NULL);
+}    
+
+HSCREENLINE ScreenClearLine(SCREEN *fpScr,HSCREENLINE hgScrLine)
+{
+    SCREENLINE *fpScrLine;
+      
+    fpScrLine=LINE_MEM_LOCK(hgScrLine);
+       memset(fpScrLine->attrib, ScreenClearAttrib, fpScr->width);
+       memset(fpScrLine->text, ' ', fpScr->width);
+    LINE_MEM_UNLOCK(hgScrLine);
+    return(hgScrLine);
+}
+
+void ScreenUnscroll(SCREEN *fpScr)
+{
+       int idx;
+    HSCREENLINE hgScrLine,hgScrLineTmp;
+    SCREENLINE *fpScrLine;
+
+    if (fpScr->screen_bottom == fpScr->buffer_bottom)
+               return;
+
+    fpScr->screen_bottom=fpScr->buffer_bottom;
+    hgScrLine=fpScr->screen_bottom;
+    for (idx = 1; idx < fpScr->height; idx++) {
+        fpScrLine=LINE_MEM_LOCK(hgScrLine);
+        if (fpScrLine==NULL)
+            return;
+        hgScrLineTmp=fpScrLine->prev;
+        LINE_MEM_UNLOCK(hgScrLine);
+        hgScrLine=hgScrLineTmp;
+    }
+    fpScr->screen_top=hgScrLine;
+}
+
+void ScreenCursorOn(SCREEN *fpScr)
+{
+       int y;
+       int nlines;
+
+       if (fpScr->screen_bottom != fpScr->buffer_bottom)
+       nlines = fpScr->numlines - GetScrollPos(fpScr->hWnd, SB_VERT);
+       else
+               nlines = 0;
+
+       y = fpScr->y + nlines;
+       SetCaretPos(fpScr->x * fpScr->cxChar, (y+1) * fpScr->cyChar);
+       ShowCaret(fpScr->hWnd);
+}
+
+void ScreenCursorOff(SCREEN *fpScr)
+{
+       HideCaret(fpScr->hWnd);
+}
+
+void ScreenELO(SCREEN *fpScr,int s)
+{
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    RECT rc;
+            
+/*  fpScrrapnow(&i,&j); */
+    if(s<0) 
+        s=fpScr->y;
+    
+    hgScrLine=GetScreenLineFromY(fpScr,s);
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+       memset(fpScrLine->attrib, ScreenClearAttrib, fpScr->width);
+       memset(fpScrLine->text, ' ', fpScr->width);
+    LINE_MEM_UNLOCK(hgScrLine);
+    rc.left=0;
+    rc.right=(fpScr->width*fpScr->cxChar);
+    rc.top=(fpScr->cyChar*s);    
+    rc.bottom=(fpScr->cyChar*(s+1));
+    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+}
+
+void ScreenEraseScreen(SCREEN *fpScr) 
+{
+    int i;
+    int x1=0,y1=0;
+    int x2=fpScr->width,y2=fpScr->height;
+    int n=(-1);
+            
+    for(i=0; i<fpScr->height; i++)
+        ScreenELO(fpScr,i);
+    InvalidateRect(fpScr->hWnd,NULL,TRUE);
+    UpdateWindow(fpScr->hWnd);
+}
+
+void ScreenTabClear(SCREEN *fpScr)
+{
+    int x=0;
+
+    while(x<=fpScr->width) {
+        fpScr->tabs[x]=' ';
+        x++;
+      } /* end while */
+}
+
+void ScreenTabInit(SCREEN *fpScr)
+{
+    int x=0;
+
+    ScreenTabClear(fpScr);
+
+    while(x<=fpScr->width) { 
+        fpScr->tabs[x]='x';
+        x+=8;
+    } /* end while */
+    fpScr->tabs[fpScr->width]='x';
+}
+
+void ScreenReset(SCREEN *fpScr)
+{
+    fpScr->top=0;
+    fpScr->bottom=fpScr->height-1;
+    fpScr->parmptr=0;
+    fpScr->escflg=0;
+    fpScr->DECAWM=1;
+    fpScr->DECCKM=0;
+    fpScr->DECPAM=0;
+/*  fpScr->DECORG=0;     */
+/*  fpScr->Pattrib=-1;   */
+    fpScr->IRM=0;
+    fpScr->attrib=0;
+    fpScr->x=0;
+    fpScr->y=0;
+//    fpScr->charset=0;
+    ScreenEraseScreen(fpScr);
+    ScreenTabInit(fpScr);
+//    set_vtwrap(fpScrn,fpScr->DECAWM);     /* QAK - 7/27/90: added because resetting the virtual screen's wrapping flag doesn't reset telnet window's wrapping */
+}
+
+
+void ScreenListMove(HSCREENLINE hTD,HSCREENLINE hBD,HSCREENLINE hTI,HSCREENLINE hBI)
+{
+    HSCREENLINE hTmpLine;
+    SCREENLINE *TD,*BD,*TI,*BI,*tmpLine;
+    
+//    OutputDebugString("ScreenListMove");
+    TD= (SCREENLINE *)GlobalLock(hTD);
+    BD= (SCREENLINE *)GlobalLock(hBD);
+    TI= (SCREENLINE *)GlobalLock(hTI);
+    BI= (SCREENLINE *)GlobalLock(hBI);
+    
+    if(TD->prev!=NULL) {
+        hTmpLine=TD->prev;
+        tmpLine=(SCREENLINE *)GlobalLock(hTmpLine);
+        tmpLine->next=BD->next;    /* Maintain circularity */
+        GlobalUnlock(hTmpLine);
+    }        
+    if(BD->next!=NULL) {
+        hTmpLine=BD->next;
+        tmpLine=(SCREENLINE *)GlobalLock(hTmpLine);
+        tmpLine->prev=TD->prev;
+        GlobalUnlock(hTmpLine);
+    }
+    TD->prev=hTI;                    /* Place the node in its new home */
+    BD->next=hBI;
+    if(TI!=NULL) 
+        TI->next=hTD;                /* Ditto prev->prev */
+    if(BI!=NULL) 
+        BI->prev=hBD;
+        
+    GlobalUnlock(hTD);
+    GlobalUnlock(hBD);
+    GlobalUnlock(hTI);
+    GlobalUnlock(hBI);            
+}
+
+
+void ScreenDelLines(SCREEN *fpScr, int n, int s)
+{
+    HSCREENLINE hBI,hTI,hTD,hBD;
+    SCREENLINE *TI;
+    SCREENLINE *BD;
+    HSCREENLINE hLine;
+    SCREENLINE *fpLine;
+    HSCREENLINE hTemp;
+       int idx;
+       RECT rc;
+       HDC hDC;
+    
+    if (s < 0) 
+        s = fpScr->y;
+
+    if (s + n - 1 > fpScr->bottom)
+        n = fpScr->bottom - s + 1;
+
+    hTD = GetScreenLineFromY(fpScr, s);
+    hBD = GetScreenLineFromY(fpScr, s + n - 1);
+    hTI = GetScreenLineFromY(fpScr, fpScr->bottom);
+    TI= LINE_MEM_LOCK(hTI);
+    hBI = TI->next;
+    LINE_MEM_UNLOCK(hTI);
+
+       /*
+       Adjust the top of the screen and buffer if they will move.
+       */
+       if (hTD == fpScr->screen_top) {
+           BD = LINE_MEM_LOCK(hBD);
+               if (fpScr->screen_top == fpScr->buffer_top)
+                       fpScr->buffer_top = BD->next;
+               fpScr->screen_top = BD->next;
+           LINE_MEM_UNLOCK(hBD);
+       }
+
+       /*
+       Adjust the bottom of the screen and buffer if they will move.
+       */
+       if (hTI == fpScr->screen_bottom) {
+               if (fpScr->screen_bottom == fpScr->buffer_bottom)
+                       fpScr->buffer_bottom = hBD;
+               fpScr->screen_bottom = hBD;
+       }
+
+    if (hTI != hBD)
+        ScreenListMove(hTD, hBD, hTI, hBI);
+
+       /*
+       Clear the lines moved from the deleted area to the
+       bottom of the scrolling area.
+       */
+       hLine = hTI;
+
+       for (idx = 0; idx < n; idx++) {
+               fpLine = LINE_MEM_LOCK(hLine);
+               hTemp = fpLine->next;
+               LINE_MEM_UNLOCK(hLine);
+               hLine = hTemp;
+               ScreenClearLine(fpScr, hLine);
+       }
+
+//     CheckScreen(fpScr);
+
+       /*
+       Scroll the affected area on the screen.
+       */
+    rc.left = 0;
+    rc.right = fpScr->width * fpScr->cxChar;
+    rc.top = s * fpScr->cyChar;
+    rc.bottom = (fpScr->bottom + 1) * fpScr->cyChar;
+
+    hDC = GetDC(fpScr->hWnd);
+
+    ScrollDC(hDC, 0, -fpScr->cyChar * n, &rc, &rc, NULL, NULL);
+
+    PatBlt(hDC, 0, (fpScr->bottom - n + 1) * fpScr->cyChar,
+               fpScr->width * fpScr->cxChar, n * fpScr->cyChar, WHITENESS);
+
+    ReleaseDC(fpScr->hWnd, hDC);
+
+} /* ScreenDelLines */
+
+
+void ScreenInsertLine(SCREEN *fpScr, int s)
+{
+       ScreenInsLines(fpScr, 1, s);
+} /* ScreenInsertLine */
+
+
+void ScreenInsLines(SCREEN *fpScr, int n, int s)
+{
+    HSCREENLINE hLine;
+    HSCREENLINE hTemp;
+    HSCREENLINE hTI;
+    HSCREENLINE hBI;
+    HSCREENLINE hTD;
+    HSCREENLINE hBD;
+    SCREENLINE *fpLine;
+    SCREENLINE *BI;
+       SCREENLINE *TD;
+    int idx;
+    RECT rc;
+    HDC hDC;
+//    wsprintf(strTmp, "ScreenInsLine (n=%d s=%d)", n, s);
+//    OutputDebugString(strTmp);
+
+    if (s < 0)
+               s = fpScr->y;
+
+    if (s + n - 1 > fpScr->bottom) 
+        n = fpScr->bottom - s + 1;
+
+       /*
+       Determine the top and bottom of the insert area.  Also determine
+       the top and bottom of the area to be deleted and moved to the
+       insert area.
+       */
+    hBI = GetScreenLineFromY(fpScr, s);
+    BI = LINE_MEM_LOCK(hBI);
+    hTI = BI->prev;
+    hTD = GetScreenLineFromY(fpScr, fpScr->bottom - n + 1);
+    hBD = GetScreenLineFromY(fpScr, fpScr->bottom);
+    
+       /*
+       Adjust the top of the screen and buffer if they will move.
+       */
+       if (hBI == fpScr->screen_top) {
+               if (fpScr->screen_top == fpScr->buffer_top)
+                       fpScr->buffer_top = hTD;
+               fpScr->screen_top = hTD;
+       }
+
+       /*
+       Adjust the bottom of the screen and buffer if they will move.
+       */
+       if (hBD == fpScr->screen_bottom) {
+           TD = LINE_MEM_LOCK(hTD);
+               if (fpScr->screen_bottom == fpScr->buffer_bottom)
+                       fpScr->buffer_bottom = TD->prev;
+               fpScr->screen_bottom = TD->prev;
+           LINE_MEM_UNLOCK(hTD);
+       }
+
+       /*
+       Move lines from the bottom of the scrolling region to the insert area.
+       */
+    if (hTD != hBI)
+        ScreenListMove(hTD,hBD,hTI,hBI);
+
+       /*
+       Clear the inserted lines
+       */
+    hLine = GetScreenLineFromY(fpScr, s);
+
+    for (idx = 0; idx < n; idx++) {
+               ScreenClearLine(fpScr, hLine);
+        fpLine = LINE_MEM_LOCK(hLine);
+               hTemp = fpLine->next;
+        LINE_MEM_UNLOCK(hLine);
+               hLine = hTemp;
+    }
+
+//     CheckScreen(fpScr);
+
+       /*
+       Scroll the affected area on the screen.
+       */
+    rc.left = 0;
+    rc.right = fpScr->width * fpScr->cxChar;
+    rc.top = s * fpScr->cyChar;
+    rc.bottom = (fpScr->bottom + 1) * fpScr->cyChar;
+
+    hDC = GetDC(fpScr->hWnd);
+
+    ScrollDC(hDC, 0, fpScr->cyChar * n, &rc, &rc, NULL, NULL);
+
+    PatBlt(hDC, 0, s * fpScr->cyChar,
+               fpScr->width * fpScr->cxChar, n * fpScr->cyChar, WHITENESS);
+
+    ReleaseDC(fpScr->hWnd, hDC);
+
+} /* ScreenInsLines */
+
+
+void ScreenIndex(SCREEN * fpScr)
+{
+    if(fpScr->y>=fpScr->bottom)
+        ScreenScroll(fpScr);
+    else
+        fpScr->y++;    
+}
+
+void ScreenWrapNow(SCREEN *fpScr,int *xp,int *yp)
+{
+    if(fpScr->x > fpScr->width) {
+        fpScr->x=0;
+        ScreenIndex(fpScr);
+      } /* end if */
+    *xp=fpScr->x;
+    *yp=fpScr->y;
+}
+
+void ScreenEraseToEOL(SCREEN *fpScr)
+{
+    int x1=fpScr->x,y1=fpScr->y;
+    int x2=fpScr->width,y2=fpScr->y;
+    int n=(-1);
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    RECT rc;
+        
+    ScreenWrapNow(fpScr,&x1,&y1);
+    y2=y1;
+//    wsprintf(strTmp,"[EraseEOL:%d]",y2);
+//    OutputDebugString(strTmp);
+    hgScrLine=GetScreenLineFromY(fpScr,y2);
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+       memset(&fpScrLine->attrib[x1], ScreenClearAttrib, fpScr->width-x1+1);
+       memset(&fpScrLine->text[x1], ' ', fpScr->width-x1+1);
+    LINE_MEM_UNLOCK(hgScrLine);      
+    rc.left=x1*fpScr->cxChar;
+    rc.right=(fpScr->width*fpScr->cxChar);
+    rc.top=(fpScr->cyChar*y1);    
+    rc.bottom=(fpScr->cyChar*(y1+1));
+    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+    UpdateWindow(fpScr->hWnd);
+}
+
+void ScreenDelChars(SCREEN *fpScr, int n)
+{
+    int x = fpScr->x;
+       int y = fpScr->y;
+    int width;
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    RECT rc;
+       
+    hgScrLine = GetScreenLineFromY(fpScr, y);
+    fpScrLine = LINE_MEM_LOCK(hgScrLine);
+
+       width = fpScr->width - x - n;
+
+       if (width > 0) {
+               memmove(&fpScrLine->attrib[x], &fpScrLine->attrib[x + n], width);
+               memmove(&fpScrLine->text[x], &fpScrLine->text[x + n], width);
+       }
+
+       memset(&fpScrLine->attrib[fpScr->width - n], ScreenClearAttrib, n);
+    memset(&fpScrLine->text[fpScr->width - n], ' ', n);
+       
+    LINE_MEM_UNLOCK(hgScrLine);
+
+    rc.left = x * fpScr->cxChar;
+    rc.right = fpScr->width * fpScr->cxChar;
+    rc.top = fpScr->cyChar * y;
+    rc.bottom = fpScr->cyChar * (y + 1);
+
+    InvalidateRect(fpScr->hWnd, &rc, TRUE);
+
+    UpdateWindow(fpScr->hWnd);
+}
+
+void ScreenRevIndex(SCREEN *fpScr)
+{
+    HSCREENLINE hgScrLine,hTopLine;
+    
+    hgScrLine=GetScreenLineFromY(fpScr,fpScr->y);
+    hTopLine=GetScreenLineFromY(fpScr,fpScr->top);
+    
+    if(hgScrLine==hTopLine) 
+        ScreenInsertLine(fpScr,fpScr->y);
+    else
+        fpScr->y--;
+}
+
+void ScreenEraseToBOL(SCREEN *fpScr)
+{
+    int x1=0,y1=fpScr->y;
+    int x2=fpScr->x,y2=fpScr->y;
+    int n=(-1);
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+
+    hgScrLine=GetScreenLineFromY(fpScr,fpScr->y);
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+
+    ScreenWrapNow(fpScr,&x2,&y1);
+    y2=y1;
+       memset(fpScrLine->attrib, ScreenClearAttrib, x2);
+       memset(fpScrLine->text, ' ', x2);
+    LINE_MEM_UNLOCK(hgScrLine);      
+}
+
+void ScreenEraseLine(SCREEN *fpScr,int s)
+{
+    int x1=0,y1=s;
+    int x2=fpScr->width,y2=s;
+    int n=(-1);
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    RECT rc;
+    
+    if(s<0) {
+        ScreenWrapNow(fpScr,&x1,&y1);
+        s=y2=y1;
+        x1=0;
+      } /* end if */
+
+    hgScrLine=GetScreenLineFromY(fpScr,y1);
+    fpScrLine=LINE_MEM_LOCK(hgScrLine);
+       memset(fpScrLine->attrib, ScreenClearAttrib, fpScr->width);
+       memset(fpScrLine->text, ' ', fpScr->width);
+    LINE_MEM_UNLOCK(hgScrLine);      
+    rc.left=0;
+    rc.right=(fpScr->width*fpScr->cxChar);
+    rc.top=(fpScr->cyChar*y1);    
+    rc.bottom=(fpScr->cyChar*(y1+1));
+    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+}
+
+void ScreenEraseToEndOfScreen(SCREEN *fpScr)
+{
+    register int i;
+    int x1=0,y1=fpScr->y+1;
+    int x2=fpScr->width,y2=fpScr->height;
+    int n=(-1);
+
+    ScreenWrapNow(fpScr,&x1,&y1);
+    y1++;
+    x1=0;
+    i=y1;
+    ScreenEraseToEOL(fpScr);
+    while(i<fpScr->height) {
+        ScreenELO(fpScr,i);
+        ScreenEraseLine(fpScr,i);
+        i++;
+    } /* end while */
+}
+
+void ScreenRange(SCREEN *fpScr)               /* check and resolve range errors on x and y */
+{
+    int wrap=0;
+
+    if(fpScr->DECAWM)
+        wrap=1;
+    if(fpScr->x<0)
+        fpScr->x=0;
+    if(fpScr->x>(fpScr->width+wrap))
+        fpScr->x=fpScr->width+wrap;
+    if(fpScr->y<0)
+        fpScr->y=0;
+    if(fpScr->y>=fpScr->height)
+        fpScr->y=fpScr->height-1;
+}
+
+void ScreenAlign(SCREEN *fpScr)  /* vt100 alignment, fill screen with 'E's */
+{
+    char *tt;
+    register int i,j;
+    HSCREENLINE hgScrLine,hgScrLineTmp;
+    SCREENLINE *fpScrLine;
+    
+    hgScrLine=GetScreenLineFromY(fpScr,fpScr->top);
+    ScreenEraseScreen(fpScr);        /* erase the screen */
+
+    for(j=0; j<fpScr->height; j++) {
+        fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+        tt=&fpScrLine->text[0];
+        for(i=0; i<=fpScr->width; i++)
+            *tt++='E';
+        hgScrLineTmp=fpScrLine->next;            
+        LINE_MEM_UNLOCK(hgScrLine);
+        hgScrLine=hgScrLineTmp;    
+        
+      } /* end for */
+    LINE_MEM_UNLOCK(hgScrLine);      
+}
+
+/* reset all the ANSI parameters back to the default state */
+void ScreenApClear(SCREEN *fpScr)
+{
+    for(fpScr->parmptr=5; fpScr->parmptr>=0; fpScr->parmptr--)
+        fpScr->parms[fpScr->parmptr]=-1;
+    fpScr->parmptr=0;
+}
+
+void ScreenSetOption(SCREEN *fpScr,int toggle) {
+//    int WindWidth=(fpScr->width - 1);
+
+    switch(fpScr->parms[0]) {
+        case -2:
+            switch(fpScr->parms[1]) {
+                case 1:     /* set/reset cursor key mode */
+                    fpScr->DECCKM=toggle;
+                    break;
+
+#ifdef NOT_SUPPORTED
+                case 2:     /* set/reset ANSI/vt52 mode */
+                    break;
+#endif
+
+                case 3:     /* set/reset column mode */
+                    fpScr->x=fpScr->y=0;      /* Clear the screen, mama! */
+                    ScreenEraseScreen(fpScr);
+                                       #if 0   /* removed for variable screen size */
+                           if(toggle)      /* 132 column mode */
+                           fpScr->width=fpScr->allwidth;
+                           else
+                           fpScr->width=79;
+                                       #endif
+                    break;
+
+#ifdef NOT_SUPPORTED
+                case 4:     /* set/reset scrolling mode */
+                case 5:     /* set/reset screen mode */
+                case 6:     /* set/rest origin mode */
+                    fpScr->DECORG = toggle;
+                    break;
+#endif
+
+                case 7:     /* set/reset wrap mode */
+                    fpScr->DECAWM=toggle;
+//                    set_vtwrap(fpScrn,fpScr->DECAWM);     /* QAK - 7/27/90: added because resetting the virtual screen's wrapping flag doesn't reset telnet window's wrapping */
+                    break;
+
+#ifdef NOT_SUPPORTED
+                case 8:     /* set/reset autorepeat mode */
+                case 9:     /* set/reset interlace mode */
+                    break;
+#endif
+
+                default:
+                    break;
+            } /* end switch */
+            break;
+
+        case 4:
+            fpScr->IRM=toggle;
+            break;
+
+        default:
+            break;
+
+    } /* end switch */
+}
+
+#ifdef NOT_SUPPORTED
+void ScreenTab(SCREEN *fpScr)
+{
+    if(fpScr->x>=fpScr->width)
+        fpScr->x=fpScr->width;
+    fpScr->x++;
+    while((fpScr->tabs[fpScr->x] != 'x') && (fpScr->x < fpScr->width)) 
+        fpScr->x++;
+}
+#endif
+
+int ScreenInsChar(SCREEN *fpScr,int x)
+{
+    int i;
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    RECT rc;
+        
+//    ScreenWrapNow(&i,&j);  /* JEM- Why is this here? comment out for now */
+
+//    OutputDebugString("OOPS-InsChar!");
+    hgScrLine=GetScreenLineFromY(fpScr,fpScr->y);
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+    if (fpScrLine==NULL) return (-1);
+
+    for(i=fpScr->width-x; i>=fpScr->x; i--) {
+        fpScrLine->text[x+i]=fpScrLine->text[i];
+        fpScrLine->attrib[x+i]=fpScrLine->attrib[i];
+    } /* end for */
+
+       memset(&fpScrLine->attrib[fpScr->x], ScreenClearAttrib, x);
+       memset(&fpScrLine->text[fpScr->x], ' ', x);
+
+    for(i=fpScr->x; i<fpScr->x+x; i++) {
+        fpScrLine->text[i]=' ';
+        fpScrLine->attrib[i]=ScreenClearAttrib;
+    } /* end for */
+    LINE_MEM_UNLOCK(hgScrLine);  
+    rc.left= (fpScr->cxChar*x);
+    rc.right= ((fpScr->cxChar*x)+(fpScr->cxChar*(x+fpScr->x)));
+    rc.top=(fpScr->cyChar*((fpScr->y)-1));    
+    rc.bottom=(fpScr->cyChar*(fpScr->y));
+    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+}
+
+void ScreenInsString(SCREEN *fpScr,int len,char *start)
+{
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    int idx;
+    RECT rc;
+    
+    if(fpScr->VSIDC) return;  /* Call RSinsstring which does nothing? */
+    
+    hgScrLine=GetScreenLineFromY(fpScr,fpScr->y);
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+    if (fpScrLine==NULL) return;
+
+    for(idx=fpScr->x; idx<fpScr->x+len; idx++) {
+        fpScrLine->text[idx]=start[idx];
+        fpScrLine->attrib[idx]=fpScr->attrib;
+    } /* end for */
+    LINE_MEM_UNLOCK(hgScrLine);
+    rc.left= (fpScr->cxChar*fpScr->x);
+    rc.right= ((fpScr->cxChar*fpScr->x)+(fpScr->cxChar*(fpScr->x+len)));
+    rc.top=(fpScr->cyChar*(fpScr->y));    
+    rc.bottom=(fpScr->cyChar*(fpScr->y+1));    
+    
+    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+}
+
+void ScreenSaveCursor(SCREEN *fpScr)
+{
+    fpScr->Px=fpScr->x;
+    fpScr->Py=fpScr->y;
+    fpScr->Pattrib=fpScr->attrib;
+}
+
+void ScreenRestoreCursor(SCREEN *fpScr)
+{
+    fpScr->x=fpScr->Px;
+    fpScr->y=fpScr->Py;
+    ScreenRange(fpScr);
+}
+
+void ScreenDraw(SCREEN *fpScr,int x,int y,int a,int len,char *c)
+{
+       int idx;
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    RECT rc;
+
+    hgScrLine=GetScreenLineFromY(fpScr,y);  
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+    if (fpScrLine==NULL) {
+        OutputDebugString("fpScrLine==NULL");
+        return;
+    }
+    
+    for(idx=x; idx<(x+len); idx++) {
+        fpScrLine->text[idx]=c[idx-x];
+        fpScrLine->attrib[idx-x]=a;
+    } 
+    LINE_MEM_UNLOCK(hgScrLine);
+
+       rc.left= (fpScr->cxChar*x);
+    rc.right= (fpScr->cxChar*(x+len));
+       rc.top=(fpScr->cyChar*(fpScr->y));    
+    rc.bottom=(fpScr->cyChar*((fpScr->y)+1));
+       InvalidateRect(fpScr->hWnd,&rc,TRUE);    
+    SendMessage(fpScr->hWnd,WM_PAINT,NULL,NULL);
+}
+
+#ifdef _DEBUG
+
+       BOOL CheckScreen(SCREEN *fpScr)
+       {
+               HSCREENLINE hLine;
+               HSCREENLINE hLinePrev;
+               SCREENLINE *fpLine;
+               int nscreen = 0;
+               int nbuffer = 0;
+               int topline = 0;
+               char buf[512];
+               BOOL bBottom;
+               BOOL bOK;
+
+               hLine = fpScr->buffer_top;
+
+               if (hLine == NULL) {
+                       OutputDebugString("CheckScreen: buffer_top invalid");
+                       MessageBox(NULL, "buffer_top invalid", "CheckScreen", MB_OK);
+                       return(FALSE);
+               }
+
+               bBottom = FALSE;
+               while (TRUE) {
+                       hLinePrev = hLine;
+                       if (nscreen > 0 || hLine == fpScr->screen_top)
+                               if (!bBottom)
+                                       nscreen++;
+                       nbuffer++;
+                       if (hLine == fpScr->screen_top)
+                               topline = nbuffer - 1;
+                       if (hLine == fpScr->screen_bottom)
+                               bBottom = TRUE;
+                       fpLine = LINE_MEM_LOCK(hLine);
+                       hLine = fpLine->next;
+                       LINE_MEM_UNLOCK(hLine);
+                       if (hLine == NULL)
+                               break;
+                       fpLine = LINE_MEM_LOCK(hLine);
+                       if (fpLine->prev != hLinePrev) {
+                               wsprintf(buf,
+                                       "Previous ptr of line %d does not match next ptr of line %d",
+                                       nbuffer, nbuffer - 1);
+                               OutputDebugString(buf);
+                               MessageBox(NULL, buf, "CheckScreen", MB_OK);
+                       }
+                       LINE_MEM_UNLOCK(hLine);
+               }
+
+               if (hLinePrev == fpScr->buffer_bottom && nscreen == fpScr->height)
+                       bOK = TRUE;
+               else {
+                       OutputDebugString("CheckScreen: Invalid number of lines on screen");
+                       bOK = FALSE;
+               }
+
+               wsprintf(buf, \
+                       "screen.width = %d\n"
+                       "screen.height = %d\n"
+                       "screen.maxlines = %d\n"
+                       "screen.numlines = %d\n"
+                       "screen.x = %d\n"
+                       "screen.y = %d\n"
+                       "screen.top = %d\n"
+                       "screen.bottom = %d\n"
+                       "Actual top line = %d\n"
+                       "Actual buffer lines = %d\n"
+                       "Actual screen lines = %d\n"
+                       "Bottom of buffer is %s",
+                       fpScr->width, fpScr->height, fpScr->maxlines, fpScr->numlines,
+                       fpScr->x, fpScr->y, fpScr->top, fpScr->bottom,
+                       topline, nbuffer, nscreen,
+                       (hLinePrev == fpScr->buffer_bottom) ? "valid" : "invalid");
+
+               MessageBox(NULL, buf, "CheckScreen", MB_OK);
+
+               return(bOK);
+       }
+
+#endif
diff --git a/src/windows/wintel/k5stream.c b/src/windows/wintel/k5stream.c
new file mode 100644 (file)
index 0000000..3745ed5
--- /dev/null
@@ -0,0 +1,63 @@
+/*+*************************************************************************
+** 
+** K5stream
+** 
+** Emulates the kstream package in Kerberos 4
+** 
+***************************************************************************/
+
+#include <stdio.h>
+#include <io.h>
+#include <malloc.h>
+#include "telnet.h"
+#include "k5stream.h"
+#include "auth.h"
+
+int 
+kstream_destroy (kstream ks) {
+    if (ks != NULL) {
+        auth_destroy (ks);                       /* Destroy authorizing */
+
+        closesocket (ks->fd);                    /* Close the socket??? */
+        free (ks);
+    }
+    return 0;
+}
+
+void 
+kstream_set_buffer_mode (kstream ks, int mode) {
+}
+
+
+kstream 
+kstream_create_from_fd (int fd,
+                               const struct kstream_crypt_ctl_block __far *ctl,
+                               kstream_ptr data)
+{
+    kstream ks;
+    int n;
+
+    ks = malloc (sizeof(kstream *));
+    if (ks == NULL)
+        return NULL;
+
+    ks->fd = fd;
+
+    n = auth_init (ks, data);                   /* Initialize authorizing */
+    if (n) {
+        free (ks);
+        return NULL;
+    }
+
+    return ks;
+}
+
+int 
+kstream_write (kstream ks, void __far *p_data, size_t p_len) {
+    int n;
+
+    n = send (ks->fd, p_data, p_len, 0);        /* Write the data */
+    
+    return n;                                   /* higher layer does retries */
+}
+
diff --git a/src/windows/wintel/k5stream.h b/src/windows/wintel/k5stream.h
new file mode 100644 (file)
index 0000000..0a9ce08
--- /dev/null
@@ -0,0 +1,52 @@
+/* Header file for encrypted-stream library.
+ * Written by Ken Raeburn (Raeburn@Cygnus.COM).
+ * Copyright (C) 1991, 1992, 1994 by Cygnus Support.
+ *
+ * Permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation.
+ * Cygnus Support makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef K5STREAM_H
+#define K5STREAM_H
+
+typedef struct {                                /* Object we pass around */
+    int fd;                                     /* Open socket descriptor */
+} *kstream;
+
+typedef void *kstream_ptr;                      /* Data send on the kstream */
+
+struct kstream_data_block {
+    kstream_ptr ptr;
+    size_t length;
+};
+
+struct kstream_crypt_ctl_block {
+    int (INTERFACE *encrypt) (
+      struct kstream_data_block *, /* output -- written */
+               struct kstream_data_block *, /* input */
+               kstream str);
+    int (INTERFACE *decrypt) (
+      struct kstream_data_block *, /* output -- written */
+      struct kstream_data_block *, /* input */
+      kstream str);
+    int (INTERFACE *init) (kstream str, kstream_ptr data);
+    void (INTERFACE *destroy) (kstream str);
+};
+
+
+/* Prototypes */
+
+int kstream_destroy (kstream);
+void kstream_set_buffer_mode (kstream, int);
+kstream kstream_create_from_fd (int fd,
+                               const struct kstream_crypt_ctl_block __far *ctl,
+                               kstream_ptr data);
+int kstream_write (kstream, void __far *, size_t);
+
+#endif /* K5STREAM_H */
diff --git a/src/windows/wintel/makefile b/src/windows/wintel/makefile
new file mode 100644 (file)
index 0000000..71aa824
--- /dev/null
@@ -0,0 +1,104 @@
+# makefile: Constructs the kerborized telnet client
+# Works for both k4 and k5 releases.
+#
+NAME = telnet
+OBJS = telnet.obj negotiat.obj auth.obj edit.obj emul.obj \
+       font.obj intern.obj screen.obj
+
+##### Options
+DEBUG = 1
+!IF ! defined(KVERSION)
+KVERSION = 5
+!endif
+KRB     = KRB$(KVERSION)
+
+!if $(KVERSION) == 4
+BUILDTOP = ..
+LIBDIR          = $(BUILDTOP)\lib\krb
+KLIB    = $(LIBDIR)\kerberos.lib 
+WLIB    = $(LIBDIR)\winsock.lib
+INCLUDES = /I$(BUILDTOP)\include
+XOBJS    = 
+!endif
+
+!if $(KVERSION) == 5
+BUILDTOP =..\..
+LIBDIR  = $(BUILDTOP)\lib
+KLIB    = $(LIBDIR)\libkrb5.lib
+WLIB    = $(LIBDIR)\winsock.lib
+INCLUDES = /I$(BUILDTOP)\include /I$(BUILDTOP)\include\krb5 \
+       /I$(BUILDTOP)\lib\crypto\des
+XOBJS    = k5stream.obj
+!endif
+
+##### C Compiler
+CC = cl
+CFLAGS_RELEASE = /nologo /W3 /AL /GAs /Gx /O1 /DNDEBUG
+CFLAGS_DEBUG = /nologo /W3 /AL /GAs /Gx /G2 /Zi /Od /D_DEBUG /Fd"TELNET.PDB"
+!if $(DEBUG)
+CFLAGS = $(CFLAGS_DEBUG) $(INCLUDES) /D$(KRB)=1
+!else
+CFLAGS = $(CFLAGS_RELEASE) $(INCLUDES) /D$(KRB)=1
+!endif
+
+##### RC Compiler
+RC = rc
+RFLAGS_RELEASE = /nologo
+RFLAGS_DEBUG = /nologo /D_DEBUG
+!if $(DEBUG)
+RFLAGS = $(RFLAGS_DEBUG) $(INCLUDES)
+!else
+RFLAGS = $(RFLAGS_RELEASE) $(INCLUDES)
+!endif
+
+##### Linker
+LINK = link     
+LIBS = $(KLIB) $(WLIB)
+SYSLIBS = libw llibcew commdlg
+!if $(DEBUG)
+LFLAGS = /co /nol /nod /packc:61440 /stack:32768 /align:16 /onerror:noexe
+!else
+LFLAGS = /nol /nod /packc:61440 /stack:32768 /align:16 /onerror:noexe
+!endif
+
+all: makefile $(NAME).exe
+
+$(NAME).exe: $*.def $*.res $(OBJS) $(XOBJS) $(LIBS)
+       $(LINK) $(LFLAGS) $(OBJS) $(XOBJS), $@, $*.map, \
+         $(LIBS) $(SYSLIBS), $*.def
+       $(RC) $(RFLAGS) /k $*.res $@
+
+install:
+       copy telnet.exe ..\floppy
+
+clean:
+       if exist *.obj del *.obj
+       if exist *.exe del *.exe
+       if exist *.res del *.res
+        if exist *.map del *.map
+       if exist *.pdb del *.pdb
+       if exist *.err del *.err
+       if exist ..\floppy\telnet.exe del ..\floppy\telnet.exe
+
+telnet.obj: telnet.h dialog.h screen.h struct.h wt-proto.h ini.h
+
+negotiat.obj: telnet.h dialog.h screen.h struct.h wt-proto.h ini.h
+
+auth.obj: telopts.h telnet.h dialog.h screen.h struct.h wt-proto.h ini.h
+
+edit.obj: screen.h
+
+emul.obj: screen.h
+
+font.obj: screen.h ini.h
+
+intern.obj: screen.h
+
+screen.obj: screen.h ini.h
+
+telnet.res: screen.h dialog.h telnet.dlg ncsa.ico terminal.ico
+
+!if $(KVERSION) == 5
+k5stream.c: k5stream.h auth.h
+!endif
+
diff --git a/src/windows/wintel/ncsa.ico b/src/windows/wintel/ncsa.ico
new file mode 100644 (file)
index 0000000..8a6cb6a
Binary files /dev/null and b/src/windows/wintel/ncsa.ico differ
diff --git a/src/windows/wintel/negotiat.c b/src/windows/wintel/negotiat.c
new file mode 100644 (file)
index 0000000..abace44
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+*   negotiat.c
+*
+*   Telnet option negotiation functions
+*
+
+/*
+* Includes
+*/
+
+/* #define USETEK */
+/* #define USERAS */
+
+#if 0   /* define this to print the raw network data to debuging monitor */
+#define NEGOTIATEDEBUG  
+#endif
+
+#include <time.h>
+#include "telnet.h"
+#include "telopts.h"
+#include "auth.h"
+
+unsigned char parsedat[256];
+
+/* Local functions */
+static void parse_subnegotiat(kstream ks,int end_sub);
+
+/* Local variables */
+static char *telstates[]={
+    "EOF",
+    "Suspend Process",
+    "Abort Process",
+    "Unknown (239)",
+    "Subnegotiation End",
+    "NOP",
+    "Data Mark",
+    "Break",
+    "Interrupt Process",
+    "Abort Output",
+    "Are You There",
+    "Erase Character",
+    "Erase Line",
+    "Go Ahead",
+    "Subnegotiate",
+    "Will",
+    "Won't",
+    "Do",
+    "Don't"
+};
+
+static char *teloptions[256]={      /* ascii strings for Telnet options */
+    "Binary",                               /* 0 */
+    "Echo",
+    "Reconnection",
+    "Supress Go Ahead",
+    "Message Size Negotiation",
+    "Status",                               /* 5 */
+    "Timing Mark",
+    "Remote Controlled Trans and Echo",
+    "Output Line Width",
+    "Output Page Size",
+    "Output Carriage-Return Disposition",   /* 10 */
+    "Output Horizontal Tab Stops",
+    "Output Horizontal Tab Disposition",
+    "Output Formfeed Disposition",
+    "Output Vertical Tabstops",
+    "Output Vertical Tab Disposition",      /* 15 */
+    "Output Linefeed Disposition",
+    "Extended ASCII",
+    "Logout",
+    "Byte Macro",
+    "Data Entry Terminal",                  /* 20 */
+    "SUPDUP",
+    "SUPDUP Output",
+    "Send Location",
+    "Terminal Type",
+    "End of Record",                        /* 25 */
+    "TACACS User Identification",
+    "Output Marking",
+    "Terminal Location Number",
+    "3270 Regime",
+    "X.3 PAD",                              /* 30 */
+    "Negotiate About Window Size",
+    "Terminal Speed",
+    "Toggle Flow Control",
+    "Linemode",
+    "X Display Location",                   /* 35 */
+    "Environment",
+    "Authentication",
+    "Data Encryption",
+    "39",
+    "40","41","42","43","44","45","46","47","48","49",
+    "50","51","52","53","54","55","56","57","58","59",
+    "60","61","62","63","64","65","66","67","68","69",
+    "70","71","72","73","74","75","76","77","78","79",
+    "80","81","82","83","84","85","86","87","88","89",
+    "90","91","92","93","94","95","96","97","98","99",
+    "100","101","102","103","104","105","106","107","108","109",
+    "110","111","112","113","114","115","116","117","118","119",
+    "120","121","122","123","124","125","126","127","128","129",
+    "130","131","132","133","134","135","136","137","138","139",
+    "140","141","142","143","144","145","146","147","148","149",
+    "150","151","152","153","154","155","156","157","158","159",
+    "160","161","162","163","164","165","166","167","168","169",
+    "170","171","172","173","174","175","176","177","178","179",
+    "180","181","182","183","184","185","186","187","188","189",
+    "190","191","192","193","194","195","196","197","198","199",
+    "200","201","202","203","204","205","206","207","208","209",
+    "210","211","212","213","214","215","216","217","218","219",
+    "220","221","222","223","224","225","226","227","228","229",
+    "230","231","232","233","234","235","236","237","238","239",
+    "240","241","242","243","244","245","246","247","248","249",
+    "250","251","252","253","254",
+    "Extended Options List"     /* 255 */
+};
+
+static char *LMoptions[]={      /* ascii strings for Linemode sub-options */
+    "None",     "MODE",     "FORWARDMASK",     "SLC"
+};
+
+static char *ModeOptions[]={      /* ascii strings for Linemode edit options */
+    "None",     "EDIT",     "TRAPSIG",      "ACK",     "SOFT TAB",    "LIT ECHO"
+};
+
+static char *SLCoptions[]={     /* ascii strings for Linemode SLC characters */
+    "None",     "SYNCH",    "BREAK",    "IP",       "ABORT OUTPUT",
+    "AYT",      "EOR",      "ABORT",    "EOF",      "SUSP",
+    "EC",       "EL",       "EW",       "RP",       "LNEXT",
+    "XON",      "XOFF",     "FORW1",    "FORW2",    "MCL",
+    "MCR",      "MCWL",     "MCWR",     "MCBOL",    "MCEOL",
+    "INSRT",    "OVER",     "ECR",      "EWR",      "EBOL",
+    "EEOL"
+};
+
+static char *SLCflags[]={      /* ascii strings for Linemode SLC flags */
+    "SLC_NOSUPPORT",    "SLC_CANTCHANGE",   "SLC_VALUE",    "SLC_DEFAULT"
+};
+
+    /* Linemode default character for each function */
+static unsigned char LMdefaults[NUMLMODEOPTIONS+1]={   
+    (unsigned char)-1,          /* zero isn't used */
+    (unsigned char)-1,          /* we don't support SYNCH */
+    3,                          /* ^C is default for BRK */
+    3,                          /* ^C is default for IP */
+    15,                         /* ^O is default for AO */
+    25,                         /* ^Y is default for AYT */         /* 5 */
+    (unsigned char)-1,          /* we don't support EOR */
+    3,                          /* ^C is default for ABORT */
+    4,                          /* ^D is default for EOF */
+    26,                         /* ^Z is default for SUSP */
+    8,                          /* ^H is default for EC */          /* 10 */
+    21,                         /* ^U is default for EL */
+    23,                         /* ^W is default for EW */
+    18,                         /* ^R is default for RP */
+    22,                         /* ^V is default for LNEXT */
+    17,                         /* ^Q is default for XON */         /* 15 */
+    19,                         /* ^S is default for XOFF */
+    22,                         /* ^V is default for FORW1 */
+    5,                          /* ^E is default for FORW2 */
+    (unsigned char)-1,          /* we don't support MCL */
+    (unsigned char)-1,          /* we don't support MCR */          /* 20 */
+    (unsigned char)-1,          /* we don't support MCWL */
+    (unsigned char)-1,          /* we don't support MCWR */
+    (unsigned char)-1,          /* we don't support MCBOL */
+    (unsigned char)-1,          /* we don't support MCEOL */
+    (unsigned char)-1,          /* we don't support INSRT */        /* 25 */
+    (unsigned char)-1,          /* we don't support OVER */
+    (unsigned char)-1,          /* we don't support ECR */
+    (unsigned char)-1,          /* we don't support EWR */
+    (unsigned char)-1,          /* we don't support EBOL */
+    (unsigned char)-1           /* we don't support EEOL */         /* 30 */
+};
+
+
+/*+********************************************************************
+*  Function :   start_negotiation()
+*  Purpose  :   Send the initial negotiations on the network and print
+*               the negotitations to the console screen.
+*  Parameters   :
+*           dat - the port number to write to
+*           cvs - the console's virtual screen
+*  Returns  :   none
+*  Calls    :   tprintf(), netprintf()
+*  Called by    :   dosessions()
+**********************************************************************/
+void
+start_negotiation(kstream ks)
+{
+    char buf[128];
+    
+    /* Send the initial tlnet negotiations */
+    wsprintf(buf,"%c%c%c",IAC,DOTEL,SGA);
+    TelnetSend(ks,buf,lstrlen(buf),0);
+    wsprintf(buf,"%c%c%c",IAC,DOTEL,ECHO);
+    TelnetSend(ks,buf,lstrlen(buf),0);
+    wsprintf(buf,"%c%c%c",IAC,WILLTEL,NAWS);
+    TelnetSend(ks,buf,lstrlen(buf),0);
+
+#ifdef NOT
+    /* check whether we are going to be output mapping */
+    if(tw->mapoutput) { 
+        netprintf(tw->pnum,"%c%c%c",IAC,DOTEL,BINARY);
+    /* set the flag indicating we wanted server to start transmitting binary */
+        tw->uwantbinary=1;  
+        netprintf(tw->pnum,"%c%c%c",IAC,WILLTEL,BINARY);
+    /* set the flag indicating we want to start transmitting binary */
+        tw->iwantbinary=1;  
+      } /* end if */
+#endif
+
+    /* Print to the console what we just did */
+#ifdef NEGOTIATEDEBUG
+        wsprintf(strTmp,"SEND: %ls %ls\r\n",telstates[DOTEL-LOW_TEL_OPT],
+            teloptions[ECHO]);
+        OutputDebugString(strTmp);
+        wsprintf(strTmp,"SEND: %ls %ls\r\n",telstates[DOTEL-LOW_TEL_OPT],
+            teloptions[SGA]);
+        OutputDebugString(strTmp);
+        wsprintf(strTmp,"SEND: %ls %ls\r\n",telstates[WILLTEL-LOW_TEL_OPT],
+            teloptions[NAWS]);
+        OutputDebugString(strTmp);
+
+#ifdef NOT
+        tprintf(cvs,"SEND: %ls %ls\r\n",telstates[DOTEL-LOW_TEL_OPT],
+            teloptions[BINARY]);
+        tprintf(cvs,"SEND: %ls %ls\r\n",telstates[WILLTEL-LOW_TEL_OPT],
+            teloptions[BINARY]);
+#endif      
+#endif
+}   /* end start_negotiation() */
+
+/*+*******************************************************************
+*  parse
+*   Do the telnet negotiation parsing.
+*
+*   look at the string which has just come in from outside and
+*   check for special sequences that we are interested in.
+*
+*   Tries to pass through routine strings immediately, waiting for special
+*   characters ESC and IAC to change modes.
+*/
+void
+parse (CONNECTION *con,unsigned char *st,int cnt) {
+    static int sub_pos; /* the position we are in the subnegotiation parsing */
+    static int end_sub; /* index of last byte in parsedat in a subnegotiation */
+    unsigned char *mark, *orig;
+    char buf[256];
+    kstream ks;
+        
+    ks=con->ks;
+   
+#ifdef PRINT_EVERYTHING   
+    OutputDebugString("\r\n");
+        for(i=0; i<cnt; i++) {
+            int j;
+
+            for(j=0; (j < 16) && ((i + j) < cnt); j++) {
+                wsprintf(strTmp,"%2.2X  ", *(unsigned char *) (st + i + j));
+                OutputDebugString(strTmp);
+            }    
+            i+=j-1;
+            OutputDebugString("\r\n");
+          } /* end for */
+    OutputDebugString("\r\n");
+#endif //PRINT_EVERYTHING    
+      
+    orig=st;                /* remember beginning point */
+    mark=st+cnt;            /* set to end of input string */
+
+#ifdef HUH
+    netpush(tw->pnum);
+#endif
+
+/*
+*  traverse string, looking for any special characters which indicate that
+*  we need to change modes.
+*/
+    while(st<mark) {
+        while(con->telstate!=STNORM && st<mark) {   
+            switch(con->telstate) {
+                case IACFOUND:              /* telnet option negotiation */
+                    if(*st==IAC) {          /* real data=255 */
+                        st++;               /* real 255 will get sent */
+                        con->telstate=STNORM;
+                        break;
+                      } /* end if */
+
+                    if(*st>239) {
+                        con->telstate=*st++; /* by what the option is */
+                        break;
+                      } /* end if */
+
+#ifdef NEGOTIATEDEBUG
+                    wsprintf(buf,"\r\n strange telnet option");
+                    OutputDebugString(buf);
+#endif                    
+                    orig=++st;
+                    con->telstate=STNORM;
+                    break;
+
+                case EL:     /* received a telnet erase line command */
+                case EC:     /* received a telnet erase character command */
+                case AYT:    /* received a telnet Are-You-There command */
+                case AO:     /* received a telnet Abort Output command */
+                case IP:     /* received a telnet Interrupt Process command */
+                case BREAK:  /* received a telnet Break command */
+                case DM:     /* received a telnet Data Mark command */
+                case NOP:    /* received a telnet No Operation command */
+                case SE:     /* received a telnet Subnegotiation End command */
+                case ABORT:  /* received a telnet Abort Process command */
+                case SUSP:   /* received a telnet Suspend Process command */
+                case TEL_EOF:/* received a telnet EOF command */
+#ifdef NEGOTIATEDEBUG
+                    wsprintf(buf,"RECV: %ls\r\n",
+                        telstates[con->telstate-LOW_TEL_OPT]);
+                    OutputDebugString(buf);
+#endif
+                    con->telstate=STNORM;
+                    orig=++st;
+                    break;
+
+                case GOAHEAD:       /* telnet go ahead option*/
+#ifdef NEGOTIATEDEBUG
+                    wsprintf(buf,"RECV: %ls\r\n",
+                        telstates[con->telstate-LOW_TEL_OPT]);
+                    OutputDebugString(buf);
+#endif
+                    con->telstate=STNORM;
+                    orig=++st;
+                    break;
+
+                case DOTEL:     /* received a telnet DO negotiation */
+#ifdef NEGOTIATEDEBUG
+                    wsprintf(buf,"RECV: %ls %ls\r\n",
+                        telstates[con->telstate-LOW_TEL_OPT],teloptions[*st]);
+                    OutputDebugString(buf);
+#endif
+                    switch(*st) {
+#ifdef NOT
+                        case BINARY:       /* DO: binary transmission */
+                            if(!tw->ibinary) { /* binary */
+                                if(!tw->iwantbinary) { 
+                                    netprintf(tw->pnum,"%c%c%c",
+                                        IAC,WILLTEL,BINARY);
+                                    if(tw->condebug>0)
+                                        tprintf(cv,"SEND: %ls %ls\r\n",
+                                            telstates[WILLTEL-LOW_TEL_OPT],
+                                            teloptions[BINARY]);
+                                  } /* end if */
+                                else
+                                    tw->iwantbinary=0;  /* turn off this now */
+                                tw->ibinary=1;
+                              } /* end if */
+                            else {
+                                if(tw->condebug>0)
+                                    tprintf(cv,"NO REPLY NEEDED: %ls %ls\r\n",
+                                        telstates[WILLTEL-LOW_TEL_OPT],
+                                        teloptions[BINARY]);
+                              } /* end else */
+                            break;
+#endif
+
+                        case SGA:       /* DO: Suppress go-ahead */
+                            if(!con->igoahead) { /* suppress go-ahead */
+                                wsprintf(buf,"%c%c%c",IAC,WILLTEL,SGA);
+                                TelnetSend(ks,buf,lstrlen(buf),0);
+#ifdef NEGOTIATEDEBUG
+                                wsprintf(strTmp,"SEND: %ls %ls\r\n",
+                                    telstates[WILLTEL-LOW_TEL_OPT],
+                                    teloptions[SGA]);
+                                OutputDebugString(strTmp);
+                                OutputDebugString("igoahead");
+#endif
+                                con->igoahead=1;
+                              } /* end if */
+                            else {
+#ifdef NEGOTIATEDEBUG
+                                wsprintf(strTmp,
+                                    "NO REPLY NEEDED: %ls %ls\r\n",
+                                    telstates[WILLTEL-LOW_TEL_OPT],
+                                    teloptions[SGA]);
+                                OutputDebugString(strTmp);
+#endif
+                              } /* end else */
+                            break;
+
+                        case TERMTYPE:      /* DO: terminal type negotiation */
+                            if(!con->termsent) {
+                                con->termsent=TRUE;
+                                wsprintf(buf,"%c%c%c",IAC,WILLTEL,TERMTYPE);
+                                TelnetSend(ks,buf,lstrlen(buf),0);
+#ifdef NEGOTIATEDEBUG
+                                wsprintf(strTmp,"SEND: %ls %ls\r\n",
+                                    telstates[WILLTEL-LOW_TEL_OPT],
+                                    teloptions[TERMTYPE]);
+                                OutputDebugString(strTmp);
+#endif
+                              } /* end if */
+                            else {
+#ifdef NEGOTIATEDEBUG
+                                wsprintf(strTmp,"NO REPLY NEEDED: %ls %ls\r\n",
+                                    telstates[WILLTEL-LOW_TEL_OPT],
+                                    teloptions[TERMTYPE]);
+                                OutputDebugString(strTmp);
+#endif
+                              } /* end else */
+                            break;
+
+#ifdef LATER
+                        case LINEMODE:      /* DO: linemode negotiation */
+                            tw->lmflag=1;   /* set the linemode flag */
+                            netprintf(tw->pnum,"%c%c%c",IAC,WILLTEL,LINEMODE);
+                            /*
+                            ** Tell the other side to send us
+                            ** it's default character set
+                            */
+                            netprintf(tw->pnum,"%c%c%c%c",
+                                IAC,SB,LINEMODE,SLC,0,SLC_DEFAULT,0,IAC,SE);  
+                            if(tw->condebug>0) {
+                                tprintf(cv,"SEND: %ls %ls\r\n",
+                                    telstates[WILLTEL-LOW_TEL_OPT],
+                                    teloptions[LINEMODE]);
+                                tprintf(cv,
+                            "SEND: SB LINEMODE SLC 0 SLC_DEFAULT 0 IAC SE\r\n");
+                              } /* end if */
+                            break;
+#endif
+                        case NAWS:      /* DO: Negotiate About Window Size */
+                                   con->bResizeable=TRUE;
+                                                       send_naws(con);
+                            break;
+
+                        case AUTHENTICATION: /* DO: Authentication requested */
+                            wsprintf(buf,"%c%c%c",IAC,WILLTEL,AUTHENTICATION);
+                            TelnetSend(ks,buf,lstrlen(buf),0);
+#ifdef NEGOTIATEDEBUG
+                            wsprintf(strTmp,"SEND: %ls %ls\r\n",
+                                telstates[WILLTEL-LOW_TEL_OPT],
+                                teloptions[AUTHENTICATION]);
+                            OutputDebugString(strTmp);
+#endif
+                            break;
+
+                        default:        /* DO: */
+                            wsprintf(buf,"%c%c%c",IAC,WONTTEL,*st);
+                            TelnetSend(ks,buf,lstrlen(buf),0);
+#ifdef NEGOTIATEDEBUG
+                            wsprintf(strTmp,"SEND: %ls %ls\r\n",
+                                telstates[WONTTEL-LOW_TEL_OPT],teloptions[*st]);
+                            OutputDebugString(strTmp);
+#endif
+                            break;
+
+                      } /* end switch */
+                    con->telstate=STNORM;
+                    orig=++st;
+                    break;
+
+                case DONTTEL:       /* Received a telnet DONT option */
+                                       if (*st==NAWS)
+                           con->bResizeable=FALSE;
+#ifdef NEGOTIATEDEBUG
+                    wsprintf(strTmp,"RECV: %ls %ls\r\n",
+                        telstates[con->telstate-LOW_TEL_OPT],teloptions[*st]);
+                    OutputDebugString(strTmp);
+#endif
+
+#ifdef NOT
+                    if((*st)==BINARY) { /* DONT: check for binary neg. */
+                        if(tw->ibinary) {   /* binary */
+                            if(!tw->iwantbinary) { 
+                                netprintf(tw->pnum,"%c%c%c",IAC,WONTTEL,BINARY);
+                                if(tw->condebug>0)
+                                    tprintf(cv,"SEND: %ls %ls\r\n",
+                                        telstates[WONTTEL-LOW_TEL_OPT],
+                                        teloptions[BINARY]);
+                            } /* end if */
+                            else
+                                tw->iwantbinary=0;  /* turn off this now */
+                            tw->ibinary=0;
+                            tw->mapoutput=0;    /* turn output mapping off */
+                        } /* end if */
+#ifdef NEGOTIATEDEBUG
+                        wsprintf(strTmp,"NO REPLY NEEDED: %ls %ls\r\n",
+                            telstates[WONTTEL-LOW_TEL_OPT],
+                            teloptions[BINARY]);
+                        OutputDebugString(strTmp);
+#endif
+                    }
+#endif
+                    con->telstate=STNORM;
+                    orig=++st;
+                    break;
+
+                case WILLTEL:       /* received a telnet WILL option */
+#ifdef NEGOTIATEDEBUG
+                    wsprintf(strTmp,"RECV: %ls %ls\r\n",
+                        telstates[con->telstate-LOW_TEL_OPT],
+                        teloptions[*st]);
+                    OutputDebugString(strTmp);
+#endif
+                    switch(*st) {
+#ifdef NOT
+                        case BINARY:            /* WILL: binary */
+                            if(!tw->ubinary) {   /* binary */
+                                if(!tw->uwantbinary) {
+                                    netprintf(tw->pnum,"%c%c%c",
+                                        IAC,DOTEL,BINARY);
+                                    if(tw->condebug>0)
+                                        tprintf(cv,"SEND: %ls %ls\r\n",
+                                            telstates[DOTEL-LOW_TEL_OPT],
+                                            teloptions[BINARY]);
+                                  } /* end if */
+                                else
+                                    tw->uwantbinary=0;  /* turn off this now */
+                                tw->ubinary=1;
+                              } /* end if */
+                            else {
+                                if(tw->condebug>0)    
+                                    tprintf(cv,"NO REPLY NEEDED: %ls %ls\r\n",
+                                        telstates[DOTEL-LOW_TEL_OPT],
+                                        teloptions[BINARY]);
+                              } /* end else */
+                            break;
+#endif
+
+                        case SGA:               /* WILL: suppress go-ahead */
+                            if(!con->ugoahead) {
+                                con->ugoahead=1;
+                                wsprintf(buf,"%c%c%c",IAC,DOTEL,SGA); /* ack */
+                                TelnetSend(ks,buf,lstrlen(buf),0);
+#ifdef NEGOTIATEDEBUG
+                                wsprintf(strTmp,"SEND: %ls %ls\r\n",
+                                    telstates[DOTEL-LOW_TEL_OPT],
+                                    teloptions[SGA]);
+                                OutputDebugString(strTmp);
+#endif
+                              } /* end if */
+                            break;
+
+                        case ECHO:              /* WILL: echo */
+                            if(!con->echo) {
+                                con->echo=1;
+                                wsprintf(buf,"%c%c%c",IAC,DOTEL,ECHO); /* ack */
+                                TelnetSend(ks,buf,lstrlen(buf),0);
+#ifdef NEGOTIATEDEBUG
+        
+                                wsprintf(strTmp,"SEND: %ls %ls\r\n",
+                                    telstates[DOTEL-LOW_TEL_OPT],
+                                    teloptions[ECHO]);
+                                OutputDebugString(strTmp);
+#endif
+                              } /* end if */
+                            break;
+
+                        case TIMING:        /* WILL: Timing mark */
+                            con->timing=0;
+                            break;
+
+                        default:
+                            wsprintf(buf,"%c%c%c",IAC,DONTTEL,*st);
+                            TelnetSend(ks,buf,lstrlen(buf),0);
+#ifdef NEGOTIATEDEBUG
+                            wsprintf(strTmp,"SEND: %ls %ls\r\n",
+                                telstates[DONTTEL-LOW_TEL_OPT],teloptions[*st]);
+                            OutputDebugString(strTmp);
+#endif
+                            break;
+                      } /* end switch */
+                    con->telstate=STNORM;
+                    orig=++st;
+                    break;
+
+                case WONTTEL:       /* Received a telnet WONT option */
+#ifdef NEGOTIATEDEBUG
+                    wsprintf(strTmp,"RECV: %ls %ls\r\n",
+                        telstates[con->telstate-LOW_TEL_OPT],teloptions[*st]);
+                    OutputDebugString((LPSTR)strTmp);
+#endif
+                    con->telstate=STNORM;
+                    switch(*st++) {     /* which option? */
+#ifdef NOT
+                        case BINARY:            /* WONT: binary */
+                            if(tw->ubinary) {  /* binary */
+                                if(!tw->uwantbinary) {
+                                    netprintf(tw->pnum,"%c%c%c",
+                                        IAC,DONTTEL,BINARY);
+                                    if(tw->condebug>0)
+                                        tprintf(cv,"SEND: %ls %ls\r\n",
+                                            telstates[DONTTEL-LOW_TEL_OPT],
+                                            teloptions[BINARY]);
+                                  } /* end if */
+                                else
+                                    tw->uwantbinary=0;  /* turn off this now */
+                                tw->ubinary=0;
+                                tw->mapoutput=0; /* turn output mapping off */
+                              } /* end if */
+                            else {
+                                if(tw->condebug>0) 
+                                    tprintf(cv,"NO REPLY NEEDED: %ls %ls\r\n",
+                                        telstates[DONTTEL-LOW_TEL_OPT],
+                                        teloptions[BINARY]);
+                              } /* end else */
+                            break;
+
+#endif
+                        case ECHO:              /* WONT: echo */
+                            if(con->echo) {
+                                con->echo=0;
+                                wsprintf(buf,"%c%c%c",IAC,DONTTEL,ECHO);
+                                TelnetSend(ks,buf,lstrlen(buf),0);
+#ifdef NEGOTIATEDEBUG
+                                wsprintf(strTmp,"SEND: %ls %ls\r\n",
+                                    telstates[DONTTEL-LOW_TEL_OPT],
+                                    teloptions[ECHO]);
+                                OutputDebugString(strTmp);
+                                OutputDebugString("Other side won't echo!");
+#endif
+                              } /* end if */
+                            break;
+
+                        case TIMING:    /* WONT: Telnet timing mark option */
+                            con->timing=0;
+                            break;
+
+                        default:
+                            break;
+                      } /* end switch */
+                    orig=st;
+                    break;
+
+                case SB:        /* telnet sub-options negotiation */
+//                    OutputDebugString("[SB]");
+                    con->telstate=NEGOTIATE;
+                    orig=st;
+                    end_sub=0;
+                    sub_pos=con->substate=0;     /* Defined for each */
+#ifdef OLD_WAY
+                    break;
+#endif
+
+                case NEGOTIATE:
+//                  OutputDebugString("[NEG:");
+//                  OutputDebugString(st);
+        /* until we change sub-negotiation states, accumulate bytes */
+                    if(con->substate==0) { 
+                        if(*st==IAC) {  /* check if we found an IAC byte */
+                            if(*(st+1)==IAC) {  /* skip over double IAC's */
+                                st++;
+                                parsedat[sub_pos++]=*st++;
+                              } /* end if */
+                            else {
+                                end_sub=sub_pos;
+                                con->substate=*st++;
+                              } /* end else */
+                          } /* end if */
+                        else     /* otherwise, just stash the byte */
+                            parsedat[sub_pos++]=*st++;
+                      } /* end if */
+                    else {
+                        con->substate=*st++;
+                /* check if we've really ended the sub-negotiations */
+                        if(con->substate==SE)    
+                            parse_subnegotiat(ks,end_sub);
+                        orig=st;
+                        con->telstate=STNORM;
+                      } /* end else */
+                    break;
+
+                default:
+                    con->telstate=STNORM;
+                    break;
+              } /* end switch */
+          } /* end while */
+
+/*
+* quick scan of the remaining string, skip chars while they are
+* uninteresting
+*/
+        if(con->telstate==STNORM && st<mark) {
+/*
+*  skip along as fast as possible until an interesting character is found
+*/
+            while(st<mark && *st!=27 && *st!=IAC) {
+//                if(!tw->ubinary)
+//                    *st&=127;                 /* mask off high bit */
+                st++;
+              } /* end while */
+//            if(!tw->timing) 
+//                parsewrite(tw,orig,st-orig);
+            orig=st;                /* forget what we have sent already */
+            if(st<mark)
+                switch(*st) {
+                    case IAC:           /* telnet IAC */
+                        con->telstate=IACFOUND;
+                        st++;
+                        break;
+
+                   default:
+#ifdef NEGOTIATEDEBUG
+//                        wsprintf(buf," strange char>128\r\n");
+//                        OutputDebugString(buf);
+#endif
+                        st++;
+                        break;
+                  } /* end switch */
+          } /* end if */
+      } /* end while */
+}   /* end parse() */
+
+
+/*+********************************************************************
+*  Function :   parse_subnegotiat()
+*  Purpose  :   Parse the telnet sub-negotiations read into the parsedat
+*               array.
+*  Parameters   :
+*           end_sub - index of the character in the 'parsedat' array which
+*                           is the last byte in a sub-negotiation
+*  Returns  :   none
+*  Calls    :
+*  Called by    :   parse()
+**********************************************************************/
+static void
+parse_subnegotiat(kstream ks,int end_sub) {
+    char buf[128];
+
+//    OutputDebugString("INTO SUBNEGOTIATE");
+    switch(parsedat[0]) {
+        case TERMTYPE:
+//            OutputDebugString(":INTO TERMTYPE");        
+            if(parsedat[1]==1) {
+/* QAK!!! */    wsprintf(buf,"%c%c%c%cvt100%c%c",IAC,SB,TERMTYPE,0,IAC,SE);
+                TelnetSend(ks,(LPSTR)buf,11,0);
+#ifdef NEGOTIATEDEBUG
+                wsprintf(strTmp,"SB TERMINAL-TYPE SEND\r\n"
+                    "SEND: SB TERMINAL-TYPE IS vt100 \r\n len=%d \r\n",
+                    lstrlen((LPSTR)buf));
+//                OutputDebugString(strTmp);
+#endif                
+            }    
+            break;
+
+        case AUTHENTICATION:
+            auth_parse(ks, parsedat, end_sub);
+            break;
+        default:
+            break;
+      } /* end switch */
+}   /* end parse_subnegotiat() */
+/*+********************************************************************
+*  Function :   send_naws
+*  Purpose  :   Send a window size sub-negotiation.
+*  Parameters   :
+*           ks - the kstream to send to.
+*  Returns  :   none
+**********************************************************************/
+void
+send_naws(CONNECTION *con) {
+    unsigned char buf[13];
+       int len;
+
+       wsprintf(buf, "%c%c%c", IAC, SB, NAWS);
+       len = 3;
+
+       buf[len++] = HIBYTE(con->width);
+       if (buf[len-1] == IAC) buf[len++] = IAC;
+
+       buf[len++] = LOBYTE(con->width);
+       if (buf[len-1] == IAC) buf[len++] = IAC;
+
+       buf[len++] = HIBYTE(con->height);
+       if (buf[len-1] == IAC) buf[len++] = IAC;
+
+       buf[len++] = LOBYTE(con->height);
+       if (buf[len-1] == IAC) buf[len++] = IAC;
+
+       buf[len++] = IAC;
+       buf[len++] = SE;
+
+       TelnetSend(con->ks, buf, len, 0);
+
+#ifdef NEGOTIATEDEBUG
+///    wsprintf(buf, "SEND: SB NAWS %d %d %d %d IAC SE\r\n",
+///            HIBYTE(con->width), LOBYTE(con->width),
+///     HIBYTE(con->height), LOBYTE(con->height));
+///    OutputDebugString(buf);
+#endif
+} /* send_naws */
diff --git a/src/windows/wintel/screen.c b/src/windows/wintel/screen.c
new file mode 100644 (file)
index 0000000..2f12ad0
--- /dev/null
@@ -0,0 +1,1281 @@
+#include <windows.h>
+#include <commdlg.h>
+#include <stdlib.h>
+#include <string.h>
+#include "screen.h"
+#include "ini.h"
+
+extern char *cInvertedArray;
+HSCREEN ScreenList;
+HINSTANCE hInst;
+HDC hDC;
+char gszAllocErrorMsg[]="Error Allocating Memory!";
+char gszLockErrorMsg[]="Error Locking Memory!";
+char gszLoadStrFail[]="LoadString failed!";
+
+int bDoubleClick=FALSE;
+extern LOGFONT lf;
+extern HFONT hFont;
+extern int bMouseDown;
+extern int bSelection;
+
+char szScreenClass[]="ScreenWClass";
+char szScreenMenu[]="ScreenMenu";
+
+OFSTRUCT ofFile;
+HFILE fh;
+
+#ifdef WINMEM
+CATCHBUF EndRtn;              /* error return buffer (required by WinMem)*/
+#endif
+
+//#define FILE_DEBUG
+
+void ScreenInit(HANDLE hInstance) {
+
+    WNDCLASS    wc;
+
+    hInst=hInstance;
+    
+//    wsprintf(strTmp,"hInst= %d \r\n",hInst);
+//    OutputDebugString(strTmp);
+    
+    ScreenList=NULL;
+
+    wc.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS|CS_GLOBALCLASS;       /* Class style(s).                    */
+    wc.lpfnWndProc = ScreenWndProc;         /* Function to retrieve messages for  */
+                                            /* windows of this class.             */
+    wc.cbClsExtra = 0;                      /* No per-class extra data.           */
+    wc.cbWndExtra = sizeof(HGLOBAL);        /* Only extra data is handle to screen*/
+    wc.hInstance = hInstance;               /* Application that owns the class.   */
+    wc.hIcon = LoadIcon(hInstance, "TERMINAL");
+    wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
+    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+    wc.lpszMenuName =  szScreenMenu;        /* Name of menu resource in .RC file. */
+    wc.lpszClassName = szScreenClass;      /* Name used in call to CreateWindow. */
+
+    /* Register the window class and return success/failure code. */
+    if (!RegisterClass(&wc))
+       MessageBox(NULL,"Couldn't register Class!",NULL,MB_OK);
+}
+
+int GetNewScreen(void) {
+    HGLOBAL ghScr;
+    SCREEN *fpScr, *fpTmp, *fpTmp2;
+    static int id=0;
+
+    if (ScreenList==NULL) {
+        ghScr = GlobalAlloc(GHND,sizeof(SCREEN));
+        if (ghScr==NULL) return -1;
+        fpScr = (SCREEN *)GlobalLock(ghScr);
+        if (fpScr==NULL) return -1;
+        fpScr->next=NULL;
+        fpScr->prev=NULL;
+        GlobalUnlock(ghScr);
+        ScreenList=ghScr;
+        return(id++);
+    }
+       else {
+        ghScr = GlobalAlloc(GHND,sizeof(SCREEN));
+        if (ghScr==NULL) return -1;
+        fpScr = (SCREEN *)GlobalLock(ghScr);
+        if (fpScr==NULL) return -1;
+        fpScr->next=ScreenList;
+        fpTmp = (SCREEN *)GlobalLock(ScreenList);
+               if (fpTmp != NULL) {
+            if (fpTmp->next==NULL) {
+                fpScr->next=ScreenList;
+                fpScr->prev=ScreenList;
+                fpTmp->next=ghScr;
+                fpTmp->prev=ghScr;
+            } else {
+                fpScr->prev=fpTmp->prev;
+                   fpTmp2 = (SCREEN *)GlobalLock(fpTmp->prev);
+                           if (fpTmp2 != NULL)
+                       fpTmp2->next=ghScr;
+                GlobalUnlock(fpTmp->prev);
+                   fpTmp->prev=ghScr;
+            }
+        }
+        GlobalUnlock(fpScr->next);
+        GlobalUnlock(ghScr);
+        ScreenList=ghScr;
+        return(id++);
+    }
+}
+
+HSCREENLINE ScreenNewLine(void) 
+{
+
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+
+    hgScrLine=LINE_MEM_ALLOC(sizeof(SCREENLINE)+2*MAX_LINE_WIDTH);
+    if (hgScrLine==NULL)
+               return (NULL);
+    fpScrLine=LINE_MEM_LOCK(hgScrLine);
+    if (fpScrLine==NULL)
+               return (NULL);
+       memset(fpScrLine,0,sizeof(SCREENLINE)+2*MAX_LINE_WIDTH);
+       fpScrLine->text=&fpScrLine->buffer[0];
+       fpScrLine->attrib=&fpScrLine->buffer[MAX_LINE_WIDTH];
+    LINE_MEM_UNLOCK(hgScrLine);
+    return(hgScrLine);
+}  
+
+static void MakeWindowTitle(char *host, int width, int height, char *title, int nchars)
+{
+       char buf[128];
+       int hlen;
+
+       hlen = strlen(host);
+
+       title[0] = 0;
+
+       if (hlen + 1 > nchars)
+               return;
+
+       strcpy(title, host);
+
+       wsprintf(buf, " (%dh x %dw)", height, width);
+
+       if ((int) strlen(buf) + hlen + 1 > nchars)
+               return;
+
+       strcat(title, buf);
+}
+
+HSCREEN InitNewScreen(CONFIG *Config) {
+    TEXTMETRIC  tm;
+    HMENU hMenu=NULL;
+    SCREEN *scr=NULL;
+    HSCREENLINE hgScrLine;
+    HSCREENLINE hgScrLineLast;
+    SCREENLINE *fpScrLine;
+    SCREENLINE *fpScrLineLast;
+    int id,idx=0;
+       HGLOBAL h;
+       char title[128];
+
+    id=GetNewScreen();
+    if (id == -1) return(0);
+    scr=(SCREEN *) GlobalLock(ScreenList);
+    if (scr==NULL) OutputDebugString("Scr is NULL!\r\n");
+               
+    hMenu = LoadMenu(hInst,szScreenMenu);
+    if (hMenu==NULL) OutputDebugString("hMenu is NULL! \r\n");
+    
+       scr->title=Config->title;
+       MakeWindowTitle(Config->title,Config->width,Config->height,title,sizeof(title));
+
+    scr->hWnd = CreateWindow((char *)szScreenClass,title,WS_OVERLAPPEDWINDOW|WS_VSCROLL,
+        CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,hMenu,hInst,NULL);
+    
+       if (!(scr->hWnd)) {
+               OutputDebugString("Couldn't Create Window!! \r\n");
+               return(0); 
+       }
+    scr->hwndTel=Config->hwndTel;  /* save HWND of calling window */
+       
+       if (Config->backspace) {
+        CheckMenuItem(hMenu,IDM_BACKSPACE,MF_CHECKED);
+        CheckMenuItem(hMenu,IDM_DELETE,MF_UNCHECKED);
+    }
+       else {
+        CheckMenuItem(hMenu,IDM_BACKSPACE,MF_UNCHECKED);
+        CheckMenuItem(hMenu,IDM_DELETE,MF_CHECKED);
+    }    
+    SetWindowWord(scr->hWnd,SCREEN_HANDLE,(WORD)ScreenList);
+    hDC = GetDC(scr->hWnd);
+
+    scr->lf.lfPitchAndFamily=FIXED_PITCH;
+    GetPrivateProfileString(INI_FONT,"FaceName","Courier",scr->lf.lfFaceName,
+        LF_FACESIZE,TELNET_INI);
+    scr->lf.lfHeight=(int)GetPrivateProfileInt(INI_FONT,"Height",0,TELNET_INI);
+    scr->lf.lfWidth=(int)GetPrivateProfileInt(INI_FONT,"Width",0,TELNET_INI);
+    scr->lf.lfPitchAndFamily=(BYTE)GetPrivateProfileInt(INI_FONT,"PitchAndFamily",0,TELNET_INI);
+    scr->lf.lfCharSet=(BYTE)GetPrivateProfileInt(INI_FONT,"CharSet",0,TELNET_INI);
+    scr->lf.lfEscapement=(BYTE)GetPrivateProfileInt(INI_FONT,"Escapement",0,TELNET_INI);
+    scr->lf.lfQuality=PROOF_QUALITY;
+    scr->ghSelectedFont = CreateFontIndirect((LPLOGFONT)&(scr->lf));
+    
+    SelectObject(hDC,scr->ghSelectedFont);
+                
+    GetTextMetrics(hDC,(LPTEXTMETRIC)&tm);
+    scr->cxChar = tm.tmAveCharWidth;
+    scr->cyChar = tm.tmHeight + tm.tmExternalLeading;
+
+    ReleaseDC(scr->hWnd,hDC);
+    scr->width=Config->width;
+    scr->height=Config->height;
+    scr->ID=id;
+    scr->x=0;    
+    scr->y=0;
+    scr->Oldx=0;
+    scr->Oldy=0;
+    scr->attrib=0;
+    scr->DECAWM=1;
+    scr->top=0;
+    scr->bottom=scr->height-1;
+    scr->parmptr=0;
+    scr->escflg=0;
+    scr->bAlert=FALSE;
+    scr->numlines=0;
+    scr->maxlines=150;
+
+       h=GlobalAlloc(GHND,scr->width*scr->height);
+       if (h==NULL)
+               return(0);
+       cInvertedArray=GlobalLock(h);
+
+    hgScrLineLast=ScreenNewLine();
+    scr->screen_top=scr->buffer_top=hgScrLineLast;
+       hgScrLine=hgScrLineLast;
+
+    for (idx=0; idx<scr->height-1; idx++) {
+        hgScrLine=ScreenNewLine();
+        fpScrLine=LINE_MEM_LOCK(hgScrLine);
+               if (fpScrLine == NULL)
+                       return(NULL);
+        fpScrLine->prev=hgScrLineLast;
+        LINE_MEM_UNLOCK(hgScrLine);
+
+        fpScrLineLast=LINE_MEM_LOCK(hgScrLineLast);
+               if (fpScrLineLast == NULL)
+                       return(NULL);
+        fpScrLineLast->next=hgScrLine;
+        LINE_MEM_UNLOCK(hgScrLineLast);
+
+        hgScrLineLast=hgScrLine;
+    }
+
+    scr->screen_bottom=scr->buffer_bottom=hgScrLine;
+
+    SetWindowPos(scr->hWnd,NULL,0,0,scr->cxChar * scr->width + FRAME_WIDTH,
+         scr->cyChar * scr->height + FRAME_HEIGHT, SWP_NOMOVE|SWP_NOZORDER);
+
+       CreateCaret(scr->hWnd, NULL, scr->cxChar, 2);
+       SetCaretPos(scr->x*scr->cxChar, (scr->y+1)*scr->cyChar);
+       ShowCaret(scr->hWnd);
+
+    GlobalUnlock(ScreenList);
+    return(ScreenList);
+}
+
+void DeleteTopLine(SCREEN *fpScr) {
+    HSCREENLINE hsTop;
+    SCREENLINE *fpScrLine;
+    
+    fpScrLine=(SCREENLINE *) LINE_MEM_LOCK(fpScr->buffer_top);
+    if (fpScrLine==NULL) OutputDebugString("Hosed in DeleteTopLine.\r\n");
+    hsTop=fpScrLine->next;
+    LINE_MEM_FREE(fpScr->buffer_top);
+    fpScr->buffer_top=hsTop;
+    fpScrLine=(SCREENLINE *) LINE_MEM_LOCK(fpScr->buffer_top);
+    if (fpScrLine==NULL) OutputDebugString("Hosed in DeleteTopLine.\r\n");
+    fpScrLine->prev=NULL;
+    LINE_MEM_UNLOCK(fpScr->buffer_top);
+    fpScr->numlines--;
+}
+
+
+static void SetScreenScrollBar(SCREEN *fpScr)
+{
+       if (fpScr->numlines <= 0) {
+               SetScrollRange(fpScr->hWnd, SB_VERT, 0, 100, FALSE);
+               SetScrollPos(fpScr->hWnd, SB_VERT, 0, TRUE);
+               EnableScrollBar(fpScr->hWnd, SB_VERT, ESB_DISABLE_BOTH);
+       }
+       else {
+               SetScrollRange(fpScr->hWnd, SB_VERT, 0, fpScr->numlines, FALSE);
+               SetScrollPos(fpScr->hWnd, SB_VERT, fpScr->numlines, TRUE);
+               EnableScrollBar(fpScr->hWnd, SB_VERT, ESB_ENABLE_BOTH);
+       }
+} /* SetScreenScrollBar */
+
+
+int ScreenScroll(SCREEN *fpScr)
+{
+    HSCREENLINE hgScrLine;
+    HSCREENLINE hScrollTop;
+    HSCREENLINE hScrollBottom;
+    HSCREENLINE hPrev;
+    HSCREENLINE hNext;
+    SCREENLINE *fpScrLine;
+    SCREENLINE *fpPrev;
+    SCREENLINE *fpNext;
+    SCREENLINE *fpScrollTop;
+    SCREENLINE *fpScrollBottom;
+    BOOL bFullScreen = TRUE;
+    HDC hDC;
+    RECT rc;
+
+    Edit_ClearSelection(fpScr);
+
+    hScrollTop = (HSCREENLINE) GetScreenLineFromY(fpScr, fpScr->top);
+
+    hScrollBottom = (HSCREENLINE) GetScreenLineFromY(fpScr, fpScr->bottom);
+
+    if (hScrollTop != fpScr->screen_top) {
+               bFullScreen = FALSE;
+        rc.left = 0;
+        rc.right = fpScr->cxChar * fpScr->width;
+        rc.top = fpScr->cyChar * (fpScr->top);
+        rc.bottom = fpScr->cyChar * (fpScr->bottom+1);
+
+           fpScrollTop = LINE_MEM_LOCK(hScrollTop);
+        hNext = fpScrollTop->next;
+        hPrev = fpScrollTop->prev;
+               LINE_MEM_UNLOCK(hScrollTop);
+
+        fpPrev = LINE_MEM_LOCK(hPrev);
+        fpPrev->next = hNext;        
+        fpNext = LINE_MEM_LOCK(hNext);
+        fpNext->prev = hPrev;
+        LINE_MEM_UNLOCK(hPrev);
+               LINE_MEM_UNLOCK(hNext);
+
+               hgScrLine = hScrollTop;
+               ScreenClearLine(fpScr, hgScrLine);
+    }
+       else {
+               fpScr->numlines++;                
+               hgScrLine = ScreenNewLine(); 
+               if (hgScrLine == NULL)
+                       return(0);
+               fpScrollTop = LINE_MEM_LOCK(hScrollTop);
+               fpScr->screen_top = fpScrollTop->next;
+               LINE_MEM_UNLOCK(hScrollTop);
+    }    
+
+    fpScrLine= LINE_MEM_LOCK(hgScrLine);
+    if (fpScrLine == NULL)
+               return(0);
+
+       fpScrollBottom = LINE_MEM_LOCK(hScrollBottom);
+    hNext = fpScrollBottom->next;
+       fpScrollBottom->next = hgScrLine;
+       LINE_MEM_UNLOCK(hScrollBottom);
+       fpScrLine->next = hNext;
+       fpScrLine->prev = hScrollBottom;
+       if (hNext != NULL) {
+           fpNext = LINE_MEM_LOCK(hNext);
+           fpNext->prev = hgScrLine;
+               LINE_MEM_UNLOCK(hNext);
+       }
+
+       LINE_MEM_UNLOCK(hgScrLine);
+
+    if (hScrollBottom != fpScr->screen_bottom) {
+               bFullScreen = FALSE;
+        rc.left = 0;
+        rc.right = fpScr->cxChar * fpScr->width;
+        rc.top = fpScr->cyChar * fpScr->top;
+        rc.bottom = fpScr->cyChar * (fpScr->bottom+1);
+    }
+       else {
+               if (fpScr->screen_bottom == fpScr->buffer_bottom)
+                       fpScr->buffer_bottom = hgScrLine;
+               fpScr->screen_bottom = hgScrLine;
+       }
+
+//     CheckScreen(fpScr);
+
+       fpScr->y++;
+
+       if (fpScr->y > fpScr->bottom)
+               fpScr->y = fpScr->bottom;
+
+       hDC = GetDC(fpScr->hWnd);
+       if (bFullScreen)
+               ScrollDC(hDC, 0, -fpScr->cyChar, NULL, NULL, NULL, NULL);
+       else 
+               ScrollDC(hDC, 0, -fpScr->cyChar, &rc, &rc, NULL, NULL);
+
+       PatBlt(hDC, 0, fpScr->bottom * fpScr->cyChar,
+               fpScr->width * fpScr->cxChar, fpScr->cyChar, WHITENESS);
+        
+       ReleaseDC(fpScr->hWnd, hDC);
+
+       if (fpScr->numlines == fpScr->maxlines)
+               DeleteTopLine(fpScr);
+       else
+               SetScreenScrollBar(fpScr);
+
+       return(1);
+}
+
+
+void DrawCursor(SCREEN *fpScr) {
+#ifdef NOT
+    HDC hDC;
+    char ch=95;
+
+    hDC=GetDC(fpScr->hWnd);
+    SelectObject(hDC,fpScr->ghSelectedFont);
+    SetTextColor(hDC,RGB(255,255,255));
+    TextOut(hDC,fpScr->Oldx*fpScr->cxChar,fpScr->Oldy*fpScr->cyChar,&ch,1);
+    fpScr->Oldx=fpScr->x;
+    fpScr->Oldy=fpScr->y;
+    SetTextColor(hDC,RGB(0,0,0));
+    TextOut(hDC,fpScr->x*fpScr->cxChar,fpScr->y*fpScr->cyChar,&ch,1);
+    ReleaseDC(fpScr->hWnd,hDC);                
+#endif    
+}
+
+int DrawTextScreen(RECT rcInvalid, SCREEN * fpScr, HDC hDC)
+{
+       HSCREENLINE hgScrLine, hgScrLineTmp;
+       SCREENLINE *fpScrLine;
+       int x=0, y=0;
+       int left=0, right=0;
+       int i;
+       int len;
+       char attrib;
+       #define YPOS (y*fpScr->cyChar)
+
+    hgScrLine=fpScr->screen_top;
+//    hgScrLine=GetScreenLineFromY(fpScr,0);
+//    wsprintf(strTmp,"{DTS: (%d)=%X }",fpScr->top,hgScrLine);
+//    OutputDebugString(strTmp);
+
+       for (y = 0; y < fpScr->height; y++) {
+               fpScrLine = LINE_MEM_LOCK(hgScrLine);
+
+               if (!fpScrLine)
+                       continue;
+
+               if (YPOS >= rcInvalid.top - fpScr->cyChar && 
+                       YPOS <= rcInvalid.bottom + fpScr->cyChar) {
+
+                       if (y < 0)
+                               y = 0;
+
+                       if (y >= fpScr->height)
+                               y = fpScr->height - 1;
+
+                       left = (rcInvalid.left / fpScr->cxChar) - 1;
+
+                       right = (rcInvalid.right / fpScr->cxChar) + 1;
+
+                       if (left < 0)
+                               left = 0;
+
+                       if (right > fpScr->width - 1)
+                               right = fpScr->width - 1;
+
+                       x = left;
+
+                       while (x <= right) {
+                               if (!fpScrLine->text[x]) {
+                                       x++;
+                                       continue;
+                               }
+
+                               if (SCR_isrev(fpScrLine->attrib[x])) {
+                                       SelectObject(hDC, fpScr->ghSelectedFont);                
+                                       SetTextColor(hDC, RGB(255, 255, 255));
+                                       SetBkColor(hDC, RGB(0, 0, 0));
+                               }
+                               else if (SCR_isblnk(fpScrLine->attrib[x])) {
+                                       SelectObject(hDC, fpScr->ghSelectedFont);                
+                                       SetTextColor(hDC, RGB(255, 0, 0));
+                                       SetBkColor(hDC, RGB(255, 255, 255));
+                               }
+                               else if (SCR_isundl(fpScrLine->attrib[x])) {
+                                       SetTextColor(hDC, RGB(255, 0, 0));
+                                       SetBkColor(hDC, RGB(255, 255, 255));
+                                       SelectObject(hDC, fpScr->ghSelectedULFont);
+                               }
+                               else {
+                                       SelectObject(hDC,fpScr->ghSelectedFont);
+                                       SetTextColor(hDC,RGB(0, 0, 0));
+                                       SetBkColor(hDC,RGB(255, 255, 255));
+                               }
+
+                               len = 1;
+                               attrib = fpScrLine->attrib[x];
+                               for (i = x + 1; i <= right; i++) {
+                                       if (fpScrLine->attrib[i] != attrib || !fpScrLine->text[i])
+                                               break;
+                                       len++;
+                               }
+
+                               TextOut(hDC, x*fpScr->cxChar, y*fpScr->cyChar, &fpScrLine->text[x], len);
+                               x += len;
+                       }
+               }                
+               hgScrLineTmp = fpScrLine->next;
+               LINE_MEM_UNLOCK(hgScrLine);
+               hgScrLine = hgScrLineTmp;
+       }            
+       return(0);
+}
+
+static BOOL SetInternalScreenSize(SCREEN *fpScr, int width, int height)
+{
+       RECT rc;
+       char *p;
+       HGLOBAL h;
+       int idx;
+       int n;
+       int newlines;
+       HSCREENLINE hgNewLine;
+       SCREENLINE *fpNewLine;
+       HSCREENLINE hgTopLine;
+       SCREENLINE *fpTopLine;
+       HSCREENLINE hgBottomLine;
+       SCREENLINE *fpBottomLine;
+       #if 0
+               int col;
+               int row;
+               int dydestbottom;
+       #endif
+
+       GetClientRect(fpScr->hWnd, &rc);
+
+       width = (rc.right - rc.left) / fpScr->cxChar;
+       height = (rc.bottom - rc.top) / fpScr->cyChar;
+
+       if (fpScr->height == height && fpScr->width == width)
+               return(FALSE);
+
+    fpScr->Oldx = 0;
+    fpScr->Oldy = 0;
+    fpScr->attrib = 0;
+
+       /*
+       Reallocate the inverted array of bytes and copy the values
+       from the old screen to the new screen.
+       */
+       h = GlobalAlloc(GHND, width * height);
+       if (h == NULL)
+               return(0);
+
+       ScreenCursorOff(fpScr);
+
+       p = GlobalLock(h);
+
+       #if 0   /* Copy inversion array to desitination */
+               for (col = 0; col < width; col++) {
+                       for (row = 0; row < height; row++) {
+                               dydestbottom = height - 1 - row;
+                               if (col < fpScr->width && dydestbottom < fpScr->height - 1)
+                                       p[row * width + col] =
+                                               cInvertedArray[(fpScr->height - 1 - dydestbottom) * fpScr->width + col];
+                       }
+               }
+       #endif
+
+       h = LOWORD(GlobalHandle(SELECTOROF(cInvertedArray)));
+       GlobalUnlock(h);
+       GlobalFree(h);
+       cInvertedArray = p;
+
+       /*
+       Append any new lines which need to be added to accomodate the new
+       screen size.
+       */
+       hgBottomLine = fpScr->buffer_bottom;
+       newlines = height - (fpScr->height + fpScr->numlines);
+
+       if (newlines > 0) {
+               fpScr->y += fpScr->numlines;
+               fpScr->numlines = 0;
+
+       for (idx = 0; idx < newlines; idx++) {
+               hgNewLine = ScreenNewLine();
+               fpNewLine = LINE_MEM_LOCK(hgNewLine);
+                       if (fpNewLine == NULL)
+                               return(FALSE);
+               fpNewLine->prev = hgBottomLine;
+
+                       fpBottomLine = LINE_MEM_LOCK(hgBottomLine);
+                       if (fpBottomLine == NULL)
+                               return(FALSE);
+                       fpBottomLine->next = hgNewLine;
+                       LINE_MEM_UNLOCK(hgBottomLine);
+
+                       LINE_MEM_UNLOCK(hgNewLine);
+
+                       hgBottomLine = hgNewLine;
+       }
+       }
+
+       /*
+       If we already have plenty of lines, then we need to get rid of the
+       scrollback lines, if too many exist.  The cursor should end up
+       the same distance from the bottom of the screen as is started out
+       in this instance.
+       */
+       if (newlines < 0) {
+               fpScr->y = (height - 1) - (fpScr->bottom - fpScr->y);
+               if (fpScr->y < 0)
+                       fpScr->y = 0;
+               fpScr->numlines = -newlines;
+               n = fpScr->numlines - fpScr->maxlines;
+               for (idx = 0; idx < n; idx++)
+                       DeleteTopLine(fpScr);
+       }
+               
+       /*
+       Calculate the position of the buffer relative to the screen.
+       */
+    fpScr->screen_bottom = hgBottomLine;
+       fpScr->buffer_bottom = hgBottomLine;
+
+       hgTopLine = hgBottomLine;
+
+       for (idx = 1; idx < height; idx++) {
+               fpTopLine = LINE_MEM_LOCK(hgTopLine);
+               hgTopLine = fpTopLine->prev;
+               LINE_MEM_UNLOCK(hgTopLine);
+       }
+
+       fpScr->screen_top = hgTopLine;
+    fpScr->width = width;
+    fpScr->height = height;
+    fpScr->top = 0;
+    fpScr->bottom = height - 1;
+
+       if (fpScr->x >= width)
+               fpScr->x = width - 1;
+
+       if (fpScr->y >= height)
+               fpScr->y = height - 1;
+
+       SetScreenScrollBar(fpScr);
+       ScreenCursorOn(fpScr);
+       return(TRUE);
+}
+
+static int ScreenAdjustUp(SCREEN *fpScr, int n)
+{
+       int idx;
+       HSCREENLINE hslLine1;
+       HSCREENLINE hslLine2;
+       SCREENLINE *fpScrLine1;
+       SCREENLINE *fpScrLine2;
+
+       for (idx = 0; idx < n; idx++) {
+           if (fpScr->screen_top == fpScr->buffer_top)
+                       return(-idx);
+               fpScrLine1 = LINE_MEM_LOCK(fpScr->screen_top);
+       hslLine1 = fpScrLine1->prev;
+       LINE_MEM_UNLOCK(fpScr->screen_top);
+       if (hslLine1 == NULL)
+                       return(-idx);
+       fpScrLine2 = LINE_MEM_LOCK(fpScr->screen_bottom);
+       hslLine2 = fpScrLine2->prev;
+       LINE_MEM_UNLOCK(fpScr->screen_bottom);
+       if (hslLine2 == NULL)
+                       return(-idx);
+       fpScr->screen_top = hslLine1;
+       fpScr->screen_bottom = hslLine2;                    
+       }
+       return(idx);
+}
+
+static int ScreenAdjustDown(SCREEN *fpScr, int n)
+{
+       int idx;
+       HSCREENLINE hslLine1;
+       HSCREENLINE hslLine2;
+       SCREENLINE *fpScrLine1;
+       SCREENLINE *fpScrLine2;
+
+       for (idx = 0; idx < n; idx++) {
+       if (fpScr->screen_bottom == fpScr->buffer_bottom)
+                       return(-idx);
+       fpScrLine1 = LINE_MEM_LOCK(fpScr->screen_top);
+       hslLine1 = fpScrLine1->next;
+       LINE_MEM_UNLOCK(fpScr->screen_top);
+       if (hslLine1 == NULL)
+                       return(-idx);
+       fpScrLine2 = LINE_MEM_LOCK(fpScr->screen_bottom);
+       hslLine2 = fpScrLine2->next;
+       LINE_MEM_UNLOCK(fpScr->screen_bottom);
+       if (hslLine2 == NULL)
+                       return(-idx);
+       fpScr->screen_top = hslLine1;
+       fpScr->screen_bottom = hslLine2;
+       }
+       return(idx);
+}
+
+long FAR PASCAL ScreenWndProc(hWnd, message, wParam, lParam)
+HWND hWnd;                /* window handle           */
+UINT message;                 /* type of message         */
+WPARAM wParam;                  /* additional information          */
+LPARAM lParam;                  /* additional information          */
+{
+       MINMAXINFO *lpmmi;
+    SCREEN *fpScr;                              
+    HGLOBAL hgScr;
+    HMENU hMenu;
+    PAINTSTRUCT ps;    
+    int x=0,
+        y=0,
+        ScrollPos,tmpScroll=0,
+        idx;
+    HSCREENLINE hslLine;
+       HDC hDC;
+       RECT rc;
+       char title[128];
+         
+    switch (message) {
+
+    case WM_COMMAND:
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+           fpScr=(SCREEN *)GlobalLock(hgScr);
+           if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+
+        switch (wParam) {               
+
+        case IDM_BACKSPACE:
+            hMenu=GetMenu(hWnd);
+            CheckMenuItem(hMenu,IDM_BACKSPACE,MF_CHECKED);
+            CheckMenuItem(hMenu,IDM_DELETE,MF_UNCHECKED);
+            SendMessage(fpScr->hwndTel,WM_MYSCREENCHANGEBKSP,VK_BACK,(HSCREEN)hgScr);                                
+            break;
+        case IDM_DELETE:
+            hMenu=GetMenu(hWnd);
+            CheckMenuItem(hMenu,IDM_BACKSPACE,MF_UNCHECKED);
+            CheckMenuItem(hMenu,IDM_DELETE,MF_CHECKED);
+            SendMessage(fpScr->hwndTel,WM_MYSCREENCHANGEBKSP,0x7f,(HSCREEN)hgScr);                                
+            break;    
+        case IDM_FONT:
+                       ScreenCursorOff(fpScr);
+            ProcessFontChange(hWnd);
+                       ScreenCursorOn(fpScr);
+            break;
+        case IDM_COPY:
+            Edit_Copy(hWnd);
+            hMenu=GetMenu(hWnd);
+            Edit_ClearSelection(fpScr);                
+            GlobalUnlock(hgScr);
+            break;
+        case IDM_PASTE:
+            Edit_Paste(hWnd);
+            break;
+#ifdef _DEBUG
+               case IDM_DEBUG:
+                       CheckScreen(fpScr);
+                       break;
+#endif
+        }        
+
+               GlobalUnlock(hgScr);
+        break;
+
+    case WM_CREATE:
+//        OutputDebugString("WM_CREATE\r\n");
+        SetWindowWord(hWnd,SCREEN_HANDLE,NULL);
+        SetScrollRange(hWnd,SB_VERT,0,100,FALSE);
+               SetScrollPos(hWnd,SB_VERT,0,TRUE);
+               EnableScrollBar(hWnd,SB_VERT,ESB_DISABLE_BOTH);
+        ShowWindow(hWnd,SW_SHOW);
+#ifdef FILE_DEBUG
+        fh=OpenFile("d:\\debug.txt",&ofFile,OF_CREATE|OF_WRITE);
+#endif
+        break;
+        
+    case WM_VSCROLL:
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+        fpScr=(SCREEN *)GlobalLock(hgScr);
+        if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+
+               ScreenCursorOff(fpScr);
+
+        switch(wParam) {
+        case SB_LINEDOWN:
+                       if (ScreenAdjustDown(fpScr, 1) <= 0)
+                               break;
+                       hDC = GetDC(hWnd);
+                       rc.left = 0;
+                       rc.right = fpScr->cxChar * fpScr->width;
+                       rc.top = 0;
+                       rc.bottom = fpScr->cyChar * (fpScr->bottom+1);
+                       ScrollDC(hDC, 0, -fpScr->cyChar, &rc, &rc, NULL, NULL);
+                       ReleaseDC(hWnd, hDC);
+                       rc.top = fpScr->cyChar * fpScr->bottom;
+                       InvalidateRect(hWnd, &rc, TRUE);
+            ScrollPos=GetScrollPos(hWnd,SB_VERT);
+            SetScrollPos(hWnd,SB_VERT,ScrollPos+1,TRUE);
+                       UpdateWindow(hWnd);
+            break;
+
+        case SB_LINEUP:
+                       if (ScreenAdjustUp(fpScr, 1) <= 0)
+                               break;
+                       hDC = GetDC(hWnd);
+                       rc.left = 0;
+                       rc.right = fpScr->cxChar * fpScr->width;
+                       rc.top = 0;
+                       rc.bottom = fpScr->cyChar * (fpScr->bottom+1);
+                       ScrollDC(hDC, 0, fpScr->cyChar, &rc, &rc, NULL, NULL);
+                       ReleaseDC(hWnd, hDC);
+                       rc.bottom = fpScr->cyChar;
+                       InvalidateRect(hWnd, &rc, TRUE);
+            ScrollPos=GetScrollPos(fpScr->hWnd,SB_VERT);
+            SetScrollPos(hWnd,SB_VERT,ScrollPos-1,TRUE);
+                       UpdateWindow(hWnd);
+            break;
+
+        case SB_PAGEDOWN:
+                       idx = abs(ScreenAdjustDown(fpScr, fpScr->height));
+                       hDC = GetDC(hWnd);
+                       rc.left = 0;
+                       rc.right = fpScr->cxChar * fpScr->width;
+                       rc.top = 0;
+                       rc.bottom = fpScr->cyChar * (fpScr->bottom+1);
+                       ScrollDC(hDC, 0, -idx * fpScr->cyChar, &rc, &rc, NULL, NULL);
+                       ReleaseDC(hWnd, hDC);
+                       rc.top = fpScr->cyChar * (fpScr->bottom - idx + 1);
+                       InvalidateRect(hWnd, &rc, TRUE);
+            ScrollPos=GetScrollPos(hWnd,SB_VERT);
+            SetScrollPos(hWnd,SB_VERT,ScrollPos+idx,TRUE);
+            break;
+
+        case SB_PAGEUP:
+                       idx = abs(ScreenAdjustUp(fpScr, fpScr->height));
+                       hDC = GetDC(hWnd);
+                       rc.left = 0;
+                       rc.right = fpScr->cxChar * fpScr->width;
+                       rc.top = 0;
+                       rc.bottom = fpScr->cyChar * (fpScr->bottom+1);
+                       ScrollDC(hDC, 0, idx * fpScr->cyChar, &rc, &rc, NULL, NULL);
+                       ReleaseDC(hWnd, hDC);
+                       rc.bottom = idx * fpScr->cyChar;
+                       InvalidateRect(hWnd, &rc, TRUE);
+            ScrollPos=GetScrollPos(hWnd,SB_VERT);
+            SetScrollPos(hWnd,SB_VERT,ScrollPos-idx,TRUE);
+            break;
+
+        case SB_THUMBPOSITION:
+        case SB_THUMBTRACK:
+            ScrollPos = GetScrollPos(hWnd,SB_VERT);
+            tmpScroll = ScrollPos - LOWORD(lParam);
+                       if (tmpScroll == 0)
+                               break;
+                       if (tmpScroll > 0)
+                               ScreenAdjustUp(fpScr, tmpScroll);
+                       else
+                               ScreenAdjustDown(fpScr, -tmpScroll);
+                       if (abs(tmpScroll) < fpScr->height) {
+                               hDC=GetDC(hWnd);
+                               rc.left = 0;
+                               rc.right = fpScr->cxChar * fpScr->width;
+                               rc.top = 0;
+                               rc.bottom = fpScr->cyChar * (fpScr->bottom+1);
+                               ScrollDC(hDC,0,tmpScroll*fpScr->cyChar,&rc,&rc,NULL,NULL);
+                               ReleaseDC(hWnd, hDC);
+                               if (tmpScroll > 0) {
+                                       rc.bottom = tmpScroll * fpScr->cyChar;
+                                       InvalidateRect(hWnd, &rc, TRUE);
+                               }
+                               else {
+                                       rc.top = (fpScr->bottom + tmpScroll + 1) * fpScr->cyChar;
+                                       InvalidateRect(hWnd, &rc, TRUE);
+                               }
+                       }
+                       else
+                               InvalidateRect(hWnd, NULL, TRUE);
+
+            SetScrollPos(hWnd,SB_VERT,LOWORD(lParam),TRUE);
+                       UpdateWindow(hWnd);
+            break;
+        }
+               ScreenCursorOn(fpScr);
+        GlobalUnlock(hgScr);
+        break;
+    
+    case WM_KEYDOWN:
+        if (wParam==VK_INSERT) {
+            if (GetKeyState(VK_SHIFT)<0) 
+                PostMessage(hWnd,WM_COMMAND,IDM_PASTE,NULL);
+            else if (GetKeyState(VK_CONTROL)<0)
+                PostMessage(hWnd,WM_COMMAND,IDM_COPY,NULL);
+            break;
+        }        
+        if ((wParam < VK_PRIOR)||(wParam > VK_DOWN)) break;
+        switch (wParam) {
+        case VK_PRIOR: /* Page up   */
+            SendMessage(hWnd,WM_VSCROLL,SB_PAGEUP,NULL);               
+            break;
+        case VK_NEXT:  /* Page down */
+            SendMessage(hWnd,WM_VSCROLL,SB_PAGEDOWN,NULL);
+            break;
+        case VK_UP:            /* Line up   */
+            SendMessage(hWnd,WM_VSCROLL,SB_LINEUP,NULL);
+            break;
+        case VK_DOWN:  /* Line down */
+            SendMessage(hWnd,WM_VSCROLL,SB_LINEDOWN,NULL);
+            break;
+        }
+        UpdateWindow(hWnd);
+        break;
+        
+    case WM_CHAR:
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr == NULL) {
+               OutputDebugString("Hosed #1.\r\n");
+               break;
+        }      
+        fpScr=(SCREEN *)GlobalLock(hgScr);
+        if (fpScr == NULL) {
+               OutputDebugString("Hosed #2.\r\n");
+               break;
+        }      
+        SendMessage(fpScr->hwndTel,WM_MYSCREENCHAR,wParam,(HSCREEN)hgScr);
+        GlobalUnlock(hgScr);
+        break;
+
+    case WM_SYSCHAR:
+        if ((wParam=='c')||(wParam=='e'))
+            return (DefWindowProc(hWnd, message, wParam, lParam));
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr == NULL) {
+               OutputDebugString("Hosed #1.\r\n");
+               break;
+        }      
+        fpScr=(SCREEN *)GlobalLock(hgScr);
+        if (fpScr == NULL) {
+               OutputDebugString("Hosed #2.\r\n");
+               break;
+        }
+        SendMessage(fpScr->hwndTel,WM_MYSYSCHAR,wParam,(HSCREEN)hgScr);
+        GlobalUnlock(hgScr);
+        break;
+
+    case WM_INITMENU:
+        if (IsClipboardFormatAvailable(CF_TEXT))
+            EnableMenuItem((HMENU) wParam,IDM_PASTE,MF_ENABLED);
+        else EnableMenuItem((HMENU) wParam,IDM_PASTE,MF_GRAYED);
+        if (bSelection) EnableMenuItem((HMENU) wParam,IDM_COPY,MF_ENABLED);
+        else EnableMenuItem((HMENU) wParam,IDM_COPY,MF_GRAYED);
+        break;
+                              
+    case WM_GETMINMAXINFO:
+//        OutputDebugString("WM_GETMINMAX_INFO\r\n");
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr == NULL) break;
+        fpScr=(SCREEN *)GlobalLock(hgScr);
+//        if (fpScr == NULL) OutputDebugString("Hosed in GetMinMaxInfo.\r\n");
+//        wsprintf(strTmp,"cx=%d cy=%d width=%d height=%d",fpScr->cxChar,fpScr->cyChar,fpScr->width,fpScr->height);
+//        OutputDebugString(strTmp);
+           lpmmi = (MINMAXINFO *) lParam;
+               if (FRAME_WIDTH + MAX_LINE_WIDTH * fpScr->cxChar < lpmmi->ptMaxSize.x)
+                       lpmmi->ptMaxSize.x = FRAME_WIDTH + MAX_LINE_WIDTH * fpScr->cxChar;
+               lpmmi->ptMaxTrackSize.x = lpmmi->ptMaxSize.x;
+               lpmmi->ptMinTrackSize.x = FRAME_WIDTH + 20 * fpScr->cxChar;
+               lpmmi->ptMinTrackSize.y = FRAME_HEIGHT + 4 * fpScr->cyChar;
+           GlobalUnlock(hgScr);
+        break;
+    
+    case WM_LBUTTONDOWN: 
+        if (bDoubleClick) Edit_TripleClick(hWnd,lParam);
+        else Edit_LbuttonDown(hWnd,lParam);
+        break;
+    
+    case WM_LBUTTONUP:
+        Edit_LbuttonUp(hWnd,lParam);
+        break;
+
+    case WM_LBUTTONDBLCLK:
+        bDoubleClick=TRUE;
+        SetTimer(hWnd,TIMER_TRIPLECLICK,GetDoubleClickTime(),NULL);
+        Edit_LbuttonDblclk(hWnd,lParam);
+        break;
+
+    case WM_TIMER:
+        if (wParam==TIMER_TRIPLECLICK) bDoubleClick=FALSE;
+        break;
+
+    case WM_RBUTTONUP:
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr == NULL) {
+               OutputDebugString("Hosed #1.\r\n");
+               break;
+        }      
+        fpScr=(SCREEN *)GlobalLock(hgScr);
+        if (fpScr == NULL) {
+               OutputDebugString("Hosed #2.\r\n");
+               break;
+        }
+        Edit_Copy(hWnd);
+        Edit_ClearSelection(fpScr);                
+        Edit_Paste(hWnd);
+        GlobalUnlock(hgScr);
+        break;
+                            
+    case WM_MOUSEMOVE:
+        if (bMouseDown) Edit_MouseMove(hWnd,lParam);
+        break;
+        
+    case WM_RBUTTONDOWN: {
+        HSCREENLINE hgScrLine;
+        SCREENLINE *fpScrLine;
+        
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr == NULL) {
+               OutputDebugString("Hosed #1.\r\n");
+               break;
+        }      
+        fpScr=(SCREEN *)GlobalLock(hgScr);
+        if (fpScr == NULL) {
+               OutputDebugString("Hosed #2.\r\n");
+               break;
+        }
+        hgScrLine=fpScr->screen_top;
+        fpScrLine=LINE_MEM_LOCK(hgScrLine);
+
+//        wsprintf(strTmp,"fp->x=%d fp->y=%d text=%s \r\n",fpScr->x,fpScr->y,fpScrLine->text);
+//        OutputDebugString(strTmp);
+        LINE_MEM_LOCK(hgScrLine);
+        }        
+        break;
+            
+    case WM_PAINT:        
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr == NULL) {
+               OutputDebugString("Hosed #1.\r\n");
+               break;
+        }      
+        fpScr=(SCREEN *)GlobalLock(hgScr);
+        if (fpScr == NULL) {
+               OutputDebugString("Hosed #2.\r\n");
+               break;
+        }
+        BeginPaint (hWnd,&ps);
+        SelectObject(ps.hdc,fpScr->ghSelectedFont);
+        hslLine=fpScr->screen_bottom;
+        if (hslLine==NULL) {
+            OutputDebugString("screen_bottom is NULL.\r\n");
+            EndPaint(hWnd,&ps);                
+            GlobalUnlock(hgScr);
+            break;
+        }
+        DrawTextScreen(ps.rcPaint, fpScr, ps.hdc);
+        EndPaint(hWnd,&ps);                
+        DrawCursor(fpScr);
+        GlobalUnlock(hgScr);
+        break;         
+
+    case WM_CLOSE:
+#ifdef FILE_DEBUG
+        _lclose(fh);
+#endif
+        if (MessageBox(hWnd,"Terminate this connection?","Telnet",MB_OKCANCEL) == IDOK) {
+            hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+            if (hgScr == NULL) OutputDebugString("Hosed #1.\r\n");
+            fpScr=(SCREEN *)GlobalLock(hgScr);
+            if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+            SendMessage(fpScr->hwndTel,WM_MYSCREENCLOSE,NULL,(HSCREEN)hgScr);
+            return (DefWindowProc(hWnd, message, wParam, lParam));
+        }    
+        break;
+
+    case WM_DESTROY:
+        hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+        if (hgScr != NULL) {
+               fpScr=(SCREEN *)GlobalLock(hgScr);
+               if (fpScr != NULL)
+                DeleteObject(fpScr->ghSelectedFont);
+               }
+        return (DefWindowProc(hWnd, message, wParam, lParam));
+
+    case WM_ACTIVATE:
+       if (wParam!=WA_INACTIVE) {
+            hgScr=(HGLOBAL)GetWindowWord(hWnd,SCREEN_HANDLE);
+            if (hgScr == NULL) return (DefWindowProc(hWnd, message, wParam, lParam));
+            fpScr=(SCREEN *)GlobalLock(hgScr);
+            if (fpScr == NULL) OutputDebugString("Hosed #2.\r\n");
+            if (fpScr->bAlert) {
+                char strTitle[128];
+                int idx;
+
+                GetWindowText(hWnd,strTitle,sizeof(strTitle));
+                if (strTitle[0] == ALERT) {
+                    idx=lstrlen(strTitle);
+                    strTitle[idx-2]=0;
+                    SetWindowText(hWnd,&strTitle[2]);
+                    fpScr->bAlert=FALSE;
+                }
+            }
+            GlobalUnlock(hgScr);
+        }  /* Allow control to drop down to DefWindowProc() */
+        return (DefWindowProc(hWnd, message, wParam, lParam));
+        break;
+
+       case WM_SIZE:
+               if (wParam == SIZE_MINIMIZED)
+                       break;
+
+               hgScr = (HGLOBAL) GetWindowWord(hWnd, SCREEN_HANDLE);
+               if (hgScr == NULL)
+                       break;
+               fpScr = (SCREEN *) GlobalLock(hgScr);
+               if (fpScr == NULL)
+                       break;
+
+               if (SetInternalScreenSize(fpScr, LOWORD(lParam), HIWORD(lParam))) {
+                       SendMessage(fpScr->hwndTel, WM_MYSCREENSIZE, 0,
+                               MAKELONG(fpScr->width, fpScr->height));
+                       MakeWindowTitle(fpScr->title,fpScr->width,fpScr->height,title,sizeof(title));
+            SetWindowText(hWnd,title);
+               }
+
+               GlobalUnlock(hgScr);
+               break;
+
+       case WM_SETFOCUS:
+               hgScr = (HGLOBAL) GetWindowWord(hWnd, SCREEN_HANDLE);
+               if (hgScr == NULL)
+                       break;
+               fpScr = (SCREEN *) GlobalLock(hgScr);
+               if (fpScr == NULL)
+                       break;
+
+               CreateCaret(hWnd, NULL, fpScr->cxChar, 2);
+               ScreenCursorOn(fpScr);
+               break;
+
+       case WM_KILLFOCUS:
+               DestroyCaret();
+               break;
+
+    default:              /* Passes it on if unproccessed    */
+        return (DefWindowProc(hWnd, message, wParam, lParam));
+    }
+
+    return (NULL);
+}
+
+/**************************************************************************
+*                                                                         *
+*  Function:  ReportError(WORD)                                           *
+*                                                                         *
+*   Purpose:  To report an error that has occurred while allocating       *
+*             memory for the CD struct, locking the memory or while       *
+*             trying to load a resource string.                           *
+*                                                                         *
+*   Returns:  void                                                        *
+*                                                                         *
+*  Comments:                                                              *
+*                                                                         *
+*   History:  Date      Reason                                            *
+*             --------  -----------------------------------               *
+*                                                                         *
+*             10/01/91  Created                                           *
+*                                                                         *
+**************************************************************************/
+void ReportError(WORD wErrorType){
+   LPSTR lpszErrorMsg;
+
+   switch( wErrorType )
+      {
+         case IDC_ALLOCFAIL:
+
+            lpszErrorMsg=gszAllocErrorMsg;
+            break;
+
+         case IDC_LOCKFAIL:
+
+            lpszErrorMsg=gszLockErrorMsg;
+            break;
+
+         case IDC_LOADSTRINGFAIL:
+
+            lpszErrorMsg=gszLoadStrFail;
+            break;
+
+         default:    //let's hope we never get here!
+            return;
+      }
+
+   MessageBox(NULL, (LPSTR)lpszErrorMsg, NULL, MB_OK);
+
+   return;
+}
+
+void ScreenBell(SCREEN *fpScr) {
+    MessageBeep(MB_ICONEXCLAMATION);
+    if (fpScr->hWnd != GetActiveWindow()) {
+        char strTitle[128];
+        int idx;
+
+        FlashWindow(fpScr->hWnd,TRUE);
+        if (!fpScr->bAlert) {
+            strTitle[0]=ALERT;
+            strTitle[1]=SPACE;
+            GetWindowText(fpScr->hWnd,&strTitle[2],sizeof(strTitle)-2);
+            idx=lstrlen(strTitle);
+            strTitle[idx]=SPACE;
+            strTitle[idx+1]=ALERT;
+            strTitle[idx+2]=0;
+            SetWindowText(fpScr->hWnd,strTitle);
+        }
+        FlashWindow(fpScr->hWnd,FALSE);
+        fpScr->bAlert=TRUE;
+    }
+}
+
+void ScreenBackspace(SCREEN * fpScr) {
+    RECT rc;
+    
+//    hDC=GetDC(fpScr->hWnd);
+//    SelectObject(hDC,fpScr->ghSelectedFont);
+//    TextOut(hDC,fpScr->x*fpScr->cxChar,fpScr->y*fpScr->cyChar," ",1);
+//    ReleaseDC(fpScr->hWnd,hDC);
+    rc.left=fpScr->x*fpScr->cxChar;
+    rc.right=((fpScr->x+1)*fpScr->cxChar);
+    rc.top=(fpScr->cyChar*fpScr->y);    
+    rc.bottom=(fpScr->cyChar*fpScr->y+1);
+    InvalidateRect(fpScr->hWnd,&rc,TRUE);
+    fpScr->x--;
+    if (fpScr->x < 0) fpScr->x=0;
+//    DrawCursor(fpScr);
+    UpdateWindow(fpScr->hWnd);
+    
+}
+
+void ScreenTab(SCREEN *fpScr) {
+    int num_spaces,idx;
+    HSCREENLINE hgScrLine;
+    SCREENLINE *fpScrLine;
+    int iTest=0;
+    
+    num_spaces = TAB_SPACES - (fpScr->x % TAB_SPACES);
+    if ((fpScr->x + num_spaces) >= fpScr->width) {
+       ScreenScroll(fpScr);
+       num_spaces -= fpScr->width - fpScr->x;
+       fpScr->x=0;
+    }
+//    hgScrLine=fpScr->buffer_bottom;
+    hgScrLine=GetScreenLineFromY(fpScr,fpScr->y);
+    if (hgScrLine==NULL) return;
+    fpScrLine=(SCREENLINE *)LINE_MEM_LOCK(hgScrLine);
+    if (fpScrLine==NULL) return;
+    for (idx=0; idx<num_spaces; idx++,fpScr->x++) {
+        if (!fpScrLine->text[fpScr->x])
+            iTest=1;
+        if (iTest)
+            fpScrLine->text[fpScr->x]=SPACE;
+    }
+//    fpScrLine->text[fpScr->x]=0;
+    hDC=GetDC(fpScr->hWnd);
+    SelectObject(hDC,fpScr->ghSelectedFont);
+    TextOut(hDC,(fpScr->x-num_spaces)*fpScr->cxChar,fpScr->y*fpScr->cyChar,
+        fpScrLine->text+fpScr->x-num_spaces,num_spaces);
+    ReleaseDC(fpScr->hWnd,hDC);                
+    LINE_MEM_UNLOCK(hgScrLine);
+    DrawCursor(fpScr);
+}
+
+void ScreenCarriageFeed(SCREEN *fpScr) {
+    DrawCursor(fpScr);
+    fpScr->x=0;    
+}
diff --git a/src/windows/wintel/screen.h b/src/windows/wintel/screen.h
new file mode 100644 (file)
index 0000000..edc4d13
--- /dev/null
@@ -0,0 +1,206 @@
+extern long FAR PASCAL ScreenWndProc(HWND,UINT,WPARAM,LPARAM);
+
+//#define WINMEM
+
+/*
+*          Definition of attribute bits in the Virtual Screen
+*
+*          0   -   Bold
+*          1   -   
+*          2   -
+*          3   -   Underline
+*          4   -   Blink
+*          5   -
+*          6   -   Reverse
+*          7   -   Graphics character set
+*
+*/
+#define SCR_isbold(x)   (x & 0x01)
+#define SCR_isundl(x)   (x & 0x08)
+#define SCR_isblnk(x)   (x & 0x10)
+#define SCR_isrev(x)    (x & 0x40)
+#define SCR_setrev(x)   (x ^= 0x40)
+#define SCR_isgrph(x)   (x & 0x80)
+#define SCR_inattr(x)   (x & 0xd9)
+#define SCR_graph(x)    (x | 0x80)
+#define SCR_notgraph(x) (x & 0x7F)
+
+#define SCREEN_HANDLE            0    /* offset in extra window info */
+
+#define WM_MYSCREENCHAR                        (WM_USER+1)
+#define WM_MYSCREENBLOCK               (WM_USER+2)
+#define WM_MYSYSCHAR                   (WM_USER+3)
+#define WM_MYSCREENCLOSE               (WM_USER+4)
+#define WM_MYSCREENCHANGEBKSP  (WM_USER+5)
+#define WM_MYSCREENSIZE                        (WM_USER+6)
+#define WM_NETWORKEVENT                        (WM_USER+7)
+#define WM_HOSTNAMEFOUND               (WM_USER+8)
+
+#define FRAME_HEIGHT ((2* GetSystemMetrics(SM_CYFRAME))+GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYMENU)+3)
+#define FRAME_WIDTH  (2*GetSystemMetrics(SM_CXFRAME)+GetSystemMetrics(SM_CXVSCROLL))
+#define TAB_SPACES 8
+#define SPACE 32
+#define ALERT 0x21
+#define MAX_LINE_WIDTH 256 /* not restricted to 1 byte */
+
+#ifdef WINMEM
+#define HSCREENLINE DWORD
+#define LINE_MEM_ALLOC(x) sAlloc(x)
+#define LINE_MEM_LOCK(x) (SCREENLINE *)sLock(x)
+#define LINE_MEM_UNLOCK(x) sUnlock(x)
+#define LINE_MEM_FREE(x) sFree(x)
+#else
+#define HSCREENLINE HGLOBAL
+#define LINE_MEM_ALLOC(x) GlobalAlloc(GHND,x)
+#define LINE_MEM_LOCK(x) (SCREENLINE *) GlobalLock(x)
+#define LINE_MEM_UNLOCK(x) GlobalUnlock(x)
+#define LINE_MEM_FREE(x) GlobalFree(x)
+#endif
+
+#define HSCREEN HGLOBAL
+
+typedef struct SCREENLINE {
+       HSCREENLINE next;
+       HSCREENLINE prev;
+       int width;
+       char *text;
+       char *attrib;
+       char buffer[0];
+} SCREENLINE;
+
+typedef struct SCREEN {
+    LPSTR title;
+    HWND hWnd;
+    HWND hwndTel;
+    HSCREENLINE screen_top,
+                screen_bottom,
+                buffer_top,
+                buffer_bottom;
+       int ID,
+        type,
+        width,
+        height,
+        maxlines,       //Maximum number of scrollback lines
+        numlines,       //Current number of scrollback lines
+        savelines,      //Save lines off top?
+        ESscroll,       //Scroll screen when ES received
+        attrib,         //current attribute
+        x,y,            //current cursor position
+        Oldx,Oldy,      // internally used to redraw cursor
+        Px,Py,Pattrib,  //saved cursor pos and attribute
+        VSIDC,          // Insert/Delete character mode 0=draw line
+        DECAWM,         // AutoWrap mode 0=off
+        DECCKM,         // Cursor key mode
+        DECPAM,         // keyPad Application mode
+        IRM,            // Insert/Replace mode
+        escflg,         // Current Escape level        
+        top,bottom,     // Vertical bounds of screen
+        parmptr,
+        cxChar,         /* Width of the current font */
+        cyChar;         /* Height of the current font */
+    BOOL bAlert;
+    int parms[6];       //Ansi Params
+    LOGFONT lf;
+    HFONT ghSelectedFont,ghSelectedULFont;
+    char tabs[MAX_LINE_WIDTH];
+    HSCREEN next, prev;
+} SCREEN;
+
+typedef struct CONFIG {
+    LPSTR title;
+    HWND hwndTel;
+    int ID,
+        type,
+        height,
+        width,
+        maxlines,       //Maximum number of scrollback lines
+        backspace,
+        ESscroll,       //Scroll screen when ES received
+        VSIDC,          // Insert/Delete character mode 0=draw line
+        DECAWM,         // AutoWrap mode 0=off
+        IRM;            // Insert/Replace mode
+} CONFIG;
+
+#define TELNET_SCREEN   0
+#define CONSOLE_SCREEN  1
+
+#define IDM_FONT        100
+#define IDM_BACKSPACE   101
+#define IDM_DELETE      102
+
+#define IDM_COPY        200
+#define IDM_PASTE       201
+#define IDM_DEBUG       202
+
+#define TIMER_TRIPLECLICK 1000
+
+#define IDC_ALLOCFAIL           1
+#define IDC_LOCKFAIL            2
+#define IDC_LOADSTRINGFAIL      3
+#define IDC_FONT                6
+
+#define DESIREDPOINTSIZE 12
+
+
+void        ReportError(WORD);
+LPSTR NEAR AllocAndLockMem(HANDLE *hChunk, WORD wSize);
+void NEAR InitializeStruct(WORD wCommDlgType, LPSTR lpStruct, HWND hWnd);
+
+void ScreenInit(HANDLE hInstance);
+HSCREENLINE ScreenNewLine();
+void ScreenBell(SCREEN *fpScr);
+void ScreenBackspace(SCREEN * fpScr);
+void ScreenTab(SCREEN *fpScr);
+void ScreenCarriageFeed(SCREEN *fpScr);
+int ScreenScroll(SCREEN *fpScr);
+void DeleteTopLine(SCREEN *fpScr);
+/* emul.c */
+void ScreenEm(LPSTR c,int len,HSCREEN hsScr);
+
+
+/* intern.c */
+HSCREENLINE GetScreenLineFromY(SCREEN *fpScr,int y);
+HSCREENLINE ScreenClearLine(SCREEN *fpScr,HSCREENLINE hgScrLine);
+void ScreenUnscroll(SCREEN *fpScr);
+void ScreenELO(SCREEN *fpScr,int s);
+void ScreenEraseScreen(SCREEN *fpScr);
+void ScreenTabClear(SCREEN *fpScr);
+void ScreenTabInit(SCREEN *fpScr);
+void ScreenReset(SCREEN *fpScr);
+void ScreenIndex(SCREEN * fpScr);
+void ScreenWrapNow(SCREEN *fpScr,int *xp,int *yp);
+void ScreenEraseToEOL(SCREEN *fpScr);
+void ScreenEraseToBOL(SCREEN *fpScr);
+void ScreenEraseLine(SCREEN *fpScr,int s);
+void ScreenEraseToEndOfScreen(SCREEN *fpScr);
+void ScreenRange(SCREEN *fpScr);
+void ScreenAlign(SCREEN *fpScr);
+void ScreenApClear(SCREEN *fpScr);
+int ScreenInsChar(SCREEN *fpScr,int x);
+void ScreenInsString(SCREEN *fpScr,int len,char *start);
+void ScreenSaveCursor(SCREEN *fpScr);
+void ScreenRestoreCursor(SCREEN *fpScr);
+void ScreenDraw(SCREEN *fpScr,int x,int y,int a,int len,char *c);
+void ScreenCursorOff(SCREEN *fpScr);
+void ScreenCursorOn(SCREEN *fpScr);
+void ScreenDelChars(SCREEN *fpScr, int n);
+void ScreenRevIndex(SCREEN *fpScr);
+void ScreenDelLines(SCREEN *fpScr, int n, int s);
+void ScreenInsLines(SCREEN *fpScr, int n, int s);
+#ifdef _DEBUG
+       BOOL CheckScreen(SCREEN *fpScr);
+#endif
+
+void ProcessFontChange(HWND hWnd);
+void Edit_LbuttonDown(HWND hWnd,LPARAM lParam);
+void Edit_LbuttonDblclk(HWND hWnd,LPARAM lParam);
+void Edit_LbuttonUp(HWND hWnd, LPARAM lParam);
+void Edit_TripleClick(HWND hWnd, LPARAM lParam);
+void Edit_MouseMove(HWND hWnd, LPARAM lParam);
+void Edit_ClearSelection(SCREEN *fpScr);
+void Edit_Copy(HWND hWnd);
+void Edit_Paste(HWND hWnd);
+
+HSCREEN InitNewScreen(CONFIG *Config);
+
+
diff --git a/src/windows/wintel/struct.h b/src/windows/wintel/struct.h
new file mode 100644 (file)
index 0000000..b31fa9a
--- /dev/null
@@ -0,0 +1,30 @@
+#include "winsock.h"
+#ifdef KRB4
+   #include "kstream.h"
+#endif
+#ifdef KRB5
+   #include "k5stream.h"
+#endif
+
+#define HCONNECTION HGLOBAL
+
+typedef struct CONNECTION {
+       HSCREEN hScreen; // handle to screen associated with connection
+       kstream ks;
+       SOCKET socket;
+       int pnum;       // port number associated with connection
+       int telstate;   // telnet state for this connection
+       int substate;   // telnet subnegotiation state
+       int termsent;
+       int echo;
+       int ugoahead;
+       int igoahead;
+       int timing;
+       int backspace;
+       int ctrl_backspace;
+       int termstate;  // terminal type for this connection
+       int width;
+       int height;
+       BOOL bResizeable;
+} CONNECTION;
+
diff --git a/src/windows/wintel/telnet.c b/src/windows/wintel/telnet.c
new file mode 100644 (file)
index 0000000..a334cf9
--- /dev/null
@@ -0,0 +1,814 @@
+/****************************************************************************
+
+    PROGRAM: telnet.c
+
+    PURPOSE: Windows networking kernel - Telnet
+
+    FUNCTIONS:
+
+    WinMain() - calls initialization function, processes message loop
+    InitApplication() - initializes window data and registers window
+    InitInstance() - saves instance handle and creates main window
+    MainWndProc() - processes messages
+    About() - processes messages for "About" dialog box
+
+    COMMENTS:
+
+        Windows can have several copies of your application running at the
+        same time.  The variable hInst keeps track of which instance this
+        application is so that processing will be to the correct window.
+
+****************************************************************************/
+
+#include <windows.h>            
+#include <string.h>
+#include "telnet.h"
+#include "auth.h"
+
+HANDLE hInst;                                   /* current instance      */
+HWND hWnd;                                      /* Main window handle.   */
+CONFIG *tmpConfig;
+GLOBALHANDLE hGlobalMem, hTitleMem;
+CONNECTION *con = NULL;
+char hostdata[MAXGETHOSTSTRUCT];
+HGLOBAL ghCon;
+SCREEN *fpScr;
+int debug = 1;
+
+char __near strTmp[1024];
+
+BOOL bAutoConnection = FALSE; 
+char szAutoHostName[64];
+char szUserName[64];
+char szHostName[64];
+
+#ifdef KRB4
+       #define WINDOW_CLASS   "telnetWClass_4"
+#endif
+
+#ifdef KRB5
+       krb5_context k5_context;
+    #define WINDOW_CLASS   "telnetWClass"
+#endif
+
+/*+**************************************************************************
+
+    FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
+
+    PURPOSE: calls initialization function, processes message loop
+
+    COMMENTS:
+
+        Windows recognizes this function by name as the initial entry point 
+        for the program.  This function calls the application initialization 
+        routine, if no other instance of the program is running, and always 
+        calls the instance initialization routine.  It then executes a message 
+        retrieval and dispatch loop that is the top-level control structure 
+        for the remainder of execution.  The loop is terminated when a WM_QUIT 
+        message is received, at which time this function exits the application 
+        instance by returning the value passed by PostQuitMessage(). 
+
+        If this function must abort before entering the message loop, it 
+        returns the conventional value NULL.  
+
+****************************************************************************/
+
+int PASCAL
+WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
+HANDLE hInstance;                /* current instance             */
+HANDLE hPrevInstance;            /* previous instance            */
+LPSTR lpCmdLine;                 /* command line                 */
+int nCmdShow;                    /* show-window type (open/icon) */
+{
+    MSG msg;                     /* message                      */
+
+    if (!hPrevInstance)
+       if (!InitApplication(hInstance)) /* Initialize shared things */
+               return (FALSE);      /* Exits if unable to initialize    */
+
+    /* Perform initializations that apply to a specific instance */
+
+       if (lpCmdLine[0]) {
+               bAutoConnection = TRUE;
+               lstrcpy((char *) szAutoHostName, lpCmdLine);
+       }
+       else bAutoConnection = FALSE;
+       
+    if (!InitInstance(hInstance, nCmdShow))
+        return (FALSE);
+
+    /* Acquire and dispatch messages until a WM_QUIT message is received. */
+
+    while (GetMessage(&msg, NULL, NULL, NULL)) {
+        TranslateMessage(&msg); /* Translates virtual key codes  */
+        DispatchMessage(&msg);  /* Dispatches message to window  */
+    }
+    return (msg.wParam);    /* Returns the value from PostQuitMessage */
+}
+
+
+/*+**************************************************************************
+
+    FUNCTION: InitApplication(HANDLE)
+
+    PURPOSE: Initializes window data and registers window class
+
+    COMMENTS:
+
+        This function is called at initialization time only if no other 
+        instances of the application are running.  This function performs 
+        initialization tasks that can be done once for any number of running 
+        instances.  
+
+        In this case, we initialize a window class by filling out a data 
+        structure of type WNDCLASS and calling the Windows RegisterClass() 
+        function.  Since all instances of this application use the same window 
+        class, we only need to do this when the first instance is initialized.  
+
+
+****************************************************************************/
+
+BOOL
+InitApplication(hInstance)
+HANDLE hInstance;                  /* current instance       */
+{
+    WNDCLASS  wc;
+
+       ScreenInit(hInstance);
+
+    /* Fill in window class structure with parameters that describe the       */
+    /* main window.                                                           */
+
+    wc.style = CS_HREDRAW|CS_VREDRAW;   /* Class style(s).                    */
+    wc.lpfnWndProc = MainWndProc;       /* Function to retrieve messages for  */
+                                        /* windows of this class.             */
+    wc.cbClsExtra = 0;                  /* No per-class extra data.           */
+    wc.cbWndExtra = 0;                  /* No per-window extra data.          */
+    wc.hInstance = hInstance;           /* Application that owns the class.   */
+    wc.hIcon = NULL; //LoadIcon(hInstance, "NCSA");
+    wc.hCursor = NULL; //Cursor(NULL, IDC_ARROW);
+    wc.hbrBackground = NULL; //GetStockObject(WHITE_BRUSH); 
+    wc.lpszMenuName =  NULL;   /* Name of menu resource in .RC file. */
+    wc.lpszClassName = WINDOW_CLASS;    /* Name used in call to CreateWindow. */
+
+    /* Register the window class and return success/failure code. */
+    return (RegisterClass(&wc));
+}
+
+
+/*+**************************************************************************
+
+    FUNCTION:  InitInstance(HANDLE, int)
+
+    PURPOSE:  Saves instance handle and creates main window
+
+    COMMENTS:
+
+        This function is called at initialization time for every instance of 
+        this application.  This function performs initialization tasks that 
+        cannot be shared by multiple instances.  
+
+        In this case, we save the instance handle in a static variable and 
+        create and display the main program window.  
+        
+****************************************************************************/
+BOOL
+InitInstance(hInstance, nCmdShow)
+    HANDLE          hInstance;          /* Current instance identifier.       */
+    int             nCmdShow;           /* Param for first ShowWindow() call. */
+{
+    int xScreen = 0, yScreen = 0;
+
+    /* Save the instance handle in static variable, which will be used in  */
+    /* many subsequence calls from this application to Windows.            */
+
+    hInst = hInstance;
+
+    /* Create a main window for this application instance.  */
+    hWnd = CreateWindow(
+        WINDOW_CLASS,                   /* See RegisterClass() call.          */
+        "TCPWin",                       /* Text for window title bar.         */
+        WS_SYSMENU,                     /* Window style.                      */
+        xScreen/3,                      /* Default horizontal position.       */
+        yScreen/3,                      /* Default vertical position.         */
+        xScreen/3,                      /* Default width.                     */
+        yScreen/3,                      /* Default height.                    */
+        NULL,                           /* Overlapped windows have no parent. */
+        NULL,                           /* Use the window class menu.         */
+        hInstance,                      /* This instance owns this window.    */
+        NULL                            /* Pointer not needed.                */
+    );
+    if (!hWnd)
+        return (FALSE);
+        
+//    ShowWindow(hWnd, SW_SHOW);   /* Show the window   */
+//    UpdateWindow(hWnd);          /* Sends WM_PAINT message      */        
+
+    {
+        WSADATA wsaData;
+        if (WSAStartup(0x0101, &wsaData) != 0) {   /* Initialize the network */
+               MessageBox(NULL, "Couldn't initialize Winsock!", 
+                NULL, MB_OK | MB_ICONEXCLAMATION);
+               return FALSE;
+               }               
+    }
+
+       if (! OpenTelnetConnection()) {
+               WSACleanup();
+               return(FALSE);
+       }
+
+    #ifdef KRB5
+               krb5_init_context(&k5_context);
+               krb5_init_ets(k5_context);
+    #endif
+    return (TRUE);
+}
+
+/*+***************************************************************************
+
+    FUNCTION: MainWndProc(HWND, UINT, WPARAM, LPARAM)
+
+    PURPOSE:  Processes messages
+
+    MESSAGES:
+
+    WM_COMMAND    - application menu (About dialog box)
+    WM_DESTROY    - destroy window
+
+****************************************************************************/
+
+long FAR PASCAL
+MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
+    HSCREEN hgScr;
+    SCREEN *fpScr;
+    HGLOBAL hBuffer;
+    LPSTR lpBuffer; 
+    char c;
+    int iEvent, namelen, cnt, ret;
+    char buf[1024];
+    struct sockaddr_in name;
+       struct sockaddr_in remote_addr;
+       struct hostent *remote_host;
+       char *tmpCommaLoc;
+    
+    switch (message) {
+
+       case WM_MYSCREENCHANGEBKSP:
+           if (!con) break;
+           con->backspace = wParam;
+           if (con->backspace == VK_BACK) {
+               con->ctrl_backspace = 0x7f;
+                       WritePrivateProfileString(INI_TELNET, INI_BACKSPACE, 
+                INI_BACKSPACE_BS, TELNET_INI);
+               }
+           else {
+               con->ctrl_backspace = VK_BACK;
+                       WritePrivateProfileString(INI_TELNET, INI_BACKSPACE, 
+                INI_BACKSPACE_DEL, TELNET_INI);
+               }
+               GetPrivateProfileString(INI_HOSTS, INI_HOST "0", "", buf, 128, 
+            TELNET_INI);
+               tmpCommaLoc = strchr(buf, ',');
+               if (tmpCommaLoc) {
+                       tmpCommaLoc++;
+                       if (con->backspace == VK_BACK)
+                               strcpy(tmpCommaLoc, INI_HOST_BS);
+                       else
+                               strcpy(tmpCommaLoc, INI_HOST_DEL);
+               }
+               WritePrivateProfileString(INI_HOSTS, INI_HOST "0", buf, TELNET_INI);
+           break;
+
+       case WM_MYSCREENCHAR:
+           if (!con) break;
+           if (wParam == VK_BACK)
+               wParam = con->backspace;
+               else
+               if (wParam == 0x7f)
+                   wParam = con->ctrl_backspace;
+           TelnetSend(con->ks, (char *)&wParam, 1, NULL);
+           break;
+       
+       case WM_MYSYSCHAR:
+           if (!con) break;
+           c = (char) wParam;
+           switch (c) {
+               case 'f':
+                   getsockname(con->socket, (struct sockaddr *) &name, 
+                    (int *) &namelen);
+                   wsprintf(buf, "ftp %d.%d.%d.%d\n", 
+                       name.sin_addr.S_un.S_un_b.s_b1, 
+                       name.sin_addr.S_un.S_un_b.s_b2, 
+                       name.sin_addr.S_un.S_un_b.s_b3, 
+                       name.sin_addr.S_un.S_un_b.s_b4);
+                   TelnetSend(con->ks, buf, lstrlen(buf), NULL);
+                   break;                
+               case 'x':
+                   hgScr = con->hScreen;
+                   fpScr = (SCREEN *) GlobalLock(hgScr);
+                   if (fpScr == NULL) break;
+                   PostMessage(fpScr->hWnd, WM_CLOSE, NULL, NULL);
+                   break;
+                                   
+           }                
+           break;
+               
+       case WM_MYSCREENBLOCK:
+           if (!con) break;
+           hBuffer = (HGLOBAL) wParam;
+           lpBuffer = GlobalLock(hBuffer);
+           TelnetSend(con->ks, lpBuffer, lstrlen(lpBuffer), NULL);
+           GlobalUnlock(hBuffer);
+           break;
+
+       case WM_MYSCREENCLOSE:
+           if (!con) break;
+           kstream_destroy(con->ks);
+               DestroyWindow(hWnd);
+           break;        
+
+       case WM_QUERYOPEN:
+           return(0);
+           break;
+
+       case WM_DESTROY:          /* message: window being destroyed */
+           kstream_destroy(con->ks);
+           GlobalUnlock(ghCon);
+           GlobalFree(ghCon); 
+           WSACleanup();
+           PostQuitMessage(0);
+           break;
+
+       case WM_NETWORKEVENT: 
+               iEvent = WSAGETSELECTEVENT(lParam);
+
+               switch (iEvent) {       
+
+               case FD_READ:
+               cnt = recv(con->socket, buf, 1024, NULL);
+                       /*
+                       The following line has been removed until kstream supports
+                       non-blocking IO or larger size reads (jrivlin@fusion.com).
+                       */
+                       /* cnt = kstream_read(con->ks, buf, 1024); */
+               buf[cnt] = 0;
+               parse((CONNECTION *) con, (unsigned char *) buf, cnt);
+               ScreenEm(buf, cnt, con->hScreen);
+               break;
+
+           case FD_CLOSE:
+                       kstream_destroy(con->ks);
+                       GlobalUnlock(ghCon);
+                       GlobalFree(ghCon); 
+                       WSACleanup();
+                       PostQuitMessage(0);
+                       break;
+
+               case FD_CONNECT:
+                       ret = WSAGETSELECTERROR(lParam);
+                       if (ret) {
+                               wsprintf(buf, "Error %d on Connect", ret);
+            OutputDebugString (buf);
+                       MessageBox(NULL, buf, NULL, MB_OK|MB_ICONEXCLAMATION);
+                               kstream_destroy(con->ks);
+                               GlobalUnlock(ghCon);
+                               GlobalFree(ghCon); 
+                               WSACleanup();
+                               PostQuitMessage(0);
+                               break;
+                   }
+                       start_negotiation(con->ks);
+                       break;          
+           }
+           break;              
+
+       case WM_HOSTNAMEFOUND:
+               ret = WSAGETASYNCERROR(lParam);
+               if (ret) {
+                       wsprintf(buf, "Error %d on GetHostbyName", ret);
+               MessageBox(NULL, buf, NULL, MB_OK|MB_ICONEXCLAMATION);
+                   kstream_destroy(con->ks);
+                   GlobalUnlock(ghCon);
+                   GlobalFree(ghCon); 
+                   WSACleanup();
+                   PostQuitMessage(0);
+               break;
+        }
+        remote_host = (struct hostent *) hostdata;
+               remote_addr.sin_family = AF_INET;    
+               remote_addr.sin_addr.S_un.S_un_b.s_b1 = remote_host->h_addr[0];
+               remote_addr.sin_addr.S_un.S_un_b.s_b2 = remote_host->h_addr[1];
+               remote_addr.sin_addr.S_un.S_un_b.s_b3 = remote_host->h_addr[2];
+               remote_addr.sin_addr.S_un.S_un_b.s_b4 = remote_host->h_addr[3];
+        #ifdef KRB4
+               remote_addr.sin_port = htons(23);
+        #endif
+        #ifdef KRB5
+               remote_addr.sin_port = htons(13131);
+        #endif
+               
+               connect(con->socket, (struct sockaddr*) &remote_addr, 
+                       sizeof(struct sockaddr));    
+               break;
+
+       case WM_MYSCREENSIZE:
+               con->width = LOWORD(lParam);                    /* width in characters */
+               con->height = HIWORD(lParam);           /* height in characters */
+               if (con->bResizeable && con->ks)
+                       send_naws(con);
+               wsprintf(buf, "%d", con->height);
+               WritePrivateProfileString(INI_TELNET, INI_HEIGHT, buf, TELNET_INI);
+               wsprintf(buf, "%d", con->width);
+               WritePrivateProfileString(INI_TELNET, INI_WIDTH, buf, TELNET_INI);
+           break;
+               
+       default:              /* Passes it on if unproccessed    */
+           return(DefWindowProc(hWnd, message, wParam, lParam));
+    }
+    return (NULL);
+}
+
+
+/*+***************************************************************************
+
+    FUNCTION: SaveHostName(hostname)
+
+    PURPOSE: Saves the currently selected host name in the KERBEROS.INI file
+               and returns the preferred backspace setting if one exists for
+               that host.
+
+       RETURNS: VK_BACK or 0x7f depending on the desired backspace setting.
+
+****************************************************************************/
+
+int
+SaveHostName(char *host)
+{
+    char buf[128];
+       char hostName[10][128];
+       char *tmpCommaLoc;
+       char tmpName[128];
+       char tmpBuf[80];
+       int nhosts;
+       int n;
+    int iHostNum;
+       int bs;
+
+       nhosts = 0;
+    for (iHostNum = 0; iHostNum < 10; iHostNum++) {
+        wsprintf(tmpBuf, INI_HOST "%d", iHostNum);
+        GetPrivateProfileString(INI_HOSTS, tmpBuf, "", hostName[iHostNum], 
+            128, TELNET_INI);
+               strcpy(tmpName, hostName[iHostNum]);
+        tmpCommaLoc = strchr(tmpName, ',');  
+        if (tmpCommaLoc) {
+                       *tmpCommaLoc = '\0';
+                       while (tmpCommaLoc[1] == ' ')
+                               tmpCommaLoc++;
+               }
+               if (!hostName[iHostNum][0])
+                       break;
+               nhosts++;
+        if (strcmp(tmpName, host) == 0)
+                       break;
+    }
+
+       for (iHostNum++; iHostNum < 10; iHostNum++) {
+        wsprintf(tmpBuf, INI_HOST "%d", iHostNum);
+        GetPrivateProfileString(INI_HOSTS, tmpBuf, "", hostName[iHostNum], 
+            128, TELNET_INI);
+               if (!hostName[iHostNum][0])
+                       break;
+               nhosts++;
+       }
+
+    if (tmpCommaLoc)
+               tmpCommaLoc++;
+
+    if (tmpName[0] && tmpCommaLoc) {
+               if (_stricmp(tmpCommaLoc, INI_HOST_DEL) == 0)
+                       bs = 0x7f;
+               else if (_stricmp(tmpCommaLoc, INI_HOST_BS) == 0)
+                       bs = VK_BACK;
+       }
+    else {
+           GetPrivateProfileString(INI_TELNET, INI_BACKSPACE, INI_BACKSPACE_BS, 
+                       tmpBuf, sizeof(tmpBuf), TELNET_INI);
+               if (_stricmp(tmpBuf, INI_BACKSPACE_DEL) == 0)
+                       bs = 0x7f;
+               else
+                       bs = VK_BACK;
+       }
+
+       strcpy(buf, tmpConfig->title);
+       strcat(buf, ", ");
+       if (bs == VK_BACK)
+               strcat(buf, INI_BACKSPACE_BS);
+       else
+               strcat(buf, INI_BACKSPACE_DEL);
+
+       WritePrivateProfileString(INI_HOSTS, INI_HOST "0", buf, TELNET_INI);
+       n = 1;
+    for (iHostNum = 0; iHostNum < nhosts; iHostNum++) {
+               strcpy(tmpName, hostName[iHostNum]);
+        tmpCommaLoc = strchr(tmpName, ',');  
+        if (tmpCommaLoc) {
+                       *tmpCommaLoc = '\0';
+                       while (tmpCommaLoc[1] == ' ')
+                               tmpCommaLoc++;
+               }
+        if (strcmp(tmpName, host) != 0) {
+               wsprintf(tmpBuf, INI_HOST "%d", n++);
+                       WritePrivateProfileString(INI_HOSTS, tmpBuf, hostName[iHostNum], 
+                TELNET_INI);
+               }
+    }
+       return (bs);
+}
+
+/*+*/
+int
+OpenTelnetConnection(void) {
+    int nReturn, ret;
+    struct sockaddr_in sockaddr;
+       char *p;
+       static struct kstream_crypt_ctl_block ctl;
+    char buf[128];
+
+    hGlobalMem = GlobalAlloc(GPTR, sizeof(CONFIG));
+    tmpConfig = (CONFIG *) GlobalLock(hGlobalMem);
+    
+    if (bAutoConnection) {
+               hTitleMem = GlobalAlloc(GPTR, lstrlen(szAutoHostName));
+               tmpConfig->title = (char *) GlobalLock(hTitleMem);            
+               lstrcpy(tmpConfig->title, (char *) szAutoHostName);
+    } else {
+       nReturn = DoDialog("OPENTELNETDLG", OpenTelnetDlg);
+       if (nReturn == FALSE) return(FALSE);
+       }
+                       
+    con = (CONNECTION *) GetNewConnection();
+    if (con == NULL) return(0);
+
+       tmpConfig->width = GetPrivateProfileInt(INI_TELNET, INI_WIDTH, 
+        DEF_WIDTH, TELNET_INI);
+       tmpConfig->height = GetPrivateProfileInt(INI_TELNET, INI_HEIGHT, 
+        DEF_HEIGHT, TELNET_INI);
+       con->width = tmpConfig->width;
+       con->height = tmpConfig->height;
+
+       con->backspace = SaveHostName(tmpConfig->title);
+
+       if (con->backspace == VK_BACK) {
+        tmpConfig->backspace = TRUE;
+        con->ctrl_backspace = 0x7f;
+    } else {
+        tmpConfig->backspace = FALSE;
+        con->ctrl_backspace = 0x08;
+       }
+
+    tmpConfig->hwndTel = hWnd;
+    con->hScreen = (HSCREEN) InitNewScreen((CONFIG *) tmpConfig);
+    if (!(con->hScreen)) {
+       OutputDebugString("Failed to initialize new screen! \r\n");
+        GlobalUnlock(con->hScreen);
+        GlobalUnlock(ghCon);
+        GlobalFree(ghCon);
+        GlobalUnlock(hGlobalMem); 
+        GlobalFree(hGlobalMem);
+        return(-1);
+    }
+
+    ret = (SOCKET) socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    
+    if (ret == SOCKET_ERROR) {
+        wsprintf(buf, "Socket error on socket = %d!", WSAGetLastError());
+        MessageBox(NULL, buf, NULL, MB_OK|MB_ICONEXCLAMATION);
+        fpScr = (SCREEN *) GlobalLock(con->hScreen);
+        if (fpScr != NULL)
+               DestroyWindow(fpScr->hWnd);
+        GlobalUnlock(con->hScreen);
+        GlobalUnlock(ghCon);
+        GlobalFree(ghCon);
+        GlobalUnlock(hGlobalMem);
+        GlobalFree(hGlobalMem);
+        return(-1);
+    } 
+    
+    con->socket = ret;
+    
+    sockaddr.sin_family = AF_INET ;  
+    sockaddr.sin_addr.s_addr = htonl( INADDR_ANY );
+    sockaddr.sin_port = htons( 0 ) ;
+    
+    ret = bind(con->socket, (struct sockaddr *) &sockaddr, 
+        (int) sizeof(struct sockaddr_in));
+    
+    if (ret == SOCKET_ERROR) {
+        wsprintf(buf, "Socket error on bind!");
+        MessageBox(NULL, buf, NULL, MB_OK|MB_ICONEXCLAMATION);
+        fpScr = (SCREEN *) GlobalLock(con->hScreen);
+        if (fpScr != NULL)
+               DestroyWindow(fpScr->hWnd);
+        GlobalUnlock(con->hScreen);
+        GlobalUnlock(ghCon);
+        GlobalFree(ghCon);
+        GlobalUnlock(hGlobalMem);
+        GlobalFree(hGlobalMem);
+        return(-1);
+    }
+    WSAAsyncSelect(con->socket, hWnd, WM_NETWORKEVENT, 
+        FD_READ | FD_CLOSE | FD_CONNECT);
+
+       lstrcpy(szHostName, tmpConfig->title);
+       p = strchr(szHostName, '@');
+       if (p != NULL) {
+               *p = 0;
+               strcpy (szUserName, szHostName);
+               strcpy(szHostName, ++p);
+       }
+
+       WSAAsyncGetHostByName(hWnd, WM_HOSTNAMEFOUND, szHostName, hostdata, 
+        MAXGETHOSTSTRUCT); 
+    GlobalUnlock(con->hScreen);
+//    GlobalUnlock(ghCon);
+//    GlobalFree(ghCon);
+    GlobalUnlock(hGlobalMem);
+    GlobalFree(hGlobalMem);
+
+       ctl.encrypt = auth_encrypt;
+       ctl.decrypt = auth_decrypt;
+       ctl.init    = auth_init;
+       ctl.destroy = auth_destroy;
+
+       con->ks = kstream_create_from_fd(con->socket, &ctl, NULL);
+
+       kstream_set_buffer_mode(con->ks, 0);
+
+       if (con->ks == NULL)
+               return(-1);
+
+    return(1);
+}
+
+/*+*/
+CONNECTION *
+GetNewConnection(void) {
+    CONNECTION *fpCon;
+
+    ghCon = GlobalAlloc(GHND, sizeof(CONNECTION));
+    if (ghCon == NULL) return NULL;
+    fpCon = (CONNECTION *) GlobalLock(ghCon);
+    if (fpCon == NULL) return NULL;
+    fpCon->backspace = TRUE;
+       fpCon->bResizeable = TRUE;
+    return(fpCon);
+}
+   
+/*+***************************************************************************/
+int NEAR
+DoDialog(char *szDialog, FARPROC lpfnDlgProc) {
+    int nReturn;
+    
+    lpfnDlgProc = MakeProcInstance(lpfnDlgProc, hInst);
+    if (lpfnDlgProc == NULL)
+        MessageBox(hWnd, "Couldn't make procedure instance", NULL, MB_OK);    
+    
+    nReturn = DialogBox(hInst, szDialog, hWnd, lpfnDlgProc);
+    FreeProcInstance(lpfnDlgProc);
+    return (nReturn);
+}    
+
+/*+***************************************************************************
+
+    FUNCTION: OpenTelnetDlg(HWND, unsigned, WORD, LONG)
+
+    PURPOSE:  Processes messages for "Open New Telnet Connection" dialog box
+
+    MESSAGES:
+
+    WM_INITDIALOG - initialize dialog box
+    WM_COMMAND    - Input received
+
+****************************************************************************/
+
+BOOL FAR PASCAL
+OpenTelnetDlg(HWND hDlg, WORD message, WORD wParam, LONG lParam) {
+    char szConnectName[256];
+    HDC  hDC;
+    int  xExt, yExt;
+    DWORD Ext;
+    HWND hEdit;
+    int  nLen;
+    int iHostNum = 0;
+    char tmpName[128], tmpBuf[80];
+    char *tmpCommaLoc;
+    
+    switch (message) {
+        case WM_INITDIALOG:        /* message: initialize dialog box */
+            hDC = GetDC(hDlg);
+            Ext = GetDialogBaseUnits();
+            xExt = (190 *LOWORD(Ext)) /4 ;
+            yExt = (72 * HIWORD(Ext)) /8 ;
+            GetPrivateProfileString(INI_HOSTS, INI_HOST "0", "", tmpName, 
+                128, TELNET_INI);
+            if (tmpName[0]) {
+               tmpCommaLoc = strchr(tmpName, ',');
+                               if (tmpCommaLoc)
+                                       *tmpCommaLoc = '\0';
+               SetDlgItemText(hDlg, TEL_CONNECT_NAME, tmpName);
+            }  
+            hEdit = GetWindow(GetDlgItem(hDlg, TEL_CONNECT_NAME), GW_CHILD);
+            while (TRUE) {
+                wsprintf(tmpBuf, INI_HOST "%d", iHostNum++);
+                GetPrivateProfileString(INI_HOSTS, tmpBuf, "", tmpName, 
+                    128, TELNET_INI);
+                tmpCommaLoc = strchr(tmpName, ',');  
+                if (tmpCommaLoc)
+                                       *tmpCommaLoc = '\0';
+                if (tmpName[0])
+                    SendDlgItemMessage(hDlg, TEL_CONNECT_NAME, CB_ADDSTRING, 0, 
+                        (LPARAM) ((LPSTR) tmpName));
+                else
+                                       break;
+            }
+            SetWindowPos(hDlg, NULL, (GetSystemMetrics(SM_CXSCREEN)/2)-(xExt/2), 
+                (GetSystemMetrics(SM_CYSCREEN)/2)-(yExt/2), 0, 0, 
+                SWP_NOSIZE|SWP_NOZORDER|SWP_SHOWWINDOW);
+            ReleaseDC(hDlg, hDC);      
+            SendMessage(hEdit, WM_USER+1, NULL, NULL);
+            SendMessage(hDlg, WM_SETFOCUS, NULL, NULL);
+            return (TRUE);
+
+        case WM_COMMAND:              /* message: received a command */
+            switch (wParam) {
+                case TEL_CANCEL:
+                     EndDialog(hDlg, FALSE);        /* Exits the dialog box   */
+                     break;
+                 
+                case TEL_OK:
+                     GetDlgItemText(hDlg, TEL_CONNECT_NAME, szConnectName, 256);
+                     nLen = lstrlen(szConnectName);
+                     if (nLen == 0) { 
+                        MessageBox(hDlg, "You must enter a session name!", 
+                            NULL, MB_OK);
+                        break;
+                        }
+                     hTitleMem = GlobalAlloc(GPTR, nLen);
+                     tmpConfig->title = (char *) GlobalLock(hTitleMem);
+                     lstrcpy(tmpConfig->title, szConnectName);
+                     EndDialog(hDlg, TRUE);
+                     break;
+            }                
+            return (FALSE);                    
+    }
+    return (FALSE);               /* Didn't process a message    */
+}
+
+/*+***************************************************************************
+
+    FUNCTION: TelnetSend(kstream ks, char *buf, int len, int flags)
+
+    PURPOSE:   This is a replacement for the WinSock send() function, to
+               send a buffer of characters to an output socket.  It differs
+               by retrying endlessly if sending the bytes would cause
+               the send() to block.  <gnu@cygnus.com> observed EWOULDBLOCK
+               errors when running using TCP Software's PC/TCP 3.0 stack, 
+               even when writing as little as 109 bytes into a socket
+               that had no more than 9 bytes queued for output.  Note also that
+               a kstream is used during output rather than a socket to facilitate
+               encryption.
+
+               Eventually, for cleanliness and responsiveness, this
+               routine should not loop; instead, if the send doesn't
+               send all the bytes, it should put them into a buffer
+               and return.  Message handling code would send out the
+               buffer whenever it gets an FD_WRITE message.
+
+****************************************************************************/
+
+int
+TelnetSend(kstream ks, char *buf, int len, int flags) {
+
+       int writelen;
+       int origlen = len;
+
+       while (TRUE) {
+               writelen = kstream_write(ks, buf, len);
+
+               if (writelen == len)       /* Success, first or Nth time */
+                       return (origlen);
+
+               if (writelen == SOCKET_ERROR) {
+                       if (WSAGetLastError() != WSAEWOULDBLOCK)
+                               return (SOCKET_ERROR);  /* Some error */
+                       /* For WOULDBLOCK, immediately repeat the send. */
+               }
+               else {
+                       /* Partial write; update the pointers and retry. */
+                       len -= writelen;
+                       buf += writelen;
+               }
+       }
+}
diff --git a/src/windows/wintel/telnet.def b/src/windows/wintel/telnet.def
new file mode 100644 (file)
index 0000000..e5c1061
--- /dev/null
@@ -0,0 +1,49 @@
+; module-definition file for testdll -- used by LINK.EXE
+NAME         telnet        ; application's module name
+
+DESCRIPTION  'Sample Microsoft Windows Application'
+
+EXETYPE      WINDOWS       ; required for all Windows applications
+
+STUB         'WINSTUB.EXE' ; Generates error message if application
+               ; is run without Windows
+
+;CODE can be moved in memory and discarded/reloaded
+CODE  PRELOAD MOVEABLE 
+;DISCARDABLE
+
+;DATA must be MULTIPLE if program can be invoked more than once
+DATA  PRELOAD MOVEABLE
+
+
+HEAPSIZE     10240
+
+; All functions that will be called by any Windows routine
+; MUST be exported.
+
+EXPORTS
+    MainWndProc   @1   ; name of window processing function
+    OpenTelnetDlg @3   ; name of "Open New Telnet Connection" Dialog Function
+
+IMPORTS 
+        WINSOCK.WSAStartup
+        WINSOCK.WSACleanup
+        WINSOCK.WSAAsyncSelect
+        WINSOCK.WSAGetLastError
+        WINSOCK.WSAAsyncGetHostByName
+        WINSOCK.listen
+        WINSOCK.accept
+        WINSOCK.__wsafdisset
+        WINSOCK.socket
+        WINSOCK.bind
+        WINSOCK.gethostbyname
+        WINSOCK.getsockname
+        WINSOCK.htons
+        WINSOCK.connect
+        WINSOCK.recv
+        WINSOCK.send
+        WINSOCK.htonl
+        WINSOCK.closesocket
+        WINSOCK.select
+        WINSOCK.ioctlsocket
+        WINSOCK.getpeername
diff --git a/src/windows/wintel/telnet.dlg b/src/windows/wintel/telnet.dlg
new file mode 100644 (file)
index 0000000..8b73ee8
--- /dev/null
@@ -0,0 +1,77 @@
+DLGINCLUDE RCDATA DISCARDABLE
+BEGIN
+    "DIALOG.H\0"
+END
+
+OPENTELNETDLG DIALOG 63, 65, 175, 51
+STYLE DS_ABSALIGN | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Open New Telnet Connection"
+FONT 8, "MS Sans Serif"
+BEGIN
+       CONTROL "To Host:", -1, "STATIC", NOT WS_GROUP, 3, 10, 33, 10
+       CONTROL "", TEL_CONNECT_NAME, "COMBOBOX", CBS_DROPDOWN | WS_VSCROLL | WS_GROUP | WS_TABSTOP, 42, 9, 128, 60
+       CONTROL "OK", TEL_OK, "BUTTON", WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON, 27, 30, 51, 14
+       CONTROL "Cancel", TEL_CANCEL, "BUTTON", WS_TABSTOP, 97, 30, 51, 14
+END
+
+ABOUTBOX DIALOG 69, 33, 175, 148
+STYLE DS_ABSALIGN | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About TCPwin"
+BEGIN
+       ICON "NCSA", -1, 15, 12, 16, 16
+       CTEXT "Microsoft Windows", -1, 48, 11, 93, 8
+       CTEXT "NCSA TCP/IP Networking Kernel", -1, 38, 21, 120, 8
+       CTEXT "Version 1.0b2", -1, 20, 31, 144, 8
+       CONTROL "OK", IDOK, "BUTTON", WS_GROUP, 72, 126, 39, 14
+       CTEXT "Written By:", 606, 20, 50, 144, 8
+       CTEXT "Jon Mittelhauser (jonm@ncsa.uiuc.edu)", 607, 20, 61, 144, 8
+       CTEXT "Chris Wilson (cwilson@ncsa.uiuc.edu)", 608, 20, 71, 144, 8
+       CTEXT "Special Thanks to:", 609, 21, 97, 143, 8
+       CTEXT "Joe Lepore for DPMI interface code", 610, 20, 107, 144, 8
+       CTEXT "Keberized by: Cygnus Support", 611, 20, 82, 144, 8
+END
+
+CONFIG_DLG DIALOG 6, 18, 160, 130
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Configure Session"
+FONT 8, "MS Sans Serif"
+BEGIN
+    LTEXT           "Session Name:", 301, 1, 5, 54, 8
+    LTEXT           "Default Session", CON_SESSIONNAME, 55, 5, 105, 8
+    LTEXT           "Window Title:", 303, 1, 17, 49, 8
+    EDITTEXT        CON_WINDOWTITLE, 53, 15, 102, 12, ES_AUTOHSCROLL
+    CONTROL         "132", CON_COLUMNS132, "Button", BS_AUTORADIOBUTTON | 
+                    WS_GROUP, 53, 33, 39, 10
+    CONTROL         "80", CON_COLUMNS80, "Button", BS_AUTORADIOBUTTON, 110, 
+                    33, 39, 10
+    CONTROL         "Backspace", CON_BACKSPACE, "Button", BS_AUTORADIOBUTTON | 
+                    WS_GROUP, 53, 46, 49, 10
+    CONTROL         "Delete", CON_DELETE, "Button", BS_AUTORADIOBUTTON, 110, 
+                    46, 39, 10
+    CONTROL         "CRLF", CON_CRLF, "Button", BS_AUTORADIOBUTTON | 
+                    WS_GROUP, 53, 59, 39, 10
+    CONTROL         "CR-NUL", CON_CRNUL, "Button", BS_AUTORADIOBUTTON, 110, 
+                    59, 39, 10
+    CONTROL         "Buffers", CON_BUFFERS, "Button", BS_AUTORADIOBUTTON | 
+                    WS_GROUP, 53, 72, 39, 10
+    CONTROL         "Sends", CON_SENDS, "Button", BS_AUTORADIOBUTTON, 110, 
+                    72, 39, 10
+    LTEXT           "Columns", 313, 1, 33, 49, 8
+    LTEXT           "Backspace is", 314, 1, 46, 51, 8
+    LTEXT           "Return Sends", 315, 1, 59, 49, 8
+    LTEXT           "Echo Mode", 316, 1, 72, 49, 8
+    CONTROL         "Scrollback", CON_SCRLBCK, "Button", BS_AUTOCHECKBOX | 
+                    WS_TABSTOP, 1, 86, 50, 10
+    EDITTEXT        CON_NUMLINES, 53, 85, 28, 12, ES_AUTOHSCROLL
+    LTEXT           "lines", 319, 85, 86, 33, 8
+    DEFPUSHBUTTON   "OK", CON_OK, 20, 108, 50, 14, WS_GROUP
+    PUSHBUTTON      "Use Defaults", CON_USEDEFAULTS, 90, 108, 50, 14
+END
+
+IDM_PRINTQUEUE DIALOG 69, 25, 160, 80
+STYLE WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | 
+    WS_VSCROLL | WS_HSCROLL | WS_SYSMENU
+CAPTION "Print Queue"
+FONT 8, "MS Sans Serif"
+BEGIN
+END
diff --git a/src/windows/wintel/telnet.h b/src/windows/wintel/telnet.h
new file mode 100644 (file)
index 0000000..ee68d76
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef TELNET_H_INC
+#define TELNET_H_INC
+
+#include <windows.h>
+#include <stdarg.h>
+
+#ifdef KRB5
+#include "krb5.h"
+#include "k5stream.h"
+#endif
+
+#include "dialog.h"
+#include "screen.h"
+#include "struct.h"
+#include "wt-proto.h"
+#include "winsock.h"
+#include "ini.h"
+
+/* globals */
+extern char szAutoHostName[64];
+extern char szUserName[64];
+extern char szHostName[64];
+
+#ifdef KRB5
+   extern krb5_context k5_context;
+#endif
+
+extern void parse(CONNECTION *con,unsigned char *st,int cnt);
+extern void send_naws(CONNECTION *con);
+extern char __near strTmp[];
+
+#define DEF_WIDTH 80
+#define DEF_HEIGHT 24
+
+#endif /* TELNET_H_INC */
+
diff --git a/src/windows/wintel/telnet.rc b/src/windows/wintel/telnet.rc
new file mode 100644 (file)
index 0000000..bcdcdb5
--- /dev/null
@@ -0,0 +1,26 @@
+#include <windows.h>
+#include "dialog.h"
+#include "telnet.dlg" 
+#include "screen.h"
+
+NCSA           ICON    ncsa.ico
+TERMINAL    ICON       terminal.ico
+
+ScreenMenu MENU
+BEGIN
+       POPUP "&Configure"
+       BEGIN
+               MENUITEM "&Backspace", IDM_BACKSPACE, CHECKED
+               MENUITEM "&Delete", IDM_DELETE
+               MENUITEM SEPARATOR
+               MENUITEM "&Font...", IDM_FONT
+       END
+       POPUP "&Edit"
+       BEGIN
+               MENUITEM "&Copy     Cltr+Ins",IDM_COPY
+               MENUITEM "&Paste    Shift+Ins", IDM_PASTE
+               #ifdef _DEBUG
+                       MENUITEM "&Debug", IDM_DEBUG
+               #endif
+       END                            
+END
diff --git a/src/windows/wintel/telopts.h b/src/windows/wintel/telopts.h
new file mode 100644 (file)
index 0000000..e928a84
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+*    telopts.h
+*  Used for telnet options
+****************************************************************************
+*                                                                          *
+*                                                                          *
+*      NCSA Telnet                                                         *
+*      by Tim Krauskopf, VT100 by Gaige Paulsen, Tek by Aaron Contorer     *
+*                      Additions by Kurt Mahan, Heeren Pathak, & Quincey Koziol           *
+*                                                                          *
+*      National Center for Supercomputing Applications                     *
+*      152 Computing Applications Building                                 *
+*      605 E. Springfield Ave.                                             *
+*      Champaign, IL  61820                                                *
+*                                                                          *
+****************************************************************************
+*      Quincey Koziol
+*   Defines for telnet options and related things
+*/
+
+#ifndef TELOPTS_H
+#define TELOPTS_H
+
+#define NUMLMODEOPTIONS 30
+
+/* Definitions for telnet protocol */
+
+#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 WILLTEL        251
+#define WONTTEL        252
+#define DOTEL          253
+#define DONTTEL        254
+#define IAC                    255
+
+/* Assigned Telnet Options */
+#define BINARY                         0
+#define ECHO                           1
+#define RECONNECT                      2
+#define SGA                            3
+#define AMSN                           4
+#define STATUS                         5
+#define TIMING                         6
+#define RCTAN                          7
+#define OLW                                    8
+#define OPS                                    9
+#define OCRD                           10
+#define OHTS                           11
+#define OHTD                           12
+#define OFFD                           13
+#define OVTS                           14
+#define OVTD                           15
+#define OLFD                           16
+#define XASCII                         17
+#define LOGOUT                         18
+#define BYTEM                          19
+#define DET                                    20
+#define SUPDUP                         21
+#define SUPDUPOUT                      22
+#define SENDLOC                                23
+#define TERMTYPE                       24
+#define EOR                                    25
+#define TACACSUID                      26
+#define OUTPUTMARK                     27
+#define TERMLOCNUM                     28
+#define REGIME3270                     29
+#define X3PAD                          30
+#define NAWS                           31
+#define TERMSPEED                      32
+#define TFLOWCNTRL                     33
+#define LINEMODE                       34
+       #define MODE 1
+        #define MODE_EDIT       1
+        #define MODE_TRAPSIG    2
+        #define MODE_ACK        4
+        #define MODE_SOFT_TAB   8
+        #define MODE_LIT_ECHO   16
+
+       #define FORWARDMASK 2
+
+       #define SLC 3 
+        #define SLC_DEFAULT     3
+        #define SLC_VALUE       2
+        #define SLC_CANTCHANGE  1
+        #define SLC_NOSUPPORT   0
+        #define SLC_LEVELBITS   3
+
+        #define SLC_ACK         128
+        #define SLC_FLUSHIN     64
+        #define SLC_FLUSHOUT    32
+
+               #define SLC_SYNCH               1
+               #define SLC_BRK                 2
+               #define SLC_IP                  3
+               #define SLC_AO                  4
+               #define SLC_AYT                 5
+               #define SLC_EOR                 6
+               #define SLC_ABORT               7
+               #define SLC_EOF                 8
+               #define SLC_SUSP                9
+               #define SLC_EC                  10
+               #define SLC_EL                  11
+               #define SLC_EW                  12
+               #define SLC_RP                  13
+               #define SLC_LNEXT               14
+               #define SLC_XON                 15
+               #define SLC_XOFF                16
+               #define SLC_FORW1               17
+               #define SLC_FORW2               18
+        #define SLC_MCL         19
+        #define SLC_MCR         20
+        #define SLC_MCWL        21
+        #define SLC_MCWR        22
+        #define SLC_MCBOL       23
+        #define SLC_MCEOL       24
+        #define SLC_INSRT       25
+        #define SLC_OVER        26
+        #define SLC_ECR         27
+        #define SLC_EWR         28
+        #define SLC_EBOL        29
+        #define SLC_EEOL        30
+
+#define XDISPLOC                       35
+#define ENVIRONMENT         36
+#define AUTHENTICATION         37
+#define DATA_ENCRYPTION     38
+#define XOPTIONS                       255
+
+#define LINEMODE_MODES_SUPPORTED    0x1B
+/* set this flag for linemode special functions which are supported by Telnet, even though they are not currently active */
+/* This is to allow the other side to negotiate to a "No Support" state for an option */
+/* and then change later to supporting it, so we know it's ok to change our "No Support" */
+/* state to something else ("Can't Change", "Value", whatever) */
+#define SLC_SUPPORTED       0x10    
+       
+#define ESCFOUND 5
+#define IACFOUND 6
+#define NEGOTIATE 1
+
+#endif  /* telopts.h */
+
diff --git a/src/windows/wintel/terminal.ico b/src/windows/wintel/terminal.ico
new file mode 100644 (file)
index 0000000..7ec59e9
Binary files /dev/null and b/src/windows/wintel/terminal.ico differ
diff --git a/src/windows/wintel/wt-proto.h b/src/windows/wintel/wt-proto.h
new file mode 100644 (file)
index 0000000..67f550c
--- /dev/null
@@ -0,0 +1,19 @@
+int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);
+BOOL InitApplication(HANDLE);
+BOOL InitInstance(HANDLE, int);
+long FAR PASCAL MainWndProc(HWND, UINT, WPARAM, LPARAM);
+BOOL FAR PASCAL About(HWND, WORD, WORD, LONG);
+BOOL FAR PASCAL OpenTelnetDlg(HWND, WORD, WORD, LONG);
+int TelnetSend(kstream, char *, int, int);
+BOOL FAR PASCAL ConfigSessionDlg(HWND, WORD, WORD, LONG);
+
+int OpenTelnetConnection(void);
+int NEAR DoDialog(char *szDialog, FARPROC lpfnDlgProc);
+///HCONNECTION FindConnectionFromPortNum(int ID);
+///HCONNECTION FindConnectionFromTelstate(int telstate);
+///HCONNECTION FindConnectionFromScreen(HSCREEN hScreen);
+CONNECTION * GetNewConnection(void);
+void start_negotiation(kstream ks);
+/* somewhere... */
+struct machinfo * FAR PASCAL Shostlook(char *hname);
+