Files correlati : Ricompilazione Demo : [ ] Commento :sistemati errori legati al nuovo wxWidgets git-svn-id: svn://10.65.10.50/trunk@13937 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1144 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1144 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <wx/wx.h>
 | |
| 
 | |
| #include "baseserv.h"
 | |
| 
 | |
| #include <wx/dbtable.h>
 | |
| #include <wx/dynarray.h>
 | |
| #include <wx/mstream.h>
 | |
| 
 | |
| wxString GetSoapParam(const TXmlItem &xmlMethod, const char* strParam)
 | |
| {
 | |
| 	wxString val;
 | |
|   const TXmlItem* xml = xmlMethod.FindFirst(strParam);
 | |
|   if (xml != NULL)
 | |
| 		val = xml->GetEnclosedText();
 | |
| 	return val;
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TRecord
 | |
| // Tabella di database con 1 o piu' viste in base alla chiave
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TRecord : public wxObject
 | |
| {
 | |
| private:
 | |
|   wxArrayString m_Fields;
 | |
|   wxString m_strLocker;  // User locking the record
 | |
|   bool m_bDeleted;
 | |
| 
 | |
| public:
 | |
|   bool Locked() const { return !m_strLocker.IsEmpty(); }
 | |
|   const wxString& LockedBy() const { return m_strLocker; }
 | |
|   
 | |
|   bool Deleted() const { return m_bDeleted; }
 | |
|   void MarkAsDeleted() { m_bDeleted = true; }
 | |
|   void MarkAsUndeleted() { m_bDeleted = false; }
 | |
| 
 | |
|   void Add(const wxString& strValue) { m_Fields.Add(strValue); }
 | |
| 
 | |
|   const wxString& operator[] (size_t i) const { return m_Fields[i]; }
 | |
|   wxString& operator[] (size_t i) { return m_Fields[i]; }
 | |
| };
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TArrayObject
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| WX_DEFINE_ARRAY(wxObject*, TArrayObject);
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TIndexEntry
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| struct TIndexEntry : public wxObject
 | |
| {
 | |
|   wxString m_strkey;
 | |
|   long m_nRecno;
 | |
| };
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TIndex
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TIndex : public wxObject
 | |
| {
 | |
|   enum { MAX_KEY_ENTRIES = 8 };
 | |
|   int m_nField[MAX_KEY_ENTRIES];
 | |
|   int m_nSize[MAX_KEY_ENTRIES];
 | |
|   bool m_bUpper[MAX_KEY_ENTRIES];
 | |
|   int m_nKeyFields;
 | |
| 
 | |
|   TArrayObject m_ndx;
 | |
| 
 | |
| protected:  
 | |
|   void AddRecord(const TRecord& rec, long recno);
 | |
|   long FindPosition(long recno) const;
 | |
| 
 | |
| public:
 | |
|   void AddKeyField(int nPos, int nSize, bool upper);
 | |
|   long FindPosition(const wxString& key) const;
 | |
|   long SkipTo(long recno, long offset) const;
 | |
|   void Update(const TArrayObject& records);
 | |
|   bool Ok() const { return m_nKeyFields > 0; }
 | |
|   long GetCount() const { return m_ndx.GetCount(); }
 | |
| 
 | |
|   TIndex();
 | |
| };
 | |
| 
 | |
| void TIndex::AddKeyField(int nPos, int nSize, bool upper)
 | |
| {
 | |
|   if (m_nKeyFields < MAX_KEY_ENTRIES)
 | |
|   {
 | |
|     m_nField[m_nKeyFields] = nPos;
 | |
|     m_nSize[m_nKeyFields] = nPos;
 | |
|     m_bUpper[m_nKeyFields] = upper;
 | |
|     m_nKeyFields++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| long TIndex::FindPosition(const wxString& key) const
 | |
| {
 | |
|   int nFirst = 0;
 | |
|   int nLast = m_ndx.GetCount()-1;
 | |
|   while (nFirst <= nLast)
 | |
|   {
 | |
|     const int nCurr = (nFirst + nLast) / 2;
 | |
|     const int nCmp = ((TIndexEntry*)m_ndx[nCurr])->m_strkey.Cmp(key);
 | |
|     if (nCmp == 0)
 | |
|       return nCurr;
 | |
|     if (nCmp > 0)
 | |
|       nLast = nCurr-1;
 | |
|     if (nCmp < 0)
 | |
|       nFirst = nCurr+1;
 | |
|   }
 | |
|   return nFirst;
 | |
| }
 | |
| 
 | |
| long TIndex::FindPosition(long recno) const
 | |
| {
 | |
|   long i;
 | |
|   for (i = m_ndx.GetCount()-1; i >= 0; i--)
 | |
|     if (((TIndexEntry*)m_ndx[i])->m_nRecno == recno)
 | |
|       break;
 | |
|   return i;
 | |
| }
 | |
| 
 | |
| long TIndex::SkipTo(long recno, long offset) const
 | |
| {
 | |
|   const long tot = m_ndx.GetCount();
 | |
|   long i = 0;
 | |
|   if (tot > 0)
 | |
|   {
 | |
|     if (recno == 0) // Goto first
 | |
|       i = ((TIndexEntry*)m_ndx[0])->m_nRecno; else
 | |
|     if (recno < 0)  // Goto last
 | |
|       i = ((TIndexEntry*)m_ndx[tot-1])->m_nRecno; else
 | |
|     {
 | |
|       const long p = FindPosition(recno) + offset;
 | |
|       if (p >= 0 && p < tot)
 | |
|         i = ((TIndexEntry*)m_ndx[p])->m_nRecno;
 | |
|     }
 | |
|   }
 | |
|   return i;
 | |
| }
 | |
| 
 | |
| void TIndex::AddRecord(const TRecord& rec, long recno)
 | |
| {
 | |
|   TIndexEntry* e = new TIndexEntry;
 | |
|   e->m_nRecno = recno;
 | |
|   for (int i = 0; i < m_nKeyFields; i++)
 | |
|   {
 | |
|     const char* val = rec[m_nField[i]];
 | |
|     if (m_bUpper[i])
 | |
|     {
 | |
|       e->m_strkey.Printf("%*s", -m_nSize[i], val);
 | |
|       e->m_strkey.Upper();
 | |
|     }
 | |
|     else
 | |
|       e->m_strkey.Printf("%*s", m_nSize[i], val);
 | |
|   }
 | |
|   
 | |
|   const int nPos = FindPosition(e->m_strkey);
 | |
|   m_ndx.Insert(e, nPos);
 | |
| }
 | |
| 
 | |
| void TIndex::Update(const TArrayObject& records)
 | |
| {
 | |
|   WX_CLEAR_ARRAY(m_ndx);
 | |
|   for (size_t i = 0; i < records.GetCount(); i++)
 | |
|     AddRecord(*((TRecord*)records[i]), i+1);
 | |
| }
 | |
| 
 | |
| TIndex::TIndex() : m_nKeyFields(0) 
 | |
| { }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TTable
 | |
| // Tabella di database con 1 o piu' viste in base alla chiave
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TTable : public wxObject
 | |
| {
 | |
|   wxDbColInf* m_ci;
 | |
|   wxDbTable* m_table;
 | |
|   UWORD m_nColumns;
 | |
|   char* m_field[128];
 | |
| 
 | |
|   TArrayObject m_Records, m_Indexes;
 | |
|   long m_nCurrent;
 | |
| 
 | |
| protected:
 | |
|   void KillRecordSet();
 | |
|   bool FillRecordSet();
 | |
|   bool GoTo(long& recno);
 | |
| 
 | |
|   int FindColumn(const char* name) const;
 | |
| 
 | |
| public:
 | |
|   long Rows(int index) const;
 | |
|   void GetRecord(long recno, wxOutputStream& out);
 | |
|   void GetRecordLength(wxOutputStream& out);
 | |
|   bool CreateIndex(int index, const TXmlItem& fields);
 | |
|   TIndex& Index(int n);
 | |
| 
 | |
|   bool ok() const { return m_nColumns > 0; }
 | |
| 
 | |
|   TTable(wxDb* db, const wxString& strName);
 | |
|   virtual ~TTable();
 | |
| };
 | |
| 
 | |
| long TTable::Rows(int index) const
 | |
| {
 | |
|   const TIndex& idx = ((TTable*)this)->Index(index);
 | |
|   return idx.Ok() ? idx.GetCount() : m_Records.GetCount();
 | |
| }
 | |
| 
 | |
| bool TTable::GoTo(long& rec)
 | |
| {
 | |
|   const long tot = m_Records.GetCount();
 | |
|   bool ok = false;
 | |
|   if (rec < 0)  // -1 = last record
 | |
|     rec = tot + rec + 1;
 | |
|   if (rec > 0 && rec <= tot)
 | |
|   {
 | |
|     m_nCurrent = rec;
 | |
|     ok = true;
 | |
|   }
 | |
|   return ok;
 | |
| }
 | |
| 
 | |
| void TTable::GetRecord(long recno, wxOutputStream& out)
 | |
| {
 | |
|   if (GoTo(recno))
 | |
|   {
 | |
|     const TRecord& record = *((TRecord*)m_Records[m_nCurrent-1]);
 | |
| 
 | |
|     TXmlItem rec; rec.SetTag("Record");
 | |
|     rec.SetAttr("RecNo", recno);
 | |
|     for (UWORD c = 0; c < m_nColumns; c++)
 | |
|     {
 | |
|       const wxString& str = record[c];
 | |
|       if (!str.IsEmpty() && str != "1899-12-30")
 | |
|         rec.AddSoapString("Field", str).SetAttr("Name", m_ci[c].colName);
 | |
|     }
 | |
|     rec.Write(out, 2);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void TTable::GetRecordLength(wxOutputStream& out)
 | |
| {
 | |
|   int len = 0;
 | |
|   for (UWORD i = 0; i < m_nColumns; i++)
 | |
|   {
 | |
|     const wxDbColInf& ci = m_ci[i];
 | |
|     switch (ci.sqlDataType)
 | |
|     {
 | |
|     case SQL_C_DATE: 
 | |
|       len += 8; 
 | |
|       break;
 | |
|     default: 
 | |
|       if (ci.bufferSize > 128) // It's a MEMO!
 | |
|         len += 10;
 | |
|       else
 | |
|         len += ci.bufferSize; 
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   out << wxString::Format("%d", len);
 | |
| }
 | |
| 
 | |
| int TTable::FindColumn(const char* name) const
 | |
| {
 | |
|   int i = m_nColumns-1;
 | |
|   for ( ; i >= 0; i--)
 | |
|   {
 | |
|     if (wxStricmp(m_ci[i].colName, name) == 0)
 | |
|       break;
 | |
|   }
 | |
|   return i;
 | |
| }
 | |
| 
 | |
| TIndex& TTable::Index(int index)
 | |
| {
 | |
|   if (index < 0 || index > 8)
 | |
|     index = 0;
 | |
|   for (int i = m_Indexes.GetCount(); i <= index; i++)
 | |
|     m_Indexes.Add(new TIndex);
 | |
|   return *((TIndex*)m_Indexes[index]);
 | |
| }
 | |
| 
 | |
| bool TTable::CreateIndex(int index, const TXmlItem& fields)
 | |
| {
 | |
|   TIndex& ndx = Index(index);
 | |
|   if (!ndx.Ok())
 | |
|   {
 | |
|     for (int c = 0; c < fields.GetChildren(); c++)
 | |
|     {
 | |
|       const TXmlItem& field = *fields.GetChild(c);
 | |
|       if (field.GetTag() == "Field")
 | |
|       {
 | |
|         const int i = FindColumn(field.GetAttr("Name"));
 | |
|         if (i >= 0)
 | |
|         {
 | |
|           const bool upper = !field.GetAttr("Upper").IsEmpty();
 | |
|           ndx.AddKeyField(i, m_ci[i].bufferSize, upper);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     ndx.Update(m_Records);
 | |
|   }
 | |
| 
 | |
|   return ndx.Ok();
 | |
| }
 | |
| 
 | |
| void TTable::KillRecordSet()
 | |
| {
 | |
|   WX_CLEAR_ARRAY(m_Records);
 | |
|   m_Records.Clear();
 | |
| }
 | |
| 
 | |
| bool TTable::FillRecordSet()
 | |
| {
 | |
|   KillRecordSet();
 | |
|   const bool ok = m_table->Query();
 | |
|   if (ok)
 | |
|   {  
 | |
|     while (m_table->GetNext())
 | |
|     {
 | |
|       TRecord* rec = new TRecord;
 | |
|       for (UWORD i = 0; i < m_nColumns; i++)
 | |
|       {
 | |
|         char* spc = NULL;
 | |
|         for (char* c = m_field[i]; *c; c++)
 | |
|         {
 | |
|           if (*c == ' ')
 | |
|           {
 | |
|             if (spc == NULL) 
 | |
|               spc = c;
 | |
|           }
 | |
|           else
 | |
|             spc = NULL;
 | |
|         }
 | |
|         if (spc != NULL)
 | |
|           *spc = '\0';     
 | |
|         rec->Add(m_field[i]); 
 | |
|       }
 | |
|       m_Records.Add(rec);
 | |
|     }
 | |
|   }
 | |
|   for (size_t i = 1; i < m_Indexes.GetCount(); i++)
 | |
|   {
 | |
|     TIndex& ndx = Index(i);
 | |
|     if (ndx.Ok())
 | |
|       ndx.Update(m_Records);
 | |
|   }
 | |
|   return ok;
 | |
| }
 | |
| 
 | |
| 
 | |
| TTable::TTable(wxDb* db, const wxString& strName)
 | |
| {
 | |
|   m_ci = db->GetColumns(strName, &m_nColumns);
 | |
| 
 | |
|   m_table = new wxDbTable(db, strName, m_nColumns, strName, false);
 | |
| 
 | |
|   // Bind columns
 | |
|   for (UWORD i = 0; i < m_nColumns; i++)
 | |
|   {
 | |
|     const wxDbColInf& ci = m_ci[i];
 | |
|     const int length = ci.bufferSize+1;
 | |
|     m_field[i] = new char[length];
 | |
|     memset(m_field[i], 0, length);
 | |
|     int nSqlType = ci.sqlDataType;
 | |
|     if (nSqlType <= 0 || nSqlType == 2)
 | |
|       nSqlType = SQL_C_CHAR;
 | |
|     m_table->SetColDefs(i, ci.colName, DB_DATA_TYPE_VARCHAR, 
 | |
|                         m_field[i], nSqlType, length);
 | |
|   }
 | |
| 
 | |
|   if (m_table->Open(false, false))
 | |
|   {
 | |
|     if (!FillRecordSet())
 | |
|       GetServerApp().WriteLog(wxString::Format("Can't query table %s", strName.c_str()));
 | |
|   }
 | |
|   else
 | |
|     GetServerApp().WriteLog(wxString::Format("Can't open table %s", strName.c_str()));
 | |
| 
 | |
|   m_nCurrent = 0;  // Before the first
 | |
| }
 | |
| 
 | |
| 
 | |
| TTable::~TTable()
 | |
| {
 | |
|   KillRecordSet();
 | |
|   
 | |
|   delete m_table;
 | |
| 
 | |
|   for (UWORD i = 0; m_field[i] != NULL; i++)
 | |
|     delete m_field[i];
 | |
| 
 | |
|   delete m_ci;
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TDataBase
 | |
| // Database di dati comuni (COM) o di DITTA (00001A, ecc...)
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TDataBase : public wxHashTable
 | |
| {
 | |
|   wxDbConnectInf m_ci;
 | |
|   wxDb* m_db;
 | |
| 
 | |
| public:
 | |
| 	bool Open(const wxString& dsn, const wxString& user, const wxString& password);
 | |
| 	bool IsOpen() const;
 | |
| 	void Close();
 | |
| 	wxDb& DataBase() { return *m_db; } 
 | |
| 
 | |
|   TTable* Table(const wxString& strName);
 | |
| 
 | |
| 	TDataBase();
 | |
| 	virtual ~TDataBase();
 | |
| };
 | |
| 
 | |
| bool TDataBase::Open(const wxString& dsn, const wxString& user, const wxString& password)
 | |
| {
 | |
|   Close();
 | |
| 
 | |
|   m_ci.SetDsn(dsn);
 | |
|   m_ci.SetUserID(user);
 | |
|   m_ci.SetPassword(password);
 | |
| 	
 | |
|   if (m_ci.AllocHenv())
 | |
| 	{
 | |
| 		m_db = ::wxDbGetConnection(&m_ci, false); // Forward only?
 | |
| 		if (m_db == NULL)
 | |
|       m_ci.FreeHenv();
 | |
| 		else
 | |
| 		{
 | |
| 			const wxString strLog = GetServerApp().GetLogFileName();
 | |
| 			if (!strLog.IsEmpty())
 | |
| 			  m_db->SetSqlLogging(sqlLogON, strLog, TRUE);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return IsOpen();
 | |
| }
 | |
| 
 | |
| void TDataBase::Close()
 | |
| {
 | |
|   if (m_db)
 | |
| 	{
 | |
| 		m_db->SetSqlLogging(sqlLogOFF);
 | |
| 		::wxDbFreeConnection(m_db);
 | |
| 		m_db = NULL;
 | |
| 		m_ci.FreeHenv();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| bool TDataBase::IsOpen() const
 | |
| {
 | |
| 	return m_db != NULL;
 | |
| }
 | |
| 
 | |
| TTable* TDataBase::Table(const wxString& strName)
 | |
| {
 | |
| 	TTable* s = (TTable*)Get(strName);
 | |
|   if (s == NULL)
 | |
|   {
 | |
|     s = new TTable(m_db, strName);
 | |
|     if (s->ok())
 | |
|       Put(strName, s);
 | |
|   }
 | |
|   return s;
 | |
| }
 | |
| 
 | |
| TDataBase::TDataBase() : wxHashTable(wxKEY_STRING), m_db(NULL)
 | |
| {
 | |
| 	m_ci.Henv = 0;
 | |
| 	DeleteContents(true);
 | |
| }
 | |
| 
 | |
| TDataBase::~TDataBase()
 | |
| {
 | |
| 	Close();
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TStudy
 | |
| // Elenco di Databases: COM, 00001A, 00002A, ecc...
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TStudy : public wxHashTable
 | |
| {
 | |
|   wxString m_strUser, m_strPass;
 | |
| 	wxString m_strName;
 | |
| 
 | |
| public:
 | |
| 	TDataBase& DB(long firm); // 0 = COM
 | |
| 	TStudy(const char* strName, const char* strUser, const char* strPass);
 | |
| };
 | |
| 
 | |
| TDataBase& TStudy::DB(long firm)
 | |
| {
 | |
| 	TDataBase* db = (TDataBase*)Get(firm);
 | |
| 	if (db == NULL)
 | |
| 	{
 | |
|   	wxString strDsn, strPath;
 | |
| 
 | |
| 		if (firm > 0)
 | |
| 			strDsn.sprintf("%s_%05lda", m_strName.c_str(), firm);
 | |
| 		else
 | |
| 			strDsn.sprintf("%s_COM", m_strName.c_str());
 | |
| 
 | |
| 		db = new TDataBase;
 | |
| 
 | |
| 		db->Open(strDsn, m_strUser, m_strPass);
 | |
| 		Put(firm, db);
 | |
| 	}
 | |
| 	return *db;
 | |
| }
 | |
| 
 | |
| TStudy::TStudy(const char* strName, const char* strUser, const char* strPass) 
 | |
|       : wxHashTable(wxKEY_INTEGER), m_strUser(strUser), m_strPass(strPass), m_strName(strName)
 | |
| {
 | |
| 	DeleteContents(true);
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TCommercialist
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TCommercialist : public wxHashTable
 | |
| {
 | |
|   wxString m_strUser, m_strPass;  // User impersonated by the TCommenrcialist
 | |
| 
 | |
| public:
 | |
|   const wxString& User() const { return m_strUser; }
 | |
|   const wxString& Password() const { return m_strPass; }
 | |
| 
 | |
| 	TStudy& Study(const wxString& strStudy);
 | |
|   TTable* Table(const TXmlItem& item);
 | |
| 
 | |
|   TCommercialist();
 | |
| };
 | |
| 
 | |
| TStudy& TCommercialist::Study(const wxString& strStudy)
 | |
| {
 | |
| 	TStudy* s = (TStudy*)Get(strStudy);
 | |
|   if (s == NULL)
 | |
|   {
 | |
|     if (m_strUser.IsEmpty())
 | |
|     {
 | |
|       TBaseServerApp& a = GetServerApp();
 | |
|       m_strUser = a.GetConfigString("User", "ADMIN");
 | |
|       m_strPass = a.GetConfigString("Password", "AD.MIN");
 | |
|     }
 | |
|     s = new TStudy(strStudy, m_strUser, m_strPass);
 | |
|     Put(strStudy, s);
 | |
|   }
 | |
|   return *s;
 | |
| }
 | |
| 
 | |
| TTable* TCommercialist::Table(const TXmlItem& xmlMethod)
 | |
| {
 | |
|   TTable* tab = NULL;
 | |
|   const wxString strStudy = GetSoapParam(xmlMethod, "Study");
 | |
|   const long nFirm = atol(GetSoapParam(xmlMethod, "Firm"));
 | |
|   TStudy& study = Study(strStudy);
 | |
|   TDataBase& firm = study.DB(nFirm);
 | |
|   if (firm.IsOpen())
 | |
|   {
 | |
|     const wxString strTable = GetSoapParam(xmlMethod, "Table");
 | |
|     tab = firm.Table(strTable);
 | |
|   }
 | |
|   return tab;
 | |
| }
 | |
| 
 | |
| TCommercialist::TCommercialist()
 | |
| {
 | |
| 	DeleteContents(true);
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TDataBaseServer
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TDataBaseServer : public TBaseServerApp
 | |
| {
 | |
|   TCommercialist m_caminetti;
 | |
| 
 | |
| protected:  
 | |
| 	virtual const wxChar* GetAppName() const;
 | |
|   virtual void ProcessCommand(wxString cmd, wxSocketBase& outs);
 | |
|   virtual bool Initialization();
 | |
|   virtual bool Deinitialization();
 | |
| 
 | |
| protected:  
 | |
|   void AddAsterisk(const wxString& strField, const wxString& strQuery, 
 | |
| 									 TDataBase& db, wxArrayString& arr);
 | |
|   wxString ParseQuery(const wxString& strOriginalQuery, TDataBase& db, wxArrayString& arr);
 | |
|   void WriteTable(wxString strDsn, wxString strUser,
 | |
| 									wxString strPass, wxString strOriginalQuery,
 | |
| 									wxOutputStream& out);
 | |
| 
 | |
|   void SoapProcessMethod(const TXmlItem& xmlMethod, wxOutputStream& out);
 | |
|   void SoapProcessQuery(const TXmlItem &xmlMethod, wxOutputStream& out);
 | |
|   
 | |
|   void SoapProcessTableRows(const TXmlItem &xmlMethod, wxOutputStream& out);
 | |
| 	void SoapProcessGetRecord(const TXmlItem &xmlMethod, wxOutputStream& out);
 | |
| 	void SoapProcessGetRecordLength(const TXmlItem &xmlMethod, wxOutputStream& out);
 | |
| 	void SoapProcessCreateIndex(const TXmlItem &xmlMethod, wxOutputStream& out);
 | |
|   void SoapProcessSkipRecord(const TXmlItem &xmlMethod, wxOutputStream& out);
 | |
| 
 | |
| public:
 | |
| 	bool IsMagicName(wxString& strFilename) const;
 | |
| 
 | |
|   void ProcessFormQuery(const wxString& strFileName, THashTable& hashArgs);
 | |
|   void ProcessFormCommand(wxString cmd, wxSocketBase& outs);
 | |
|   void ProcessSoapCommand(wxString cmd, wxSocketBase& outs);
 | |
| 
 | |
|   void GenerateIndex(wxString& strFilename);
 | |
|   void GenerateSql(wxString& strFilename);
 | |
|   void GenerateFile(wxString& strFilename);
 | |
| };
 | |
| 
 | |
| // Implementare almeno queste due funzioni pure virtuali
 | |
| 
 | |
| const wxChar* TDataBaseServer::GetAppName() const
 | |
| {
 | |
| 	return "DataBase";
 | |
| }
 | |
| 
 | |
| bool TDataBaseServer::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 == "sql")
 | |
| 	{
 | |
| 		strFilename = strName;
 | |
| 		return true;
 | |
| 	}
 | |
| 	if (strName == "log")
 | |
| 	{
 | |
| 		strFilename = GetLogFileName();
 | |
| 	}
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::GenerateIndex(wxString& strFilename)
 | |
| {
 | |
| 	TXmlItem html; 
 | |
| 	TXmlItem& body = CreatePageBody(html).AddChild("center");
 | |
| 
 | |
| 	TXmlItem& table = body.AddChild("table");
 | |
|   table.SetAttr("border", "1");
 | |
| 	table.SetAttr("width", "70%");
 | |
| 
 | |
| 	TXmlItem& tr0 = body.AddChild("tr");
 | |
|   TXmlItem& aq = tr0.AddChild("td").AddChild("a");
 | |
| 	aq.SetAttr("href", "sql.htm"); aq << "SQL query";
 | |
| 	tr0.AddChild("td") << "Perform any SQL query on the selected Data Source";
 | |
| 
 | |
| 	TXmlItem& tr1 = body.AddChild("tr");
 | |
|   TXmlItem& al = tr1.AddChild("td").AddChild("a");
 | |
| 	al.SetAttr("href", "Log"); al << "Log File";
 | |
| 	tr1.AddChild("td") << "Display current server log";
 | |
| 
 | |
| 	TXmlItem& tr2 = body.AddChild("tr");
 | |
|   TXmlItem& as = tr2.AddChild("td").AddChild("a");
 | |
| 	as.SetAttr("href", "stop.cgi"); as << "Stop";
 | |
| 	tr2.AddChild("td") << "Stop this database server";
 | |
| 	
 | |
| 	strFilename = GetTempFilename();
 | |
| 	html.Save(strFilename);
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::GenerateSql(wxString& strFilename)
 | |
| {
 | |
| 	TXmlItem html; 
 | |
| 	TXmlItem& body = CreatePageBody(html).AddChild("center");
 | |
| 
 | |
| 	TXmlItem& form = body.AddChild("form");
 | |
| 	form.SetAttr("method", "post");
 | |
| 	form.SetAttr("action", "Query.cgi");
 | |
| 
 | |
|   TXmlItem& table = form.AddChild("table").SetAttr("width", "70%");
 | |
|   
 | |
| 	TXmlItem& tr0 = table.AddChild("tr");
 | |
| 	tr0.AddChild("td") << "Data Source Name";
 | |
| 	TXmlItem& dsn = tr0.AddChild("td").AddChild("input");
 | |
| 	dsn.SetAttr("type", "string"); dsn.SetAttr("name", "Dsn");
 | |
| 	dsn.SetAttr("value", GetConfigString("Dsn"));
 | |
| 
 | |
| 	TXmlItem& tr1 = table.AddChild("tr");
 | |
| 	tr1.AddChild("td") << "User";
 | |
| 	TXmlItem& user = tr1.AddChild("td").AddChild("input");
 | |
| 	user.SetAttr("type", "string"); user.SetAttr("name", "User");
 | |
| 	user.SetAttr("value", GetConfigString("User"));
 | |
| 
 | |
| 	TXmlItem& tr2 = table.AddChild("tr");
 | |
| 	tr2.AddChild("td") << "Password";
 | |
| 	TXmlItem& pass = tr2.AddChild("td").AddChild("input");
 | |
| 	pass.SetAttr("type", "password"); pass.SetAttr("name", "User");
 | |
| 
 | |
| 	form.AddChild("br");
 | |
| 	form.AddChild("h3") << "SQL query:";
 | |
| 	TXmlItem& q = form.AddChild("textarea");
 | |
| 	q.SetAttr("name", "Sql");
 | |
| 	q.SetAttr("cols", "80"); q.SetAttr("rows", "10");
 | |
| 
 | |
| 	wxString query = GetConfigString("Sql");
 | |
| 	q << query;
 | |
|       
 | |
| 	form.AddChild("br");
 | |
| 	form.AddChild("br");
 | |
| 
 | |
| 	TXmlItem& sub = form.AddChild("input");
 | |
| 	sub.SetAttr("type", "submit"); 
 | |
| 	sub.SetAttr("value", "Execute");
 | |
| 
 | |
| 	AddLinkButton(body, "Return to main page", "/");
 | |
| 
 | |
| 	strFilename = GetTempFilename();
 | |
| 	html.Save(strFilename);
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::GenerateFile(wxString& strFilename)
 | |
| {
 | |
|   wxString strName, strArgs;
 | |
| 	wxSplitPath(strFilename, NULL, &strName, NULL);
 | |
|   strName.MakeLower();
 | |
|   const int q = strFilename.Find('?');
 | |
| 	if (q > 0)
 | |
| 		strArgs = strFilename.Mid(q+1);
 | |
| 
 | |
| 	if (strName == "index")
 | |
|     GenerateIndex(strFilename); else
 | |
| 	if (strName == "sql")
 | |
|     GenerateSql(strFilename); else
 | |
| 	if (strName == "log")
 | |
| 		strFilename = GetLogFileName();
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::AddAsterisk(const wxString& strField, const wxString& strQuery, 
 | |
| 																 TDataBase& db, wxArrayString& arr)
 | |
| {
 | |
| 	wxString strTable;
 | |
| 	const int nDot = strField.Find(".*");
 | |
| 	if (nDot < 0)
 | |
| 	{
 | |
| 		const int nFrom = strQuery.Find("FROM ");
 | |
| 		if (nFrom > 0)
 | |
| 			strTable = strQuery.Mid(nFrom+5);
 | |
| 		const int nComma = strTable.Find(',');
 | |
| 		const int nSpace = strTable.Find(' ');
 | |
| 		int nTrunc = strTable.Length();
 | |
| 		if (nComma > 0)
 | |
| 			nTrunc = nComma;
 | |
| 		if (nSpace > 0 && nSpace < nTrunc)
 | |
| 			nTrunc = nSpace;
 | |
| 		strTable.Truncate(nTrunc);
 | |
| 	}
 | |
| 	else
 | |
| 		strTable = strField.Left(nDot);
 | |
| 	strTable.Trim(false); strTable.Trim(true);
 | |
| 
 | |
| 	UWORD numCols;
 | |
| 	wxDbColInf* dci = db.DataBase().GetColumns(strTable, &numCols);
 | |
| 
 | |
| 	wxString strFieldName;
 | |
| 	for (UWORD i = 0; i < numCols; i++)
 | |
| 	{
 | |
| 		if (strField == "*")
 | |
| 			strFieldName = dci[i].colName;
 | |
| 		else
 | |
| 		{
 | |
| 		  strFieldName = strTable;
 | |
| 		  strFieldName += ".";
 | |
| 		  strFieldName += dci[i].colName;
 | |
| 		}
 | |
|     arr.Add(strFieldName);
 | |
| 	}
 | |
| 
 | |
|   delete dci;
 | |
| }
 | |
| 
 | |
| wxString TDataBaseServer::ParseQuery(const wxString& strOriginalQuery, TDataBase& db, wxArrayString& arr)
 | |
| {
 | |
| 	wxString strQuery;
 | |
| 
 | |
|   const int nSelect = strOriginalQuery.Find("SELECT ");
 | |
| 	const int nFrom = strOriginalQuery.Find("FROM ");
 | |
| 
 | |
| 	if (nSelect >= 0 && nFrom > nSelect)
 | |
| 	{
 | |
| 		wxString strFields = strOriginalQuery.Mid(nSelect+7, nFrom-nSelect-7);
 | |
| 		strFields.Trim(false); strFields.Trim(true);
 | |
| 		while(!strFields.IsEmpty())
 | |
| 		{
 | |
| 			const int nComma = strFields.Find(',');
 | |
| 			wxString strField = nComma < 0 ? strFields : strFields.Mid(0, nComma);
 | |
| 			strField.Trim(); strField.Trim(false);
 | |
| 			if (strField.Find("*") >= 0)
 | |
|         AddAsterisk(strField, strOriginalQuery, db, arr);
 | |
| 			else
 | |
| 				arr.Add(strField);
 | |
| 			if (nComma > 0)
 | |
| 				strFields = strFields.Mid(nComma+1);
 | |
| 			else
 | |
| 				break;
 | |
| 		}
 | |
| 		strQuery = "SELECT ";
 | |
| 		for (size_t i = 0; i < arr.GetCount(); i++)
 | |
| 		{
 | |
| 			if (i > 0)
 | |
| 				strQuery << ",";
 | |
| 			strQuery << arr[i];
 | |
| 		}
 | |
| 		strQuery << strOriginalQuery.Mid(nFrom-1);
 | |
| 	}
 | |
| 	else
 | |
|     strQuery = strOriginalQuery; 
 | |
| 
 | |
| 	return strQuery;
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::WriteTable(wxString strDsn, wxString strUser,
 | |
| 																 wxString strPass, wxString strOriginalQuery,
 | |
| 																 wxOutputStream& out)
 | |
| {
 | |
| 	const clock_t tTotalStart = clock();
 | |
| 
 | |
| 	clock_t tQueryTime = 0;
 | |
| 	clock_t tRetrieveTime = 0;
 | |
|   clock_t tTotalTime = 0;
 | |
| 	size_t nRecords = 0;
 | |
| 	
 | |
| 	out << "<table border=1>\n";
 | |
| 
 | |
|   if (strDsn.IsEmpty())
 | |
|     strDsn = GetConfigString("DataPath");
 | |
|   
 | |
|   if (strUser.IsEmpty())
 | |
|     strUser = GetConfigString("User");
 | |
|   
 | |
|   if (strPass.IsEmpty())
 | |
|     strPass = GetConfigString("Password");
 | |
| 
 | |
|   TStudy s(strDsn, strUser, strPass);
 | |
| 	TDataBase& d = s.DB(0); // Ditta/COM
 | |
| 	if (d.IsOpen())
 | |
| 	{
 | |
| 		wxArrayString arr;
 | |
| 		const wxString strQuery = ParseQuery(strOriginalQuery, d, arr);
 | |
| 
 | |
| 		wxDb& db = d.DataBase();
 | |
| 
 | |
| 		const clock_t tQueryStart = clock();
 | |
| 		db.ExecSql(strQuery);
 | |
| 		tQueryTime    = clock() - tQueryStart;
 | |
| 		
 | |
| 		const int nColumns = arr.GetCount();
 | |
| 		if (nColumns > 0)
 | |
| 		{
 | |
| 			out << " <thead>\n";
 | |
| 			for (int i = 0; i < nColumns; i++)
 | |
| 				out << "  <th>" << arr[i] << "</th>\n";
 | |
| 			out << " </thead>\n";
 | |
| 	
 | |
| 			const int bufsize = 33000;
 | |
| 			wxChar* buffer = new wxChar[bufsize];
 | |
| 
 | |
| 			const clock_t tRetrieveStart = clock();
 | |
| 			for (nRecords = 0; db.GetNext(); nRecords++)
 | |
| 			{
 | |
| 				out << " <tr>\n";
 | |
| 				for (int c = 1; c <= nColumns; c++)
 | |
| 				{
 | |
| 					SDWORD cb;
 | |
| 					if (db.GetData(c, SQL_C_CHAR, buffer, bufsize, &cb))
 | |
| 					{
 | |
| 						if (strcmp(buffer, "1899-12-30") == 0)
 | |
| 							*buffer = '\0';
 | |
| 						out << "  <td>" << buffer << "</td>\n";
 | |
| 					}
 | |
| 					else
 | |
| 						break;
 | |
| 				}
 | |
| 				out << " </tr>\n";
 | |
| 			}
 | |
| 			delete buffer;
 | |
| 			tRetrieveTime = clock() - tRetrieveStart;
 | |
| 		}
 | |
| 	}
 | |
|   out << "</table>\n";
 | |
| 
 | |
| 	tTotalTime = clock() - tTotalStart;
 | |
| 
 | |
| 	WriteLog(wxString::Format("--- %u Records. Query:%u Retrieve:%u Total:%u", 
 | |
| 		                        nRecords, (unsigned int) tQueryTime, (unsigned int) tRetrieveTime, (unsigned int) tTotalTime));
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::ProcessFormQuery(const wxString& strFileName, THashTable& hashArgs)
 | |
| {
 | |
| 	const wxString strDsn = hashArgs.Get("DSN");
 | |
| 	const wxString strUser = hashArgs.Get("User");
 | |
| 	const wxString strPass = hashArgs.Get("Password");
 | |
| 	const wxString strOriginalQuery = hashArgs.Get("SQL");
 | |
| 
 | |
| 	SetConfigString("DSN", strDsn);
 | |
| 	SetConfigString("User", strUser);
 | |
| 
 | |
|   wxString strQuery = strOriginalQuery;
 | |
|   strQuery.Replace("\r\n", " ");
 | |
| 	SetConfigString("SQL", strQuery);
 | |
| 
 | |
| 	wxFileOutputStream out(strFileName);
 | |
| 
 | |
| 	out << "<html>\n";
 | |
| 	out << "<body bgcolor='#EFCEAD' background='back.gif'>\n";
 | |
| 
 | |
| 	WriteTable(strDsn, strUser, strPass, strOriginalQuery, out);
 | |
| 
 | |
| 	out << "</body>\n";
 | |
| 	out << "</html>\n";
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::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 == "Query")
 | |
| 		ProcessFormQuery(strFileName, hashArgs);
 | |
| 
 | |
| 	SendFile(strFileName, outs);
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::SoapProcessQuery(const TXmlItem &xmlMethod, wxOutputStream& out)
 | |
| {
 | |
| 	const wxString dsn = GetSoapParam(xmlMethod, "DSN");
 | |
| 	const wxString usr = GetSoapParam(xmlMethod, "User");
 | |
| 	const wxString pwd = GetSoapParam(xmlMethod, "Password");
 | |
| 	const wxString sql = GetSoapParam(xmlMethod, "SQL");
 | |
| 	WriteTable(dsn, usr, pwd, sql, out);
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::SoapProcessTableRows(const TXmlItem &xmlMethod, wxOutputStream& out)
 | |
| {
 | |
|   TTable* tab = m_caminetti.Table(xmlMethod);
 | |
|   if (tab != NULL)
 | |
|   {
 | |
|     const int index = atoi(GetSoapParam(xmlMethod, "Index"));
 | |
|     out << wxString::Format("%ld", tab->Rows(index));
 | |
|   }
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::SoapProcessGetRecord(const TXmlItem &xmlMethod, wxOutputStream& out)
 | |
| {
 | |
|   TTable* tab = m_caminetti.Table(xmlMethod);
 | |
|   if (tab != NULL)
 | |
|   {
 | |
|     const long recno = atol(GetSoapParam(xmlMethod, "RecNo"));
 | |
|     tab->GetRecord(recno, out);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::SoapProcessSkipRecord(const TXmlItem &xmlMethod, wxOutputStream& out)
 | |
| {
 | |
|   TTable* tab = m_caminetti.Table(xmlMethod);
 | |
|   if (tab != NULL)
 | |
|   {
 | |
|     const int index = atoi(GetSoapParam(xmlMethod, "Index"));
 | |
|     const long recno = atol(GetSoapParam(xmlMethod, "RecNo"));
 | |
|     const long offset = atol(GetSoapParam(xmlMethod, "Offset"));
 | |
|     const long newrecno = tab->Index(index).SkipTo(recno, offset);
 | |
|     tab->GetRecord(newrecno, out);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| void TDataBaseServer::SoapProcessGetRecordLength(const TXmlItem &xmlMethod, wxOutputStream& out)
 | |
| {
 | |
|   TTable* tab = m_caminetti.Table(xmlMethod);
 | |
|   if (tab != NULL)
 | |
|     tab->GetRecordLength(out);
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::SoapProcessCreateIndex(const TXmlItem &xmlMethod, wxOutputStream& out)
 | |
| {
 | |
|   TTable* tab = m_caminetti.Table(xmlMethod);
 | |
|   if (tab != NULL)
 | |
|   {
 | |
|     const int index = atoi(GetSoapParam(xmlMethod, "Index"));
 | |
|     const bool ok = index > 0 && tab->CreateIndex(index, xmlMethod);
 | |
|     out << (ok ? "1" : "0");
 | |
|   }
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::SoapProcessMethod(const TXmlItem &xmlMethod, wxOutputStream& out)
 | |
| {
 | |
|   const wxString strTag = xmlMethod.GetTag();
 | |
| 	wxString str = strTag;
 | |
| 	str << "Result";
 | |
| 	out << "<" << str << ">\n";
 | |
| 	
 | |
| 	if (strTag == "m:GetRecord")
 | |
| 		SoapProcessGetRecord(xmlMethod, out); else
 | |
| 	if (strTag == "m:SkipRecord")
 | |
| 		SoapProcessSkipRecord(xmlMethod, out); else
 | |
| 	if (strTag == "m:GetRecordLength")
 | |
| 		SoapProcessGetRecordLength(xmlMethod, out); else
 | |
| 	if (strTag == "m:TableRows")
 | |
| 		SoapProcessTableRows(xmlMethod, out); else
 | |
| 	if (strTag == "m:CreateIndex")
 | |
| 		SoapProcessCreateIndex(xmlMethod, out); else
 | |
| 	if (strTag == "m:Query")
 | |
| 		SoapProcessQuery(xmlMethod, out);
 | |
| 	
 | |
| 	out << "</" << str << ">\n";
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::ProcessSoapCommand(wxString cmd, wxSocketBase& sock)
 | |
| {
 | |
| 	wxMemoryOutputStream outf;
 | |
| 	outf << "<SOAP-ENV:Envelope>\n<SOAP-ENV:Body>\n";
 | |
| 	
 | |
| 	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:"))
 | |
| 				{
 | |
| 					SoapProcessMethod(*pxmlMethod, outf);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	outf << "</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\n";
 | |
| 
 | |
|   const size_t nSize = outf.GetSize();
 | |
|   char* mem = new char[nSize];
 | |
|   outf.CopyTo(mem, nSize);
 | |
| 
 | |
|   sock << "HTTP/1.1 200 OK\n";
 | |
| 	sock << "Server: " << GetAppName() << "\n";
 | |
| 	sock << "Host: " << wxGetFullHostName() << "\n";
 | |
|   sock << "Connection: keep-alive\n";
 | |
| 	sock << "Content-Type: text/xml; charset=utf-8\n";
 | |
|  	sock << "Content-Length: " << nSize << "\n";
 | |
| 	sock << "Date: " << wxDateTime::Now().Format("%#c") << "\n";
 | |
|   sock << "\n" << mem;
 | |
| 
 | |
| 	delete mem;
 | |
| }
 | |
| 
 | |
| void TDataBaseServer::ProcessCommand(wxString cmd, wxSocketBase& outs)
 | |
| {
 | |
| 	if (cmd.StartsWith("GET "))
 | |
| 	{
 | |
| 		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
 | |
| 		{
 | |
| 			const int ims = cmd.Find("If-Modified-Since: ");
 | |
| 			if (ims > 0)
 | |
| 			{
 | |
| 				const wxString strDate = cmd.Mid(ims+19, 24);
 | |
| 				wxDateTime tIms; 
 | |
| 				if (tIms.ParseDateTime(strDate))
 | |
| 				{
 | |
| 					const wxDateTime tFile = ::wxFileModificationTime(strFilename);
 | |
| 					if (tFile <= tIms)
 | |
|           {
 | |
| 						SendNotModifiedFile(outs);
 | |
| 						return;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	  SendFile(strFilename, outs);
 | |
| 	} else
 | |
|   if (cmd.StartsWith("POST "))
 | |
| 	{
 | |
|     if (cmd.Find("SOAPAction") > 0)
 | |
| 			ProcessSoapCommand(cmd, outs);
 | |
| 		else
 | |
|       ProcessFormCommand(cmd, outs);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| bool TDataBaseServer::Initialization()
 | |
| {
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool TDataBaseServer::Deinitialization()
 | |
| {
 | |
| 	wxDbCloseConnections();
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| // Istanziare l'applicazione principale
 | |
| 
 | |
| IMPLEMENT_APP(TDataBaseServer)
 |