Fixed fzip's extracting of nested folders, added --logging-allocator option to leak.
// RemoteConsole.cpp
//
// Copyright (c) 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Accenture - Initial contribution
//
#include "Misc.h"
#include "stdafx.h"
#include <commdlg.h>
#include "console_host.h"
#include "RemoteConsole.h"
#include "ConsoleWindow.h"
LPCTSTR KWindowClassName = TEXT("RemoteConsoleWindowClass");
LPCTSTR KRemoteConsoleName = TEXT("Remote Console");
LPCTSTR KRemoteConsoleCommandReaderName = TEXT("Remote Console Command Reader");
bool CRemoteConsole::sWindowClassRegistered = FALSE;
int CRemoteConsole::sNextId = 1;
CRemoteConsole* CRemoteConsole::sFirst = NULL;
CRemoteConsole* CRemoteConsole::sLast = NULL;
CRemoteConsole* CRemoteConsole::Instance(int aId)
{
CRemoteConsole* console = sFirst;
bool found(0);
while (console && !found)
{
if (console->iId == aId)
{
found = 1;
}
else
{
console = console->iNext;
}
}
if (found)
{
return console;
}
return NULL;
}
CRemoteConsole* CRemoteConsole::New(HINSTANCE aAppHandle, CSocketCommandReader& aCommandReader, LPCTSTR aTitle, int aWidth, int aHeight, TPreferences& aPreferences)
{
std::auto_ptr<CRemoteConsole> self(new(EThrow) CRemoteConsole(aCommandReader, aPreferences));
self->Construct(aAppHandle, aTitle, aWidth, aHeight);
return self.release();
}
CRemoteConsole::~CRemoteConsole()
{
iConsole->StopCaptureToFile();
delete iCommandReader;
delete iKeyEventSocket;
delete iConsole;
if (sLast == this)
{
ASSERT(iNext == NULL);
sLast = iPrevious;
}
if (sFirst == this)
{
sFirst = iNext;
}
if (iPrevious)
{
iPrevious->iNext = iNext;
}
if (iNext)
{
iNext->iPrevious = iPrevious;
}
}
int CRemoteConsole::Id() const
{
return iId;
}
void CRemoteConsole::AttachKeyEventSocket(CClientSocket& aSocket)
{
ASSERT(iKeyEventSocket == NULL);
iKeyEventSocket = &aSocket;
iKeyEventSocket->SetClosureObserver(this);
}
CRemoteConsole::CRemoteConsole(CSocketCommandReader& aCommandReader, TPreferences& aPreferences)
: iId(sNextId++), iCommandReader(&aCommandReader), iKeyEventSocket(NULL), iNext(NULL), iPrevious(NULL), iClosing(FALSE), iPreferences(aPreferences)
{
if (sFirst == NULL)
{
ASSERT(sLast == NULL);
sFirst = this;
sLast = this;
}
else
{
sLast->iNext = this;
iPrevious = sLast;
sLast = this;
}
}
void CRemoteConsole::Construct(HINSTANCE aAppHandle, LPCTSTR aTitle, int aWidth, int aHeight)
{
if (!sWindowClassRegistered)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = (WNDPROC)CWindow::HandleMessage;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = aAppHandle;
wcex.hIcon = LoadIcon(aAppHandle, (LPCTSTR)IDI_CONSOLE_HOST);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = (LPCTSTR)ID_REMOTE_CONSOLE_MENU;
wcex.lpszClassName = KWindowClassName;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
if (RegisterClassEx(&wcex) == 0)
{
throw KExceptionWindowClassRegistrationFailed;
}
sWindowClassRegistered = TRUE;
}
int posX = CW_USEDEFAULT;
int posY = CW_USEDEFAULT;
if (!iPreferences.SystemPositionedWindows())
{
posX = iPreferences.DefaultWindowPosX();
posY = iPreferences.DefaultWindowPosY();
}
iConsole = CConsoleWindow::New(aAppHandle, KWindowClassName, aTitle, posX, posY, (aWidth == -1) ? iPreferences.DefaultWindowWidth() : aWidth, (aHeight == -1) ? iPreferences.DefaultWindowHeight() : aHeight, iPreferences.NumOverflowLines(), this, this, FALSE);
iConsole->SetName(KRemoteConsoleName);
iCommandReader->ChangeHandler(*this);
iCommandReader->SetName(KRemoteConsoleCommandReaderName);
iCommandReader->ReadCommand();
}
void CRemoteConsole::HandleSocketClosure(CSocket& aSocket)
{
if (!iClosing)
{
iConsole->SetTitle(TEXT("Remote console closed - press any key to close window"));
iConsole->SetDimmed(TRUE);
iClosing = TRUE;
}
}
void CRemoteConsole::HandleWindowClosure(CWindow&)
{
delete this;
}
LRESULT CRemoteConsole::HandleWindowCommand(UINT aMessage, WPARAM aWParam, LPARAM aLParam)
{
switch (LOWORD(aWParam))
{
case ID_RC_CAPTURE:
{
UINT checkMenuItem = MF_BYCOMMAND | MF_UNCHECKED;
if (iConsole->IsCapturingToFile())
{
iConsole->StopCaptureToFile();
}
else
{
TCHAR captureFileName[MAX_PATH];
if (GetCaptureFileName(captureFileName))
{
iConsole->CaptureToFile(captureFileName);
checkMenuItem = MF_BYCOMMAND | MF_CHECKED;
}
}
CheckMenuItem(GetMenu(iConsole->Handle()), ID_RC_CAPTURE, checkMenuItem);
break;
}
case ID_RC_CLOSE:
{
DestroyWindow(iConsole->Handle());
break;
}
case ID_EDIT_COPY:
{
iConsole->CopyToClipboard();
break;
}
case ID_EDIT_PASTE:
{
iConsole->PasteFromClipboard();
break;
}
default:
{
return DefWindowProc(iConsole->Handle(), aMessage, aWParam, aLParam);
}
}
return 0;
}
class TKeyEvent
{
public:
TCHAR iChar;
UINT iModifiers;
};
void CRemoteConsole::HandleConsoleChar(TCHAR aChar, UINT aModifiers)
{
if (iClosing)
{
DestroyWindow(iConsole->Handle());
}
else if (iKeyEventSocket)
{
TKeyEvent keyEvent;
keyEvent.iChar = aChar;
keyEvent.iModifiers = aModifiers;
iKeyEventSocket->Write((char*)&keyEvent, sizeof(TKeyEvent));
}
}
void CRemoteConsole::HandleConsoleString(LPCTSTR aString, int aLength)
{
if (iClosing)
{
DestroyWindow(iConsole->Handle());
}
else if (iKeyEventSocket)
{
for (int i = 0; i < aLength; ++i)
{
HandleConsoleChar(*(aString + i), 0);
}
}
}
void CRemoteConsole::HandleSocketCommand(TPacketHeader::TPacketType aCommand, const char* aPacket, int aPacketLength, CSocketCommandReader& aReader)
{
ASSERT(&aReader == iCommandReader);
switch (aCommand)
{
case TPacketHeader::ECommandWrite:
{
const int* toWriteLength = new((char*)aPacket) int;
LPTSTR toWrite = (TCHAR*)(aPacket + sizeof(int));
iConsole->Write(toWrite, *toWriteLength);
break;
}
case TPacketHeader::ECommandGetCursorPos:
{
class TPos
{
public:
int iX;
int iY;
};
TPos pos;
iConsole->GetCursorPos(pos.iX, pos.iY);
iCommandReader->SendResponse((char*)&pos, sizeof(TPos));
break;
}
case TPacketHeader::ECommandSetAbsCursorPos:
{
const int* x = new((char*)aPacket) int;
const int* y = new(((char*)aPacket) + sizeof(int)) int;
iConsole->SetAbsCursorPos(*x, *y);
break;
}
case TPacketHeader::ECommandSetRelCursorPos:
{
const int* x = new((char*)aPacket) int;
const int* y = new(((char*)aPacket) + sizeof(int)) int;
iConsole->SetRelCursorPos(*x, *y);
break;
}
case TPacketHeader::ECommandSetCursorHeight:
{
const int* height = new((char*)aPacket) int;
iConsole->SetCursorHeight(*height);
break;
}
case TPacketHeader::ECommandGetScreenSize:
{
class TSize
{
public:
int iWidth;
int iHeight;
};
TSize size;
iConsole->GetConsoleSize(size.iWidth, size.iHeight);
iCommandReader->SendResponse((char*)&size, sizeof(TSize));
break;
}
case TPacketHeader::ECommandSetTitle:
{
iConsole->SetTitle((TCHAR*)aPacket);
break;
}
case TPacketHeader::ECommandClearScreen:
{
iConsole->ClearScreen();
break;
}
case TPacketHeader::ECommandClearToEndOfLine:
{
iConsole->ClearToEndOfLine();
break;
}
default:
{
// Unknown command - do nothing.
}
}
iCommandReader->ReadCommand();
}
void CRemoteConsole::HandleSocketClosure(CSocketCommandReader& aReader)
{
HandleSocketClosure(aReader.Socket());
}
bool CRemoteConsole::GetCaptureFileName(LPTSTR aFileName) const
{
GetDefaultCaptureFileName(aFileName);
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = iConsole->Handle();
ofn.lpstrFile = aFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFilter = TEXT("All\0*.*\0Text\0*.TXT\0");
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
ofn.lpstrTitle = TEXT("Capture to");
bool ok = !(GetSaveFileName(&ofn) == 0);
if (ok)
{
if (FileExists(aFileName))
{
LPCTSTR constErrorText = TEXT(" already exists. Overwrite it?");
std::auto_ptr<TCHAR> errorText(new(EThrow) TCHAR[wcslen(aFileName) + wcslen(constErrorText) + 1]);
wcscpy(errorText.get(), aFileName);
wcscat(errorText.get(), constErrorText);
if (MessageBox(iConsole->Handle(), errorText.get(), TEXT("Warning"), MB_OKCANCEL | MB_ICONWARNING) == IDOK)
{
if (DeleteFile(aFileName) <= 0)
{
throw KExceptionFailedToDeleteExistingCaptureFile;
}
}
else
{
ok = FALSE;
}
}
}
if (ok)
{
SetDefaultCaptureFilePath(aFileName);
}
return ok;
}
void CRemoteConsole::GetDefaultCaptureFileName(LPTSTR aFileName) const
{
TCHAR formatString[MAX_PATH];
wcscpy(formatString, iPreferences.DefaultCaptureFilePath());
TCHAR windowTitle[MAX_PATH];
iConsole->GetTitle(windowTitle, MAX_PATH);
if (wcslen(formatString) + wcslen(windowTitle) + 10 > MAX_PATH) // + 10 for the '_%03d.txt\0'.
{
wcscpy(formatString, TEXT("c:\\"));
}
wcscat(formatString, windowTitle);
wcscat(formatString, TEXT("_%03d.txt"));
int i = 1;
bool uniqueNameFound(FALSE);
do
{
_snwprintf(aFileName, MAX_PATH, formatString, i++);
if (!FileExists(aFileName))
{
uniqueNameFound = TRUE;
}
}
while (!uniqueNameFound);
}
void CRemoteConsole::SetDefaultCaptureFilePath(LPCTSTR aFileName) const
{
int pathLength;
for (pathLength = wcslen(aFileName) - 1; (pathLength > 0) && (aFileName[pathLength - 1] != TCHAR('\\')); --pathLength);
TCHAR path[MAX_PATH];
wcsncpy(path, aFileName, pathLength);
*(path + pathLength) = CHAR('\0');
iPreferences.SetDefaultCaptureFilePath(path);
iPreferences.Write();
}