#include "BaseServ.h" #include #include #include #include ////////////////////////////////////////////////////////// // Sorted array of THashString /////////////////////////////////////////////////////////// static int CompareNodes(wxNode** n1, wxNode** n2) { return strcmp((*n1)->GetKeyString(), (*n2)->GetKeyString()); } WX_DEFINE_ARRAY(wxNode*, TArrayOfNodes); ////////////////////////////////////////////////////////// // TDictionary /////////////////////////////////////////////////////////// class TDictionary : public THashTable { unsigned int m_nNewEntries; TArrayOfNodes m_sorted; protected: void ParseSpaces(const wxString& str, wxString& prefix, wxString& body, wxString& postfix) const; wxString Accentuate(const wxString& str) 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(); bool SortIfNeeded(); 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"); } wxString TDictionary::Accentuate(const wxString& str) const { const int pos = str.Find('\''); if (pos <= 0) return str; wxString bello = str.Left(pos); for (size_t a = pos; str[a]; a++) { if (str[a] == '\'') { if ((isspace(str[a+1]) || str[a+1] == '\0') && strchr("aeiou", str[a-1])) { switch(str[a-1]) { case 'a': bello[a-1] = 'à'; break; case 'e': if (a >= 2 && (isspace(str[a-2]) || str[a-2] == '\'')) bello[a-1] = 'è'; else bello[a-1] = 'é'; break; case 'i': bello[a-1] = 'ì'; break; case 'o': bello[a-1] = 'ò'; break; case 'u': bello[a-1] = 'ù'; break; default: break; } } else bello << str[a]; } else bello << str[a]; } return bello; } void TDictionary::Save() { const bool full = SortIfNeeded(); if (full) { wxFileOutputStream outf(GetFileName()); outf << "\n"; for (size_t i = 0; i < m_sorted.GetCount(); i++) { const wxNode* pNode = m_sorted[i]; outf << " \n"; outf << " "; WriteXmlString(outf, pNode->GetKeyString()); outf << "\n"; outf << " "; WriteXmlString(outf, ((THashString*)pNode->GetData())->m_str); outf << "\n"; outf << " \n"; } outf << "\n"; m_nNewEntries = 0; } } void TDictionary::SaveIfNeeded() { if (m_nNewEntries > 0) Save(); } void TDictionary::AddEntry(const wxString& ita, const wxString& eng) { const wxString key = Accentuate(ita); Put(key, eng); m_nNewEntries++; } void TDictionary::UpdateEntry(size_t nEntry, const wxString& strValue) { if (nEntry >= 0 && nEntry < m_sorted.GetCount()) { const wxNode* pNode = m_sorted[nEntry]; ((THashString*)pNode->GetData())->m_str = strValue; Save(); } } wxString TDictionary::OriginalEntry(size_t i) { SortIfNeeded(); const wxNode* pNode = m_sorted[i]; return pNode->GetKeyString(); } wxString TDictionary::TranslatedEntry(size_t i) { const wxNode* pNode = m_sorted[i]; return ((THashString*)pNode->GetData())->m_str; } wxSocketClient& operator<<(wxSocketClient& sock, const wxChar* str) { if (str && *str) sock.Write(str, wxStrlen(str)); return sock; } bool TDictionary::FillCallback(TXmlItem& item, long jolly) { if (item.GetTag() == "entry") { const TXmlItem* ita = item.GetChild(0); const TXmlItem* eng = item.GetChild(1); if (ita != NULL && eng != NULL) { ita = ita->GetChild(0); eng = eng->GetChild(0); if (ita != NULL && eng != NULL) { TDictionary* d = (TDictionary*)jolly; d->AddEntry(ita->GetText(), eng->GetText()); } } } return false; } bool TDictionary::Load() { wxFileInputStream inf(GetFileName()); if (inf.Ok()) { TXmlItem item; item.Read(inf); item.ForEach(FillCallback, (long)this); } m_nNewEntries = 0; // No last minute additions :-) return GetCount() > 0; } bool TDictionary::LoadIfEmpty() { bool full = GetCount() > 0; if (!full) full = Load(); return full; } bool TDictionary::SortIfNeeded() { const bool full = LoadIfEmpty(); if (m_sorted.GetCount() != GetCount()) { // Fill an array of nodes and sort them out m_sorted.Empty(); BeginFind(); for (wxNode* pNode = Next(); pNode != NULL; pNode = Next()) m_sorted.Add(pNode); m_sorted.Sort(CompareNodes); } return full; } inline bool IsTrimmable(wxChar c) { return strchr(" :.,;", c) != NULL; } void TDictionary::ParseSpaces(const wxString& str, wxString& prefix, wxString& body, wxString& postfix) const { int i, j; for (i = 0; IsTrimmable(str[i]); i++); for (j = str.Length()-1; j >= i && IsTrimmable(str[j]); j--); if (i > 0) prefix = str.Left(i); if (j >= i) postfix = str.Mid(j+1); body = Accentuate(str.Mid(i, j-i+1)); } wxString TDictionary::Translate(const wxString& ita) { LoadIfEmpty(); wxString prefix, body, postfix; ParseSpaces(ita, prefix, body, postfix); wxString eng = Get(body); if (!eng.IsEmpty()) { if (eng != "???") { body = prefix; body += eng; body += postfix; return body; } } else AddEntry(ita, "???"); return ita; } TDictionary::TDictionary() : THashTable(3883), m_nNewEntries(0) { } TDictionary::~TDictionary() { if (m_nNewEntries > 0) Save(); } /////////////////////////////////////////////////////////// // TDictionaryServer /////////////////////////////////////////////////////////// class TDictionaryServer : public TBaseServerApp { TDictionary m_DevotoOli; protected: virtual const wxChar* GetAppName() const; virtual void ProcessCommand(wxString cmd, wxSocketBase& outs); 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 Initialize(); virtual bool Deinitialize(); }; 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) { m_DevotoOli.SortIfNeeded(); 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.GetCount(); i++) { const wxChar cCurr = toupper(m_DevotoOli.OriginalEntry(i)[0]); 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[0]); 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("tr"); TXmlItem& th0 = table_th.AddChild("th"); TXmlItem& th1 = table_th.AddChild("th"); th1 << "Original text"; TXmlItem& th2 = table_th.AddChild("th"); th2 << "Translated text"; for (size_t i = 0; i < m_DevotoOli.GetCount(); 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); } 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); if (strName == "EditEntry") { // Convert code (B-23) to position (107) const wxChar cFirst = toupper(strArgs[0]); const size_t nPos = atoi(strArgs.Mid(2)); size_t nFound = 0; for (size_t i = 0; i < m_DevotoOli.GetCount(); i++) { const wxChar c = toupper(m_DevotoOli.OriginalEntry(i)[0]); if (c == cFirst) { if (nFound == nPos) break; nFound++; } } body.AddChild("h2") << "Edit Entry " << strArgs; body.AddChild("br"); 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", "3"); 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", wxString::Format("%d", i)); TXmlItem& eng = form.AddChild("textarea"); eng.SetAttr("name", "Trans"); eng.SetAttr("cols", "80"); eng.SetAttr("rows", "3"); 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"); } 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", "3"); 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(" 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(); wxChar strLength[16]; sprintf(strLength, "%d", strResult.Length()); wxSocketOutputStream outs(sock); outs << "HTTP/1.1 200 OK" << endl; outs << "Connection: keep-alive" << endl; outs << "Content-Length: " << strLength << endl; outs << "Content-Type: text/xml; charset=utf-8" << endl; outs << "Date: " << wxDateTime::Now().Format("%#c") << endl; outs << "Server: " << GetAppName() << endl; outs << "Host: " << wxGetHostName() << endl; outs << endl; outs << 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 size_t nEntry = atoi(hashArgs.Get("Entry")); const wxString strValue = hashArgs.Get("Trans"); m_DevotoOli.UpdateEntry(nEntry, strValue); strFileName = "dictionary"; GenerateFile(strFileName); } void TDictionaryServer::ProcessFormTranslate(wxString& strFileName, THashTable& hashArgs) { const wxString strValue = hashArgs.Get("Sentence"); TXmlItem html; TXmlItem& body = CreatePageBody(html); 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"); 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::Initialize() { return m_DevotoOli.LoadIfEmpty(); } bool TDictionaryServer::Deinitialize() { m_DevotoOli.SaveIfNeeded(); return true; } // Istanziare l'applicazione principale IMPLEMENT_APP(TDictionaryServer)