campo-sirio/server/diction.cpp
alex 0a81e1371c Modifiche dalla versione Linux sulla 2.1
git-svn-id: svn://10.65.10.50/trunk@11908 c028cbd2-c16b-5b4b-a496-9718f37d4682
2004-03-25 10:35:14 +00:00

729 lines
18 KiB
C++
Executable File

#include "baseserv.h"
#include <wx/hashmap.h>
#include <wx/mstream.h>
#include <ctype.h>
//////////////////////////////////////////////////////////
// Conversion utilities
///////////////////////////////////////////////////////////
int FindChar(const wxString& str, char c, int from)
{
if (from <= 0)
return str.Find(c);
for (int i = from; str[i]; i++)
if (str[i] == c)
return i;
return -1;
}
wxString txt2xml(const wxString& str)
{
wxString tmp;
for (int i = 0; str[i]; i++)
{
if (str[i] < ' ' || str[i] > 'z' || strchr("&<>/", str[i]) != NULL)
tmp << wxString::Format("&#%X;", (int)(unsigned char)(str[i]));
else
tmp << str[i];
}
return tmp;
}
wxString xml2txt(const wxString& str)
{
wxString tmp;
for (int i = 0; str[i]; i++)
{
if (str[i] == '&' && str[i+1] == '#')
{
i += 2;
const int semicolon = FindChar(str, ';', i);
if (semicolon > i)
{
int n;
sscanf(str.Mid(i, semicolon-i), "%X", &n);
tmp << char(n & 0xFF);
i = semicolon;
}
else
tmp << str[i] << str[i+1];
}
else
tmp << str[i];
}
return tmp;
}
//////////////////////////////////////////////////////////
// TDictionary
///////////////////////////////////////////////////////////
WX_DECLARE_STRING_HASH_MAP( wxString, TStringHashTable );
class TDictionary : public TStringHashTable
{
wxSortedArrayString m_sorted;
bool m_bDirty;
protected:
void ParseSpaces(const wxString& str, wxString& prefix,
wxString& body, wxString& postfix) const;
void AddEntry(const wxString& ita, const wxString& eng);
static bool FillCallback(TXmlItem& item, long jolly);
bool Load();
void Save();
public:
wxString Translate(const wxString& ita);
wxString GetFileName() const;
bool LoadIfEmpty();
void SaveIfNeeded();
wxString OriginalEntry(size_t i);
wxString TranslatedEntry(size_t i);
void UpdateEntry(size_t i, const wxString& strValue);
TDictionary();
~TDictionary();
};
wxString TDictionary::GetFileName() const
{
TBaseServerApp& app = (TBaseServerApp&)*wxTheApp;
return app.GetConfigString("Dictionary", "campodic.xml");
}
void TDictionary::Save()
{
const char* eol = "\r\n";
wxFileOutputStream outf(GetFileName());
outf << "<?xml version=\"1.0\"?>" << eol;
outf << "<dictionary>" << eol;
for (size_t i = 0; i < m_sorted.GetCount(); i++)
{
const wxString& ita = m_sorted[i];
outf << " <entry>" << eol;
outf << " <ita>";
WriteXmlString(outf, ita);
outf << "</ita>" << eol;
outf << " <eng>";
const wxString& eng = operator[](ita);
WriteXmlString(outf, eng);
outf << "</eng>" << eol;
outf << " </entry>" << eol;
}
outf << "</dictionary>" << eol;
m_bDirty = false;
}
void TDictionary::SaveIfNeeded()
{
if (m_bDirty)
Save();
}
void TDictionary::AddEntry(const wxString& ita, const wxString& eng)
{
operator[](ita) = eng;
m_sorted.Add(ita);
m_bDirty = true;
}
void TDictionary::UpdateEntry(size_t nEntry, const wxString& strValue)
{
if (nEntry >= 0 && nEntry < m_sorted.GetCount())
{
const wxString& ita = m_sorted[nEntry];
operator[](ita) = strValue;
Save();
}
}
wxString TDictionary::OriginalEntry(size_t i)
{
return m_sorted[i];
}
wxString TDictionary::TranslatedEntry(size_t i)
{
const wxString& ita = m_sorted[i];
return operator[](ita);
}
wxSocketClient& operator<<(wxSocketClient& sock, const wxChar* str)
{
if (str && *str)
sock.Write(str, wxStrlen(str));
return sock;
}
bool TDictionary::Load()
{
clear();
m_sorted.Clear();
wxFileInputStream scan(GetFileName());
wxString ita, line;
while (!scan.Eof())
{
scan >> line;
line.Trim(false);
if (line.StartsWith("<ita>"))
{
const int eoi = line.Find("</ita>");
ita = xml2txt(line.Mid(5, eoi-5));
} else
if (line.StartsWith("<eng>") && !ita.IsEmpty())
{
const int eoe = line.Find("</eng>");
const wxString eng = xml2txt(line.Mid(5, eoe-5));
AddEntry(ita, eng);
}
}
m_bDirty = false;
return size() > 0;
}
bool TDictionary::LoadIfEmpty()
{
bool full = size() > 0;
if (!full)
full = Load();
return full;
}
inline bool IsGoodChar(wxChar c)
{
return isalnum(c) || strchr("@%'", c);
}
void TDictionary::ParseSpaces(const wxString& str, wxString& prefix,
wxString& body, wxString& postfix) const
{
int i, j;
for (i = 0; !IsGoodChar(str[i]); i++);
for (j = str.Length()-1; j >= i && !IsGoodChar(str[j]); j--);
if (i > 0)
prefix = str.Left(i);
if (j >= i)
postfix = str.Mid(j+1);
body = str.Mid(i, j-i+1);
}
wxString TDictionary::Translate(const wxString& ita)
{
LoadIfEmpty();
wxString prefix, body, postfix;
ParseSpaces(ita, prefix, body, postfix);
const TStringHashTable::iterator i = find(body);
if (i != end())
{
const wxString& eng = i->second;
if (eng != "???")
{
body = prefix;
body += eng;
body += postfix;
return body;
}
}
else
AddEntry(ita, "???");
return ita;
}
TDictionary::TDictionary() : TStringHashTable(10000), m_bDirty(false)
{
}
TDictionary::~TDictionary()
{
SaveIfNeeded();
}
///////////////////////////////////////////////////////////
// TDictionaryServer
///////////////////////////////////////////////////////////
class TDictionaryServer : public TBaseServerApp
{
TDictionary m_DevotoOli;
protected:
virtual const wxChar* GetAppName() const;
virtual void ProcessCommand(wxString cmd, wxSocketBase& outs);
size_t FindIndex(const wxString& strKey);
public:
bool DoTranslate(const TXmlItem& xmlMethod, TXmlItem& xmlAnswer);
bool SoapProcessMethod(const TXmlItem& xmlMethod, TXmlItem& xmlAnswer);
void ProcessSoapCommand(wxString cmd, wxSocketBase& outs);
void ProcessHttpGet(wxString cmd, wxSocketBase& outs);
void ProcessFormCommand(wxString cmd, wxSocketBase& outs);
void ProcessFormUpdateEntry(wxString& strFileName, THashTable& hashArgs);
void ProcessFormTranslate(wxString& strFileName, THashTable& hashArgs);
void CallCgi(wxString& strFilename);
bool IsMagicName(wxString& strFilename) const;
bool IsCgiName(wxString strFilename) const;
void Add2Columns(TXmlItem& table, const wxChar* href0, const wxChar* td0, const wxChar* td1) const;
void AddEditableRow(TXmlItem& table, const wxChar* txt1, const wxChar* txt2) const;
void GenerateIndex(TXmlItem& body);
void GenerateFile(wxString& strFilename);
virtual bool Initialization();
virtual bool Deinitialization();
};
bool TDictionaryServer::SoapProcessMethod(const TXmlItem& xmlMethod, TXmlItem& xmlAnswer)
{
const wxString& strMethod = xmlMethod.GetTag();
if (strMethod == "m:Translate")
return DoTranslate(xmlMethod, xmlAnswer);
return false;
}
bool TDictionaryServer::DoTranslate(const TXmlItem& xmlMethod, TXmlItem& xmlAnswer)
{
const TXmlItem* xmlSentence = xmlMethod.FindFirst("sentence");
if (xmlSentence != NULL)
{
const wxString ita = xmlSentence->GetEnclosedText();
wxString result = m_DevotoOli.Translate(ita);
xmlAnswer.AddSoapString("sentence", result);
return true;
}
return false;
}
bool TDictionaryServer::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 == "dictionary")
{
return true;
}
if (strName == "log")
{
strFilename = GetLogFileName();
}
return false;
}
bool TDictionaryServer::IsCgiName(wxString strFilename) const
{
const int q = strFilename.Find('?');
if (q > 0)
strFilename = strFilename.Left(q);
wxString strExt;
wxSplitPath(strFilename, NULL, NULL, &strExt);
strExt.MakeLower();
return strExt == "cgi" || strExt == "exe";
}
void TDictionaryServer::Add2Columns(TXmlItem& table, const wxChar* href0, const wxChar* txt0, const wxChar* txt1) const
{
TXmlItem& tr = table.AddChild("tr");
TXmlItem& a = tr.AddChild("td").AddChild("a");
a.SetAttr("href", href0);
a << txt0;
tr.AddChild("td") << txt1;
}
void TDictionaryServer::GenerateIndex(TXmlItem& body)
{
TXmlItem& table = body.AddChild("table");
table.SetAttr("border", "1"); table.SetAttr("width", "100%");
TXmlItem& tr = table.AddChild("tr");
wxChar cLast = '\0';
for (size_t i = 0; i < m_DevotoOli.size(); i++)
{
const wxChar cCurr = toupper(m_DevotoOli.OriginalEntry(i)[0u]);
if (cCurr > cLast)
{
TXmlItem& td = tr.AddChild("td").SetAttr("align", "center");
td.AddChild("a").SetAttr("href", wxString::Format("Dictionary?%c", cCurr));
td << wxString::Format("%c", cCurr);
cLast = cCurr;
}
}
body.AddChild("br");
}
void TDictionaryServer::AddEditableRow(TXmlItem& table, const wxChar* txt1, const wxChar* txt2) const
{
TXmlItem& tr = table.AddChild("tr");
TXmlItem& td0 = tr.AddChild("td");
const wxString cgi = wxString::Format("EditEntry.cgi?%c-%u",
toupper(*txt1), table.GetChildren()-3);
AddLinkButton(td0, "Edit", cgi).SetAttr("width", "100%");
tr.AddChild("td") << txt1;
tr.AddChild("td") << txt2;
}
void TDictionaryServer::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();
TXmlItem html;
TXmlItem& body = CreatePageBody(html);
if (strName == "index")
{
TXmlItem& table = body.AddChild("center").AddChild("table");
table.SetAttr("border", "1"); table.SetAttr("width", "70%");
Add2Columns(table, "Dictionary", "Dictionary", "Sorted listing of entries");
Add2Columns(table, "TranslateSentence.cgi", "Translate", "Translate a sentence");
Add2Columns(table, "Log", "Log", "Server activity log");
Add2Columns(table, "stop.cgi", "Stop", "Stop the server");
strFilename = GetTempFilename();
}
if (strName == "dictionary")
{
const wxChar cFilter = strArgs.IsEmpty() ? 'A' : toupper(strArgs[ 0u]);
GenerateIndex(body);
TXmlItem& table = body.AddChild("table");
table.SetAttr("border", "1"); table.SetAttr("width", "100%");
table.AddChild("caption").AddChild("h1") << wxString::Format("%c", cFilter);
TXmlItem& table_th = table.AddChild("thead");
TXmlItem& th0 = table_th.AddChild("th"); th0.SetAttr("width", "6%");
TXmlItem& th1 = table_th.AddChild("th"); th1.SetAttr("width", "47%");
th1 << "Original text";
TXmlItem& th2 = table_th.AddChild("th").SetAttr("width", "47%");
th2 << "Translated text";
for (size_t i = 0; i < m_DevotoOli.size(); i++)
{
const wxString& orig = m_DevotoOli.OriginalEntry(i);
if (toupper(orig[0]) == cFilter)
AddEditableRow(table, orig, m_DevotoOli.TranslatedEntry(i));
}
strFilename = GetTempFilename();
}
html.Save(strFilename);
}
// Convert code (B-23) to position (107)
size_t TDictionaryServer::FindIndex(const wxString& strKey)
{
const wxChar cFirst = toupper(strKey[0]);
const size_t nPos = atoi(strKey.Mid(2));
size_t nFound = 0;
size_t i;
for (i = 0; i < m_DevotoOli.size(); i++)
{
const wxChar c = toupper(m_DevotoOli.OriginalEntry(i)[ 0u]);
if (c == cFirst)
{
if (nFound == nPos)
break;
nFound++;
}
}
return i;
}
void TDictionaryServer::CallCgi(wxString& strFileName)
{
wxString strName, strExt, strArgs;
const int q = strFileName.Find('?');
if (q > 0)
{
strArgs = strFileName.Mid(q+1);
strFileName = strFileName.Left(q);
}
wxSplitPath(strFileName, NULL, &strName, &strExt);
if (strExt == "cgi")
{
TXmlItem html;
TXmlItem& body = CreatePageBody(html).AddChild("center");
if (strName == "EditEntry")
{
const size_t i = FindIndex(strArgs);
body.AddChild("h2") << "Edit Entry " << strArgs;
TXmlItem& form = body.AddChild("form");
form.SetAttr("method", "post");
form.SetAttr("action", "UpdateEntry.cgi");
form.AddChild("h3") << "Original text:";
TXmlItem& ita = form.AddChild("textarea");
ita.SetAttr("cols", "80"); ita.SetAttr("rows", "4");
ita << m_DevotoOli.OriginalEntry(i);
form.AddChild("br");
form.AddChild("h3") << "Translated text:";
TXmlItem& ent = form.AddChild("input");
ent.SetAttr("type", "hidden"); ent.SetAttr("name", "Entry");
ent.SetAttr("value", strArgs);
TXmlItem& eng = form.AddChild("textarea");
eng.SetAttr("name", "Trans");
eng.SetAttr("cols", "80"); eng.SetAttr("rows", "4");
eng << m_DevotoOli.TranslatedEntry(i);
form.AddChild("br");
form.AddChild("br");
TXmlItem& sub = form.AddChild("input");
sub.SetAttr("type", "submit");
sub.SetAttr("value", "Update Translation");
AddLinkButton(body, "Return to main page", "/");
}
if (strName == "TranslateSentence")
{
body.AddChild("h3") << "Input the text to be translated:";
TXmlItem& form = body.AddChild("form");
form.SetAttr("method", "post");
form.SetAttr("action", "Translate.cgi");
TXmlItem& ita = form.AddChild("textarea");
ita.SetAttr("name", "Sentence");
ita.SetAttr("cols", "80"); ita.SetAttr("rows", "4");
ita << "Menu Principale";
form.AddChild("br");
form.AddChild("br");
TXmlItem& sub = form.AddChild("input");
sub.SetAttr("type", "submit");
sub.SetAttr("value", "Translate");
}
strFileName = GetTempFilename();
html.Save(strFileName);
} else
if (strExt == "exe")
{
}
}
// Implementazione delle due funzioni pure virtuali
const wxChar* TDictionaryServer::GetAppName() const
{
return "Dictionary";
}
void TDictionaryServer::ProcessSoapCommand(wxString cmd, wxSocketBase& sock)
{
TXmlItem xmlEnvelope;
xmlEnvelope.SetTag("SOAP-ENV:Envelope");
TXmlItem& xmlBody = xmlEnvelope.AddChild("SOAP-ENV:Body");
const int soapstart = cmd.Find("<SOAP-ENV:");
if (soapstart > 0)
{
const size_t soaplen = cmd.length() - soapstart;
const char* buff = (const char*)cmd;
buff += soapstart;
wxMemoryInputStream input(buff, soaplen);
TXmlItem query;
if (query.Read(input))
{
const TXmlItem* pxmlBody = query.FindFirst("SOAP-ENV:Body");
if (pxmlBody != NULL) for (int m = 0; ; m++)
{
const TXmlItem* pxmlMethod = pxmlBody->GetChild(m);
if (pxmlMethod == NULL)
break;
if (pxmlMethod->GetTag().StartsWith("m:"))
{
wxString str = pxmlMethod->GetTag(); str += "Result";
TXmlItem& xmlAnswer = xmlBody.AddChild(str);
SoapProcessMethod(*pxmlMethod, xmlAnswer);
}
}
}
}
const wxString strResult = xmlEnvelope.AsString();
sock << "HTTP/1.1 200 OK" << endl;
sock << "Connection: keep-alive" << endl;
sock << "Content-Length: " << strResult.Length() << endl;
sock << "Content-Type: text/xml; charset=utf-8" << endl;
sock << "Date: " << wxDateTime::Now().Format("%#c") << endl;
sock << "Server: " << GetAppName() << endl;
sock << "Host: " << wxGetFullHostName() << endl;
sock << endl;
sock << strResult;
}
void TDictionaryServer::ProcessHttpGet(wxString cmd, wxSocketBase& outs)
{
const int stop = cmd.Find(" HTTP");
wxString str = cmd.Mid(4, stop-4).Trim();
if (str == "/")
str += "index.htm";
wxString strFilename = GetDocumentRoot() + str;
if (IsMagicName(strFilename))
GenerateFile(strFilename); else
if (IsCgiName(strFilename))
CallCgi(strFilename);
SendFile(strFilename, outs);
}
void TDictionaryServer::ProcessFormUpdateEntry(wxString& strFileName,
THashTable& hashArgs)
{
const wxString key = hashArgs.Get("Entry");
size_t nEntry = FindIndex(key);
const wxString strValue = hashArgs.Get("Trans");
m_DevotoOli.UpdateEntry(nEntry, strValue);
TXmlItem html;
TXmlItem& body = CreatePageBody(html).AddChild("center");
body.AddChild("h2") << "Entry updated!";
body.AddChild("br");
strFileName = "dictionary?";
strFileName << key[0];
AddLinkButton(body, "Return to Dictionary", strFileName);
strFileName = GetTempFilename();
html.Save(strFileName);
}
void TDictionaryServer::ProcessFormTranslate(wxString& strFileName,
THashTable& hashArgs)
{
const wxString strValue = hashArgs.Get("Sentence");
TXmlItem html;
TXmlItem& body = CreatePageBody(html).AddChild("center");
body.AddChild("h3") << "Input the text to be translated:";
TXmlItem& form = body.AddChild("form");
form.SetAttr("method", "post");
form.SetAttr("action", "Translate.cgi");
TXmlItem& ita = form.AddChild("textarea");
ita.SetAttr("name", "Sentence");
ita.SetAttr("cols", "80"); ita.SetAttr("rows", "3");
ita << strValue;
form.AddChild("h3") << "Translated text:";
const wxString strTrans = m_DevotoOli.Translate(strValue);
if (strTrans == strValue)
{
form.AddChild("p") << "Couldn't find a good translation for your text!";
}
else
{
TXmlItem& eng = form.AddChild("textarea");
eng.SetAttr("cols", "80"); eng.SetAttr("rows", "3");
eng << strTrans;
}
form.AddChild("br");
form.AddChild("br");
TXmlItem& sub = form.AddChild("input");
sub.SetAttr("type", "submit");
sub.SetAttr("value", "Translate");
body.AddChild("br");
AddLinkButton(body, "Return to main page", "/");
strFileName = GetTempFilename();
html.Save(strFileName);
}
void TDictionaryServer::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);
const int pos = cmd.Find("\r\n\r\n");
if (pos > 0)
args = cmd.Mid(pos+4);
THashTable hashArgs(13);
ParseArguments(args, hashArgs);
strFileName = GetTempFilename();
if (strName == "UpdateEntry")
ProcessFormUpdateEntry(strFileName, hashArgs); else
if (strName == "Translate")
ProcessFormTranslate(strFileName, hashArgs);
SendFile(strFileName, outs);
}
void TDictionaryServer::ProcessCommand(wxString cmd, wxSocketBase& outs)
{
if (cmd.StartsWith("POST "))
{
if (cmd.Find("SOAPAction") > 0)
ProcessSoapCommand(cmd, outs);
else
ProcessFormCommand(cmd, outs);
} else
if (cmd.StartsWith("GET "))
ProcessHttpGet(cmd, outs);
}
bool TDictionaryServer::Initialization()
{
return m_DevotoOli.LoadIfEmpty();
}
bool TDictionaryServer::Deinitialization()
{
m_DevotoOli.SaveIfNeeded();
return true;
}
// Istanziare l'applicazione principale
IMPLEMENT_APP(TDictionaryServer)