2397 lines
87 KiB
C++
2397 lines
87 KiB
C++
// $Id: MySession.cpp 705 2012-03-16 13:01:13Z felfert $
|
|
//
|
|
// Copyright (C) 2006 The OpenNX Team
|
|
// Author: Fritz Elfert
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Library General Public License as
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Library General Public
|
|
// License along with this program; if not, write to the
|
|
// Free Software Foundation, Inc.,
|
|
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
//
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#if defined(__GNUG__) && !defined(__APPLE__)
|
|
#pragma implementation "SessionList.h"
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#include "CardWaiterDialog.h"
|
|
#include "ConnectDialog.h"
|
|
#include "MySession.h"
|
|
#include "MyXmlConfig.h"
|
|
#include "MyIPC.h"
|
|
#include "ResumeDialog.h"
|
|
#include "WinShare.h"
|
|
#include "opennxApp.h"
|
|
#include "osdep.h"
|
|
#include "pwcrypt.h"
|
|
#include "ProxyPasswordDialog.h"
|
|
#include "SimpleXauth.h"
|
|
#include "Icon.h"
|
|
#include "SupressibleMessageDialog.h"
|
|
#include "PulseAudio.h"
|
|
|
|
#include <wx/filename.h>
|
|
#include <wx/regex.h>
|
|
#include <wx/wfstream.h>
|
|
#include <wx/txtstrm.h>
|
|
#include <wx/socket.h>
|
|
#include <wx/config.h>
|
|
#include <wx/utils.h>
|
|
#include <wx/tokenzr.h>
|
|
#include <wx/regex.h>
|
|
#include <wx/protocol/http.h>
|
|
#include <wx/sckstrm.h>
|
|
#include <wx/dir.h>
|
|
#include <wx/process.h>
|
|
#include <wx/textfile.h>
|
|
#ifdef __VISUALC__
|
|
# include <fstream.h>
|
|
#else
|
|
# include <fstream>
|
|
#endif
|
|
#ifndef __WXMSW__
|
|
# include <grp.h>
|
|
#endif
|
|
|
|
#ifdef __UNIX__
|
|
# include <X11/Xauth.h>
|
|
#endif
|
|
|
|
#include "trace.h"
|
|
ENABLE_TRACE;
|
|
|
|
static const int CUPS_PORT_OFFSET = 2000;
|
|
static const int SMB_PORT_OFFSET = 3000;
|
|
static const int PROXY_PORT_OFFSET = 4000;
|
|
static const int X_PORT_OFFSET = 6000;
|
|
static const int SOUND_PORT_OFFSET = 7000;
|
|
static const int KBD_PORT_OFFSET = 8000;
|
|
static const int HTTP_PORT_OFFSET = 9000;
|
|
static const int USBIP_PORT_OFFSET = 40000;
|
|
|
|
#define X11ARCH_NONE 0
|
|
#define X11ARCH_CYGWIN 1
|
|
#define X11ARCH_MINGW 2
|
|
|
|
#ifdef __WXMSW__
|
|
wxString cygPath(const wxString &dir, const wxString &file = wxEmptyString)
|
|
{
|
|
wxFileName fn(dir);
|
|
wxString ret = wxT("/cygdrive/");
|
|
ret += fn.GetVolume().Lower();
|
|
ret += fn.GetShortPath().AfterFirst(wxT(':'));
|
|
if (!file.IsEmpty())
|
|
ret << wxT("\\") << file;
|
|
ret.Replace(wxT("\\"), wxT("/"));
|
|
return ret;
|
|
}
|
|
|
|
class FontpathTraverser : public wxDirTraverser
|
|
{
|
|
public:
|
|
wxString GetFontPath(MySession::tXarch x11arch)
|
|
{
|
|
switch (x11arch) {
|
|
case MySession::XARCH_CYGWIN:
|
|
return m_sFontPathCygwin;
|
|
break;
|
|
case MySession::XARCH_XMING:
|
|
return m_sFontPath;
|
|
break;
|
|
default:
|
|
wxLogError(_("Invalid X11 server platform"));
|
|
break;
|
|
}
|
|
return wxEmptyString;
|
|
}
|
|
|
|
virtual wxDirTraverseResult OnFile(const wxString& WXUNUSED(filename))
|
|
{
|
|
return wxDIR_CONTINUE;
|
|
}
|
|
|
|
virtual wxDirTraverseResult OnDir(const wxString& dirname)
|
|
{
|
|
if (!m_sFontPath.IsEmpty())
|
|
m_sFontPath += wxT(",");
|
|
m_sFontPath += dirname;
|
|
if (!m_sFontPathCygwin.IsEmpty())
|
|
m_sFontPathCygwin += wxT(",");
|
|
m_sFontPathCygwin += cygPath(dirname);
|
|
return wxDIR_IGNORE;
|
|
}
|
|
|
|
private:
|
|
wxString m_sFontPath;
|
|
wxString m_sFontPathCygwin;
|
|
|
|
};
|
|
|
|
#else
|
|
wxString cygPath(const wxString &path)
|
|
{
|
|
return wxFileName(path).GetFullPath();
|
|
}
|
|
|
|
wxString cygPath(const wxString &dir, const wxString &file)
|
|
{
|
|
return wxFileName(dir, file).GetFullPath();
|
|
}
|
|
#endif
|
|
|
|
class RunLog : public wxLogChain
|
|
{
|
|
public:
|
|
RunLog(wxLog *logger) :wxLogChain(logger) { SetVerbose(true); }
|
|
|
|
void DoLogRecord(wxLogLevel level, const wxString & szString, const wxLogRecordInfo & info)
|
|
{
|
|
PassMessages(level <= minlevel);
|
|
wxLogChain::DoLogRecord((level > minlevel) ? minlevel : level, szString, info);
|
|
}
|
|
private:
|
|
static const wxLogLevel minlevel = wxLOG_Message;
|
|
};
|
|
|
|
class SessionCleaner : public wxDirTraverser
|
|
{
|
|
public:
|
|
SessionCleaner(const wxString &toplevel)
|
|
{
|
|
m_sTopLevel = toplevel;
|
|
wxString s = wxFileName::GetPathSeparator();
|
|
if (!toplevel.EndsWith(s))
|
|
m_sTopLevel += s;
|
|
wxString r = m_sTopLevel + wxT("temp") + s + wxT("([0-9]+)");
|
|
r.Replace(wxT("\\"), wxT("\\\\"));
|
|
m_cRegex.Compile(r, wxRE_ADVANCED);
|
|
wxASSERT(m_cRegex.IsValid());
|
|
}
|
|
|
|
~SessionCleaner()
|
|
{
|
|
wxLogNull nolog;
|
|
int n = m_aFiles.GetCount() - 1;
|
|
while (n >= 0)
|
|
::wxRemoveFile(m_aFiles[n--]);
|
|
n = m_aDirs.GetCount() - 1;
|
|
while (n >= 0)
|
|
::wxRmdir(m_aDirs[n--]);
|
|
}
|
|
|
|
virtual wxDirTraverseResult OnFile(const wxString &name)
|
|
{
|
|
for (size_t i = 0; i < m_aDirs.GetCount(); i++) {
|
|
if (name.StartsWith(m_aDirs[i])) {
|
|
myLogTrace(MYTRACETAG, wxT("adding file '%s'"), VMB(name));
|
|
m_aFiles.Add(name);
|
|
return wxDIR_CONTINUE;
|
|
}
|
|
}
|
|
return wxDIR_CONTINUE;
|
|
}
|
|
|
|
virtual wxDirTraverseResult OnDir(const wxString &name)
|
|
{
|
|
if (name.StartsWith(m_sTopLevel + wxT("S-"))) {
|
|
myLogTrace(MYTRACETAG, wxT("Session dir: '%s'"), VMB(name));
|
|
wxTextFile tf(name + wxFileName::GetPathSeparator() + wxT("session"));
|
|
if (tf.Exists()) {
|
|
wxString line;
|
|
if (tf.Open()) {
|
|
for (line = tf.GetFirstLine(); !tf.Eof(); line = tf.GetNextLine()) {
|
|
if (line.Contains(wxT("mode with pid"))) {
|
|
long pid;
|
|
line.AfterFirst(wxT('\'')).BeforeLast(wxT('\'')).ToLong(&pid);
|
|
myLogTrace(MYTRACETAG, wxT("Proxy-PID: %d"), (int)pid);
|
|
if (!wxProcess::Exists(pid)) {
|
|
myLogTrace(MYTRACETAG, wxT("PID does not exist, adding '%s'"),
|
|
VMB(name));
|
|
m_aDirs.Add(name);
|
|
return wxDIR_CONTINUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("Keeping '%s'"), VMB(name));
|
|
}
|
|
if (name.StartsWith(m_sTopLevel + wxT("D-"))) {
|
|
myLogTrace(MYTRACETAG, wxT("Service dir: '%s'"), VMB(name));
|
|
wxTextFile tf(name + wxFileName::GetPathSeparator() + wxT("pid"));
|
|
if (tf.Exists()) {
|
|
long pid;
|
|
if (tf.Open()) {
|
|
tf.GetFirstLine().ToLong(&pid);
|
|
myLogTrace(MYTRACETAG, wxT("Service-PID: %d"), (int)pid);
|
|
if (!wxProcess::Exists(pid)) {
|
|
myLogTrace(MYTRACETAG, wxT("PID does not exist, adding '%s'"), VMB(name));
|
|
m_aDirs.Add(name);
|
|
return wxDIR_CONTINUE;
|
|
}
|
|
}
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("Keeping '%s'"), VMB(name));
|
|
}
|
|
if (name.StartsWith(m_sTopLevel + wxT("F-"))) {
|
|
myLogTrace(MYTRACETAG, wxT("Failed session dir: '%s'"), VMB(name));
|
|
m_aDirs.Add(name);
|
|
return wxDIR_CONTINUE;
|
|
}
|
|
if (m_cRegex.Matches(name)) {
|
|
myLogTrace(MYTRACETAG, wxT("Temp dir: '%s'"), VMB(name));
|
|
long mpid = 0;
|
|
long spid = 0;
|
|
m_cRegex.GetMatch(name, 1).ToLong(&mpid);
|
|
myLogTrace(MYTRACETAG, wxT("Main PID: %d"), (int)mpid);
|
|
wxTextFile tf(name + wxFileName::GetPathSeparator() + wxT("sshlog"));
|
|
if (tf.Exists()) {
|
|
if (tf.Open()) {
|
|
wxString line = tf.GetFirstLine();
|
|
line.AfterLast(wxT(':')).Strip(wxString::both).ToLong(&spid);
|
|
myLogTrace(MYTRACETAG, wxT("Ssh-PID: %d"), (int)spid);
|
|
}
|
|
}
|
|
if (mpid && (!wxProcess::Exists(mpid)) && ((!spid) || (!wxProcess::Exists(spid)))) {
|
|
myLogTrace(MYTRACETAG, wxT("PIDs do not exist, adding '%s'"), VMB(name));
|
|
m_aDirs.Add(name);
|
|
return wxDIR_CONTINUE;
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("Keeping '%s'"), VMB(name));
|
|
return wxDIR_IGNORE;
|
|
}
|
|
if (name.StartsWith(m_sTopLevel + wxT("temp")))
|
|
return wxDIR_CONTINUE;
|
|
return wxDIR_IGNORE;
|
|
}
|
|
|
|
private:
|
|
wxArrayString m_aDirs;
|
|
wxArrayString m_aFiles;
|
|
wxString m_sTopLevel;
|
|
wxRegEx m_cRegex;
|
|
};
|
|
|
|
DECLARE_EVENT_TYPE(wxEVT_SESSION, -6);
|
|
DEFINE_EVENT_TYPE(wxEVT_SESSION);
|
|
|
|
/**
|
|
* This class is a helper for watching a file until a specific
|
|
* string has appeared in it. When found, it triggers an event.
|
|
*/
|
|
class SessionWatch : public wxThreadHelper
|
|
{
|
|
public:
|
|
SessionWatch(wxEvtHandler *handler, const wxString &logfile, const wxString &search)
|
|
: wxThreadHelper()
|
|
{
|
|
m_pHandler = handler;
|
|
m_sLog = logfile;
|
|
m_sSearch = search;
|
|
if (CreateThread() == wxTHREAD_NO_ERROR)
|
|
GetThread()->Run();
|
|
}
|
|
|
|
private:
|
|
virtual wxThread::ExitCode Entry() {
|
|
wxStopWatch sw;
|
|
wxTextFile tf(m_sLog);
|
|
long timeout = 5000;
|
|
bool bFound = false;
|
|
while ((!bFound) && (sw.Time() < timeout)) {
|
|
if (tf.Exists()) {
|
|
if (timeout == 5000)
|
|
timeout = sw.Time() + 10000;
|
|
if (!tf.Open())
|
|
break;
|
|
wxString line;
|
|
for (line = tf.GetFirstLine(); !tf.Eof(); line = tf.GetNextLine()) {
|
|
if (line.Contains(m_sSearch)) {
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
tf.Close();
|
|
}
|
|
wxThread::Sleep(500);
|
|
}
|
|
if (m_pHandler) {
|
|
wxCommandEvent upevent(wxEVT_SESSION, wxID_ANY);
|
|
upevent.SetInt(bFound ? 1 : 0);
|
|
m_pHandler->AddPendingEvent(upevent);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
wxEvtHandler *m_pHandler;
|
|
wxString m_sLog;
|
|
wxString m_sSearch;
|
|
};
|
|
|
|
/**
|
|
* Our specialization of wxHTTP. Needed, because wxHTTP stops
|
|
* parsing headers when recognizing an error status header (4xx, 5xx ...)
|
|
* but we want it to continue parsing in order to get the Server: header.
|
|
*/
|
|
class MyHTTP : public wxHTTP {
|
|
public:
|
|
MyHTTP() : wxHTTP() {}
|
|
wxInputStream *GetInputStream(const wxString& path)
|
|
{
|
|
wxSocketInputStream *inp_stream;
|
|
wxString new_path;
|
|
m_lastError = wxPROTO_CONNERR;
|
|
if (!m_addr)
|
|
return NULL;
|
|
|
|
// We set m_connected back to false so wxSocketBase will know what to do.
|
|
#ifdef __WXMAC__
|
|
wxSocketClient::Connect(*m_addr , false );
|
|
wxSocketClient::WaitOnConnect(10);
|
|
|
|
if (!wxSocketClient::IsConnected())
|
|
return NULL;
|
|
#else
|
|
if (!wxProtocol::Connect(*m_addr))
|
|
return NULL;
|
|
#endif
|
|
|
|
if (!BuildRequest(path, m_postBuffer.IsEmpty() ? wxT("GET") : wxT("POST")))
|
|
return NULL;
|
|
|
|
inp_stream = new wxSocketInputStream(*this);
|
|
|
|
Notify(false);
|
|
SetFlags(wxSOCKET_BLOCK | wxSOCKET_WAITALL);
|
|
|
|
return inp_stream;
|
|
}
|
|
|
|
protected:
|
|
bool BuildRequest(const wxString& path, const wxString& method)
|
|
{
|
|
bool ret = wxHTTP::BuildRequest(path, method);
|
|
myLogTrace(MYTRACETAG, wxT("calling ParseHeaders()"));
|
|
ParseHeaders();
|
|
return ret;
|
|
}
|
|
|
|
};
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(MySession, wxEvtHandler);
|
|
|
|
BEGIN_EVENT_TABLE(MySession, wxEvtHandler)
|
|
EVT_COMMAND(wxID_ANY, wxEVT_NXSSH, MySession::OnSshEvent)
|
|
EVT_COMMAND(wxID_ANY, wxEVT_SESSION, MySession::OnSessionEvent)
|
|
END_EVENT_TABLE();
|
|
|
|
MySession::MySession(wxString dir, wxString status, wxString stype, wxString host, int port, wxString md5)
|
|
: wxEvtHandler()
|
|
, m_pSshLog(NULL)
|
|
, m_pNxSsh(NULL)
|
|
, m_pCfg(NULL)
|
|
, m_pDlg(NULL)
|
|
, m_pParent(NULL)
|
|
, m_pSessionWatch(NULL)
|
|
, m_bTouched(true)
|
|
, m_iPort(port)
|
|
, m_lPid(0)
|
|
, m_eSessionType(None)
|
|
, m_eSessionStatus(Unknown)
|
|
, m_sHost(host)
|
|
, m_sMd5(md5)
|
|
, m_sDir(dir)
|
|
{
|
|
m_bValid = false;
|
|
if (stype == wxT("C"))
|
|
m_eSessionType = Server;
|
|
if (stype == wxT("S"))
|
|
m_eSessionType = Client;
|
|
|
|
if (status == wxT("T"))
|
|
m_eSessionStatus = Terminated;
|
|
if (status == wxT("F"))
|
|
m_eSessionStatus = Failed;
|
|
|
|
m_rePID.Compile(wxT("([[:digit:]]+)"));
|
|
initversion();
|
|
|
|
CheckState();
|
|
}
|
|
|
|
MySession::MySession(const MySession &src)
|
|
: wxEvtHandler()
|
|
, m_pSshLog(NULL)
|
|
, m_pNxSsh(NULL)
|
|
, m_pCfg(NULL)
|
|
, m_pDlg(NULL)
|
|
, m_pParent(NULL)
|
|
, m_pSessionWatch(NULL)
|
|
{
|
|
m_sHost = src.m_sHost;
|
|
m_iPort = src.m_iPort;
|
|
m_lPid = src.m_lPid;
|
|
m_sMd5 = src.m_sMd5;
|
|
m_eSessionType = src.m_eSessionType;
|
|
m_eSessionStatus = src.m_eSessionStatus;
|
|
m_sDir = src.m_sDir;
|
|
m_bTouched = src.m_bTouched;
|
|
m_rePID.Compile(wxT("([[:digit:]]+)"));
|
|
m_iReader = src.m_iReader;
|
|
m_lProtocolVersion = src.m_lProtocolVersion;
|
|
m_lSrvProtocolVersion = src.m_lSrvProtocolVersion;
|
|
m_sProtocolVersion = src.m_sProtocolVersion;
|
|
}
|
|
|
|
MySession::MySession()
|
|
: wxEvtHandler()
|
|
, m_pSshLog(NULL)
|
|
, m_pNxSsh(NULL)
|
|
, m_pCfg(NULL)
|
|
, m_pDlg(NULL)
|
|
, m_pParent(NULL)
|
|
, m_pSessionWatch(NULL)
|
|
{
|
|
m_iReader = -1;
|
|
initversion();
|
|
}
|
|
|
|
MySession & MySession::operator =(const MySession &src)
|
|
{
|
|
m_pSshLog = NULL;
|
|
m_pCfg = NULL;
|
|
m_pDlg = NULL;
|
|
m_pNxSsh = NULL;
|
|
m_pParent = NULL;
|
|
m_pSessionWatch = NULL;
|
|
m_sHost = src.m_sHost;
|
|
m_iPort = src.m_iPort;
|
|
m_lPid = src.m_lPid;
|
|
m_iReader = src.m_iReader;
|
|
m_sMd5 = src.m_sMd5;
|
|
m_eSessionType = src.m_eSessionType;
|
|
m_eSessionStatus = src.m_eSessionStatus;
|
|
m_sDir = src.m_sDir;
|
|
m_bTouched = src.m_bTouched;
|
|
m_rePID.Compile(wxT("([[:digit:]]+)"));
|
|
m_lProtocolVersion = src.m_lProtocolVersion;
|
|
m_lSrvProtocolVersion = src.m_lSrvProtocolVersion;
|
|
m_sProtocolVersion = src.m_sProtocolVersion;
|
|
return *this;
|
|
}
|
|
|
|
MySession::~MySession()
|
|
{
|
|
myLogTrace(MYTRACETAG, wxT("~MySession"));
|
|
if (m_pSshLog) {
|
|
m_pSshLog->Flush();
|
|
delete m_pSshLog;
|
|
}
|
|
m_pSshLog = NULL;
|
|
if (m_pSessionWatch) {
|
|
delete m_pSessionWatch;
|
|
m_pSessionWatch = NULL;
|
|
}
|
|
wxLog *l = wxLog::SetActiveTarget(NULL);
|
|
if (l)
|
|
delete l;
|
|
}
|
|
|
|
wxString
|
|
MySession::sGetCreationTime()
|
|
{
|
|
wxString ret(_("unknown"));
|
|
if (m_bValid) {
|
|
wxLogNull l;
|
|
wxDateTime ctime;
|
|
wxFileName fn(m_sDir, wxT("session"));
|
|
if (fn.GetTimes(NULL, NULL, &ctime)) {
|
|
ret = ctime.Format();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
wxString
|
|
MySession::sGetSessionStatus()
|
|
{
|
|
switch (m_eSessionStatus) {
|
|
case Terminated:
|
|
return _("terminated");
|
|
break;
|
|
case Failed:
|
|
return _("failed");
|
|
break;
|
|
case Running:
|
|
return _("running");
|
|
break;
|
|
case Unknown:
|
|
return _("unknown");
|
|
break;
|
|
}
|
|
return _("unknown");
|
|
}
|
|
|
|
wxString
|
|
MySession::sGetSessionType()
|
|
{
|
|
switch (m_eSessionType) {
|
|
case Server:
|
|
return _("Server");
|
|
break;
|
|
case Client:
|
|
return _("Client");
|
|
break;
|
|
case None:
|
|
return _("Unknown");
|
|
break;
|
|
}
|
|
return _("Unknown");
|
|
}
|
|
|
|
bool
|
|
MySession::bGetPidFromFile()
|
|
{
|
|
m_lPid = 0;
|
|
if (!m_bValid)
|
|
return false;
|
|
wxFileInputStream input(m_sDir + wxFileName::GetPathSeparator() + wxT("session"));
|
|
wxTextInputStream text(input);
|
|
int cnt = 0;
|
|
|
|
while ((!input.Eof()) && (cnt < 100)) {
|
|
wxString line = text.ReadLine();
|
|
int idx = line.Find(wxT("pid"));
|
|
|
|
if (idx != wxNOT_FOUND &&
|
|
(!(line.Contains(wxT("NXAGENT")) || line.Contains(wxT("Agent")))))
|
|
{
|
|
line = line.Mid(idx + 4);
|
|
if (m_rePID.Matches(line))
|
|
m_rePID.GetMatch(line, 1).ToLong(&m_lPid);
|
|
}
|
|
cnt++;
|
|
}
|
|
return (m_lPid > 0);
|
|
}
|
|
|
|
void
|
|
MySession::CheckState()
|
|
{
|
|
wxString logfilename = m_sDir + wxFileName::GetPathSeparator() + wxT("session");
|
|
m_eSessionStatus = Unknown;
|
|
|
|
if (!wxFile::Exists(logfilename))
|
|
return;
|
|
if ((m_eSessionStatus == Terminated) || (m_eSessionStatus == Failed))
|
|
return;
|
|
|
|
wxFile fi(logfilename);
|
|
if (!fi.IsOpened())
|
|
return;
|
|
|
|
m_bValid = true;
|
|
wxFileInputStream input(fi);
|
|
|
|
wxTextInputStream text(input);
|
|
while (!input.Eof()) {
|
|
wxString line = text.ReadLine();
|
|
if (line.StartsWith(wxT("Session: Session terminated"))) {
|
|
m_eSessionStatus = Terminated;
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (bGetPidFromFile()) {
|
|
if (wxProcess::Exists(m_lPid))
|
|
m_eSessionStatus = Running;
|
|
}
|
|
}
|
|
|
|
unsigned short
|
|
MySession::getFirstFreePort(unsigned short startPort)
|
|
{
|
|
#ifdef __WXMAC__
|
|
// wxSocketServer appears to be broken on wxMac,
|
|
// so we use plain unix code, implemented in osdep.c ...
|
|
return macFirstFreePort(startPort);
|
|
#else
|
|
unsigned short port = startPort;
|
|
wxIPV4address a;
|
|
|
|
a.LocalHost();
|
|
while (port < 65535) {
|
|
a.Service(port);
|
|
wxSocketServer ss(a);
|
|
if (ss.Ok())
|
|
return port;
|
|
port++;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
wxString
|
|
MySession::getXauthCookie(int display /* = 0 */, wxString proto)
|
|
{
|
|
|
|
#ifdef __UNIX__
|
|
wxString dpy;
|
|
wxString ret;
|
|
if (wxGetEnv(wxT("DISPLAY"), &dpy) && (!dpy.IsEmpty())) {
|
|
wxString dpyNr = dpy.AfterFirst(wxT(':'));
|
|
const char *fn = XauFileName();
|
|
FILE *f = fopen(fn, "r");
|
|
if (f) {
|
|
Xauth *auth = NULL;
|
|
// Fetch the first entry of FamilyLocal and a matching display number
|
|
while (ret.IsEmpty() && (NULL != (auth = XauReadAuth(f)))) {
|
|
if (FamilyLocal == auth->family) {
|
|
wxString edpy((const char *)auth->number, *wxConvCurrent, auth->number_length);
|
|
if (edpy.IsSameAs(dpyNr)) {
|
|
int i;
|
|
for (i = 0; i < auth->data_length; ++i) {
|
|
ret.Append(wxString::Format(wxT("%02x"), auth->data[i] & 0xff));
|
|
}
|
|
}
|
|
}
|
|
XauDisposeAuth(auth);
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
return ret;
|
|
#endif
|
|
#ifdef __WXMSW__
|
|
// On windows we *create* the cookie instead
|
|
SimpleXauth xa(getXauthPath());
|
|
xa.AddDisplay(display);
|
|
return xa.GetCookie();
|
|
#else
|
|
wxUnusedVar(display);
|
|
wxUnusedVar(proto);
|
|
#endif
|
|
return wxEmptyString;
|
|
}
|
|
|
|
wxString
|
|
MySession::getXauthPath(tXarch xarch)
|
|
{
|
|
#ifdef __UNIX__
|
|
wxUnusedVar(xarch);
|
|
const char *xafn = XauFileName(); // static in libXau, DO NOT free() !!
|
|
return wxString(xafn, *wxConvCurrent);
|
|
#endif
|
|
#ifdef __WXMSW__
|
|
wxFileName fn;
|
|
switch (xarch) {
|
|
case XARCH_CYGWIN:
|
|
return cygPath(m_sUserDir, wxT(".Xauthority"));
|
|
case XARCH_XMING:
|
|
fn.Assign(m_sUserDir, wxT(".Xauthority"));
|
|
return fn.GetFullPath();
|
|
default:
|
|
wxLogError(_("Invalid X11 server platform"));
|
|
return wxEmptyString;
|
|
}
|
|
#endif
|
|
return wxEmptyString;
|
|
}
|
|
|
|
wxString
|
|
MySession::formatOptFilename()
|
|
{
|
|
#ifdef __WXMSW__
|
|
return cygPath(m_sOptFilename);
|
|
#else
|
|
return m_sOptFilename;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MySession::OnSessionEvent(wxCommandEvent &event)
|
|
{
|
|
if (event.GetInt())
|
|
m_bSessionEstablished = true;
|
|
else
|
|
m_bGotError = true;
|
|
}
|
|
|
|
void
|
|
MySession::SshLog(const wxChar *fmt, ...)
|
|
{
|
|
if (m_pSshLog) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
wxLog *oldLog = wxLog::SetActiveTarget(m_pSshLog);
|
|
::wxVLogMessage(fmt, args);
|
|
wxLog::SetActiveTarget(oldLog);
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
void
|
|
MySession::OnSshEvent(wxCommandEvent &event)
|
|
{
|
|
MyIPC::tSessionEvents e = wx_static_cast(MyIPC::tSessionEvents, event.GetInt());
|
|
wxString msg(event.GetString());
|
|
wxString scmd;
|
|
|
|
switch (e) {
|
|
case MyIPC::ActionNone:
|
|
case MyIPC::ActionStdout:
|
|
case MyIPC::ActionStderr:
|
|
break;
|
|
case MyIPC::ActionStatus:
|
|
m_pDlg->SetStatusText(msg);
|
|
break;
|
|
case MyIPC::ActionHello:
|
|
initversion(msg);
|
|
m_eConnectState = STATE_HELLO;
|
|
break;
|
|
case MyIPC::ActionLog:
|
|
m_pDlg->SetProgress(m_iProgress++);
|
|
if (m_bCollectSessions || m_bCollectResources)
|
|
m_aParseBuffer.Add(msg);
|
|
if (m_bCollectConfig) {
|
|
m_sConfigBuffer << msg << wxT("\n");
|
|
if (m_sConfigBuffer.Length() >= m_nSessionPushLength) {
|
|
wxLogInfo(wxT("session override finished"));
|
|
m_bCollectConfig = false;
|
|
m_pCfg->LoadFromString(m_sConfigBuffer, true);
|
|
if (m_pCfg->IsWritable())
|
|
m_pCfg->SaveToFile();
|
|
}
|
|
}
|
|
SshLog(msg);
|
|
break;
|
|
case MyIPC::ActionWarning:
|
|
{
|
|
wxString cfgid(wxT("sshwarn."));
|
|
SupressibleMessageDialog d(m_pParent, msg,
|
|
_("Warning - OpenNX"), wxOK|wxICON_EXCLAMATION);
|
|
d.ShowConditional(cfgid.Append(msg.Left(15)), wxID_OK);
|
|
}
|
|
break;
|
|
case MyIPC::ActionError:
|
|
wxLogError(msg);
|
|
m_bGotError = true;
|
|
break;
|
|
case MyIPC::ActionPromptYesNo:
|
|
{
|
|
wxString cfgid(wxT("sshyesno."));
|
|
SupressibleMessageDialog d(m_pParent, msg,
|
|
_("Warning - OpenNX"), wxYES_NO|wxICON_EXCLAMATION);
|
|
if (d.ShowConditional(cfgid.Append(msg.Left(15)), wxID_YES) == wxID_YES)
|
|
printSsh(wxT("yes"));
|
|
else {
|
|
printSsh(wxT("no"));
|
|
m_bGotError = true;
|
|
}
|
|
}
|
|
break;
|
|
case MyIPC::ActionKeyChangedYesNo:
|
|
{
|
|
wxString cfgid(wxT("sshkeychanged."));
|
|
msg << _("\nDo you want to delete the key and retry ?");
|
|
SupressibleMessageDialog d(m_pParent, msg,
|
|
_("Warning - OpenNX"), wxYES_NO|wxICON_EXCLAMATION);
|
|
if (d.ShowConditional(cfgid.Append(msg.Left(15)), wxID_YES) == wxID_YES)
|
|
m_bRemoveKey = true;
|
|
m_bGotError = true;
|
|
}
|
|
break;
|
|
case MyIPC::ActionOffendingKey:
|
|
m_sOffendingKey = msg;
|
|
break;
|
|
case MyIPC::ActionSendUsername:
|
|
{
|
|
// At this point key-based auth is finished and
|
|
// thus the key-file isn't needed anymore
|
|
wxLogNull logdummy;
|
|
wxFileName fn;
|
|
fn.Assign(m_sTempDir, wxT("keylog"));
|
|
if (fn.IsFileWritable())
|
|
::wxRemoveFile(fn.GetFullPath());
|
|
}
|
|
m_pDlg->SetStatusText(_("Sending username"));
|
|
//printSsh(m_pCfg->sGetSessionUser());
|
|
break;
|
|
case MyIPC::ActionSendPassword:
|
|
m_pDlg->SetStatusText(_("Authenticating"));
|
|
if (m_pCfg->bGetRememberPassword())
|
|
printSsh(m_pCfg->sGetSessionPassword(), false);
|
|
else
|
|
printSsh(m_sClearPassword, false);
|
|
break;
|
|
case MyIPC::ActionWelcome:
|
|
m_pDlg->SetStatusText(_("Authentication successful"));
|
|
m_eConnectState = (m_lProtocolVersion >= 0x00040000)
|
|
? STATE_LIST_RESOURCES : STATE_LIST_SESSIONS;
|
|
break;
|
|
case MyIPC::ActionSessionPushLength:
|
|
// Session file length: 213
|
|
msg.Mid(21).ToULong(&m_nSessionPushLength);
|
|
break;
|
|
case MyIPC::ActionSessionPushStart:
|
|
m_sConfigBuffer.Empty();
|
|
m_bCollectConfig = true;
|
|
wxLogInfo(wxT("receiving %d bytes of session override"),
|
|
(int)m_nSessionPushLength);
|
|
break;
|
|
case MyIPC::ActionNextCommand:
|
|
m_iProgress += 4;
|
|
m_pDlg->SetProgress(m_iProgress);
|
|
switch (m_eConnectState) {
|
|
case STATE_WAIT:
|
|
m_pDlg->SetStatusText(_("Waiting user prompt"));
|
|
break;
|
|
case STATE_INIT:
|
|
case STATE_ABORT:
|
|
break;
|
|
case STATE_HELLO:
|
|
m_pDlg->SetStatusText(_("Authenticating"));
|
|
printSsh(wxT("hello NXCLIENT - Version ") + m_sProtocolVersion);
|
|
m_eConnectState = STATE_SHELLMODE;
|
|
break;
|
|
case STATE_SHELLMODE:
|
|
scmd = wxT("SET SHELL_MODE SHELL\n");
|
|
scmd << wxT("SET AUTH_MODE PASSWORD\n");
|
|
scmd << wxT("login\n");
|
|
scmd << m_pCfg->sGetSessionUser();
|
|
printSsh(scmd);
|
|
m_eConnectState = STATE_LOGIN;
|
|
break;
|
|
// Do not delete it!
|
|
// Sending multiple messages at the same time does not
|
|
// correspond to the exchange protocol, but these messages
|
|
// are always sent in that order.
|
|
// FreeNX understands and correctly processes this.
|
|
// This does not give much startup acceleration, but still
|
|
// gives.
|
|
/*
|
|
printSsh(wxT("SET SHELL_MODE SHELL"));
|
|
m_eConnectState = STATE_AUTHMODE;
|
|
break;
|
|
case STATE_AUTHMODE:
|
|
printSsh(wxT("SET AUTH_MODE PASSWORD"));
|
|
m_eConnectState = STATE_LOGIN;
|
|
break;
|
|
case STATE_LOGIN:
|
|
printSsh(wxT("login"));
|
|
break;
|
|
*/
|
|
case STATE_LIST_RESOURCES:
|
|
m_pDlg->SetStatusText(_("Query server-side features"));
|
|
printSsh(wxT("resourcelist"));
|
|
m_eConnectState = STATE_PARSE_RESOURCES;
|
|
m_bNextCmd = false;
|
|
break;
|
|
case STATE_PARSE_RESOURCES:
|
|
// Server has sent list of attachable sessions
|
|
m_bCollectResources = false;
|
|
wxLogInfo(wxT("received end of feature list"));
|
|
parseResources();
|
|
// intentionally fall thru
|
|
case STATE_LIST_SESSIONS:
|
|
m_pDlg->SetStatusText(_("Query server-side sessions"));
|
|
scmd = wxT("listsession") + m_pCfg->sGetListParams(m_lProtocolVersion);
|
|
m_bInParseSessions = false;
|
|
printSsh(scmd);
|
|
m_eConnectState = STATE_PARSE_SESSIONS;
|
|
m_bNextCmd = false;
|
|
break;
|
|
case STATE_PARSE_SESSIONS:
|
|
m_bNextCmd = true;
|
|
if (m_bIsShadow) {
|
|
// Server has sent list of attachable sessions
|
|
m_bCollectSessions = false;
|
|
wxLogInfo(wxT("received end of attachable session list"));
|
|
parseSessions(false);
|
|
}
|
|
break;
|
|
case STATE_START_SESSION:
|
|
m_pDlg->SetStatusText(_("Starting session"));
|
|
scmd = wxT("startsession");
|
|
scmd << m_pCfg->sGetSessionParams(m_lProtocolVersion, true, m_sClearPassword);
|
|
printSsh(scmd);
|
|
m_eConnectState = STATE_FINISH;
|
|
break;
|
|
case STATE_ATTACH_VIEW_SESSION:
|
|
case STATE_ATTACH_SESSION:
|
|
m_pDlg->SetStatusText(_("Attaching to session"));
|
|
scmd = wxT("attachsession");
|
|
scmd << m_pCfg->sGetSessionParams(m_lProtocolVersion, false, m_sClearPassword)
|
|
<< wxT(" --display=\"") << m_sResumePort
|
|
<< wxT("\" --id=\"") << m_sResumeId << wxT("\"")
|
|
// TODO: Check, since which version this is supported
|
|
<< wxT(" --resize=\"1\"");
|
|
if (m_eConnectState == STATE_ATTACH_VIEW_SESSION)
|
|
scmd << wxT(" --shadowviewonly=\"1\"");
|
|
printSsh(scmd);
|
|
m_eConnectState = STATE_FINISH;
|
|
break;
|
|
case STATE_RESUME_SESSION:
|
|
m_pDlg->SetStatusText(_("Resuming session"));
|
|
scmd = wxT("restoresession");
|
|
scmd << m_pCfg->sGetSessionParams(m_lProtocolVersion, true, m_sClearPassword)
|
|
<< wxT(" --session=\"") << m_sResumeName
|
|
<< wxT("\" --type=\"") << m_sResumeType
|
|
<< wxT("\" --id=\"") << m_sResumeId << wxT("\"");
|
|
printSsh(scmd);
|
|
m_eConnectState = STATE_FINISH;
|
|
break;
|
|
case STATE_KILL_SESSION:
|
|
m_pDlg->SetStatusText(_("Terminate session"));
|
|
scmd = wxT("terminate --sessionid=\"");
|
|
scmd << m_sKillId << wxT("\"");
|
|
printSsh(scmd);
|
|
m_eConnectState = STATE_LIST_SESSIONS;
|
|
break;
|
|
case STATE_FINISH:
|
|
if (m_bGotError) {
|
|
m_eConnectState = STATE_ABORT;
|
|
printSsh(wxT("quit"), true, wxT("Mainloop: Got error, "));
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case MyIPC::ActionPinDialog:
|
|
printSsh(wxGetPasswordFromUser(
|
|
_("Enter PIN for Smart Card access."), _("Smart Card PIN"),
|
|
wxEmptyString, m_pParent), false);
|
|
break;
|
|
case MyIPC::ActionPassphraseDialog:
|
|
scmd = ::wxGetPasswordFromUser(::wxGetTranslation(msg),
|
|
_("Enter passphrase"), wxEmptyString, m_pParent);
|
|
if (scmd.IsEmpty()) {
|
|
msg = _("Empty passphrase");
|
|
m_bGotError = true;
|
|
}
|
|
printSsh(scmd, false);
|
|
break;
|
|
case MyIPC::ActionSetShadowGeometry:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sShadowGeometry = msg;
|
|
break;
|
|
case MyIPC::ActionSetSessionID:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sSessionID = msg;
|
|
break;
|
|
case MyIPC::ActionSetProxyCookie:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sProxyCookie = msg;
|
|
break;
|
|
case MyIPC::ActionSetProxyIP:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sProxyIP = msg;
|
|
break;
|
|
case MyIPC::ActionSetSessionType:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sSessionType = msg;
|
|
break;
|
|
case MyIPC::ActionSetSessionCache:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sSessionCache = msg;
|
|
break;
|
|
case MyIPC::ActionSetSessionDisplay:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sSessionDisplay = msg;
|
|
break;
|
|
case MyIPC::ActionSetAgentCookie:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sAgentCookie = msg;
|
|
break;
|
|
case MyIPC::ActionSetSslTunneling:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_bSslTunneling = (msg == wxT("1"));
|
|
break;
|
|
case MyIPC::ActionSetSubscription:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sSubscription = msg;
|
|
break;
|
|
case MyIPC::ActionSetSmbPort:
|
|
m_pDlg->SetStatusText(_("Negotiating session parameter"));
|
|
m_sSmbPort = msg;
|
|
break;
|
|
case MyIPC::ActionExit:
|
|
if (m_eConnectState == STATE_ABORT) {
|
|
m_bAbort = true;
|
|
} else {
|
|
if (m_eConnectState == STATE_FINISH) {
|
|
m_pDlg->SetStatusText(_("Starting session"));
|
|
msg = wxT("NX> 299 Switch connection to: ");
|
|
if (m_lProtocolVersion > 0x00020000) {
|
|
msg << wxT("NX mode: ")
|
|
<< (m_bSslTunneling ? wxT("encrypted") : wxT("unencrypted"))
|
|
<< wxT(" options: nx,options=")
|
|
<< formatOptFilename() << wxT(":") << m_sSessionDisplay;
|
|
} else {
|
|
msg << m_sProxyIP << wxT(":") << m_sProxyPort
|
|
<< wxT(" cookie: ") << m_sProxyCookie;
|
|
}
|
|
m_bSessionRunning = true;
|
|
wxString slog = m_sSessionDir;
|
|
slog << wxFileName::GetPathSeparator() << wxT("session");
|
|
m_pSessionWatch = new SessionWatch(this, slog,
|
|
wxT("Session: Session started at"));
|
|
printSsh(msg);
|
|
} else {
|
|
m_bSessionRunning = true;
|
|
}
|
|
}
|
|
break;
|
|
case MyIPC::ActionTerminated:
|
|
if ((m_eConnectState <= STATE_PARSE_SESSIONS) && (!m_bGotError) && (!m_bRemoveKey) && (m_sOffendingKey.IsEmpty())) {
|
|
msg = _("Unexpected termination of nxssh");
|
|
wxLogError(msg);
|
|
m_bGotError = true;
|
|
}
|
|
break;
|
|
case MyIPC::ActionStartProxy:
|
|
if (m_eConnectState == STATE_FINISH) {
|
|
m_pDlg->SetStatusText(_("Starting session"));
|
|
startSharing();
|
|
startProxy();
|
|
}
|
|
break;
|
|
case MyIPC::ActionSessionRunning:
|
|
m_bSessionRunning = true;
|
|
{
|
|
wxString slog = m_sSessionDir;
|
|
slog << wxFileName::GetPathSeparator() << wxT("session");
|
|
m_pSessionWatch = new SessionWatch(this, slog,
|
|
wxT("Session: Session started at"));
|
|
}
|
|
break;
|
|
case MyIPC::ActionSessionListStart:
|
|
// Server starts sending session list
|
|
wxLogInfo(wxT("receiving session list .."));
|
|
m_aParseBuffer.Empty();
|
|
m_bCollectSessions = true;
|
|
break;
|
|
case MyIPC::ActionSessionListEnd:
|
|
// Server has sent list of running & suspended sessions
|
|
m_bCollectSessions = false;
|
|
wxLogInfo(wxT("received end of session list"));
|
|
parseSessions((event.GetExtraLong() == 148) && (!m_bIsShadow));
|
|
break;
|
|
case MyIPC::ActionResList:
|
|
// NX4: Server starts sending resource info
|
|
wxLogInfo(wxT("receiving resource info .."));
|
|
m_aParseBuffer.Empty();
|
|
m_bCollectResources = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
MySession::initversion(const wxString &s /* = wxEmptyString */)
|
|
{
|
|
wxString s02; wxString s1 = s.BeforeFirst(wxT('-'), &s02);
|
|
m_lProtocolVersion = 0;
|
|
if (!::wxGetEnv(wxT("NX_PROTOCOL_VERSION"), &m_sProtocolVersion))
|
|
m_sProtocolVersion = wxT(NX_PROTOCOL_VERSION);
|
|
if (!s1.IsEmpty())
|
|
m_sProtocolVersion = s1;
|
|
wxStringTokenizer t(m_sProtocolVersion, wxT("."));
|
|
int digits = 0;
|
|
while (t.HasMoreTokens()) {
|
|
long n;
|
|
t.GetNextToken().ToLong(&n);
|
|
m_lProtocolVersion = (m_lProtocolVersion << 8) + n;
|
|
if (++digits > 3)
|
|
break;
|
|
}
|
|
while (digits++ < 3)
|
|
m_lProtocolVersion = (m_lProtocolVersion << 8);
|
|
myLogTrace(MYTRACETAG, wxT("protocol version: %08x"), (int)m_lProtocolVersion);
|
|
wxString s3; wxString s2 = s02.BeforeFirst(wxT('-'), &s3);
|
|
m_lSrvProtocolVersion = 0;
|
|
if (s3 != wxT("CE"))
|
|
return;
|
|
digits = 0; t.SetString(s2, wxT("."));
|
|
while (t.HasMoreTokens()) {
|
|
long n;
|
|
t.GetNextToken().ToLong(&n);
|
|
m_lSrvProtocolVersion = (m_lSrvProtocolVersion << 8) + n;
|
|
if (++digits > 3)
|
|
break;
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("server protocol version: %08x"), (int)m_lSrvProtocolVersion);
|
|
}
|
|
|
|
void
|
|
MySession::printSsh(const wxString &s, bool doLog /* = true */, const wxString &reason /* = wxT("") */)
|
|
{
|
|
if (m_pNxSsh) {
|
|
myLogTrace(MYTRACETAG, wxT("%ssending '%s'"), VMB(reason),
|
|
#ifdef __WXMSW__
|
|
(doLog ? VMB(s) : wxT("********")));
|
|
#else
|
|
(doLog ? VMB(s) : "********"));
|
|
#endif
|
|
m_pNxSsh->Print(s, doLog);
|
|
}
|
|
}
|
|
|
|
void
|
|
MySession::parseResources()
|
|
{
|
|
size_t n = m_aParseBuffer.GetCount();
|
|
myLogTrace(MYTRACETAG, wxT("parseResources: Got %d lines to parse"), (int)n);
|
|
wxRegEx re(wxT("^((?:session)|(?:service)|(?:feature))\\s+([^\\s]+)(?:\\s+([^\\s]+))?$"), wxRE_ADVANCED);
|
|
wxASSERT(re.IsValid());
|
|
for (size_t i = 0; i < n; i++) {
|
|
wxString line(m_aParseBuffer[i].Strip(wxString::both));
|
|
if (re.Matches(line) && (4 == re.GetMatchCount())) {
|
|
if (re.GetMatchCount() == 4) {
|
|
wxString sClass(re.GetMatch(line, 1));
|
|
wxString sType(re.GetMatch(line, 2));
|
|
wxString sValue(re.GetMatch(line, 3));
|
|
myLogTrace(MYTRACETAG, wxT("parseResources: match c='%s' t='%s', v='%s'"),
|
|
VMB(sClass), VMB(sType), VMB(sValue));
|
|
if (sClass.IsSameAs(wxT("session"))) {
|
|
// Not yet clear what to do with that data.
|
|
}
|
|
if (sClass.IsSameAs(wxT("service"))) {
|
|
// Not yet clear what to do with that data.
|
|
}
|
|
if (sClass.IsSameAs(wxT("feature"))) {
|
|
// Not yet clear what to do with that data.
|
|
}
|
|
}
|
|
} else
|
|
myLogTrace(MYTRACETAG, wxT("parseResources: NO match line='%s'"), VMB(line));
|
|
}
|
|
}
|
|
|
|
void
|
|
MySession::parseSessions(bool moreAllowed)
|
|
{
|
|
if (m_bInParseSessions)
|
|
return;
|
|
m_bInParseSessions = true;
|
|
size_t n = m_aParseBuffer.GetCount();
|
|
myLogTrace(MYTRACETAG, wxT("parseSessions: Got %d lines to parse"), (int)n);
|
|
wxRegEx re(
|
|
wxT("^(\\d+)\\s+([\\w-]+)\\s+([0-9A-F]{32})\\s+([A-Z-]{8})\\s+(\\d+)\\s+(\\d+x\\d+)\\s+(\\w+)\\s+([^\\s].*)$"),
|
|
wxRE_ADVANCED);
|
|
wxASSERT(re.IsValid());
|
|
wxRegEx re2(
|
|
wxT("^(\\d+)\\s+([\\w-]+)\\s+([0-9A-F]{32})\\s+([A-Z-]{8})\\s+(N/A)\\s+(N/A)\\s+(\\w+)\\s+([^\\s].*)$"),
|
|
wxRE_ADVANCED);
|
|
wxASSERT(re2.IsValid());
|
|
wxRegEx re3(
|
|
wxT("^(\\d+)\\s+(shadow)\\s+([0-9A-F]{32})\\s+([A-Z-]{8})\\s+(\\w+)\\s+([^\\s].*)$"),
|
|
wxRE_ADVANCED);
|
|
wxASSERT(re3.IsValid());
|
|
ResumeDialog d(NULL);
|
|
bool bFound = false;
|
|
int iSessionCount = 0;
|
|
wxString sName;
|
|
wxString sUser(m_pCfg->sGetSessionUser());
|
|
if (m_bIsShadow) {
|
|
d.SetAttachMode(true);
|
|
} else {
|
|
d.SetPreferredSession(m_pCfg->sGetName());
|
|
}
|
|
for (size_t i = 0; i < n; i++) {
|
|
wxString line = m_aParseBuffer[i].Trim();
|
|
myLogTrace(MYTRACETAG, wxT("parseSessions: line='%s'"), VMB(line));
|
|
if (re.Matches(line)) {
|
|
myLogTrace(MYTRACETAG, wxT("parseSessions: re match"));
|
|
wxString sPort(re.GetMatch(line, 1));
|
|
wxString sType(re.GetMatch(line, 2));
|
|
wxString sId(re.GetMatch(line, 3));
|
|
wxString sOpts(re.GetMatch(line, 4));
|
|
wxString sColors(re.GetMatch(line, 5));
|
|
wxString sSize(re.GetMatch(line, 6));
|
|
wxString sState(re.GetMatch(line, 7));
|
|
sName = re.GetMatch(line, 8);
|
|
if (m_bIsShadow) {
|
|
// In shadow session mode, a username follows the session name.
|
|
// Our RE matches both in sName, so we have to split off the usernam.
|
|
sUser = sName.AfterLast(wxT(' '));
|
|
sName = sName.BeforeLast(wxT(' ')).Trim();
|
|
}
|
|
d.AddSession(sName, sState, sType, sSize, sColors, sPort, sOpts, sId, sUser);
|
|
bFound = true;
|
|
iSessionCount++;
|
|
continue;
|
|
}
|
|
if (re2.Matches(line)) {
|
|
myLogTrace(MYTRACETAG, wxT("parseSessions: re2 match"));
|
|
wxString sPort(re2.GetMatch(line, 1));
|
|
wxString sType(re2.GetMatch(line, 2));
|
|
wxString sId(re2.GetMatch(line, 3));
|
|
wxString sOpts(re2.GetMatch(line, 4));
|
|
wxString sColors(re2.GetMatch(line, 5));
|
|
wxString sSize(re2.GetMatch(line, 6));
|
|
wxString sState(re2.GetMatch(line, 7));
|
|
sName = re2.GetMatch(line, 8);
|
|
if (m_bIsShadow) {
|
|
// In shadow session mode, a username follows the session name.
|
|
// Our RE matches both in sName, so we have to split off the usernam.
|
|
sUser = sName.AfterLast(wxT(' '));
|
|
sName = sName.BeforeLast(wxT(' ')).Trim();
|
|
}
|
|
d.AddSession(sName, sState, sType, sSize, sColors, sPort, sOpts, sId, sUser);
|
|
bFound = true;
|
|
iSessionCount++;
|
|
continue;
|
|
}
|
|
if (m_bIsShadow && re3.Matches(line)) {
|
|
myLogTrace(MYTRACETAG, wxT("parseSessions: re3 match"));
|
|
wxString sPort(re3.GetMatch(line, 1));
|
|
wxString sType(re3.GetMatch(line, 2));
|
|
wxString sId(re3.GetMatch(line, 3));
|
|
wxString sOpts(re3.GetMatch(line, 4));
|
|
wxString sColors;
|
|
wxString sSize;
|
|
wxString sState(re3.GetMatch(line, 5));
|
|
sName = re3.GetMatch(line, 6);
|
|
sUser = wxT("");
|
|
d.AddSession(sName, sState, sType, sSize, sColors, sPort, sOpts, sId, sUser);
|
|
bFound = true;
|
|
iSessionCount++;
|
|
continue;
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("parseSessions: NO match"));
|
|
}
|
|
if (bFound) {
|
|
d.EnableNew(moreAllowed);
|
|
if ((!m_bIsShadow) && wxGetApp().AutoResume() && (iSessionCount == 1) && (sName.IsSameAs(m_pCfg->sGetName()))) {
|
|
wxLogInfo(wxT("RESUME"));
|
|
m_sResumeName = sName;
|
|
m_sResumeType = d.GetSelectedType();
|
|
m_sResumeId = d.GetSelectedId();
|
|
m_eConnectState = STATE_RESUME_SESSION;
|
|
} else {
|
|
m_eConnectState = STATE_WAIT;
|
|
switch (d.ShowModal()) {
|
|
case wxID_OK:
|
|
myLogTrace(MYTRACETAG, wxT("ResumeDialog returned OK"));
|
|
switch (d.GetMode()) {
|
|
case ResumeDialog::Refresh:
|
|
wxLogInfo(wxT("REFRESH"));
|
|
m_eConnectState = STATE_LIST_SESSIONS;
|
|
printSsh(wxEmptyString);
|
|
break;
|
|
case ResumeDialog::Terminate:
|
|
wxLogInfo(wxT("TERMINATE"));
|
|
m_sKillId = d.GetSelectedId();
|
|
m_eConnectState = STATE_KILL_SESSION;
|
|
printSsh(wxEmptyString);
|
|
break;
|
|
case ResumeDialog::Resume:
|
|
wxLogInfo(wxT("RESUME"));
|
|
m_sResumeName = d.GetSelectedName();
|
|
m_sResumeType = d.GetSelectedType();
|
|
m_sResumeId = d.GetSelectedId();
|
|
m_sResumePort = d.GetSelectedPort();
|
|
m_eConnectState = m_bIsShadow ? STATE_ATTACH_SESSION : STATE_RESUME_SESSION;
|
|
printSsh(wxEmptyString);
|
|
break;
|
|
case ResumeDialog::Takeover:
|
|
wxLogInfo(wxT("TAKEOVER"));
|
|
m_sResumeName = d.GetSelectedName();
|
|
m_sResumeType = d.GetSelectedType();
|
|
m_sResumeId = d.GetSelectedId();
|
|
if (m_bIsShadow)
|
|
m_sResumePort = d.GetSelectedPort();
|
|
m_eConnectState = m_bIsShadow ? STATE_ATTACH_VIEW_SESSION : STATE_RESUME_SESSION;
|
|
printSsh(wxEmptyString);
|
|
break;
|
|
case ResumeDialog::New:
|
|
m_eConnectState = STATE_START_SESSION;
|
|
printSsh(wxEmptyString);
|
|
break;
|
|
}
|
|
if (m_bNextCmd) {
|
|
wxCommandEvent upevent(wxEVT_NXSSH, wxID_ANY);
|
|
upevent.SetInt(MyIPC::ActionNextCommand);
|
|
AddPendingEvent(upevent);
|
|
}
|
|
break;
|
|
case wxID_CANCEL:
|
|
printSsh(wxT("quit"), true, wxT("ResumeDialog returned CANCEL, "));
|
|
m_eConnectState = STATE_ABORT;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (m_bIsShadow) {
|
|
m_eConnectState = STATE_ABORT;
|
|
m_bGotError = true;
|
|
m_bAbort = true;
|
|
printSsh(wxT("quit"), true, wxT("No sessions to attach, "));
|
|
wxMessageDialog d(m_pParent,
|
|
_("There are no sessions which can be attached to."),
|
|
_("Error - OpenNX"), wxOK);
|
|
d.SetIcon(CreateIconFromFile(wxT("res/nx.png")));
|
|
d.ShowModal();
|
|
} else {
|
|
if (moreAllowed)
|
|
m_eConnectState = STATE_START_SESSION;
|
|
else {
|
|
printSsh(wxT("quit"), true, wxT("No more sessions allowed, "));
|
|
wxMessageDialog d(m_pParent,
|
|
_("You have reached your session limit. No more sessions allowed"),
|
|
_("Error - OpenNX"), wxOK);
|
|
d.SetIcon(CreateIconFromFile(wxT("res/nx.png")));
|
|
d.ShowModal();
|
|
m_bGotError = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MySession::startSharing()
|
|
{
|
|
if (!m_pCfg->bGetUseCups() && !m_pCfg->bGetEnableSmbSharing())
|
|
return;
|
|
ArrayOfShareGroups sg = m_pCfg->aGetShareGroups();
|
|
wxArrayString used = m_pCfg->aGetUsedShareGroups();
|
|
CupsClient cc;
|
|
SmbClient sc;
|
|
ArrayOfShares sa;
|
|
if (m_pCfg->bGetUseCups() && cc.IsAvailable())
|
|
sa = cc.GetShares();
|
|
if (m_pCfg->bGetEnableSmbSharing() && sc.IsAvailable())
|
|
WX_APPEND_ARRAY(sa, sc.GetShares());
|
|
|
|
long cupsport;
|
|
long smbport;
|
|
m_sSessionDisplay.ToLong(&cupsport);
|
|
m_sSessionDisplay.ToLong(&smbport);
|
|
cupsport += CUPS_PORT_OFFSET;
|
|
smbport += SMB_PORT_OFFSET;
|
|
for (size_t i = 0; i < sg.GetCount(); i++) {
|
|
if (used.Index(sg[i].m_sGroupName) == wxNOT_FOUND)
|
|
continue;
|
|
bool bAvailable = false;
|
|
wxString sn = sg[i].m_sShareName;
|
|
myLogTrace(MYTRACETAG, wxT("startSharing: considering share '%s'"), VMB(sn));
|
|
for (size_t j = 0; j < sa.GetCount(); j++) {
|
|
if ((sa[j].sharetype == sg[i].m_eType) && (sa[j].name == sn)) {
|
|
bAvailable = true;
|
|
break;
|
|
}
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("'%s' is %savailable"), VMB(sn),
|
|
(bAvailable ? "" : "not "));
|
|
if (!bAvailable)
|
|
continue;
|
|
wxString shcmd;
|
|
switch (sg[i].m_eType) {
|
|
case SharedResource::SHARE_UNKNOWN:
|
|
break;
|
|
case SharedResource::SHARE_SMB_DISK:
|
|
shcmd = wxT("addmount");
|
|
shcmd
|
|
<< wxT(" --port=\"") << smbport << wxT("\"")
|
|
<< wxT(" --username=\"")
|
|
<< MyXmlConfig::UrlEsc(sg[i].m_sUsername) << wxT("\"")
|
|
<< wxT(" --password=\"")
|
|
<< MyXmlConfig::UrlEsc(sg[i].m_sPassword) << wxT("\"")
|
|
<< wxT(" --share=\"") << MyXmlConfig::UrlEsc(sn) << wxT("\"")
|
|
<< wxT(" --computername=\"")
|
|
<< MyXmlConfig::UrlEsc(::wxGetFullHostName()) << wxT("\"")
|
|
<< wxT(" --session_id=\"") << m_sSessionID.Right(32) << wxT("\"")
|
|
<< wxT(" --dir=\"")
|
|
<< MyXmlConfig::UrlEsc(sg[i].m_sAlias) << wxT("\"");
|
|
printSsh(shcmd);
|
|
break;
|
|
case SharedResource::SHARE_SMB_PRINTER:
|
|
shcmd = wxT("addprinter");
|
|
shcmd << wxT(" --type=\"smb\"")
|
|
<< wxT(" --username=\"")
|
|
<< MyXmlConfig::UrlEsc(sg[i].m_sUsername) << wxT("\"")
|
|
<< wxT(" --password=\"")
|
|
<< MyXmlConfig::UrlEsc(sg[i].m_sPassword) << wxT("\"")
|
|
<< wxT(" --port=\"") << (int)smbport << wxT("\"")
|
|
<< wxT(" --share=\"") << MyXmlConfig::UrlEsc(sn) << wxT("\"")
|
|
<< wxT(" --computername=\"")
|
|
<< MyXmlConfig::UrlEsc(::wxGetHostName()) << wxT("\"")
|
|
<< wxT(" --session_id=\"") << m_sSessionID.Right(32) << wxT("\"")
|
|
<< wxT(" --model=\"") << sg[i].m_sDriver << wxT("\"");
|
|
if (sg[i].m_bDefault)
|
|
shcmd << wxT(" --defaultprinter=\"1\"");
|
|
if (sg[i].m_bPublic)
|
|
shcmd << wxT(" --public=\"1\"");
|
|
printSsh(shcmd);
|
|
break;
|
|
case SharedResource::SHARE_CUPS_PRINTER:
|
|
shcmd = wxT("addprinter");
|
|
shcmd << wxT(" --type=\"ipp\"")
|
|
<< wxT(" --username=\"") << MyXmlConfig::UrlEsc(sg[i].m_sUsername) << wxT("\"")
|
|
<< wxT(" --port=\"") << cupsport << wxT("\"")
|
|
<< wxT(" --session_id=\"") << m_sSessionID.Right(32) << wxT("\"")
|
|
<< wxT(" --printer=\"") << MyXmlConfig::UrlEsc(sn) << wxT("\"")
|
|
<< wxT(" --password=\"")
|
|
<< MyXmlConfig::UrlEsc(sg[i].m_sPassword) << wxT("\"")
|
|
<< wxT(" --model=\"cups%20printer\"");
|
|
if (sg[i].m_bDefault)
|
|
shcmd << wxT(" --defaultprinter=\"1\"");
|
|
if (sg[i].m_bPublic)
|
|
shcmd << wxT(" --public=\"1\"");
|
|
printSsh(shcmd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MySession::checkXarch()
|
|
{
|
|
m_eXarch = XARCH_NONE;
|
|
#ifdef __WXMSW__
|
|
wxFileName fn(m_sSysDir, wxT("nxwin.exe"));
|
|
fn.AppendDir(wxT("bin"));
|
|
if (fn.IsFileExecutable()) {
|
|
m_eXarch = XARCH_CYGWIN;
|
|
return;
|
|
}
|
|
fn.SetFullName(wxT("XMing.exe"));
|
|
if (fn.IsFileExecutable())
|
|
m_eXarch = XARCH_XMING;
|
|
#endif
|
|
}
|
|
|
|
#ifdef __WXMSW__
|
|
wxString
|
|
MySession::getXfontPath(tXarch Xarch)
|
|
{
|
|
wxLogNull l;
|
|
wxFileName fn(m_sSysDir, wxEmptyString);
|
|
fn.AppendDir(wxT("share"));
|
|
fn.AppendDir(wxT("fonts"));
|
|
wxDir d(fn.GetShortPath());
|
|
FontpathTraverser t;
|
|
d.Traverse(t);
|
|
wxString ret = t.GetFontPath(Xarch);
|
|
if (!ret.IsEmpty())
|
|
ret.Prepend(wxT(" -fp "));
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
MySession::unhideNXWin()
|
|
{
|
|
if (XARCH_CYGWIN == m_eXarch) {
|
|
// Required only for NXWin - Xming shows up by itself
|
|
DWORD stored_nxserver_version = ::RegisterWindowMessage(wxT("STORED_NXSERVER_VERSION"));
|
|
HWND h = ::GetTopWindow(0);
|
|
while (h) {
|
|
wxString wclass;
|
|
int r = GetClassName(h, wxStringBuffer(wclass,40), 38);
|
|
if ((r > 0) && wclass.Contains(wxT("cygwin/xfree86"))) {
|
|
DWORD pid;
|
|
GetWindowThreadProcessId(h, &pid);
|
|
if ((int)pid == m_iXserverPID) {
|
|
// Trigger unhiding of fullscreen NXWin
|
|
SendMessage(h, WM_USER + 1, 0, 0);
|
|
// Trigger for worked close button NXWin
|
|
::SendMessage(h, stored_nxserver_version, 1, 1);
|
|
SetForegroundWindow(h);
|
|
break;
|
|
}
|
|
}
|
|
h = ::GetNextWindow(h , GW_HWNDNEXT);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MySession::terminateXserver()
|
|
{
|
|
// nxwin and nonencrypted: keep running (here we need it?)
|
|
if ((XARCH_CYGWIN == m_eXarch) && (!m_bSslTunneling))
|
|
return;
|
|
// Xming non-fullscreen: keep running
|
|
if ((XARCH_CYGWIN == m_eXarch) ||
|
|
(MyXmlConfig::DPTYPE_FULLSCREEN == m_pCfg->eGetDisplayType())) {
|
|
if ((0 != m_iXserverPID) && wxProcess::Exists(m_iXserverPID))
|
|
wxProcess::Kill(m_iXserverPID, wxSIGKILL, wxKILL_NOCHILDREN);
|
|
}
|
|
}
|
|
|
|
bool
|
|
MySession::startXserver()
|
|
{
|
|
int display = getFirstFreePort(X_PORT_OFFSET);
|
|
myLogTrace(MYTRACETAG, wxT("startXServer first free port is %d"), display);
|
|
if (0 == display)
|
|
return false;
|
|
display -= X_PORT_OFFSET;
|
|
wxString dpyStr = wxT(":");
|
|
dpyStr << display;
|
|
|
|
wxString wxWinCmd;
|
|
wxFileName fn(m_sSysDir, wxT("nxwin.exe"));
|
|
fn.AppendDir(wxT("bin"));
|
|
|
|
switch (m_eXarch) {
|
|
case XARCH_CYGWIN:
|
|
m_sXauthCookie = getXauthCookie(display, wxT("/unix"));
|
|
if (m_sXauthCookie.IsEmpty()) {
|
|
wxLogError(_("Could not create X11 authentication cookie"));
|
|
return false;
|
|
}
|
|
wxWinCmd = fn.GetShortPath();
|
|
wxWinCmd << wxT(" -nowinkill");
|
|
wxWinCmd << wxT(" -clipboard");
|
|
wxWinCmd << wxT(" -noloadxkb");
|
|
wxWinCmd << wxT(" -agent");
|
|
wxWinCmd << wxT(" -hide");
|
|
wxWinCmd << wxT(" -noreset");
|
|
wxWinCmd << wxT(" -auth ") << getXauthPath(XARCH_CYGWIN);
|
|
wxWinCmd << wxT(" -nolisten tcp");
|
|
wxWinCmd << getXfontPath(m_eXarch);
|
|
wxWinCmd << m_pCfg->sGetXserverParams(true);
|
|
if ( ( (m_pCfg->eGetDesktopType() == MyXmlConfig::DTYPE_CUSTOM) &&
|
|
(!m_pCfg->bGetVirtualDesktop())
|
|
) ||
|
|
( (m_pCfg->eGetSessionType() == MyXmlConfig::STYPE_WINDOWS) &&
|
|
(m_pCfg->bGetRdpRootless())
|
|
) ||
|
|
( (m_pCfg->eGetSessionType() == MyXmlConfig::STYPE_VNC) &&
|
|
(m_pCfg->bGetVncRootless())
|
|
)
|
|
)
|
|
wxWinCmd << wxT(" -multiwindow ");
|
|
else if (m_pCfg->eGetDisplayType()==MyXmlConfig::DPTYPE_NODECORATION)
|
|
wxWinCmd << wxT(" -nodecoration");
|
|
{
|
|
wxString title = m_pCfg->sGetUsername();
|
|
if (m_pCfg->bGetGuestMode()) {
|
|
title = m_pCfg->sGetGuestUser();
|
|
if (title.IsEmpty())
|
|
title << wxT("guest");
|
|
}
|
|
wxWinCmd << wxT(" -name ") << title << wxT("@") << m_pCfg->sGetName();
|
|
}
|
|
/* Warning from Djelf: format of cmd string at its end
|
|
always MUST BE "-name <name@addr> :<display>" */
|
|
wxWinCmd << wxT(" ") << dpyStr;
|
|
break;
|
|
case XARCH_XMING:
|
|
if (m_pCfg->eGetDisplayType() != MyXmlConfig::DPTYPE_FULLSCREEN) {
|
|
// If not fullscreen, we use a single instance of Xming, running in
|
|
// multiwindow mode. In this case, we check for a running Xming, by
|
|
// using a win32 named mutex.
|
|
int xdpy = getXmingPort(display + X_PORT_OFFSET);
|
|
if (0 != xdpy) {
|
|
dpyStr = wxT("127.0.0.1:");
|
|
dpyStr << xdpy - X_PORT_OFFSET;
|
|
::wxSetEnv(wxT("DISPLAY"), dpyStr);
|
|
wxLogInfo(wxT("env: DISPLAY='%s'"), VMB(dpyStr));
|
|
// Xauth cookie and X<dpy>.hosts are still existing
|
|
// from initial startup
|
|
return true;
|
|
}
|
|
}
|
|
fn.SetFullName(wxT("Xming.exe"));
|
|
m_sXauthCookie = getXauthCookie(display, wxEmptyString);
|
|
if (m_sXauthCookie.IsEmpty()) {
|
|
wxLogError(_("Could not create X11 authentication cookie"));
|
|
return false;
|
|
}
|
|
wxWinCmd = fn.GetShortPath();
|
|
wxWinCmd << wxT(" ") << dpyStr;
|
|
fn.Assign(m_sUserDir, wxString::Format(wxT("X%d.log"), (int)display));
|
|
wxWinCmd << wxT(" -logfile \"") << fn.GetFullPath() << wxT("\"");
|
|
wxWinCmd << wxT(" -br");
|
|
wxWinCmd << wxT(" -nowinkill");
|
|
wxWinCmd << wxT(" -clipboard ");
|
|
switch (m_pCfg->iGetClipFilter()) {
|
|
case 0:
|
|
wxWinCmd << wxT("primary");
|
|
break;
|
|
case 1:
|
|
wxWinCmd << wxT("clipboard");
|
|
break;
|
|
case 2:
|
|
wxWinCmd << wxT("both");
|
|
break;
|
|
}
|
|
wxWinCmd << wxT(" -notrayicon");
|
|
wxWinCmd << getXfontPath(m_eXarch);
|
|
wxWinCmd << wxT(" -silent-dup-error");
|
|
if (::checkMultiMonitors() > 1)
|
|
wxWinCmd << wxT(" -multimonitors");
|
|
wxWinCmd << m_pCfg->sGetXserverParams(false);
|
|
fn.Assign(m_sSysDir, wxEmptyString);
|
|
fn.AppendDir(wxT("share"));
|
|
fn.AppendDir(wxT("Xming"));
|
|
fn.MakeAbsolute();
|
|
::wxSetEnv(wxT("XMING_BASEDIR"), fn.GetPath());
|
|
wxLogInfo(wxT("env: XMING_BASEDIR='%s'"), VMB(fn.GetPath()));
|
|
dpyStr.Prepend(wxT("127.0.0.1"));
|
|
break;
|
|
default:
|
|
wxLogError(_("No X server found."));
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
wxLogInfo(wxT("Executing %s"), VMB(wxWinCmd));
|
|
int r = CreateDetachedProcess(wxWinCmd.ToUTF8());
|
|
if (r != 0) {
|
|
wxLogError(_("Could not execute %s: %s\n"), VMB(wxWinCmd), wxSysErrorMsg(r));
|
|
return false;
|
|
}
|
|
m_iXserverPID = GetDetachedPID();
|
|
AllowSetForegroundWindow(m_iXserverPID);
|
|
::wxSetEnv(wxT("DISPLAY"), dpyStr);
|
|
wxLogInfo(wxT("env: DISPLAY='%s'"), VMB(dpyStr));
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
MySession::startProxy()
|
|
{
|
|
myLogTrace(MYTRACETAG, wxT("MySession::startProxy() called"));
|
|
long cupsport = m_pCfg->iGetCupsPort();
|
|
wxString popts;
|
|
if (m_lProtocolVersion >= 0x00030000)
|
|
popts << wxT("nx/");
|
|
popts << wxT("nx,cookie=") << m_sProxyCookie;
|
|
if (m_lProtocolVersion < 0x00030000)
|
|
popts << wxT(",root=") << cygPath(m_sUserDir);
|
|
popts << m_pCfg->sGetProxyParams(m_lProtocolVersion);
|
|
if (!m_sSubscription.IsEmpty())
|
|
popts << wxT(",product=") << m_sSubscription;
|
|
if (m_pCfg->bGetEnableSmbSharing()) {
|
|
SmbClient sc;
|
|
if (sc.IsAvailable()) {
|
|
if (m_sSmbPort.IsEmpty()) {
|
|
popts << wxT(",samba=") << m_pCfg->iGetSmbPort();
|
|
} else {
|
|
popts << wxT(",samba=") << m_sSmbPort;
|
|
}
|
|
}
|
|
}
|
|
if ((getActiveCupsPrinters().GetCount() > 0) && (isCupsRunning()))
|
|
popts << wxT(",cups=") << cupsport;
|
|
#ifdef SUPPORT_USBIP
|
|
if (m_pCfg->bGetEnableUSBIP())
|
|
popts << wxT(",http=") << wxConfigBase::Get()->Read(wxT("Config/UsbipPort"), 3420);
|
|
#endif
|
|
if ((m_bEsdRunning || m_bNativePARunning) && (0 < m_lEsdPort))
|
|
popts << wxT(",media=") << m_lEsdPort;
|
|
popts
|
|
<< wxT(",encryption=") << (m_bSslTunneling ? 1 : 0)
|
|
<< wxT(",session=session");
|
|
popts << wxT(",id=") << m_sSessionID;
|
|
if (m_bSslTunneling) {
|
|
if (m_lProtocolVersion <= 0x00020000) {
|
|
m_sProxyIP = wxT("127.0.0.1");
|
|
m_sProxyPort = wxString::Format(wxT("%d"), (int)getFirstFreePort(PROXY_PORT_OFFSET));
|
|
popts << wxT(",listen=") << m_sProxyPort;
|
|
}
|
|
} else
|
|
popts << wxT(",connect=") << m_sProxyIP;
|
|
|
|
// Undocumented feature of the original:
|
|
// If a file ~/.nx/options exists, it's content is
|
|
// appended to the regular options.
|
|
wxFileName mergeOpts(m_sUserDir, wxT("options"));
|
|
if (mergeOpts.FileExists()) {
|
|
wxLogNull dummy;
|
|
wxTextFile f(mergeOpts.GetFullPath());
|
|
if (f.Open()) {
|
|
wxString mopts = f.GetFirstLine().Strip(wxString::both);
|
|
if (!mopts.IsEmpty()) {
|
|
if ((!popts.IsEmpty()) && (!mopts.StartsWith(wxT(","))))
|
|
popts << wxT(",");
|
|
popts << mopts;
|
|
}
|
|
f.Close();
|
|
}
|
|
}
|
|
|
|
popts << wxT(":") << m_sSessionDisplay;
|
|
/* but in nxclient now is:
|
|
popts << wxT(",display=:0:") << m_sSessionDisplay;
|
|
*/
|
|
m_sSessionDir = m_sUserDir;
|
|
m_sSessionDir << wxFileName::GetPathSeparator()
|
|
<< wxT("S-") << m_sSessionID;
|
|
{
|
|
if (!wxFileName::Mkdir(m_sSessionDir, 0700, wxPATH_MKDIR_FULL)) {
|
|
wxLogSysError(_("Could not create session directory\n%s\n"),
|
|
VMB(m_sSessionDir));
|
|
m_bGotError = true;
|
|
}
|
|
m_sOptFilename = m_sSessionDir;
|
|
m_sOptFilename << wxFileName::GetPathSeparator() << wxT("options");
|
|
wxFile f;
|
|
if (f.Open(m_sOptFilename, wxFile::write, wxS_IRUSR|wxS_IWUSR)) {
|
|
f.Write(popts + wxT("\n"));
|
|
f.Close();
|
|
wxLogInfo(wxT("Option file='%s'\n"), VMB(m_sOptFilename));
|
|
wxLogInfo(wxT("Session options='%s'\n"), VMB(popts));
|
|
wxString pcmd;
|
|
wxConfigBase::Get()->Read(wxT("Config/SystemNxDir"), &pcmd);
|
|
pcmd << wxFileName::GetPathSeparator() << wxT("bin")
|
|
<< wxFileName::GetPathSeparator() << wxT("nxproxy -S nx,options=")
|
|
<< cygPath(m_sOptFilename) << wxT(":") << m_sSessionDisplay;
|
|
printSsh(wxT("bye"), true, wxT("Options file written, "));
|
|
if (m_lProtocolVersion <= 0x00020000) {
|
|
wxLogInfo(wxT("Executing %s"), VMB(pcmd));
|
|
#ifdef __WXMSW__
|
|
if (m_eXarch == XARCH_XMING)
|
|
CreateDetachedProcess(pcmd.ToUTF8());
|
|
if (m_iXserverPID)
|
|
AllowSetForegroundWindow(m_iXserverPID);
|
|
#else
|
|
setTurboPath(true);
|
|
::wxExecute(pcmd, wxEXEC_ASYNC);
|
|
setTurboPath(false);
|
|
#endif
|
|
}
|
|
} else {
|
|
wxLogSysError(_("Could not write session options\n%s\n"),
|
|
VMB(m_sOptFilename));
|
|
m_bGotError = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
ArrayOfShareGroups
|
|
MySession::getActiveCupsPrinters()
|
|
{
|
|
ArrayOfShareGroups ret;
|
|
if (!m_pCfg->bGetUseCups())
|
|
return ret;
|
|
CupsClient cc;
|
|
if (cc.IsAvailable()) {
|
|
ArrayOfShares sa = cc.GetShares();
|
|
ret = m_pCfg->aGetShareGroups();
|
|
wxArrayString used = m_pCfg->aGetUsedShareGroups();
|
|
for (size_t i = ret.GetCount(); i > 0; i--) {
|
|
size_t idx = i - 1;
|
|
if (used.Index(ret[idx].m_sGroupName) == wxNOT_FOUND) {
|
|
myLogTrace(MYTRACETAG, wxT("removing[%d] '%s'"),
|
|
(int)idx, VMB(ret[idx].m_sShareName));
|
|
ret.RemoveAt(idx);
|
|
continue;
|
|
}
|
|
if (ret[idx].m_eType != SharedResource::SHARE_CUPS_PRINTER) {
|
|
myLogTrace(MYTRACETAG, wxT("removing[%d] '%s'"),
|
|
(int)idx, VMB(ret[idx].m_sShareName));
|
|
ret.RemoveAt(idx);
|
|
continue;
|
|
}
|
|
bool bAvailable = false;
|
|
myLogTrace(MYTRACETAG, wxT("Considering CUPS printer '%s' %d"),
|
|
VMB(ret[idx].m_sShareName), (int)idx);
|
|
for (size_t j = 0; j < sa.GetCount(); j++) {
|
|
if (sa[j].name == ret[idx].m_sShareName) {
|
|
bAvailable = true;
|
|
break;
|
|
}
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("'%s' is %savailable"),
|
|
VMB(ret[idx].m_sShareName),
|
|
(bAvailable ? "" : "not "));
|
|
if (!bAvailable) {
|
|
myLogTrace(MYTRACETAG, wxT("removing[%d] '%s'"),
|
|
(int)idx, VMB(ret[idx].m_sShareName));
|
|
ret.RemoveAt(idx);
|
|
}
|
|
}
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("# of active printers: %d"), (int)ret.GetCount());
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
MySession::isCupsRunning()
|
|
{
|
|
bool ret = m_bCupsRunning;
|
|
if (!ret) {
|
|
CupsClient cc;
|
|
ret = cc.IsAvailable();
|
|
m_bCupsRunning = ret;
|
|
}
|
|
myLogTrace(MYTRACETAG, wxT("isCupsRunning returning %s"), (ret ? "true" : "false"));
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
MySession::setTurboPath(bool enable)
|
|
{
|
|
#ifdef __WXMAC__
|
|
return;
|
|
wxString ldpath;
|
|
bool isset = ::wxGetEnv(wxT("DYLD_LIBRARY_PATH"), &ldpath);
|
|
bool contains = isset && ldpath.Contains(wxT("libjpeg-turbo"));
|
|
if (enable) {
|
|
if (!contains) {
|
|
# if defined(__x86_64) || defined(__IA64__)
|
|
wxString archlib = wxT("lib64");
|
|
# else
|
|
wxString archlib = wxT("lib");
|
|
# endif
|
|
wxString turbopath;
|
|
wxFileName tjpeg;
|
|
tjpeg.AssignDir(wxT("/usr"));
|
|
tjpeg.AppendDir(archlib);
|
|
tjpeg.AppendDir(wxT("libjpeg-turbo"));
|
|
if (tjpeg.DirExists()) {
|
|
turbopath = tjpeg.GetPath();
|
|
ldpath.Prepend(tjpeg.GetPath().Append(wxT(":")));
|
|
} else {
|
|
tjpeg.AssignDir(wxT("/opt/libjpeg-turbo"));
|
|
tjpeg.AppendDir(archlib);
|
|
if (tjpeg.DirExists()) {
|
|
turbopath = tjpeg.GetPath();
|
|
ldpath.Prepend(tjpeg.GetPath().Append(wxT(":")));
|
|
}
|
|
}
|
|
if (!turbopath.IsEmpty()) {
|
|
if (!ldpath.IsEmpty())
|
|
ldpath.Prepend(wxT(":"));
|
|
ldpath.Prepend(turbopath);
|
|
}
|
|
::myLogDebug(wxT("DYLD_LIBRARY_PATH='%s'"), VMB(ldpath));
|
|
if (!::wxSetEnv(wxT("DYLD_LIBRARY_PATH"), ldpath)) {
|
|
wxLogSysError(wxT("Cannot set DYLD_LIBRARY_PATH"));
|
|
}
|
|
}
|
|
} else {
|
|
if (contains) {
|
|
wxString newpath;
|
|
wxStringTokenizer t(ldpath, wxT(":"));
|
|
while (t.HasMoreTokens()) {
|
|
wxString fragment = t.GetNextToken();
|
|
if ((!fragment.IsEmpty()) && (!fragment.Contains(wxT("libjpeg-turbo")))) {
|
|
if (!newpath.IsEmpty())
|
|
newpath.Append(wxT(":"));
|
|
newpath.Append(fragment);
|
|
}
|
|
}
|
|
if (newpath.IsEmpty()) {
|
|
::wxUnsetEnv(wxT("DYLD_LIBRARY_PATH"));
|
|
} else {
|
|
::myLogDebug(wxT("DYLD_LIBRARY_PATH='%s'"), VMB(newpath));
|
|
if (!::wxSetEnv(wxT("DYLD_LIBRARY_PATH"), newpath)) {
|
|
wxLogSysError(wxT("Cannot set DYLD_LIBRARY_PATH"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
wxUnusedVar(enable);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
MySession::cleanupOldSessions()
|
|
{
|
|
wxDir ud;
|
|
myLogTrace(MYTRACETAG, wxT("Cleaning up old session datav in %s"), VMB(m_sUserDir));
|
|
if (ud.Open(m_sUserDir)) {
|
|
SessionCleaner sc(m_sUserDir);
|
|
ud.Traverse(sc);
|
|
}
|
|
}
|
|
|
|
void
|
|
MySession::clearSshKeys(const wxString &keyloc)
|
|
{
|
|
myLogTrace(MYTRACETAG, wxT("Clearing keys for %s at %s"),
|
|
VMB(m_pCfg->sGetServerHost()), VMB(keyloc));
|
|
wxString keyfile = keyloc.BeforeLast(wxT(':'));
|
|
#ifdef __WXMSW__
|
|
if (keyfile.StartsWith(wxT("/cygdrive/"), &keyfile)) {
|
|
keyfile = keyfile.BeforeFirst(wxT('/')).Upper().Append(wxT(":/")).Append(keyfile.AfterFirst(wxT('/')));
|
|
keyfile.Replace(wxT("/"), wxT("\\"));
|
|
myLogTrace(MYTRACETAG, wxT("Keyfile: %s"), VMB(keyfile));
|
|
}
|
|
#endif
|
|
long n;
|
|
if (keyloc.AfterLast(wxT(':')).ToLong(&n)) {
|
|
n--;
|
|
wxTextFile tf(keyfile);
|
|
if (tf.Exists()) {
|
|
if (tf.Open()) {
|
|
myLogTrace(MYTRACETAG, wxT("Removing '%s'"), VMB(tf[n]));
|
|
tf.RemoveLine(n);
|
|
wxIPV4address ip;
|
|
if (ip.Hostname(m_pCfg->sGetServerHost())) {
|
|
wxString ipnum = ip.IPAddress();
|
|
wxString line;
|
|
for (line = tf.GetFirstLine(); !tf.Eof(); line = tf.GetNextLine()) {
|
|
if (line.Contains(ipnum)) {
|
|
myLogTrace(MYTRACETAG, wxT("Removing '%s'"), VMB(line));
|
|
tf.RemoveLine(tf.GetCurrentLine());
|
|
}
|
|
}
|
|
}
|
|
tf.Write();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
MySession::Create(MyXmlConfig &cfgpar, const wxString password, wxWindow *parent)
|
|
{
|
|
m_sClearPassword = password;
|
|
m_bSessionRunning = false;
|
|
m_bCupsRunning = false;
|
|
m_bEsdRunning = false;
|
|
m_bNativePARunning = false;
|
|
m_lEsdPort = 0;
|
|
m_bAbort = false;
|
|
m_bSessionEstablished = false;
|
|
m_bCollectSessions = false;
|
|
m_bCollectConfig = false;
|
|
m_bCollectResources = false;
|
|
m_bIsShadow = false;
|
|
m_bNextCmd = false;
|
|
m_sSessionID = wxEmptyString;
|
|
m_pParent = parent;
|
|
MyXmlConfig cfg(cfgpar.sGetFileName());
|
|
m_pCfg = &cfg;
|
|
|
|
if (cfg.IsValid()) {
|
|
// Copy misc values from login dialog
|
|
m_pCfg->bSetUseSmartCard(cfgpar.bGetUseSmartCard());
|
|
m_pCfg->bSetEnableSSL(cfgpar.bGetEnableSSL());
|
|
m_pCfg->bSetGuestMode(cfgpar.bGetGuestMode());
|
|
if (!cfgpar.bGetGuestMode()) {
|
|
m_pCfg->sSetUsername(cfgpar.sGetUsername());
|
|
m_pCfg->sSetPassword(password);
|
|
}
|
|
|
|
wxConfigBase::Get()->Read(wxT("Config/SystemNxDir"), &m_sSysDir);
|
|
wxConfigBase::Get()->Read(wxT("Config/UserNxDir"), &m_sUserDir);
|
|
checkXarch();
|
|
|
|
wxFileName fn(m_sSysDir, wxEmptyString);
|
|
fn.AppendDir(wxT("bin"));
|
|
#ifdef __WXMSW__
|
|
fn.SetName(wxT("nxssh.exe"));
|
|
#else
|
|
fn.SetName(wxT("nxssh"));
|
|
#endif
|
|
wxString nxsshcmd = fn.GetShortPath();
|
|
nxsshcmd << wxT(" -nx -x -2 -4")
|
|
<< wxT(" -p ") << m_pCfg->iGetServerPort()
|
|
<< wxT(" -o 'RhostsAuthentication no'")
|
|
<< wxT(" -o 'PasswordAuthentication no'")
|
|
<< wxT(" -o 'RSAAuthentication no'")
|
|
<< wxT(" -o 'RhostsRSAAuthentication no'")
|
|
<< wxT(" -o 'PubkeyAuthentication yes'");
|
|
m_sTempDir = m_sUserDir;
|
|
m_sTempDir << wxFileName::GetPathSeparator() << wxT("temp")
|
|
<< wxFileName::GetPathSeparator() << ::wxGetProcessId();
|
|
wxFileName::Mkdir(m_sTempDir, 0700, wxPATH_MKDIR_FULL);
|
|
|
|
wxString logfn = m_sTempDir +
|
|
wxFileName::GetPathSeparator() + wxT("runlog");
|
|
#ifdef __VISUALC__
|
|
ofstream *log = new ofstream();
|
|
#else
|
|
std::ofstream *log = new std::ofstream();
|
|
#endif
|
|
log->open(logfn.ToUTF8());
|
|
new RunLog(new wxLogStream(log));
|
|
|
|
logfn = m_sTempDir +
|
|
wxFileName::GetPathSeparator() + wxT("sshlog");
|
|
#ifdef __VISUALC__
|
|
log = new ofstream();
|
|
#else
|
|
log = new std::ofstream();
|
|
#endif
|
|
log->open(logfn.ToUTF8());
|
|
m_pSshLog = new wxLogStream(log);
|
|
wxLog::SetLogLevel(wxLOG_Max);
|
|
|
|
m_bIsShadow = (m_pCfg->eGetSessionType() == MyXmlConfig::STYPE_SHADOW);
|
|
if (m_pCfg->bGetRemoveOldSessionFiles())
|
|
cleanupOldSessions();
|
|
|
|
if (m_pCfg->bGetUseSmartCard()) {
|
|
myLogTrace(MYTRACETAG, wxT("Checking for SmartCard"));
|
|
CardWaiterDialog wd;
|
|
m_iReader = wd.WaitForCard(parent);
|
|
if (m_iReader == -1)
|
|
return false;
|
|
nxsshcmd << wxT(" -I ") << m_iReader;
|
|
} else {
|
|
if (m_pCfg->sGetSshKey().IsEmpty()) {
|
|
fn.Assign(m_sSysDir, wxT("server.id_dsa.key"));
|
|
fn.AppendDir(wxT("share"));
|
|
fn.AppendDir(wxT("keys"));
|
|
} else {
|
|
fn.Assign(m_sTempDir, wxT("keylog"));
|
|
wxFile f;
|
|
if (fn.FileExists())
|
|
::wxRemoveFile(fn.GetFullPath());
|
|
if (f.Open(fn.GetFullPath(), wxFile::write_excl, wxS_IRUSR|wxS_IWUSR)) {
|
|
f.Write(m_pCfg->sGetSshKey());
|
|
f.Close();
|
|
} else {
|
|
wxLogSysError(_("Could not write %s"), VMB(fn.GetFullPath()));
|
|
return false;
|
|
}
|
|
}
|
|
nxsshcmd << wxT(" -i ") << fn.GetShortPath();
|
|
}
|
|
|
|
if (m_pCfg->bGetUseProxy()) {
|
|
if (m_pCfg->bGetExternalProxy()) {
|
|
if (!m_pCfg->sGetProxyCommand().IsEmpty())
|
|
nxsshcmd << wxT(" -o 'ProxyCommand ") << m_pCfg->sGetProxyCommand() << wxT("'");
|
|
} else {
|
|
|
|
if (!m_pCfg->sGetProxyHost().IsEmpty()) {
|
|
// Internal (NoMachine) proxy
|
|
if (m_pCfg->sGetProxyUser().IsEmpty())
|
|
nxsshcmd << wxT(" -P ") << m_pCfg->sGetProxyHost() << wxT(":") << m_pCfg->iGetProxyPort();
|
|
else {
|
|
wxString proxyPass = m_pCfg->sGetProxyPass();
|
|
if (!m_pCfg->bGetProxyPassRemember()) {
|
|
ProxyPasswordDialog dlg(m_pParent);
|
|
if (dlg.ShowModal() == wxID_OK)
|
|
proxyPass = dlg.GetPassword();
|
|
else
|
|
return false;
|
|
}
|
|
nxsshcmd << wxT(" -P ") << m_pCfg->sGetProxyUser() << wxT(":") << proxyPass << wxT("@")
|
|
<< m_pCfg->sGetProxyHost() << wxT(":") << m_pCfg->iGetProxyPort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
nxsshcmd << wxT(" -4 -B -E") << wxT(" nx@") << m_pCfg->sGetServerHost();
|
|
m_sHost = m_pCfg->sGetServerHost();
|
|
|
|
wxString stmp;
|
|
::wxGetEnv(wxT("PATH"), &stmp);
|
|
// Prepend our system directory, so that pconnect can be found by nxssh (if necessary)
|
|
fn.Assign(m_sSysDir, wxT("bin"));
|
|
if (!stmp.Contains(fn.GetShortPath())) {
|
|
#ifdef __WXMSW__
|
|
stmp.Prepend(wxT(";")).Prepend(fn.GetShortPath());
|
|
#else
|
|
stmp.Prepend(wxT(":")).Prepend(fn.GetShortPath());
|
|
#endif
|
|
#ifdef __WXMAC__
|
|
stmp.Append(wxT(":/usr/X11R6/bin:/usr/X11/bin"));
|
|
#endif
|
|
::wxSetEnv(wxT("PATH"), stmp);
|
|
}
|
|
wxLogInfo(wxT("env: PATH='%s'"), VMB(stmp));
|
|
fn.Assign(wxFileName::GetHomeDir());
|
|
::wxSetEnv(wxT("NX_HOME"), fn.GetShortPath());
|
|
wxLogInfo(wxT("env: NX_HOME='%s'"), VMB(fn.GetShortPath()));
|
|
::wxSetEnv(wxT("HOME"), fn.GetShortPath());
|
|
wxLogInfo(wxT("env: HOME='%s'"), VMB(fn.GetShortPath()));
|
|
fn.Assign(m_sUserDir);
|
|
::wxSetEnv(wxT("NX_ROOT"), fn.GetShortPath());
|
|
wxLogInfo(wxT("env: NX_ROOT='%s'"), VMB(fn.GetShortPath()));
|
|
fn.Assign(m_sSysDir);
|
|
::wxSetEnv(wxT("NX_SYSTEM"), fn.GetShortPath());
|
|
wxLogInfo(wxT("env: NX_SYSTEM='%s'"), VMB(fn.GetShortPath()));
|
|
fn.Assign(::wxGetApp().GetSelfPath());
|
|
::wxSetEnv(wxT("NX_CLIENT"), fn.GetShortPath());
|
|
wxLogInfo(wxT("env: NX_CLIENT='%s'"), VMB(fn.GetShortPath()));
|
|
::wxSetEnv(wxT("NX_VERSION"), m_sProtocolVersion);
|
|
wxLogInfo(wxT("env: NX_VERSION='%s'"), VMB(m_sProtocolVersion));
|
|
if (m_pCfg->eGetDisplayType() == MyXmlConfig::DPTYPE_FULLSCREEN) {
|
|
bool bVal = false;
|
|
wxConfigBase::Get()->Read(wxT("Config/DisableMagicPixel"), &bVal, false);
|
|
if (bVal) {
|
|
int dspw, dsph;
|
|
::wxDisplaySize(&dspw, &dsph);
|
|
wxString w = wxString::Format(wxT("%d"), (int)dspw);
|
|
::wxSetEnv(wxT("NX_KIOSK_X"), w);
|
|
wxLogInfo(wxT("env: NX_KIOSK_X='%s'"), VMB(w));
|
|
}
|
|
}
|
|
::wxSetEnv(wxT("XAUTHORITY"), getXauthPath(m_eXarch));
|
|
wxLogInfo(wxT("env: XAUTHORITY='%s'"), VMB(getXauthPath(m_eXarch)));
|
|
#ifdef __UNIX__
|
|
// NX needs TEMP or NX_TEMP to be set to the same dir
|
|
// where .X11-unix resides (typically /tmp)
|
|
stmp = wxConvLocal.cMB2WX(x11_socket_path);
|
|
if (!stmp.IsEmpty()) {
|
|
fn.Assign(stmp);
|
|
fn.RemoveLastDir();
|
|
fn.SetName(wxEmptyString);
|
|
::wxSetEnv(wxT("NX_TEMP"), cygPath(fn.GetFullPath()));
|
|
wxLogInfo(wxT("env: NX_TEMP='%s'"), VMB(cygPath(fn.GetShortPath())));
|
|
} else {
|
|
::wxSetEnv(wxT("NX_TEMP"), wxT("/tmp"));
|
|
wxLogInfo(wxT("env: NX_TEMP='/tmp'"));
|
|
}
|
|
#else
|
|
::wxSetEnv(wxT("NX_TEMP"), cygPath(m_sTempDir));
|
|
wxLogInfo(wxT("env: NX_TEMP='%s'"), VMB(cygPath(m_sTempDir)));
|
|
#endif
|
|
|
|
#ifdef __WXMSW__
|
|
if (m_eXarch == XARCH_CYGWIN) {
|
|
wxString srvstr = wxT("server");
|
|
::wxSetEnv(wxT("CYGWIN"), srvstr);
|
|
wxLogInfo(wxT("env: CYGWIN='%s'"), VMB(srvstr));
|
|
}
|
|
if (!startXserver()) {
|
|
wxLogError(_("Could not start local X server"));
|
|
return false;
|
|
}
|
|
if (XARCH_XMING == m_eXarch) {
|
|
// Now, that the X server has been started, // set XAUTHORITY
|
|
// again, but this time in cygwin notation (for nxssh).
|
|
::wxSetEnv(wxT("XAUTHORITY"), getXauthPath(XARCH_CYGWIN));
|
|
wxLogInfo(wxT("env: XAUTHORITY='%s'"), VMB(getXauthPath(XARCH_CYGWIN)));
|
|
// Configure XMing's special clipboard filter
|
|
HWND clpWnd = FindWindow(NULL ,wxT("OpenNXWinClip"));
|
|
if (NULL != clpWnd) {
|
|
PostMessage(clpWnd, WM_USER + 1004, m_pCfg->iGetClipFilter() + 1, 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
fn.Assign(m_sSysDir, wxT("bin"));
|
|
m_iProgress = 0;
|
|
ConnectDialog dlg(m_pParent);
|
|
m_pDlg = &dlg;
|
|
dlg.Show(true);
|
|
dlg.SetStatusText(wxString::Format(_("Connecting to %s ..."),
|
|
VMB(m_pCfg->sGetServerHost())));
|
|
if (m_pCfg->bGetEnableMultimedia()) {
|
|
m_bEsdRunning = false; m_bNativePARunning = false;
|
|
dlg.SetStatusText(_("Preparing multimedia service ..."));
|
|
PulseAudio pa;
|
|
if (pa.IsAvailable()) {
|
|
wxLogInfo(wxT("using existing pulseaudio"));
|
|
m_lEsdPort = wxConfigBase::Get()->Read(wxT("State/nxesdPort"), -1);
|
|
if (m_lEsdPort < 0)
|
|
m_lEsdPort = getFirstFreePort(6000);
|
|
if (0 < m_lEsdPort) {
|
|
bool pa_started = false;
|
|
if (m_pCfg->bGetEnableNativePA()) {
|
|
wxLogInfo(wxT("Activating Native Module in pulseaudio on port %ld"), m_lEsdPort);
|
|
int pa_rate = 0;
|
|
switch (m_pCfg->eGetRatePA()) {
|
|
case MyXmlConfig::RATEPA_NORESAMPLE:
|
|
pa_rate = 0; break;
|
|
case MyXmlConfig::RATEPA_48000:
|
|
pa_rate = 48000; break;
|
|
case MyXmlConfig::RATEPA_44100:
|
|
pa_rate = 44100; break;
|
|
case MyXmlConfig::RATEPA_32000:
|
|
pa_rate = 32000; break;
|
|
case MyXmlConfig::RATEPA_16000:
|
|
pa_rate = 16000; break;
|
|
case MyXmlConfig::RATEPA_8000:
|
|
pa_rate = 8000; break;
|
|
}
|
|
bool pa_mono = pa_rate > 0 ? m_pCfg->bGetEnableMonoPA() : false;
|
|
pa_started = m_bNativePARunning = pa.ActivateNative(m_lEsdPort, pa_rate, pa_mono);
|
|
} else {
|
|
wxLogInfo(wxT("Activating ESD Module in pulseaudio on port %ld"), m_lEsdPort);
|
|
pa_started = m_bEsdRunning = pa.ActivateEsound(m_lEsdPort);
|
|
}
|
|
if (pa_started) {
|
|
wxConfigBase::Get()->Write(wxT("State/nxesdPort"), m_lEsdPort);
|
|
wxConfigBase::Get()->Write(wxT("State/nxesdPID"), -1);
|
|
} else {
|
|
wxLogWarning(_("Could not start multimedia support"));
|
|
}
|
|
} else
|
|
wxLogWarning(_("Could not assign a free port for multimedia support"));
|
|
}
|
|
#ifndef __WXMSW__
|
|
if (!m_bEsdRunning && !m_bNativePARunning) {
|
|
// Fallback: original old nxesd
|
|
long esdpid = wxConfigBase::Get()->Read(wxT("State/nxesdPID"), -1);
|
|
m_lEsdPort = wxConfigBase::Get()->Read(wxT("State/nxesdPort"), -1);
|
|
if ((-1 != esdpid) && (0 < m_lEsdPort))
|
|
m_bEsdRunning = wxProcess::Exists(esdpid);
|
|
if ((!dlg.bGetAbort()) && (!m_bEsdRunning)) {
|
|
wxFileName fn(m_sSysDir, wxEmptyString);
|
|
fn.AppendDir(wxT("bin"));
|
|
fn.SetName(wxT("nxesd"));
|
|
if (fn.FileExists()) {
|
|
wxString esdcmd = fn.GetFullPath();
|
|
m_lEsdPort = getFirstFreePort(6000);
|
|
if (0 < m_lEsdPort) {
|
|
esdcmd << wxT(" -tcp -nobeeps -bind 127.0.0.1 -spawnfd 1 -port ") << m_lEsdPort;
|
|
wxLogInfo(wxT("starting in background: %s"), VMB(esdcmd));
|
|
wxProcess *nxesd = wxProcess::Open(esdcmd,
|
|
wxEXEC_ASYNC|wxEXEC_MAKE_GROUP_LEADER);
|
|
if (nxesd) {
|
|
nxesd->CloseOutput();
|
|
wxStopWatch sw;
|
|
while (!(dlg.bGetAbort() || nxesd->IsInputAvailable())) {
|
|
::wxGetApp().Yield(true);
|
|
wxLog::FlushActive();
|
|
// Timeout after 10 sec
|
|
if (sw.Time() > 10000)
|
|
break;
|
|
}
|
|
char msg = '\0';
|
|
if (nxesd->IsInputAvailable())
|
|
nxesd->GetInputStream()->Read(&msg, 1);
|
|
long esdpid = nxesd->GetPid();
|
|
nxesd->Detach();
|
|
if (msg) {
|
|
m_bEsdRunning = true;
|
|
wxConfigBase::Get()->Write(wxT("State/nxesdPID"), esdpid);
|
|
wxConfigBase::Get()->Write(wxT("State/nxesdPort"), m_lEsdPort);
|
|
}
|
|
}
|
|
if (!m_bEsdRunning)
|
|
wxLogWarning(_("Could not start multimedia support"));
|
|
} else
|
|
wxLogWarning(_("Could not assign a free port for multimedia support"));
|
|
} else
|
|
wxLogWarning(_("Could not start multimedia support"));
|
|
}
|
|
}
|
|
#endif
|
|
dlg.SetStatusText(wxString::Format(_("Connecting to %s ..."),
|
|
VMB(m_pCfg->sGetServerHost())));
|
|
}
|
|
|
|
if (dlg.bGetAbort()) {
|
|
#ifdef __WXMSW__
|
|
terminateXserver();
|
|
#endif
|
|
return false;
|
|
}
|
|
if (getActiveCupsPrinters().GetCount() > 0) {
|
|
dlg.SetStatusText(_("Preparing CUPS service ..."));
|
|
dlg.SetStatusText(wxString::Format(_("Connecting to %s ..."),
|
|
VMB(m_pCfg->sGetServerHost())));
|
|
}
|
|
|
|
MyIPC nxssh;
|
|
m_pNxSsh = &nxssh;
|
|
|
|
wxLogInfo(wxT("Starting %s"), VMB(nxsshcmd));
|
|
do {
|
|
m_bRemoveKey = false;
|
|
m_sOffendingKey = wxEmptyString;
|
|
setTurboPath(true);
|
|
if (nxssh.SshProcess(nxsshcmd, fn.GetShortPath(), this)) {
|
|
setTurboPath(false);
|
|
m_bGotError = false;
|
|
m_eConnectState = STATE_INIT;
|
|
while (!(dlg.bGetAbort() || m_bGotError || m_bAbort ||
|
|
(m_bSessionRunning && m_bSessionEstablished))) {
|
|
wxLog::FlushActive();
|
|
::wxGetApp().Yield(true);
|
|
#ifdef __WXMSW__
|
|
if (m_iXserverPID)
|
|
AllowSetForegroundWindow(m_iXserverPID);
|
|
#endif
|
|
}
|
|
if (dlg.bGetAbort() || m_bGotError || m_bAbort) {
|
|
if (m_bRemoveKey) {
|
|
while (m_sOffendingKey.IsEmpty()) {
|
|
wxLog::FlushActive();
|
|
::wxGetApp().Yield(true);
|
|
}
|
|
} else {
|
|
#ifndef __WXMSW__
|
|
nxssh.Kill();
|
|
#endif
|
|
#ifdef __WXMSW__
|
|
terminateXserver();
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
/*
|
|
// but original nxclient stay leave nxssh in case of unencrypted conn
|
|
else {
|
|
if (m_bSessionEstablished && (!m_bSslTunneling)) {
|
|
// Unecrypted session (handled by nxproxy), get rid of nxssh
|
|
nxssh.Kill();
|
|
}
|
|
}
|
|
*/
|
|
wxThread::Sleep(500);
|
|
#ifdef __WXMSW__
|
|
if (m_iXserverPID)
|
|
AllowSetForegroundWindow(m_iXserverPID);
|
|
#endif
|
|
} else {
|
|
setTurboPath(false);
|
|
wxLogError(_("Called command was: ") + nxsshcmd);
|
|
wxLogError(_("Could not start nxssh."));
|
|
#ifdef __WXMSW__
|
|
terminateXserver();
|
|
#endif
|
|
return false;
|
|
}
|
|
if (m_bRemoveKey)
|
|
clearSshKeys(m_sOffendingKey);
|
|
} while (m_bRemoveKey);
|
|
nxssh.Detach();
|
|
|
|
#ifdef __WXMSW__
|
|
if (m_iXserverPID)
|
|
AllowSetForegroundWindow(m_iXserverPID);
|
|
#endif
|
|
|
|
if (m_pCfg->bGetEnableUSBIP()) {
|
|
myLogTrace(MYTRACETAG, wxT("Enabling UsbIp"));
|
|
::wxGetApp().SetNxSshPID(nxssh.GetPID());
|
|
::wxGetApp().SetSessionCfg(*m_pCfg);
|
|
::wxGetApp().SetSessionID(m_sSessionID.Right(32));
|
|
::wxGetApp().SetRequireStartUsbIp(true);
|
|
} else {
|
|
if (m_pCfg->bGetUseSmartCard()) {
|
|
myLogTrace(MYTRACETAG, wxT("Enabling WatchReader %d"), (int)m_iReader);
|
|
::wxGetApp().SetNxSshPID(nxssh.GetPID());
|
|
::wxGetApp().SetReader(m_iReader);
|
|
::wxGetApp().SetRequireWatchReader(true);
|
|
}
|
|
}
|
|
#ifdef __WXMSW__
|
|
unhideNXWin();
|
|
#endif
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|