CLIENT.C
/* 
Copyright (c) 1994, 1993 Microsoft Corporation 
 
Module Name: 
    Client.c 
 
Abstract: 
    The Client component of Remote. Connects to the remote 
    server using named pipes. It sends its stdin to 
    the server and output everything from server to 
    its stdout. 
 
Author: 
    Rajivendra Nath (rajnath) 2-Jan-1993 
 
Environment: 
    Console App. User mode. 
 
Revision History: 
Alex Wetmore (t-alexwe) 6-Jun-1994 
- converted remote to use APPC with Windows SNA Server instead of named 
  pipes 
*/ 
 
#include <windows.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <io.h> 
#include <string.h> 
#include <winappc.h> 
#include "appclib.h" 
#include "aremote.h" 
 
tpconvid_t EstablishSession(TCHAR *locallu, TCHAR *serverlu, TCHAR *tpname,  
TCHAR *loctpname, TCHAR *mode_name); 
DWORD WINAPI GetServerOut(PVOID *Noarg); 
DWORD WINAPI SendServerInp(PVOID *Noarg); 
BOOL FilterClientInp(TCHAR *buff, int count); 
BOOL Mych(DWORD ctrlT); 
VOID SendMyInfo(tpconvid_t tpconv); 
 
 
HANDLE iothreads[2]; 
HANDLE MyStdInp; 
HANDLE MyStdOut; 
tpconvid_t tpconv; 
 
 
CONSOLE_SCREEN_BUFFER_INFO csbi; 
 
TCHAR   MyEchoStr[30]; 
BOOL   CmdSent; 
DWORD  LinesToSend=LINESTOSEND; 
 
VOID Client(TCHAR *local_lu, TCHAR *server_lu, TCHAR *tp_name,  
        TCHAR *loc_tp_name, TCHAR *mode_name) { 
    DWORD  tid; 
 
 
    MyStdInp=GetStdHandle(STD_INPUT_HANDLE); 
    MyStdOut=GetStdHandle(STD_OUTPUT_HANDLE); 
 
    WRITEF((VBuff,TEXT("**************************************\n"))); 
    WRITEF((VBuff,TEXT("***********     REMOTE    ************\n"))); 
    WRITEF((VBuff,TEXT("***********     CLIENT    ************\n"))); 
    WRITEF((VBuff,TEXT("**************************************\n"))); 
 
tpconv = EstablishSession(local_lu, server_lu, tp_name, loc_tp_name,  
mode_name); 
if (tpconv == NULL) { 
appcdestroy(); 
return; 
} 
 
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)Mych,TRUE); 
 
    // Start Thread For Server --> Client Flow 
    if ((iothreads[0]=CreateThread((LPSECURITY_ATTRIBUTES)NULL,     // No security attributes. 
            (DWORD)0,                           // Use same stack size. 
            (LPTHREAD_START_ROUTINE)GetServerOut, // Thread procedure. 
            (LPVOID)NULL,              // Parameter to pass. 
            (DWORD)0,                           // Run immediately. 
            (LPDWORD)&tid))==NULL)              // Thread identifier. 
    { 
 
        Errormsg(TEXT("Could Not Create rwSrv2Cl Thread")); 
        return; 
    } 
 
 
 
    // 
    // Start Thread for Client --> Server Flow 
    // 
 
    if ((iothreads[1]=CreateThread((LPSECURITY_ATTRIBUTES)NULL,           // No security attributes. 
                    (DWORD)0,                           // Use same stack size. 
                    (LPTHREAD_START_ROUTINE)SendServerInp, // Thread procedure. 
                    (LPVOID)NULL,          // Parameter to pass. 
                    (DWORD)0,                           // Run immediately. 
                    (LPDWORD)&tid))==NULL)              // Thread identifier. 
    { 
 
        Errormsg(TEXT("Could Not Create rwSrv2Cl Thread")); 
        return; 
    } 
 
    WaitForSingleObject(iothreads[0], INFINITE); 
 
    TerminateThread(iothreads[1],1); 
 
appcclose(tpconv); 
appcdestroy(); 
 
WRITEF((VBuff,TEXT("*** SESSION OVER ***\n"))); 
} 
 
 
DWORD WINAPI GetServerOut(PVOID *Noarg) { 
    TCHAR buffin[1024]; 
    DWORD dread=0,tmp; 
 
while (appcvalid(tpconv)) { 
dread = appcread(tpconv, (void *) buffin, 1000); 
if (dread > 0) { 
if (!WriteConsole(MyStdOut, buffin, dread/2, &tmp, NULL)) 
break; 
} 
} 
    return 1; 
} 
 
DWORD WINAPI SendServerInp(PVOID *Noarg) { 
    TCHAR buff[1000]; 
    DWORD dread; 
    SetLastError(0); 
 
    while(ReadConsole(MyStdInp,buff,999,&dread,NULL)) { 
        if (FilterClientInp(buff, dread)) continue; 
appcwrite(tpconv, (void *) buff, dread * sizeof(TCHAR)); 
    } 
    return 0; 
} 
 
BOOL FilterClientInp(TCHAR *buff, int count) { 
    if (count==0) 
        return(TRUE); 
 
    if (buff[0]==2)  //Adhoc screening of ^B so that i386kd/mipskd 
        return(TRUE);//do not terminate. 
 
    if (buff[0]==COMMANDCHAR) { 
        switch (tolower(buff[1])) { 
        case TEXT('k'): 
        case TEXT('q'): 
            return(FALSE); 
 
        case TEXT('h'): 
            WRITEF((VBuff,TEXT("%cM : Send Message\n"),COMMANDCHAR)); 
            WRITEF((VBuff,TEXT("%cP : Show Popup on Server\n"),COMMANDCHAR)); 
            WRITEF((VBuff,TEXT("%cS : Status of Server\n"),COMMANDCHAR)); 
            WRITEF((VBuff,TEXT("%cQ : Quit client\n"),COMMANDCHAR)); 
            WRITEF((VBuff,TEXT("%cH : This Help\n"),COMMANDCHAR)); 
            return(TRUE); 
 
        default: 
            return(FALSE); 
        } 
 
    } 
    return(FALSE); 
} 
 
 
BOOL Mych(DWORD ctrlT) { 
    TCHAR  c[3]; 
    DWORD send; 
 
    if (ctrlT==CTRL_C_EVENT) { 
c[0] = 3; 
send = 1; 
appcwrite(tpconv, (void *) c, send); 
    } 
    if ((ctrlT==CTRL_BREAK_EVENT) || 
        (ctrlT==CTRL_CLOSE_EVENT) || 
        (ctrlT==CTRL_LOGOFF_EVENT) || 
        (ctrlT==CTRL_SHUTDOWN_EVENT)) { 
c[0] = COMMANDCHAR; 
c[1] = TEXT('q'); 
send = 2; 
appcwrite(tpconv, (void *) c, send); 
    } 
    return(TRUE); 
} 
 
tpconvid_t EstablishSession(TCHAR *local_lu, TCHAR *server_lu, TCHAR *tp_name,  
                            TCHAR *loc_tp_name, TCHAR *mode_name) { 
TCHAR buf[255]; 
tpconvid_t tpconv; 
 
appcinit(); 
WRITEF((VBuff, TEXT("\nClient Connection Information:\n"))); 
WRITEF((VBuff, TEXT("  Local LU       = %ws\n"), local_lu)); 
WRITEF((VBuff, TEXT("  Server LU      = %ws\n"), server_lu)); 
WRITEF((VBuff, TEXT("  Server TP Name = %ws\n"), tp_name)); 
WRITEF((VBuff, TEXT("  Client TP Name = %ws\n"), loc_tp_name)); 
WRITEF((VBuff, TEXT("  Mode Name      = %ws\n"), mode_name)); 
WRITEF((VBuff, TEXT("\n"))); 
WRITEF((VBuff, TEXT("Connecting . . . "))); 
 
// connect to the server 
tpconv = appcconnect(local_lu, server_lu, tp_name, loc_tp_name, mode_name); 
 
// the server will either send us zero bytes (signifying a valid  
// connection), or close our connection.  If it is closed then 
// let the client know 
appcread(tpconv, buf, 255); 
if (!appcvalid(tpconv)) { 
WRITEF((VBuff,  
TEXT("Remote: server doesn't have any available sessions\n"))); 
return NULL; 
} 
if (lstrcmp(buf, REMOTE_INIT_MSG) != 0) { 
WRITEF((VBuff,  
TEXT("Remote: this doesn't seem to be a remote server\n"))); 
return NULL; 
} 
 
WRITEF((VBuff, TEXT("\rConnected        \n\n"))); 
SendMyInfo(tpconv); 
 
return tpconv; 
} 
 
VOID SendMyInfo(tpconvid_t tpconv) { 
    DWORD  hostlen=HOSTNAMELEN-1; 
    DWORD  tmp, BytesToRead; 
    SESSION_STARTUPINFO ssi; 
    SESSION_STARTREPLY  ssr; 
    TCHAR   *buff; 
 
// fill out the SESSION_STARTUPINFO structure 
    ssi.MagicNumber = MAGICNUMBER; 
    GetComputerName((TCHAR *) ssi.ClientName, &hostlen); 
    ssi.LinesToSend = LinesToSend; 
    ssi.Flag = ClientToServerFlag; 
appcwrite(tpconv, (void *) &ssi, sizeof(ssi)); 
 
// receive a SESSION_STARTUPREPLY structure 
appcread(tpconv, (void *) &ssr, sizeof(ssr)); 
 
if (ssr.MagicNumber < MAGICNUMBER) { 
WRITEF((VBuff, TEXT("Warning: this APPC Remote server is older than your client\n"))); 
} else if (ssr.MagicNumber > MAGICNUMBER) { 
WRITEF((VBuff, TEXT("Warning: your APPC Remote client is older than the server \n"))); 
} 
 
    BytesToRead=MINIMUM(ssr.FileSize,ssi.LinesToSend*CHARS_PER_LINE); 
    buff=calloc(BytesToRead+1,sizeof(TCHAR)); 
    if (buff!=NULL) 
    { 
        DWORD  bytesread=0; 
 
        bytesread = appcread(tpconv, (void *) buff, BytesToRead*sizeof(TCHAR)); 
 
        WriteConsole(MyStdOut,buff,bytesread/sizeof(TCHAR),&tmp,NULL); 
        LocalFree(buff); 
    } 
 
}