#include "baseserv.h"

#include "dongle.h"
#include "MD5Checksum.h"

#include <wx/hashset.h>
#include <wx/textfile.h>

///////////////////////////////////////////////////////////
// TUserInfo
///////////////////////////////////////////////////////////

class TUserInfo : public wxObject
{
public:
	wxString m_strName;
	wxString m_strHost;
	wxDateTime m_time;
	size_t m_nPrograms;
		
	TUserInfo(const wxChar* user, const wxChar* host);
};

TUserInfo::TUserInfo(const wxChar* user, const wxChar* host)
         : m_strName(user), m_strHost(host), 
				   m_time(wxDateTime::Now()), m_nPrograms(0) 
{ 
}

WX_DECLARE_HASH_MAP( wxString, TUserInfo*, wxStringHash, wxStringEqual, TUsersHashMap );

class TUserTable : public TUsersHashMap
{
protected:
  wxString BuildKey(wxSocketBase& sock, const wxChar* user, int session) const;

public:
  TUserInfo* AddConnection(wxSocketBase& sock, const wxChar* user, int session);
	TUserInfo* Find(wxSocketBase& sock, const wxChar* user, int session);
	void RemoveConnection(wxSocketBase& sock, const wxChar* user, int session);
	void Kill(const wxChar* strUserAtHost);
  void KillSession(wxSocketBase& sock, int session);

	size_t GetCount() const { return size(); } 
	size_t GetLicenses() const; 

	TUserTable();
};

WX_DECLARE_HASH_SET( wxString, wxStringHash, wxStringEqual, THostSet );

size_t TUserTable::GetLicenses() const
{
	THostSet hsHosts;
  for( TUsersHashMap::const_iterator it = begin(); it != end(); ++it )
    hsHosts.insert(it->first);
	return hsHosts.size();
}

wxString TUserTable::BuildKey(wxSocketBase& sock, const wxChar* user, int session) const
{
  wxIPV4address peer; sock.GetPeer(peer);
  wxString host;
  host.Printf("%s:%d", peer.Hostname().c_str(), session);
  wxString strUserAtHost;
  strUserAtHost.Printf("%s@%s", user, host.c_str());
  return strUserAtHost;
}

TUserInfo* TUserTable::AddConnection(wxSocketBase& sock, const wxChar* user, int session)
{
	TUserInfo* ui = Find(sock, user, session);
	if (ui == NULL)
	{
    const wxString strUserAtHost = BuildKey(sock, user, session);
    ui = new TUserInfo(user, strUserAtHost.After('@'));
		(*this)[strUserAtHost] = ui;
	}
	ui->m_nPrograms++;

	return ui;
}

TUserInfo* TUserTable::Find(wxSocketBase& sock, const wxChar* user, int session)
{
  const wxString strUserAtHost = BuildKey(sock, user, session);
	if (user && *user)
    return (*this)[strUserAtHost];

  const wxString strHost = strUserAtHost.After('@');
  for( TUsersHashMap::iterator it = begin(); it != end(); ++it )
  {
    TUserInfo* ui = it->second;
		if (ui->m_strHost == strHost)
			return ui;
	}

	return NULL;
}

void TUserTable::RemoveConnection(wxSocketBase& sock, const wxChar* user, int session)
{
	TUserInfo* ui = Find(sock, user, session);
	if (ui)
	{
		ui->m_nPrograms--;
		if (ui->m_nPrograms <= 0)
    {
      const wxString strUserAtHost = BuildKey(sock, user, session);
		  erase(strUserAtHost);
    }
	}
}

void TUserTable::Kill(const wxChar* strUserAtHost)
{
  erase(strUserAtHost);
}

void TUserTable::KillSession(wxSocketBase& sock, int session)
{
  while (true)
  {
	  TUserInfo* ui = Find(sock, NULL, session);
		if (ui != NULL)
    {
      const wxString strUserAtHost = BuildKey(sock, ui->m_strName.c_str(), session);
		  erase(strUserAtHost);
    }
    else
			break;
	}
}

TUserTable::TUserTable()
{ 
	clear(); 
}

///////////////////////////////////////////////////////////
// TAuthorizationServer
///////////////////////////////////////////////////////////

class TAuthorizationServer : public TBaseServerApp
{
private:
	TDongle m_Dongle;
	unsigned long m_Modules[2];
	unsigned int m_nModules;
	wxString m_strLastPassword;
	wxString m_strLastApp;
  unsigned int m_nPwdCount;
	unsigned int m_MaxTries;

	TUserTable m_Users;

protected:  
	virtual const wxChar* GetAppName() const;
  virtual bool ProcessCommand(wxString cmd, wxSocketBase& outs);

  void AddNumber(TXmlItem& tr, int n) const;
  wxString DescribeModule(int m) const;
  bool KeyIsGood(const wxString& key, const wxString& gar) const;

	void InitModules();
  wxString GetModulesFilename() const;
  wxString Garble(unsigned short n, const wxDateTime& date) const;
  wxString GarbleMD5(unsigned short n, const wxDateTime& date) const;

public:
	bool IsMagicName(wxString& strFilename) const;

  void GenerateIndex(wxString& strFilename);
  void GenerateUsers(wxString& strFilename);
  void GenerateModules(wxString& strFilename);
	void GenerateFile(wxString& strFile);
  void ProcessFormCommand(wxString cmd, wxSocketBase& outs);

  void ProcessActivation(int nModuble, bool act, wxSocketBase& outs);
	bool ReturnInt(wxSocketBase& outs, unsigned int i);
	bool ReturnBool(wxSocketBase&, bool b);

  unsigned int DecodePassword(const wxChar* strPassword, const wxChar* strApp);
	void ProcessUserLogin(wxString cmd, wxSocketBase& sock);
	bool ProcessUserLogout(wxString cmd, wxSocketBase& sock);

	virtual bool Initialization();
	virtual bool Deinitialization();
};

void TAuthorizationServer::InitModules()
{
	m_nModules = 0;
	memset(m_Modules, 0, sizeof(m_Modules));
	if (m_Dongle.Ok())
	{
		for (int i = 0; i < 48; i++)
		{
			if (m_Dongle.Active(i+1))
			{
				const size_t index = i / 32;
				const unsigned long mask = 1 << (i & 31);
				m_Modules[index] |= mask;
				m_nModules++;
			}
		}
	}
}

wxString TAuthorizationServer::Garble(unsigned short n, const wxDateTime& date) const
{
  const long val = date2julian(date);
  
  unsigned short data[4];
  data[0] = m_Dongle.Number();
  data[1] = n;
  data[2] = (unsigned short)(val >> 16);
  data[3] = (unsigned short)(val & 0xFFFF);
  m_Dongle.garble(data);
  return wxString::Format("%04X%04X", data[0], data[1]);
}

wxString TAuthorizationServer::GarbleMD5(unsigned short n, const wxDateTime& date) const
{
  const long nANSIdate = date.GetYear()*10000 + (date.GetMonth()+1)*100 + date.GetDay();

  wxString strModule;
  wxTextFile txt(GetModulesFilename());
  if (txt.Open())
    strModule = txt.GetLine(n).Left(2).Upper();

  wxString chiaro; chiaro.Printf("%8ld%d%s", nANSIdate, m_Dongle.Number(), strModule);

  unsigned char* buffer = (unsigned char*)chiaro.c_str();
  const wxString cifrato = wxMD5Checksum::GetMD5(buffer, chiaro.Len());
  return cifrato.Right(8); 
}

// Implementare almeno queste due funzioni pure virtuali

const wxChar* TAuthorizationServer::GetAppName() const
{
	return "Authorization";
}

bool TAuthorizationServer::IsMagicName(wxString& strFilename) const
{
  wxString strName;
	wxSplitPath(strFilename, NULL, &strName, NULL);
  strName.MakeLower();
  const int q = strName.Find('?');
	if (q > 0)
	  strName.Truncate(q);

	if (strName == "index" || strName == "users" || strName == "modules")
	{
		strFilename = strName;
		return true;
	} else
	if (strName == "log")
	{
		strFilename = GetLogFileName();
	} else
	if (strName == "activate" || strName == "deactivate" || 
		  strName == "year" || strName == "maxusers" || strName == "kill.cgi")
	{
		return true;
	}

  return false;
}

wxString TAuthorizationServer::GetModulesFilename() const
{ return wxT("../campo.aut"); }

wxString TAuthorizationServer::DescribeModule(int m) const
{
  const wxString strAut = GetModulesFilename();
	wxFileInputStream aut(strAut);
	wxString line;
	for (int nModule = 0; !aut.Eof(); nModule++)
	{
    aut >> line;
    if (nModule == m)
			return line.Mid(3).Trim();
	}
	return line;  // Should never happen!
}

void TAuthorizationServer::AddNumber(TXmlItem& tr, int n) const
{
	TXmlItem& td = tr.AddChild("td");
	td.SetAttr("align", "right");
	td << wxString::Format("%d", n);
}

void TAuthorizationServer::GenerateIndex(wxString& strFilename)
{
	TXmlItem html; 
	TXmlItem& body = CreatePageBody(html);

	TXmlItem& title = body.AddChild("h1").AddChild("center");
	if (m_Dongle.Ok())
	{
  	TXmlItem& tr = title.AddChild("table").SetAttr("width", "40%").AddChild("tr");
		
		TXmlItem& td = tr.AddChild("td").SetAttr("width", "30%");
		const bool hard = m_Dongle.hardware() == _dongle_hardlock;
		TXmlItem& img = td.AddChild("img");
		img.SetAttr("src", hard ? "hardlock.gif" : "eutron.gif");

		tr.AddChild("td").SetAttr("align", "center").AddChild("h1") << (hard ? "Hardlock EYE" : "Eutron Smartkey");
	}
	else
	{
		title << "No Dongle Connected!";
	}
	body.AddChild("br");

	TXmlItem& table = body.AddChild("center").AddChild("table");
  table.SetAttr("border", "1");
	table.SetAttr("width", "70%");

	TXmlItem& tr0 = body.AddChild("tr");
  tr0.AddChild("td") << "Serial Number";
	AddNumber(tr0, m_Dongle.Number());
	
	TXmlItem& tr1 = body.AddChild("tr");
  TXmlItem& ay = tr1.AddChild("td").AddChild("a");
  ay.SetAttr("href", "year.htm") << "Assistance Year";
	AddNumber(tr1, m_Dongle.YearAssist());

  int y, v, t, p; GetVersionInfo(y, v, t, p);
  wxString strVersion; strVersion.Printf(wxT("%d.%d.%d"), v, t, p);
	TXmlItem& tr1a = body.AddChild("tr");
  tr1a.AddChild("td") << "Version";
  tr1a.AddChild("td").SetAttr("align", "right") << strVersion;

	TXmlItem& tr2 = body.AddChild("tr");
	TXmlItem& mu = tr2.AddChild("td").AddChild("a");
  mu.SetAttr("href", "maxusers.htm") << "Maximum Users";
	AddNumber(tr2, m_Dongle.MaxUsers());

	TXmlItem& tr3 = body.AddChild("tr");
  TXmlItem& au = tr3.AddChild("td").AddChild("a");
  au.SetAttr("href", "Users.htm");	au << "Active Users";
	AddNumber(tr3,  m_Users.GetCount());

	TXmlItem& tr3a = body.AddChild("tr");
  TXmlItem& lu = tr3a.AddChild("td").AddChild("a");
  lu << "Active Licenses";
	AddNumber(tr3a,  m_Users.GetLicenses());

	TXmlItem& tr4 = body.AddChild("tr");
  TXmlItem& am = tr4.AddChild("td").AddChild("a");
	am.SetAttr("href", "Modules.htm"); am << "Active Modules";
	AddNumber(tr4, m_nModules);

	TXmlItem& tr5 = body.AddChild("tr");
  tr5.AddChild("td") << "Host name:port";
  wxIPV4address addr; addr.AnyAddress(); addr.Service(GetDefaultPort());
  wxString strHP; strHP << addr.Hostname() << ":" << addr.Service();
  tr5.AddChild("td").SetAttr("align", "right") << strHP;

	TXmlItem& tr6 = body.AddChild("tr");
  TXmlItem& al = tr6.AddChild("td").AddChild("a");
	al.SetAttr("href", "Log"); al << "Log File";

	TXmlItem& tr7 = body.AddChild("tr");
  TXmlItem& as = tr7.AddChild("td").AddChild("a");
	as.SetAttr("href", "stop.cgi"); as << "Stop the Server";

	strFilename = GetTempFilename();
	html.Save(strFilename);
}

void TAuthorizationServer::GenerateModules(wxString& strFilename)
{
	TXmlItem html; 
	TXmlItem& body = CreatePageBody(html, "Modules");
	TXmlItem& table = body.AddChild("table");
  table.SetAttr("border", "1");	table.SetAttr("width", "100%");

	TXmlItem& th = body.AddChild("thead");
	th.AddChild("th").SetAttr("width", "7%") << "N.";
	th.AddChild("th").SetAttr("width", "8%") << "Module";
	th.AddChild("th").SetAttr("width", "70%") << "Description";

  const bool bNormalUser = m_Dongle.Number() > 0;
  if (bNormalUser)
	  th.AddChild("th").SetAttr("width", "15%") << "De/Activate";

  const wxString strAut = GetModulesFilename();
	wxFileInputStream aut(strAut);
	for (int nModule = 0; !aut.Eof(); nModule++)
	{
  	wxString line;
    aut >> line;
    if (line.IsEmpty())
      break;

		const wxString strCode = line.Left(2);
		const wxString strDesc = line.Mid(3);
		if (nModule > 0 && strCode != "xx" && !strDesc.IsEmpty())
		{
      const bool bOn = nModule == 0 || m_Dongle.Active(nModule);
			TXmlItem& tr = body.AddChild("tr");
			AddNumber(tr, nModule);
			tr.AddChild("td").SetAttr("align", "center") << strCode;
			TXmlItem& td = tr.AddChild("td");
      td.AddChild(bOn ? "b" : "i") << strDesc;
			if (bNormalUser && nModule > 0)
			{
				const char* prompt = bOn ? "Deactivate" : "Activate";
        const wxString href = wxString::Format("%s?%d", prompt, nModule);
				TXmlItem& bu = AddLinkButton(tr.AddChild("td"), prompt, href);
				bu.SetAttr("width", "100%");
				bu.SetAttr("title", wxString::Format("Click to %s Module %d", prompt, nModule));
			}
		}
	}

	body.AddChild("br");
	AddLinkButton(body.AddChild("center"), "Return to main page", "/");
	
	strFilename = GetTempFilename();
	html.Save(strFilename);
}

void TAuthorizationServer::GenerateUsers(wxString& strFilename)
{
	TXmlItem html; 
	TXmlItem& body = CreatePageBody(html, "Users");

	TXmlItem& table = body.AddChild("table");
  table.SetAttr("border", "1");	table.SetAttr("width", "100%");

  TXmlItem& th = table.AddChild("thead");
	th.AddChild("th").SetAttr("width", "15%") << "N.";
	th.AddChild("th").SetAttr("width", "10%") << "User";
	th.AddChild("th").SetAttr("width", "15%") << "Host";
	th.AddChild("th").SetAttr("width", "15%") << "Programs";
	th.AddChild("th").SetAttr("width", "15%") << "Time";
	th.AddChild("th").SetAttr("width", "15%") << "Date";
	th.AddChild("th").SetAttr("width", "15%") << "Kill";

	int nUser = 0;
	for( TUsersHashMap::const_iterator it = m_Users.begin(); it != m_Users.end(); ++it )
	{
    const TUserInfo* ui = it->second;
    TXmlItem& tr = table.AddChild("tr");
		tr.AddChild("td").SetAttr("align", "right") << wxString::Format("%d", ++nUser);
    tr.AddChild("td").AddChild("b") << ui->m_strName;
    tr.AddChild("td") << ui->m_strHost;
    tr.AddChild("td").SetAttr("align", "right") << wxString::Format("%u", ui->m_nPrograms);
    tr.AddChild("td").SetAttr("align", "center") << ui->m_time.Format("%H:%M:%S");
    tr.AddChild("td").SetAttr("align", "center") << ui->m_time.Format("%d-%m-%Y");

    wxString strKey; strKey << ui->m_strName << wxT("@") << ui->m_strHost;
    wxString href = wxString::Format("kill.cgi?%s", strKey.c_str());
    AddLinkButton(tr.AddChild("td"), "Kill", href).SetAttr("width", "100%");
	}

	body.AddChild("br");
	AddLinkButton(body.AddChild("center"), "Return to main page", "/");

	strFilename = GetTempFilename();
	html.Save(strFilename);
}

void TAuthorizationServer::GenerateFile(wxString& strFilename)
{
  const int q = strFilename.Find('?');
	wxString strArgs;
	if (q > 0)
	{
		strArgs = strFilename.Mid(q+1);
	  strFilename.Truncate(q);
	}

  wxString strName;
	wxSplitPath(strFilename, NULL, &strName, NULL);
  strName.MakeLower();

	if (strName == "index")
	{
		GenerateIndex(strFilename);
	} else
	if (strName == "modules")
	{
		GenerateModules(strFilename);
	} else
	if (strName == "users")
	{
		GenerateUsers(strFilename);
	} else
	if (strName == "log")
	{
		strFilename = GetLogFileName();
	} else
	if (strName == "activate")
	{
		const int nModule = atoi(strArgs);

		TXmlItem html; 
		TXmlItem& body = CreatePageBody(html);
    TXmlItem& form = body.AddChild("form");
		form.SetAttr("action", "activate"); form.SetAttr("method", "post");

    TXmlItem& table = form.AddChild("center").AddChild("table");
		table.SetAttr("width", "70%").SetAttr("border", "1");
		table.AddChild("caption").AddChild("h2") << "Module Activation";
		
		TXmlItem& tr0 = table.AddChild("tr");
    tr0.AddChild("td") << wxString::Format("Module %d", nModule);
		tr0.AddChild("td") << DescribeModule(nModule);
 		TXmlItem& module = tr0.AddChild("td").AddChild("input");
		module.SetAttr("type", "hidden"); module.SetAttr("name", "module");
		module.SetAttr("value", nModule);

		TXmlItem& tr1 = table.AddChild("tr");
  	tr1.AddChild("td") << "Activation date (dd-mm-yyyy)";
		TXmlItem& date = tr1.AddChild("td").AddChild("input");
		date.SetAttr("type", "string"); date.SetAttr("name", "date");
		date.SetAttr("size", "10"); date.SetAttr("maxlength", "10");
		date.SetAttr("value", Date2String(wxDateTime::Now()));

		TXmlItem& tr2 = table.AddChild("tr");
		tr2.AddChild("td") << "Activation code";

		TXmlItem& key = tr2.AddChild("td").AddChild("input");
		key.SetAttr("type", "string"); key.SetAttr("name", "key");
		key.SetAttr("size", "8"); key.SetAttr("maxlength", "8");
		
		TXmlItem& tr3 = table.AddChild("tr");
		tr3.AddChild("td").AddChild("a").SetAttr("href", "/") << "Return to main page";
		TXmlItem& submit = tr3.AddChild("td").AddChild("input");
		submit.SetAttr("type", "submit");	
		submit.SetAttr("value", "Confirm Activation");
		
		strFilename = GetTempFilename();
		html.Save(strFilename);
	} else
	if (strName == "deactivate")
	{
		const int nModule = atoi(strArgs);
		TXmlItem html; 
		TXmlItem& body = CreatePageBody(html).AddChild("center");
		body.AddChild("h1") << "WARNING!";
		body.AddChild("br");
		body.AddChild("h3") << "You are about to deactivate the following module:";
		body.AddChild("br");
		body.AddChild("h2") << DescribeModule(nModule);
		body.AddChild("br");
    TXmlItem& form = body.AddChild("form");
		form.SetAttr("action", "deactivate"); form.SetAttr("method", "post");
		TXmlItem& module = form.AddChild("input");
		module.SetAttr("type", "hidden");
		module.SetAttr("name", "module");
		module.SetAttr("value", wxString::Format("%d", nModule));

		TXmlItem& submit = form.AddChild("input");
		submit.SetAttr("type", "submit");
		submit.SetAttr("value", "Confirm Deactivation");

		body.AddChild("br"); body.AddChild("br");
		AddLinkButton(body, "Return to modules list", "Modules");
		
		strFilename = GetTempFilename();
		html.Save(strFilename);
	} else
	if (strName == "year")
	{
		TXmlItem html; 
		TXmlItem& body = CreatePageBody(html);
    TXmlItem& form = body.AddChild("form");
		form.SetAttr("action", "year"); form.SetAttr("method", "post");

    TXmlItem& table = form.AddChild("center").AddChild("table");
		table.SetAttr("width", "70%").SetAttr("border", "1");
		table.AddChild("caption").AddChild("h2") << "Year of Assistance";
		
		TXmlItem& tr0 = table.AddChild("tr");
		tr0.AddChild("td") << "Assistance year to be activated";

		TXmlItem& year = tr0.AddChild("td").AddChild("input");
		year.SetAttr("type", "string");	year.SetAttr("name", "year");
		year.SetAttr("size", "4"); year.SetAttr("maxlength", "4");
		year.SetAttr("value", wxString::Format("%d", m_Dongle.YearAssist()+1));

		TXmlItem& tr1 = table.AddChild("tr");
  	tr1.AddChild("td") << "Activation date (dd-mm-yyyy)";
		TXmlItem& date = tr1.AddChild("td").AddChild("input");
		date.SetAttr("type", "string"); date.SetAttr("name", "date");
		date.SetAttr("size", "10"); date.SetAttr("maxlength", "10");
		date.SetAttr("value", Date2String(wxDateTime::Now()));

		TXmlItem& tr2 = table.AddChild("tr");
		tr2.AddChild("td") << "Activation code";

		TXmlItem& key = tr2.AddChild("td").AddChild("input");
		key.SetAttr("type", "string"); key.SetAttr("name", "key");
		key.SetAttr("size", "8"); key.SetAttr("maxlength", "8");
		
		TXmlItem& tr3 = table.AddChild("tr");
		tr3.AddChild("td").AddChild("a").SetAttr("href", "/") << "Return to main page";
		TXmlItem& submit = tr3.AddChild("td").AddChild("input");
		submit.SetAttr("type", "submit");	
		submit.SetAttr("value", "Confirm Activation");
		
		strFilename = GetTempFilename();
		html.Save(strFilename);
	} else
	if (strName == "maxusers")
	{
//		const int nModule = atoi(strArgs);
		TXmlItem html; 
		TXmlItem& body = CreatePageBody(html);
	  TXmlItem& form = body.AddChild("form");
		form.SetAttr("action", "maxusers"); form.SetAttr("method", "post");

    TXmlItem& table = form.AddChild("center").AddChild("table");
		table.SetAttr("width", "70%").SetAttr("border", "1");
		table.AddChild("caption").AddChild("h2") << "Maximum Users";
   	
		TXmlItem& tr0 = table.AddChild("tr");
		tr0.AddChild("td") << "Number of users";

		TXmlItem& year = tr0.AddChild("td").AddChild("input");
		year.SetAttr("type", "string");	year.SetAttr("name", "users");
		year.SetAttr("size", "4"); year.SetAttr("maxlength", "4");
		year.SetAttr("value", wxString::Format("%d", m_Dongle.MaxUsers()));

		TXmlItem& tr1 = table.AddChild("tr");
  	tr1.AddChild("td") << "Activation date (dd-mm-yyyy)";
		TXmlItem& date = tr1.AddChild("td").AddChild("input");
		date.SetAttr("type", "string"); date.SetAttr("name", "date");
		date.SetAttr("size", "10"); date.SetAttr("maxlength", "10");
		date.SetAttr("value", Date2String(wxDateTime::Now()));

		TXmlItem& tr2 = table.AddChild("tr");
		tr2.AddChild("td") << "Activation code";

		TXmlItem& key = tr2.AddChild("td").AddChild("input");
		key.SetAttr("type", "string"); key.SetAttr("name", "key");
		key.SetAttr("size", "8"); key.SetAttr("maxlength", "8");
    form.AddChild("br"); form.AddChild("br");
		
		TXmlItem& tr3 = table.AddChild("tr");
		tr3.AddChild("td").AddChild("a").SetAttr("href", "index") << "Return to main page";
		TXmlItem& submit = tr3.AddChild("td").AddChild("input");
		submit.SetAttr("type", "submit");	
		submit.SetAttr("value", "Confirm Activation");
		
		strFilename = GetTempFilename();
		html.Save(strFilename);
	} else
	if (strName == "kill")
	{
		m_Users.Kill(strArgs);
		GenerateUsers(strFilename);
	}
}

void TAuthorizationServer::ProcessActivation(int nModule, bool act, wxSocketBase& outs)
{
	if (nModule > 0)
	{
		if (act)
		  m_Dongle.Activate(nModule);
		else
		  m_Dongle.Deactivate(nModule);
		m_Dongle.Burn();
		InitModules();
	}
	wxString strFileName = "Modules";
	GenerateFile(strFileName);
	SendFile(strFileName, outs);
}

bool TAuthorizationServer::KeyIsGood(const wxString& key, const wxString& gar) const
{
  return key.IsSameAs(gar, false);
}

void TAuthorizationServer::ProcessFormCommand(wxString cmd, wxSocketBase& outs)
{
  const int stop = cmd.Find(" HTTP");
	wxString strFileName = cmd.Mid(5, stop-5).Trim();

	wxString strName, args;
	wxSplitPath(strFileName, NULL, &strName, NULL);
	strName.MakeLower();

	const int pos = cmd.Find("\r\n\r\n");
	if (pos > 0)
	  args = cmd.Mid(pos+4);

	THashTable hashArgs(13);
  ParseArguments(args, hashArgs);

	if (strName == "activate")
	{
		const int nModule = hashArgs.GetInt("module");
		const wxDateTime date = hashArgs.GetDate("date");
		const wxString key = hashArgs.Get("key");
		const wxString gar1 = Garble(nModule, date);
    const wxString gar2 = GarbleMD5(nModule, date);
		if (KeyIsGood(key, gar1) || KeyIsGood(key, gar2))
	    ProcessActivation(nModule, true, outs);
    else
			MessageBox("ERROR!", "You supplied the wrong activation code", outs);
	} else
	if (strName == "deactivate")
	{
		const int nModule = atoi(hashArgs.Get("module"));
		ProcessActivation(nModule, false, outs);
	} else
	if (strName == "year")
	{
		const int year = hashArgs.GetInt("year");
		const wxDateTime date = hashArgs.GetDate("date");
		const wxString key = hashArgs.Get("key");
		const wxString gar = Garble(year, date);
		if (KeyIsGood(key, gar))
		{
			m_Dongle.set_year_assist(year);
  		m_Dongle.Burn();
			wxString strFileName = "index";
			GenerateFile(strFileName);
			SendFile(strFileName, outs);
		}
    else
			MessageBox("ERROR!", "You supplied the wrong activation code", outs);
	} else
	if (strName == "maxusers")
	{
		const int users = atoi(hashArgs.Get("users"));
		const wxDateTime date = hashArgs.GetDate("date");
		const wxString key = hashArgs.Get("key");
		const wxString gar = Garble(users, date);
		if (KeyIsGood(key, gar))
		{
			m_Dongle.set_max_users(users);
  		m_Dongle.Burn();
			wxString strFileName = "index";
			GenerateFile(strFileName);
			SendFile(strFileName, outs);
		}
    else
			MessageBox("ERROR!", "You supplied the wrong activation code", outs);
	}
}

unsigned int TAuthorizationServer::DecodePassword(const wxChar* strPassword, const wxChar* strApp)
{
	const unsigned int BASE = 19;
  unsigned int num = 0;
	size_t len = 0;
	for (const wxChar* c = strPassword; *c; c++)
	{
		num *= BASE;
		if (*c >= '0' && *c <= '9')
		{
			num += *c - '0';
		}	
		else
		{
  		if (*c >= 'A' && *c <= 'Z')
			{
	  		num += *c - 'A' + 10;
			}
			else
				break; // Carattere non valido
		}
    len++;
	}
	// Per essereva valido deve essere divisibile per 883
	if (len >= 5 && (num%883) == 0)
	{
    if (m_strLastPassword != strPassword || m_strLastApp != strApp)
    {
		  m_strLastPassword = strPassword;
		  m_strLastApp = strApp;
      m_nPwdCount = 0;
    }
    else
      m_nPwdCount++;

    if (m_nPwdCount < m_MaxTries)
    {
		  // Creo la risposta: met� di num reso divisibile per 883
		  num /= 2;
		  while (num % 883 != 0)
			  num++;
    }
    else
      num = 0;
	}
	else
		num = 0;
	return num;
}

void TAuthorizationServer::ProcessUserLogin(wxString cmd, wxSocketBase& sock)
{
	wxChar strUser[32];
	wxChar strPassword[32];
	wxChar strProgram[32];
	int session;
	
	cmd.Replace(",", " "); 	cmd.Replace(")", " ");
	const int nStr = wxSscanf(cmd, "UserLogin(%s %s %s %d)", strUser, strPassword, strProgram, &session);
	
	if (nStr < 4)
		session = 0;

	unsigned int num = 0;
	if (m_Dongle.Connected())
	{
// Preliminary GUEST login
//		if (wxStricmp(strUser,"******")==0 && wxStricmp(strProgram, "ba0100")==0)
//		{
//			num = 1;
//		}
//		else
		{
      if (m_Users.GetLicenses() >= m_Dongle.MaxUsers() && m_Users.Find(sock, NULL, session) == NULL)
      {
        WriteLog(_("*** Maximum number of users exceeded"));
	  		num = 0;
      }
			else
			{
				if (strcmp(strPassword, "******") == 0) // Older 16 bit version
          num = 1;
				else
					num = DecodePassword(strPassword, strProgram);
  			if (num > 0)
					m_Users.AddConnection(sock, strUser, session);
        else
          WriteLog(_("*** Bad password"));
			}
		}
	}
  else
    WriteLog(_("*** Dongle not responding"));

	ReturnInt(sock, num);
}

bool TAuthorizationServer::ProcessUserLogout(wxString cmd, wxSocketBase& sock)
{
	wxChar strUser[32] = "";
  wxChar strProgram[32] = "";
	int session = -1;
	
	cmd.Replace(",", " "); 	cmd.Replace(")", " ");
	const int nStr = wxSscanf(cmd, "UserLogout(%s %d %s)", strUser, &session, strProgram);

	if (nStr < 2)
		session = 0;

  m_Users.RemoveConnection(sock, strUser, session);
  if (wxStrcmp(strProgram, "ba0100") == 0)
    m_Users.KillSession(sock, session);

	return true;
}

bool TAuthorizationServer::ReturnInt(wxSocketBase& outs, unsigned int i)
{
	const unsigned int buf[2] = { sizeof(i), i };
	outs.Write(buf, sizeof(buf));
  return outs.IsOk();
}

bool TAuthorizationServer::ReturnBool(wxSocketBase& outs, bool b)
{
	return ReturnInt(outs, b ? 1 : 0);
}

bool TAuthorizationServer::ProcessCommand(wxString cmd, wxSocketBase& outs)
{
	if (cmd.StartsWith("GET "))
	{
		const int stop = cmd.Find(" HTTP");
		wxString str;
		if (stop > 4)
			str = cmd.Mid(4, stop-4).Trim();
		else
      str = cmd.Mid(4).Trim();
		if (str == "/")
			str += "index.htm";
		wxString strFilename = GetDocumentRoot() + str;

		if (IsMagicName(strFilename))
			GenerateFile(strFilename);

		SendFile(strFilename, outs);
    return true;
	}
	
  if (cmd.StartsWith("POST "))
	{
		ProcessFormCommand(cmd, outs);
    return true;
	}
	
  if (cmd.StartsWith("UserLogin"))
	{
		ProcessUserLogin(cmd, outs);
    return true;
	}
	
  if (cmd.StartsWith("UserLogout"))
	{
		bool ok = ProcessUserLogout(cmd, outs);
		return ReturnBool(outs, ok);
	}

  if (cmd.StartsWith("DongleInfo"))
  {
    const short num = m_Dongle.Number();
    const short year = m_Dongle.YearAssist();
    const size_t nBytes = sizeof(num) + sizeof(year) + sizeof(m_Modules);
    outs.Write(&nBytes,   sizeof(nBytes));    // 4 bytes = size of data
    outs.Write(&num,      sizeof(num));       // 2 bytes = dongle number   
    outs.Write(&year,     sizeof(year));      // 2 bytes = dongle year
    outs.Write(m_Modules, sizeof(m_Modules)); // 8 bytes = 64 active modules bits
    return outs.IsOk();
	}
  
  if (cmd.StartsWith("DongleLoggedLicenses"))
    return ReturnInt(outs, m_Users.GetLicenses());
	
  if (cmd.StartsWith("DongleModules"))
	{
    const size_t nBytes = sizeof(m_Modules);
    outs.Write(&nBytes,   sizeof(nBytes));    // 4 bytes = size of data
   	outs.Write(m_Modules, sizeof(m_Modules)); // 8 bytes = data
    return outs.IsOk();
	}
	
  if (cmd.StartsWith("DongleNumber"))
		return ReturnInt(outs, m_Dongle.Number());

  if (cmd.StartsWith("DongleYear"))
		return ReturnInt(outs, m_Dongle.YearAssist());

  return TBaseServerApp::ProcessCommand(cmd, outs); // Gestisce PING!
}

#define ATOMIC_SEMAPHORE "DONGLE_SERVER_ATOM"

bool TAuthorizationServer::Initialization()
{
#ifdef __WXMSW__
	// Add global atom if not already present
	if (::GlobalFindAtom(ATOMIC_SEMAPHORE) == NULL)
	  ::GlobalAddAtom(ATOMIC_SEMAPHORE); // Same as old Frontend.exe
#endif
	const int delay =	GetConfigInt("Delay", 10);
	m_MaxTries =	GetConfigInt("MaxTries", 8);

	if (m_MaxTries < 8)
		m_MaxTries = 8;

  const bool bTestAll = IsAdvanced();
	for (unsigned int i = 0; i < m_MaxTries; i++)
	{
		if (m_Dongle.Login(bTestAll))
			break;
		wxSleep(delay);
	}
	InitModules();

	return true;
}

bool TAuthorizationServer::Deinitialization()
{
	m_Dongle.Logout();
#ifdef WIN32
	// Definitely kill global atom
	for (ATOM a = ::GlobalFindAtom(ATOMIC_SEMAPHORE);
	     a != NULL;
			 a = ::GlobalDeleteAtom(a));
#endif
	return true;
}

// Istanziare l'applicazione principale

IMPLEMENT_APP(TAuthorizationServer)