khanat-opennel-code/code/nelns/login_system/nel_launcher_windows/nel_launcherDlg.cpp
2017-03-15 20:43:10 +01:00

637 lines
14 KiB
C++

// nel_launcherDlg.cpp : implementation file
//
#include "stdafx.h"
#include "nel_launcher.h"
#include "nel_launcherDlg.h"
#include <string>
#include <vector>
#include <process.h>
#include <direct.h>
#include "mshtml.h"
#include "nel/misc/config_file.h"
#include "nel/misc/path.h"
#include "patch.h"
using namespace std;
using namespace NLMISC;
CConfigFile ConfigFile;
/*#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif*/
const char *PleaseWaitFilename = "pleasewait.html";
void CNel_launcherDlg::openUrl (const std::string &url)
{
m_explore.Navigate(url.c_str(), NULL, NULL, NULL, NULL);
}
/////////////////////////////////////////////////////////////////////////////
// CNel_launcherDlg dialog
CNel_launcherDlg::CNel_launcherDlg(CWnd* pParent /*=NULL*/)
: CDialog(CNel_launcherDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CNel_launcherDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CNel_launcherDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CNel_launcherDlg)
DDX_Control(pDX, IDC_EXPLORER1, m_explore);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CNel_launcherDlg, CDialog)
//{{AFX_MSG_MAP(CNel_launcherDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_SIZE()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CNel_launcherDlg message handlers
BOOL CNel_launcherDlg::OnInitDialog()
{
NLMISC::CApplicationContext ApplicationContext;
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
//CWebBrowser2 m_browser - member variable
// downloadFile ();
// return TRUE;
ConfigFile.load ("nel_launcher.cfg");
// get the working path
string workingPath = CPath::getFullPath (ConfigFile.getVar ("Application").asString(2));
if (!NLMISC::CFile::isExists (workingPath))
{
nlerror ("Working path '%s' doesn't exists", workingPath.c_str ());
}
// load the pleasewait html page if available in the nel_launcher directory
bool PleaseWaitLoaded = false;
string PleaseWaitFullPath;
PleaseWaitFullPath = CPath::getFullPath (PleaseWaitFilename, false);
if (NLMISC::CFile::isExists (PleaseWaitFullPath))
{
openUrl(PleaseWaitFullPath.c_str());
PleaseWaitLoaded = true;
}
_chdir (workingPath.c_str ());
// load the pleasewait html page if available in the client directory
PleaseWaitFullPath = CPath::getFullPath (PleaseWaitFilename, false);
if (!PleaseWaitLoaded && NLMISC::CFile::isExists (PleaseWaitFullPath))
{
openUrl(PleaseWaitFullPath.c_str());
}
// remove temp files
if (NLMISC::CFile::fileExists ("update_nel_launcher.bat"))
NLMISC::CFile::deleteFile ("update_nel_launcher.bat");
string Version = getVersion ();
string url = "http://"+ConfigFile.getVar ("StartupHost").asString()+ConfigFile.getVar ("StartupPage").asString();
url += "?newClientVersion=" + Version;
url += "&newClientApplication=" + ConfigFile.getVar ("Application").asString(0);
openUrl (url);
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CNel_launcherDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CNel_launcherDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
BEGIN_EVENTSINK_MAP(CNel_launcherDlg, CDialog)
//{{AFX_EVENTSINK_MAP(CNel_launcherDlg)
ON_EVENT(CNel_launcherDlg, IDC_EXPLORER1, 250 /* BeforeNavigate2 */, OnBeforeNavigate2Explorer1, VTS_DISPATCH VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PVARIANT VTS_PBOOL)
ON_EVENT(CNel_launcherDlg, IDC_EXPLORER1, 259 /* DocumentComplete */, OnDocumentCompleteExplorer1, VTS_DISPATCH VTS_PVARIANT)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
void CNel_launcherDlg::OnBeforeNavigate2Explorer1(LPDISPATCH pDisp, VARIANT FAR* URL, VARIANT FAR* Flags, VARIANT FAR* TargetFrameName, VARIANT FAR* PostData, VARIANT FAR* Headers, BOOL FAR* Cancel)
{
// set the user agent to nel_launcher changing the header
CString strHeader(Headers->bstrVal);
if (strHeader == "")
{
IWebBrowser2 *pBrowser;
LPDISPATCH pWebDisp;
pDisp->QueryInterface(IID_IWebBrowser2, (void**) &pBrowser);
pBrowser->get_Container(&pWebDisp);
BSTR bstr = SysAllocString(L"User-Agent: nel_launcher\r\n");
Headers->bstrVal = bstr;
pBrowser->Navigate2(URL, Flags, TargetFrameName, PostData, Headers);
if (!pWebDisp)
(*Cancel) = true;
if (pWebDisp)
pWebDisp->Release();
if (pBrowser)
pBrowser->Release();
SysFreeString (bstr);
return;
}
/* CString cstr = URL->bstrVal;
string str = string((const char*)cstr);
if (str.find ("clientVersion=") == string::npos)
{
string Version;
FILE *fp = fopen ("VERSION", "rb");
if (fp!=NULL)
{
char ver[1000];
if (fgets (ver, 1000, fp) != NULL)
{
Version = ver;
}
fclose (fp);
}
string url = str;
if (url.find ("?") != string::npos)
{
url += "&";
}
else
{
url += "?";
}
// url += "clientVersion=" + Version;
// url += "&clientApplication=" + ConfigFile.getVar ("Application").asString(0);
url += "toto=10";
*Cancel = TRUE;
m_explore.Navigate(url.c_str(), Flags, TargetFrameName, PostData, Headers);
*/
/*
VARIANT vurl;
VariantInit (&vurl);
vurl.vt = VT_BSTR;
vector<unsigned short> v;
for (uint i = 0; i < url.size (); i++)
v.push_back ((unsigned short)url[i]);
v.push_back (0);
BSTR bstr = SysAllocString((const unsigned short *)&(v[0]));
vurl.bstrVal = bstr;
OnBeforeNavigate2Explorer1(pDisp, &vurl, Flags, TargetFrameName, PostData, Headers, Cancel);
SysFreeString (bstr);
*/
/* }
else
{
nlinfo ("coucou");
}
*/
/* if (str.find("?nel_quit=1") != string::npos)
{
exit(0);
}
string token ("nel_exe=");
int spos = str.find (token);
if (spos == string::npos) return;
int spos2 = str.find ("&", spos+token.size ()+1);
if (spos == string::npos) return;
string path;
string exe = str.substr (spos+token.size (), spos2-spos-token.size ());
CConfigFile::CVar *var = ConfigFile.getVarPtr (exe);
if (var == NULL)
{
char str[1024];
smprintf (str, 1024, "Don't know the executable filename for the application '%s'", exe.c_str ());
MessageBox (str, "nel_launcher error");
exit(0);
}
else
{
exe = var->asString (0);
path = var->asString (1);
}
token = "nel_args=";
spos = str.find (token);
if (spos == string::npos) return;
string rawargs = str.substr (spos+token.size ());
// decode arguments (%20 -> space)
vector<string> vargs;
const char *args[50];
int argspos = 0;
int pos1 = 0, pos2 = 0;
while (true)
{
pos2 = rawargs.find("%20", pos1);
if (pos2==string::npos)
{
if(pos1!=rawargs.size())
{
string res = rawargs.substr (pos1);
vargs.push_back (res);
}
break;
}
if(pos1 != pos2)
{
string res = rawargs.substr (pos1, pos2-pos1);
vargs.push_back (res);
}
pos1 = pos2+3;
}
int i;
int size;
if(vargs.size()>47) size = 47;
else size = vargs.size();
args[0] = exe.c_str ();
for(i = 0; i < size; i++)
{
args[i+1] = vargs[i].c_str ();
}
args[i+1] = NULL;
// execute, should better use CreateProcess()
_chdir (path.c_str());
_execvp (exe.c_str(), args);
exit(0);
*/
/* string cmd;
cmd=exe+" "+rawargs;
while (true)
{
int pos = cmd.find ("%20");
if (pos == string::npos)
break;
cmd.replace (pos, 3, " ");
}
WinExec (cmd.c_str(), SW_SHOWNORMAL);
*/
}
void CNel_launcherDlg::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);
if (m_explore.m_hWnd == NULL) return;
CRect rect;
GetClientRect (&rect);
m_explore.SetWindowPos ((CWnd* )HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
}
string getValue (const string &str, const string &token)
{
string realtoken = token+"=\"";
uint spos = str.find (realtoken);
if (spos == string::npos) return "";
uint spos2 = str.find ("\"", spos+realtoken.size ());
if (spos == string::npos) return "";
return str.substr (spos+realtoken.size (), spos2-spos-realtoken.size ());
}
void CNel_launcherDlg::launch (const string &str)
{
string exe = ConfigFile.getVar ("Application").asString(1);
string path;
if (ConfigFile.getVar ("Application").size() == 4)
path = ConfigFile.getVar ("Application").asString(3);
string rawargs = getValue (str, "nelArgs");
nlinfo ("extracting string '%s'", str.c_str ());
// convert the command line in an array of string for the _execvp() function
vector<string> vargs;
const char *args[50];
int argspos = 0;
uint pos1 = 0, pos2 = 0;
while (true)
{
pos2 = rawargs.find(" ", pos1);
if (pos2==string::npos)
{
if(pos1!=rawargs.size())
{
string res = rawargs.substr (pos1);
vargs.push_back (res);
}
break;
}
if(pos1 != pos2)
{
string res = rawargs.substr (pos1, pos2-pos1);
vargs.push_back (res);
}
pos1 = pos2+1;
}
int i;
int size;
if(vargs.size()>47) size = 47;
else size = vargs.size();
args[0] = exe.c_str ();
for(i = 0; i < size; i++)
{
args[i+1] = vargs[i].c_str ();
}
args[i+1] = NULL;
// go in the good path before launching
if (!path.empty())
_chdir (path.c_str ());
// execute, should better use CreateProcess()
if (_execvp (exe.c_str(), args) == -1)
{
// error occurs during the launch
string str = toString("Can't execute '%s': code=%d %s", exe.c_str(), errno, strerror(errno));
MessageBox (str.c_str(), "Error");
}
exit(0);
}
void CNel_launcherDlg::patch (const string &str)
{
string url = "http://"+ConfigFile.getVar ("StartupHost").asString();
string serverVersion = getValue (str, "serverVersion");
string urlok = url;
urlok += getValue (str, "nelUrl");
urlok += "&newClientVersion=";
urlok += serverVersion;
string urlfailed = url;
urlfailed += getValue (str, "nelUrlFailed");
urlfailed += "&reason=";
startPatchThread (getValue (str, "nelServerPath"), serverVersion, urlok, urlfailed, "<br>");
SetTimer(0,100,NULL);
/* try
{
string serverVersion = getValue (str, "serverVersion");
patchVersion (getValue (str, "nelServerPath"), serverVersion);
// this url is where we have to go after patching success
url += getValue (str, "nelUrl");
url += "&newClientVersion=";
url += serverVersion;
}
catch (Exception &e)
{
nlwarning ("Patching failed '%s'", e.what());
url += getValue (str, "nelUrlFailed");
url += "&reason=";
url += e.what ();
}
// go to the next url
openUrl (url.c_str());*/
}
void CNel_launcherDlg::OnTimer(UINT nIDEvent)
{
string state, log;
if (patchState(state, log))
{
LPDISPATCH lpDispatch;
lpDispatch = m_explore.GetDocument();
if (lpDispatch == NULL) return;
IHTMLDocument2* pHTMLDocument2;
HRESULT hr;
hr = lpDispatch->QueryInterface(IID_IHTMLDocument2, (LPVOID*) &pHTMLDocument2);
lpDispatch->Release();
if (FAILED(hr)) return;
if (pHTMLDocument2 == NULL) return;
IHTMLElement* pBody;
hr = pHTMLDocument2->get_body(&pBody);
if (FAILED(hr)) return;
if (pBody == NULL) return;
BSTR bstr;
pBody->get_innerHTML(&bstr);
CString csourceCode( bstr );
string htmlCode( (LPCSTR)csourceCode );
SysFreeString(bstr);
string tokenStart = "<!--nel_start_state-->";
string tokenEnd = "<!--nel_end_state-->";
int pos = csourceCode.Find (tokenStart.c_str());
if (pos == -1) return;
int pos2 = csourceCode.Find (tokenEnd.c_str());
if (pos2 == -1) return;
CString oldstate = csourceCode.Mid (pos, pos2-pos);
if (csourceCode.Replace (oldstate, string(tokenStart+state).c_str ()) == 0)
return;
string tokenStartLog = "<!--nel_start_log-->";
string tokenEndLog = "<!--nel_end_log-->";
int pos3 = csourceCode.Find (tokenStartLog.c_str());
if (pos3 == -1) return;
int pos4 = csourceCode.Find (tokenEndLog.c_str());
if (pos4 == -1) return;
CString oldlog = csourceCode.Mid (pos3, pos4-pos3);
if (csourceCode.Replace (oldlog, string(tokenStartLog+log).c_str ()) == 0)
return;
pBody->put_innerHTML(csourceCode.AllocSysString ()); //insert the html
pBody->Release();
}
string url;
bool res;
if (patchEnded(url, res))
{
nlinfo ("finnish");
KillTimer (0);
if (res)
MessageBox ("Patch completed succesfuly.", "patch");
else
MessageBox ("Patch could not be completed due to an error.", "patch");
openUrl (url.c_str());
}
}
void CNel_launcherDlg::OnDocumentCompleteExplorer1(LPDISPATCH pDisp, VARIANT FAR* URL)
{
IHTMLDocument2* pHTMLDocument2;
LPDISPATCH lpDispatch;
lpDispatch = m_explore.GetDocument();
if (lpDispatch)
{
HRESULT hr;
hr = lpDispatch->QueryInterface(IID_IHTMLDocument2, (LPVOID*) &pHTMLDocument2);
lpDispatch->Release();
if (FAILED(hr))
return;
if (pHTMLDocument2 == NULL)
return;
IHTMLElement* pBody;
hr = pHTMLDocument2->get_body(&pBody);
if (FAILED(hr))
return;
if (pBody == NULL)
return;
BSTR bstr;
pBody->get_innerHTML(&bstr);
CString csourceCode( bstr );
string str( (LPCSTR)csourceCode );
SysFreeString(bstr);
pBody->Release();
// now I have the web page, look if there's something interesting in it.
// if something start with <!--nel it s cool
string action = getValue (str, "<!--nel");
if (action.empty ())
return;
string token = "<!--nel";
uint spos = str.find (token);
uint spos2 = str.find ("-->", spos+token.size ()+1);
string comment = str.substr (spos+token.size (), spos2-spos-token.size ());
if (action=="launch")
launch (comment);
else if (action=="patch")
patch (comment);
return;
}
}