Files correlati : tutti Ricompilazione Demo : [ ] Commento : Cambiata gestione chiavi alternative di ordinamento nelle maschere di ricerca Corretta gestione bottoni di filtro sulle ricerche stesse git-svn-id: svn://10.65.10.50/trunk@16788 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			602 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			602 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <applicat.h>
 | |
| #include <expr.h>
 | |
| #include <golem.h>
 | |
| #include <netsock.h>
 | |
| #include <recarray.h>
 | |
| #include <relation.h>
 | |
| #include <scanner.h>
 | |
| #include <utility.h>
 | |
| #include <xml.h>
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TRecipient
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TRecipient : public TObject
 | |
| {
 | |
|   TString _address;
 | |
|   TString _group;
 | |
|   TString _expr;
 | |
| 
 | |
| public:
 | |
|   const TString& address() const { return _address; }
 | |
|   const TString& group() const { return _group; }
 | |
|   void  add_expr(char op, const TString& expr);
 | |
|   bool can_receive(const TRectype& rec) const;
 | |
|   
 | |
|   virtual bool ok() const 
 | |
|   { return _address.not_empty() && _expr.not_empty(); }
 | |
| 
 | |
|   TRecipient(const TToken_string& str);
 | |
|   virtual ~TRecipient() { }
 | |
| };
 | |
| 
 | |
| TRecipient::TRecipient(const TToken_string& str)
 | |
| {
 | |
|   str.get(0, _address);
 | |
|   str.get(1, _group);
 | |
| }
 | |
| 
 | |
| void TRecipient::add_expr(char op, const TString& expr)
 | |
| {
 | |
|   if (_expr.not_empty())
 | |
|     _expr << (op == 'A' ? "&&" : "||");
 | |
| 
 | |
|   if (expr.blank())
 | |
|     _expr << 1;
 | |
|   else
 | |
|     _expr << '(' << expr << ')';
 | |
| }
 | |
| 
 | |
| bool TRecipient::can_receive(const TRectype& rec) const
 | |
| {
 | |
|   TExpression e(_expr, _strexpr, TRUE);
 | |
| 	TString val;
 | |
| 
 | |
|   for (int v = 0; v < e.numvar(); v++)
 | |
|   {
 | |
| 		const TFixed_string name(e.varname(v));
 | |
| 
 | |
| 		val.cut(0);
 | |
|     if (rec.exist(name))
 | |
|       val = rec.get(name);
 | |
|     else
 | |
| 		{
 | |
| 	
 | |
| 			const TFieldref f(name, 0);
 | |
| 			const int logicnum = table2logic(f.id());
 | |
| 
 | |
| 			if (logicnum > 0 && logicnum != rec.num())
 | |
| 			{
 | |
| 				TToken_string & rel = prefix().get_relation(rec.num(), logicnum);
 | |
| 				if (rel.full())
 | |
| 				{
 | |
| 					TToken_string key;
 | |
| 					FOR_EACH_TOKEN(rel, tok)
 | |
| 						key.add(rec.get(tok));
 | |
| 					const TRectype & joined_rec = cache().get(logicnum, key);
 | |
| 					val = f.read(joined_rec);
 | |
| 				}
 | |
| 			}
 | |
| 			else
 | |
| 				val = f.read(rec);
 | |
| 		}
 | |
| 		e.setvar(name, val);
 | |
|   }
 | |
|   bool yes = e.as_bool();
 | |
|   return yes;
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // TPostman
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| class TPostman : public TObject
 | |
| {
 | |
|   long _firm;
 | |
|   bool _recipients_ok;
 | |
|   TArray _recipient;
 | |
|   TAssoc_array _expr;
 | |
| 
 | |
| protected:
 | |
|   void test_firm();
 | |
|   
 | |
|   TRecipient& recipient(int r) const 
 | |
|   { return (TRecipient&)_recipient[r]; }
 | |
| 
 | |
|   void add_expr(const TString& addr,
 | |
|                 char op, const TString& expr);
 | |
| 
 | |
|   void load_filters();
 | |
| 
 | |
| public:
 | |
|   bool can_dispatch_transaction(const TRectype& rec);
 | |
|   bool dispatch_transaction(const TRectype& rec, 
 | |
|                             const TFilename& name);
 | |
| 
 | |
|   TExpression* get_filter_expr(const char* flt);
 | |
|   const char* get_filter(const char* flt);
 | |
|   bool user_can(const char* flt, const TRelation* rel);
 | |
| 
 | |
|   TPostman();
 | |
|   virtual ~TPostman() { }
 | |
| };
 | |
| 
 | |
| void TPostman::test_firm()
 | |
| {
 | |
|   const long firm = prefix().get_codditta();
 | |
|   if (firm != _firm)
 | |
|   {
 | |
|     _firm = firm;
 | |
|     _recipients_ok = FALSE;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void TPostman::add_expr(const TString& addr,
 | |
|                         char op, const TString& expr)
 | |
| {
 | |
|   for (int r = _recipient.last(); r >= 0; r--)
 | |
|   {
 | |
|     TRecipient& rec = recipient(r);
 | |
|     if (rec.address() == addr)
 | |
|     {
 | |
|       rec.add_expr(op, expr);
 | |
|       break;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if (rec.group() == addr)
 | |
|         rec.add_expr(op, expr);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool TPostman::can_dispatch_transaction(const TRectype& rec)
 | |
| {
 | |
|   test_firm();
 | |
|   if (!_recipients_ok)
 | |
|   {
 | |
|     _recipients_ok = TRUE;
 | |
|     _recipient.destroy();
 | |
|     
 | |
|     TConfig cfg(CONFIG_DITTA, "MailTransactions");
 | |
|     TAuto_token_string str; 
 | |
|     TString addr, opr, expr;
 | |
| 
 | |
|     // Costruisce la lista dei destinatari
 | |
|     for (int r = 0; cfg.exist("Recipient", r); r++)
 | |
|     {
 | |
|       str = cfg.get("Recipient", NULL, r);
 | |
|       expand_sys_vars(str);
 | |
|       TRecipient* rcp = new TRecipient(str);
 | |
|       _recipient.add(rcp);
 | |
|     }
 | |
| 
 | |
|     // Costruisce i filtri per i destinatari
 | |
|     for (int f = 0; cfg.exist("Filter", f); f++)
 | |
|     {
 | |
|       str = cfg.get("Filter", NULL, f);
 | |
|       expand_sys_vars(str);
 | |
| 
 | |
|       const int num = str.get_int(1);
 | |
|       if (num != rec.num()) continue;
 | |
| 
 | |
|       str.get(0, addr);
 | |
|       str.get(2, opr);
 | |
|       str.get(3, expr);
 | |
|       add_expr(addr, opr[0], expr);
 | |
|     }
 | |
| 
 | |
|     // Elimina destinatari inutili
 | |
|     for (int d = _recipient.last(); d >= 0; d--)
 | |
|     {
 | |
|       if (!recipient(d).ok())
 | |
|         _recipient.destroy(d, TRUE);
 | |
|     }
 | |
|   }
 | |
|   return _recipient.items() > 0;
 | |
| }
 | |
| 
 | |
| static int write_xml(TConfig& cfg, void* jolly)
 | |
| {
 | |
| 	TAssoc_array &vars = cfg.list_variables();
 | |
| 	TXmlItem &item = *(TXmlItem *) jolly;
 | |
| 	TToken_string tag(cfg.get_paragraph(), ',');
 | |
| 	const int logicnum = tag.get_int();
 | |
| 	const char * attr = logicnum > 0 ? "Field" : "Attr";
 | |
| 	int rownum = tag.get_int(); 
 | |
| 	
 | |
| 	if (logicnum > 0)
 | |
| 		tag = "Record";
 | |
| 	TXmlItem & child =item.AddChild(tag);
 | |
| 	if (logicnum > 0)
 | |
| 	{
 | |
| 		child.SetAttr("LogicNumber", logicnum);
 | |
| 		if (logicnum > LF_TAB)
 | |
| 			child.SetAttr("TableName", logic2table(logicnum));
 | |
| 		else
 | |
| 		{
 | |
| 			TString table;
 | |
| 
 | |
| 			FOR_EACH_ASSOC_STRING(vars, hobj, key, val)
 | |
| 				if (logicnum <= LF_TAB && strcmp(key, "COD") == 0)
 | |
| 				{
 | |
| 					table = val;
 | |
| 					break;
 | |
| 				}
 | |
| 			child.SetAttr("TableName", table);
 | |
| 		}
 | |
| 		
 | |
| 		if (rownum > 0)
 | |
| 			child.SetAttr("RowNumber", rownum);
 | |
| 	}
 | |
| 
 | |
| 	TString s;
 | |
| 
 | |
| 	FOR_EACH_ASSOC_STRING(vars, hobj, key, val)
 | |
| 		if (val && *val)
 | |
| 		{
 | |
| 			s = val;
 | |
| 			if (s[0] == '"' && s.ends_with("\""))
 | |
| 			{
 | |
| 				s.rtrim(1);
 | |
| 				s.ltrim(1);
 | |
| 			}
 | |
| 			s.trim();
 | |
| 			if (TDate::isdate(s))
 | |
| 			{
 | |
| 				TDate date(s);
 | |
| 
 | |
| 				child.AddSoapInt(attr, date.date2ansi()).SetAttr("Name", key);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				if (real::is_natural(s))
 | |
| 					child.AddSoapInt(attr, atoi(s)).SetAttr("Name", key);
 | |
| 				else
 | |
| 					child.AddSoapString(attr, s).SetAttr("Name", key);
 | |
| 			}
 | |
| 		}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| bool TPostman::dispatch_transaction(const TRectype& rec,
 | |
|                                     const TFilename& name)
 | |
| {
 | |
|   bool ok = can_dispatch_transaction(rec);
 | |
|   if (ok)
 | |
|   {
 | |
| 		TToken_string dest;
 | |
| 		TToken_string file_dest;
 | |
| 		TToken_string soap_dest;
 | |
|     TString last_error;
 | |
| 
 | |
| 		for (int r = 0; r < _recipient.items(); r++)
 | |
| 		{
 | |
| 			const TRecipient& a = recipient(r);
 | |
| 			if (a.can_receive(rec))
 | |
| 			{
 | |
| 				const TString& addr = a.address();
 | |
| 				if (addr.starts_with("http"))  // Indirizzo http
 | |
| 					soap_dest.add(addr); else
 | |
| 			  if (addr.find('@') > 0)  // Indirizzo posta
 | |
| 					dest.add(addr);
 | |
| 				else
 | |
|         {
 | |
|           if (fexist(addr))
 | |
| 					  file_dest.add(addr);
 | |
|           else
 | |
|           {
 | |
|             if (addr != last_error)
 | |
|             {
 | |
|               ok = error_box(FR("Non esiste la cartella di destinazione %s"), (const char*)addr);
 | |
|               last_error = addr;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (dest.items() > 0)
 | |
| 		{
 | |
| 			TMail_message msg(dest.get(0));
 | |
| 			for (const char* r = dest.get(1); r; r = dest.get())
 | |
| 				msg.add_copy_recipient(r);
 | |
| 
 | |
| 			TString16 subject;
 | |
| 			switch (rec.num())
 | |
| 			{
 | |
| 			case LF_TAB:
 | |
| 			case LF_TABCOM:
 | |
| 			case LF_TABGEN:
 | |
| 				subject << rec.get("COD"); 
 | |
|         break;
 | |
| 			default:
 | |
| 				subject << rec.num();
 | |
|         break;
 | |
| 			}
 | |
| 			msg.set_subject(subject);
 | |
| 
 | |
| 			TScanner trans(name);
 | |
| 			while (trans.good())
 | |
| 			{
 | |
| 				TString& line = trans.line();
 | |
| 				msg.add_line(line);
 | |
| 			}
 | |
| 			ok = msg.send(TRUE);
 | |
| 		}
 | |
| 
 | |
| 		if (file_dest.items() > 0)
 | |
| 		{
 | |
|       TString16 basename;
 | |
|       const struct tm* tl = xvt_time_now();
 | |
|       basename.format("%02d%02d%02d_%02d%02d%02d_0",
 | |
|                       tl->tm_year%100, tl->tm_mon+1, tl->tm_mday,
 | |
|                       tl->tm_hour, tl->tm_min, tl->tm_sec);
 | |
| 
 | |
| 			FOR_EACH_TOKEN(file_dest, r)
 | |
|       {
 | |
| 				TFilename output;
 | |
|         int retry = 0;
 | |
|         for (retry = 0; retry < 10; retry++) // Per ora tento solo 10 volte
 | |
|         {
 | |
|           output = r;
 | |
|           output.add(basename);
 | |
|           output << retry << ".ini";
 | |
|           if (!output.exist())  // Ho generato un nome buono
 | |
|             break;  
 | |
|         }
 | |
|         if (retry >= 10)
 | |
|           ok = false;
 | |
|         else
 | |
| 				  ok = fcopy(name, output);
 | |
|       }
 | |
| 		}
 | |
| 		
 | |
| 		if (soap_dest.items() > 0)
 | |
| 		{
 | |
| 			TConfig trans(name);
 | |
| 			TXmlItem item;
 | |
| 			TSocketClient socket;
 | |
| 			char * buf = new char[1024 * 256];
 | |
| 
 | |
| #ifdef WIN32  
 | |
|       ostrstream stream(buf, 1024 * 256);
 | |
| #else
 | |
|       ostringstream stream(buf);
 | |
| #endif
 | |
| 
 | |
| 			bool ok = true;
 | |
| 			
 | |
| 			item.SetTag("m:CampoTransaction");
 | |
| 			trans.for_each_paragraph(write_xml, &item);
 | |
| 			
 | |
| 			item.Write(stream, 2);
 | |
| 			stream << '\0';
 | |
| 
 | |
| #ifdef DBG
 | |
| 			TFilename name;
 | |
| 			char hostname[256];
 | |
| 			int len = strlen(buf);
 | |
| 			
 | |
| 			len += 79;
 | |
| 			xvt_sys_get_host_name(hostname, sizeof(hostname));
 | |
| 
 | |
| 			name.temp();
 | |
| 
 | |
| 			ofstream f(name);
 | |
| 			
 | |
| 			f << "POST / HTTP/1.1\n"
 | |
| 				<< "User-Agent: Campo\n"
 | |
| 				<< "Host: " << hostname << "\n"
 | |
| 				<< "Content-Type: text/xml; charset=utf-8\n"
 | |
| 				<< "Content-length: " << len << "\n"
 | |
| 				<< "SOAPAction: \"/\"\r\n\r\n"
 | |
| 				<< "<SOAP-ENV:Envelope>\n<SOAP-ENV:Body>\r\n";
 | |
| 
 | |
| 			item.Write(f, 2);
 | |
| 
 | |
| 			f << "\n</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\r\n\r\n";
 | |
| #endif
 | |
| 
 | |
| 			FOR_EACH_TOKEN(soap_dest, r)
 | |
| 			{
 | |
| 				CONNID id = socket.QueryConnection("", r);
 | |
| 				socket.HttpSoap(id, buf);
 | |
| 			}
 | |
| 		}
 | |
|   }  
 | |
|   return ok;
 | |
| }
 | |
| 
 | |
| void TPostman::load_filters()
 | |
| {
 | |
|   TRecord_cache users(LF_USER);
 | |
|   
 | |
|   TToken_string perm(4096, '\n');
 | |
|   TAuto_token_string row(80);
 | |
| 
 | |
|   // Costruisce il nome dell'applicazione principale
 | |
|   TFilename app(main_app().argv(0));
 | |
|   app.ext("");
 | |
|   app = app.name();
 | |
| 
 | |
|   for (int a = 1; a < main_app().argc(); a++)
 | |
|   {
 | |
|     row = main_app().argv(a);
 | |
|     if (row[0] != '/') 
 | |
|       app << ' ' << row;
 | |
|     else
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   // Stringhe delle espressioni i filtro
 | |
|   TAssoc_array expr;
 | |
|   
 | |
|   // Scandisce l'albero degli utenti/gruppi
 | |
|   for (TString16 u = user(); u.not_empty() && !users.already_loaded(u); )
 | |
|   {                    
 | |
|     const TRectype& urec = users.get(u);       
 | |
|     
 | |
|     // Test di validita'del record da eseguire solo la prima volta
 | |
|     if (u == user() && !urec.exist("PERMISSION")) 
 | |
|       break;
 | |
|     perm = urec.get("PERMISSION");  // Permessi del nodo corrente
 | |
|     if (!perm.blank())
 | |
|     {
 | |
|       FOR_EACH_TOKEN(perm, tok)
 | |
|       {
 | |
|         row = tok;
 | |
|         const TString80 appmod = row.get(0);
 | |
|         const bool is_mod = appmod.len() == 2;
 | |
|         // Il programma oppure il modulo corrispondono
 | |
|         if ((is_mod && app.compare(appmod, 2, TRUE) == 0) ||
 | |
|              app.compare(appmod, -1, TRUE) == 0) 
 | |
|         { 
 | |
|           TString80 key = row.get(2); key.trim(); // Tipo di filtro 
 | |
|           row = row.get(); row.trim();  // Espressione di filtro 
 | |
|           if (key.not_empty() && row.not_empty() && row != "1")
 | |
|           {
 | |
|             key.upper();
 | |
|             TString* str = (TString*)expr.objptr(key);
 | |
|             if (str == NULL)            
 | |
|             {
 | |
|               str = new TString(row);   // Crea una nuova stringa
 | |
|               expr.add(key, str);
 | |
|             }
 | |
|             else
 | |
|             {                           // Somma alla stringa precendente 
 | |
|               if (*str != "0")          // Se sono FALSE lasciami stare
 | |
|               {
 | |
|                 if (row != "0")         // Se aggiungo qualcosa di non ovvio
 | |
|                 {
 | |
|                   str->insert("(", 0);
 | |
|                   *str << ")AND(";           
 | |
|                   *str << row << ')';
 | |
|                 }
 | |
|                 else
 | |
|                   *str = "0";              
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     u = urec.get("GROUPNAME");
 | |
|   } 
 | |
| 
 | |
|   // Trasforma le stringhe in espressioni     
 | |
|   FOR_EACH_ASSOC_STRING(expr, hash, key, str)
 | |
|   {
 | |
|     TExpression* e = new TExpression(str, _strexpr, TRUE);
 | |
|     _expr.add(key, e);
 | |
|   }
 | |
| 
 | |
|   // Inserisce un elemento fasullo per segnalare l'avvenuta lettura
 | |
|   if (_expr.items() == 0)  
 | |
|     _expr.add("", NULL);  
 | |
| }
 | |
| 
 | |
| TExpression* TPostman::get_filter_expr(const char* flt)
 | |
| {
 | |
|   if (_expr.items() == 0)
 | |
|     load_filters();
 | |
|   TString80 f(flt); f.upper();
 | |
|   TExpression* e = (TExpression*)_expr.objptr(f);
 | |
|   return e;
 | |
| }
 | |
| 
 | |
| const char* TPostman::get_filter(const char* flt)
 | |
| {
 | |
|   TExpression* e = get_filter_expr(flt);
 | |
|   return e ? e->string() : NULL;
 | |
| }
 | |
| 
 | |
| bool TPostman::user_can(const char* flt, const TRelation* rel)
 | |
| {
 | |
|   bool yes_he_can = TRUE;
 | |
|   TExpression* e = get_filter_expr(flt);
 | |
|   if (e != NULL)
 | |
|   {
 | |
|     if (rel != NULL)
 | |
|     {
 | |
|       for (int i = e->numvar()-1; i >= 0; i--)
 | |
|       {
 | |
|         const TString& name = e->varname(i);
 | |
|         const TFieldref ref(name, 0);
 | |
|         const TString& val = ref.read(*rel);
 | |
|         e->setvar(name, val);
 | |
|       }
 | |
|       yes_he_can = e->as_bool();
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if (e->numvar() == 0)
 | |
|         yes_he_can = e->as_bool();
 | |
|     }
 | |
|   }
 | |
|   return yes_he_can;
 | |
| }
 | |
| 
 | |
| TPostman::TPostman() : _firm(-1), _recipients_ok(FALSE)
 | |
| {
 | |
| }
 | |
| 
 | |
| TPostman& postman()
 | |
| {
 | |
|   static TPostman* _postman = NULL;
 | |
|   if (_postman == NULL) 
 | |
|     _postman = new TPostman;
 | |
|   return *_postman;
 | |
| }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////
 | |
| // Public interface
 | |
| ///////////////////////////////////////////////////////////
 | |
| 
 | |
| bool can_dispatch_transaction(const TRectype& rec)
 | |
| {
 | |
|   return postman().can_dispatch_transaction(rec);
 | |
| }
 | |
| 
 | |
| bool dispatch_transaction(const TRectype& rec, const TFilename& name)
 | |
| {
 | |
|   return postman().dispatch_transaction(rec, name);
 | |
| }
 | |
| 
 | |
| const char* get_user_filter(const char* flt)
 | |
| {
 | |
|   return postman().get_filter(flt);
 | |
| }
 | |
| 
 | |
| const char* get_user_read_filter()
 | |
| {
 | |
|   return get_user_filter("Lettura");
 | |
| }
 | |
| 
 | |
| const char* get_user_write_filter()
 | |
| {
 | |
|   return get_user_filter("Scrittura");
 | |
| }
 | |
| 
 | |
| bool user_can_read(const TRelation* rel)
 | |
| {
 | |
|   return postman().user_can("Lettura", rel);
 | |
| }
 | |
| 
 | |
| bool user_can_write(const TRelation* rel)
 | |
| {
 | |
|   return user_can_read(rel) && postman().user_can("Scrittura", rel);
 | |
| }
 | |
| 
 | |
| bool user_can_delete(const TRelation* rel)
 | |
| {
 | |
|   return user_can_write(rel) && postman().user_can("Eliminazione", rel);
 | |
| }
 | |
| 
 | |
| bool user_can_do(const char* azione, const TRelation* rel)
 | |
| {
 | |
|   return postman().user_can(azione, rel);
 | |
| }
 | |
| 
 |