Costruire una Plug-in
Questo è un piccolo tutorial per indicare le linee guida nella realizzazione di una plug-in in Caronte Antispam.
La prima cosa da prendere in considerazione è il tipo di plug-in che si vuole realizzare facendo chiaramente una piccola analisi, sul suo funzionamento e quale livello di integrazione avrà con caronte Antispam.
In questo particolare caso andremo a realizzare una plug-in per il Sistema di analisi virus di Caronte scegliento CLAMAV come antivirus di cooperazione.
Ma entriamo nel vivo di questo tutorial.
Lo script da affiancare al cuore di Caronte Antispam (/scritp/antispam/clamav.cs)
/// con la macro "#import" il precompilatore di Caronte include il supporto e alloca // memoria per i metodi della classe. // ci servono CS_Socket per comunicare con clamav e CS_Buffer per immagazzinare le informazioni da inviare e ricevere.Analizziamo il meccanismo.
#import( class , CS_Socket ) #import( class , CS_Buffer )
/// si definiscano in ansi C alcuni costanti primitive.
#define NULL 0 #define true 1 #define false 0 //LOG #define LOGL0 0 // no log #define LOGL1 1 #define LOGL2 2 #define LOGL3 3 #define LOGALL 4 // 1+2+3 + DEBUG //STATISTIC #define MOREMORE 1 #define LESSLESS 2 #define EQUAL_VALUE 3 #define MORE_VALUE 4 #define LESS_VALUE 5 #define MAX_VALUE 6 #define MIN_VALUE 7 //RE #define RE_CASELESS 1 #define RE_MULTILINE 2 #define RE_DOTALL 4 #define RE_EXTENDED 8 /// l'istanza di ambiente per ANTISPAM !!! // si eredita tutte le funzioni base e si inizializza l'ambiente CS_ANTISPAM_SCRIPT this = new CS_ANTISPAM_SCRIPT($_this);
CS_Socket m_conn; CS_Socket m_conn_stream; int m_state = 0; int m_size = 0; string m_virus_name = ""; // funzione che registra il fatto che si può notificare un valore con il nome "notify_virus_name" // a tutti gli altri script presenti in ambiente. // il nome "notify_virus_name" può variare ad esempio si potrebbe chiamare anche "notify_virus_name_clamav" // la notifica è per cortesia verso gli altri script che potrebbero usufruire del nostro lavoro.
this->RegisterGlobalVariable("notify_virus_name"); // funzione che ottiene le ACK o gli Errori da CLAMAV sulla relativa porta // ricordiamoci che tutte le funzioni in Carontese per essere viste devo essere dichiarate e strutturate // una dopo l'altra, altrimenti non riescono a vedersi. // la classe CS_Buffer è l'unica in Caronte scripting che può ricevere dati su un socket buffer. string GetLine(CS_Socket conn) { if (conn == NULL || !conn->IsOpen()) return ""; string res; CS_Buffer buffer = new CS_Buffer(); buffer->Allocate(50); int len = conn->Riceve(buffer->GetBuffer(),5000); if (len > 0) res = this->Replace(this->Replace( buffer->ToString() ,"\r",""), "\n",""); delete buffer; buffer = NULL; return res; } int ConnectToClamav() { if (m_conn != NULL || m_state > 0) return true; if (this->GetConfig("address","CLAMAV") == "" || this->GetConfig("port","CLAMAV") == "") return false; m_conn = new CS_Socket(); if (!m_conn->ConnectTo( this->GetConfig("address","CLAMAV"), this->GetConfig("port","CLAMAV"), this->GetConfig("adapter","CONFIG"))) { delete m_conn; m_conn = NULL; return false; } if (m_conn->Send("STREAM\n",this->StrLen("STREAM\n"),1000) <= 0) { delete m_conn; m_conn = NULL; return false; } string tmp = GetLine(m_conn); if (this->REeq(tmp,"^PORT (\\d+)",RE_CASELESS)) { string streaming_port = this->$1(); m_conn_stream = new CS_Socket(); if (!m_conn_stream->ConnectTo(this->GetConfig("address","CLAMAV"),streaming_port,this->GetConfig("adapter","CONFIG"))) { m_conn->Close(); delete m_conn; delete m_conn_stream; m_conn = NULL; m_conn_stream = NULL; return false; } m_state = 1; return true; } m_conn->Close(); delete m_conn; m_conn = NULL; return false; } void streamscan(string dati) { if (m_conn == NULL || !m_conn->IsOpen()) return; if (m_conn_stream == NULL || !m_conn_stream->IsOpen()) return; int t1 = this->GetTickCount(); int deadline = t1 + 1000; int bsend = 0; int size_send = this->StrLen(dati); int send_tot = 0; int tosend = size_send; while(t1 < deadline) { t1 = this->GetTickCount(); bsend = m_conn_stream->Send(dati,tosend,50); if (bsend <= -1) break; send_tot += bsend; if (send_tot == size_send) break; else if(send_tot != size_send && bsend > 0) { tosend = size_send - bsend; dati = this->SubStr(dati,bsend,tosend); } } m_size += size_send; } string Result() { if (m_conn == NULL || !m_conn->IsOpen()) return ""; if (m_conn_stream == NULL || !m_conn_stream->IsOpen()) return ""; m_conn_stream->Close(); m_state = 2; string tmp = GetLine(m_conn); if(this->REeq(tmp, "stream: (.+) FOUND",RE_CASELESS) && this->$1() != "") return this->$1(); return ""; } void CloseAll() { if (m_conn_stream != NULL) { if (m_conn_stream->IsOpen()) { m_conn_stream->Send("QUIT\n",this->StrLen("QUIT\n"),100); m_conn_stream->Close(); } delete m_conn_stream; m_conn_stream = NULL; } if (m_conn != NULL) { if (m_conn->IsOpen()) m_conn->Close(); delete m_conn; m_conn = NULL; } } void OnAllDataMessage(string part_msg, int is_end_msg) { if (this->CharToInt(this->GetConfig("enable","CLAMAV")) == false || m_state == 2) return; if (m_state == 0) if (ConnectToClamav() == false) return; if (m_state == 1) streamscan(part_msg); if (is_end_msg == true || m_size >= this->CharToInt(this->GetConfig("size","CLAMAV"))) { m_virus_name = Result(); if (m_virus_name != "") { this->SendToClient( this->Format(this->GetConfig("rfc554"), this->Format("VIRUS FOUND %s\r\n",m_virus_name)) ); this->WriteLog(LOGL1, this->Format("VIRUS FOUND %s",m_virus_name),"SYS"); this->StatisticValue(this->Format("f16_virus_[%s]",m_virus_name),18,0,1,MOREMORE); if (this->CharToInt(this->GetConfig("imbargo_enable","CLAMAV")) == true) { int time_embrago = this->Time() + (this->CharToInt(this->GetConfig("imbargo_type","CLAMAV")) * this->CharToInt(this->GetConfig("imbargo_time","CLAMAV"))); this->WriteLog(LOGL1, this->Format("ADD IP IMBARGO: %s\r\n",this->GetClientIP()),"SYS"); this->AddIpInferno(this->GetClientIP(),time_embrago); } this->CloseClientConnAfterSendingQueue(); this->DropBufferToMTA(); this->SetGlobalVariable("notify_email_is","REJECTED"); //registrate dal core.cs this->SetGlobalVariable("notify_email_cause_rejected","virus_found"); //registrate dal core.cs this->SetGlobalVariable("notify_virus_name",m_virus_name); } else { this->WriteLog(LOGL1, "CLAMAV: Clean","SYS"); } CloseAll(); } } // Importante: se lo script è stato caricato all'inizio è quindi "in cache"
// viene richiamato il metodo "OnDestroyThis" e questo premette di liberare memoria e azzerare le variabili globali. void OnDestroyThis() { if (this != NULL) delete this; this = NULL; CloseAll(); }
#include "conf.htmch"; #include "include/libhttp.htmch"; void html() { IsSecureSession(0); Init_language(CARONTE_LING); this->echo( IncludeHeader() ); CaronteServerConn client = new CaronteServerConn(CARONTE_SERVER_NAME,CARONTE_SERVER_PORT,CARONTE_SERVER_KEY); client->SetTimeOut(CARONTE_TIME_OUT); if (!client->Connect()) { delete client; MsgError(LANG->GetS("conn_error")); } CaronteRecordSet rs = new CaronteRecordSet(client); HashArray var_html = new HashArray(); ComputeConfig(client, rs, "CLAMAV" ,var_html); if (m_user_level != 1) { string tonf; string tonf2; if (var_html->GetI("CLAMAV-enable") == 1) { tonf = this->Replace(this->Replace(LANG->GetS("1008"),"<","<"),">",">"); tonf2 = "<div class=\"v\">ON</div>"; } else { tonf = this->Replace(this->Replace(LANG->GetS("1008d"),"<","<"),">",">"); tonf2 = "<div class=\"r\">OFF</div>"; } this->echo("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"adminlist\">"); this->echo(" <tr class=\"imgheader\">"); this->echo(" <td colspan=\"4\" align=\"center\">ClamAV Antivirus</td>"); this->echo(" </tr>"); this->echo(" <tr class=\"row1\">"); this->echo(" <td align=\"center\" class=\"rowtd1\">" + tonf2 + "</td>"); this->echo(" <td colspan=\"3\">" + tonf + "</td>"); this->echo(" </tr>"); this->echo(" </table><br>"); delete var_html; var_html = NULL; client->Disconnect(); delete rs; delete client; this->includeHTML("footer.html"); this->Exit(); } if (var_html->GetI("CLAMAV-enable") == 1) var_html->AddValueS("checked1","checked"); if (var_html->GetI("CLAMAV-imbargo_enable") == 1) var_html->AddValueS("checked2","checked"); if (var_html->GetI("CLAMAV-size") > 0) { var_html->AddValueS("CLAMAV-size", this->Format("%d",var_html->GetI("CLAMAV-size") / 1024)); } var_html->AddValueS("CLAMAV-imbargo_type_combo",ComboTime("60",2)); this->echo ( TemplateVarReplace(var_html, "js_clamav.htmch", 2) ); this->echo ( TemplateVarReplace(var_html, "clamav.htmch", 1) ); delete var_html; var_html = NULL; client->Disconnect(); delete rs; delete client; this->includeHTML("footer.html"); }
Da analizzare in questo script le fuzioni di libreria:
IsSecureSession(0);
Init_language(CARONTE_LING);
Aprendo i sorgenti della "\www\include\libhttp.htmch" la prima funzione "IsSecureSession(0);" verifica che la sessione sia sicura avendo effettuato il login e lo zero indica che la chiamata non proviene da un oggetto AJAX, quindi si può applicare un Header Redirect al web server se la sessione è insicura.
La seconda funzione "Init_language(CARONTE_LING);" inizializza la lingua e capiamo che alla nostra pagina di gestione manca il file contenente le traduzione, controllando sempre i sorgenti, ci accorgiamo che tale funzione legge completamente il contenuto di una direcotry "include/language/", prima chiedendo tutti i file in lingua "inglese" poi chiedendo quelli nella lingua indicata nella "conf" della web G.U.I. con la variabile "CARONTE_LING".
Quindi dobbiamo creare il nostro file lingua che installeremo in "/www/include/language/it/clamav.xml" e lo svlilupperemo in questo modo:
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<variable>
<name>MENU_CLAMAV</name>
<value>ClamAV</value>
<type>3</type>
</variable>
<variable>
<name>MENU_CLAMAV_STB</name>
<value>Configurazione Clamav Antivirus</value>
<type>3</type>
</variable>
<variable>
<name>CLAMAV1165</name>
<value>Abilita Controllo Antivirus</value>
<type>3</type>
</variable>
<variable>
<name>CLAMAV1166</name>
<value>Ip / Host:</value>
<type>3</type>
</variable>
<variable>
<name>CLAMAV1170</name>
<value>Peso Max Msg:</value>
<type>3</type>
</variable>
<variable>
<name>CLAMAV1168</name>
<value>Porta:</value>
<type>3</type>
</variable>
<variable>
<name>CLAMAV1174</name>
<value>Tempo di Embargo:</value>
<type>3</type>
</variable>
<variable>
<name>CLAMAV1177</name>
<value>IP all'inferno</value>
<type>3</type>
</variable>
<variable>
<name>CLAMAV1178</name>
<value>Se il messaggio contiene un Virus manda all'inferno l'IP</value>
<type>3</type>
</variable>
<variable>
<name>CLAMAV1179</name>
<value>TEST Configurazione ClamAV</value>
<type>3</type>
</variable>
<variable>
<name>1008</name>
<value><strong>Antivirus</strong><br> Filtro attivato dall'amministratore del sistema.<br> Tutte le tue Email sono protette da <a href='http://www.clamav.net/' target='_blank' class='ln1'>Clamav Antivirus</a></value>
<type>4</type>
</variable>
<variable>
<name>1008d</name>
<value><strong>Antivirus</strong><br> Il filtro attivo è a discrezione dell'amministratore di sistema. Caronte Antispam ha una particolare plug-in che sfrutta Clamav Antivirus per controllare la posta elettronica. Il tuo amministratore/provider puo' aver scelto altre soluzioni per controllare la presenza di virus nella tua posta elettronica.</value>
<type>4</type>
</variable>
</config>
proseguendo nell'analisi della nostra pagina GUI troviamo:
CaronteServerConn client = new CaronteServerConn(CARONTE_SERVER_NAME,CARONTE_SERVER_PORT,CARONTE_SERVER_KEY);
client->SetTimeOut(CARONTE_TIME_OUT);
Questa classe ci permette di connettersi al cuore di Caronte tramite il servizio Remote Admin e prelevare o inserire i dati nella configurazione.
Troviamo anche:
this->echo ( TemplateVarReplace(var_html, "js_clamav.htmch", 2) ); this->echo ( TemplateVarReplace(var_html, "clamav.htmch", 1) );
Queste funzioni interne della libreria "libhttp.htmch" ci permettano, passando una classe HashArray e il file template con estezione ".htmch", di creare un sorgente HTML
da poter restituire all'utente. Guardando sempre i sorgenti di libreria ci accorgiamo anche che la funzione
"TemplateVarReplace" non si limita semplicemente ad aprire il file indicato
,cercare all'interno dei commenti HTML ,cosi strutturati:
<!--@xxxxxx@--> e replicarli con il relativo dato (se trovati) del file xml di lingua, ma anche ad applicare dei comportamenti controllando il terzo parametro di funzione e il valore del child "type" dell'xml.
Ad esempio quel "2" indica alla funzione di inserire dei tag <script ...></script> e il replace indica poi un "type 4" <type>4</type> del child XML di lingua che è html da rendere attivo. Da questo riusciamo a capire anche il perchè della struttura XML. Le definizioni del type sono nella libreria nei relativi commenti.
Quindi dobbiamo creare questi file template in puro html inseririli in "/www/include/template/" e definire il nostro testo, come titoli e descrizioni, all'interno del file come dei commenti delimitati da "@xxxx@" che poi verranno replicati da queste funzioni.
Ma il nostro script "clamav.cs" aveva anche delle fuzioni che inserivano nelle statistiche gererali di Caronte, quanti e quali virus venivano bloccati.
Dobbiamo interagire anche con l'engine della GUI che permette di visualizzare le statistiche.
Bene, guardando sempre i sorgenti della libreria "libhttp.htmch" vediamo che basta inserire un file XML di configurazione della directory "/www/include/stats/" e strutturarlo cosi:
<?xml version="1.0" encoding="UTF-8" ?>
<config>
<page>
<combolabel>STATSf1_7a</combolabel>
<url>ajax_stats_virus.htmcc</url>
</page>
</config>
Automaticamente la "combobox" della pagina statistiche riportera il link indicato.
Dove "ajax_stats_virus.htmcc " sarà una pagina che permetterà di visualizzare le statitstiche di questa plug-in.
Per realizzarla, basta vedere un attimo le altre pagine statistiche in Caronte per capirne la logica.
Andiamo avanti...
Nel caso di questa plug-in useremo le procedure già esistenti in ambiente per leggere ed inserire la nostra configurazione una volta fatto "salva".
Andremo a realizzare anche
una nostra procedura per creare un TOOLS e testare CLAMAV quando la plug-in sarà installata, quindi manipoleremo anche l'ambiente di ADMIN.
Questa è la nostra procedura "/script/admin/8001.cs"
molto simile allo script di analisi in quanto usa la stessa logica per testare CLAMAV.
8001.cs è il numero che andremo ad impegnare con la nostra procedura dentro la tabella delle procedure strutturate in admin.
Dalla 2000 alla 8000 sono libere a nostro uso e consumo, come riportato nella documentazione.
#import( class , HashArray ) #import( class , CS_Socket ) #import( class , CS_Buffer ) #include "lib.cs" CS_ADMIN_SCRIPT this = new CS_ADMIN_SCRIPT($_this); string GetLine(CS_Socket conn) { if (conn == NULL || !conn->IsOpen()) return ""; string res; CS_Buffer buffer = new CS_Buffer(); buffer->Allocate(256); int len = conn->Riceve(buffer->GetBuffer(),10000); if (len > 0) res = this->Replace(this->Replace( buffer->ToString() ,"\r",""), "\n",""); delete buffer; buffer = NULL; return res; } int SendMsg(CS_Socket conn, string msg) { if (conn == NULL || !conn->IsOpen()) return 0; int t1 = this->GetTickCount(); int deadline = t1 + 10000; int bsend = 0; int size_send = this->StrLen(msg); int send_tot = 0; int tosend = size_send; while(t1 < deadline) { t1 = this->GetTickCount(); bsend = conn->Send(msg,tosend,300); if (bsend <= -1) return 0; send_tot += bsend; if (send_tot == size_send) return 1; else if(send_tot != size_send && bsend > 0) { tosend = size_send - bsend; msg = this->SubStr(msg,bsend,tosend); } } return 0; } int Main(CAdminRequest pRequest, CAdminResponse pResponse) { //CR_TEST_clamav if (pRequest->GetColCount() == 2) { HashArray fields; fields = pRequest->GetRow(); if (fields->GetS("c1") != "" && fields->GetI("c2") > 0 && fields->GetI("c2") < 65536) { CS_Socket conn = new CS_Socket(); int start_time = this->GetTickCount(); string res; pResponse->Addnew(); pResponse->SetFieldAt(1,"Connect to: " + fields->GetS("c1") + " Port: " + fields->GetS("c2") + " ..."); pResponse->SetFieldAt(2,"0"); pResponse->SetFieldAt(3,"N"); if (!conn->ConnectTo( fields->GetS("c1"), fields->GetS("c2"), this->GetConfig("adapter_ip","CONFIG"))) { delete conn; conn = NULL; pResponse->Addnew(); pResponse->SetFieldAt(1,"Connection FAILED !!!"); pResponse->SetFieldAt(2,this->Format("%d",this->GetTickCount() - start_time)); pResponse->SetFieldAt(3,"E"); pResponse->Send(pRequest->GetCmd(),CR_ACK); return CONTINUE_SCRIPT; } pResponse->Addnew(); pResponse->SetFieldAt(1,"connected"); pResponse->SetFieldAt(2,this->Format("%d",this->GetTickCount() - start_time)); pResponse->SetFieldAt(3,"O"); ///////// start_time = this->GetTickCount(); if (!SendMsg(conn,"STREAM\r\n")) { pResponse->Addnew(); pResponse->SetFieldAt(1,"sending the command [STREAM] failed"); pResponse->SetFieldAt(2,this->Format("%d",this->GetTickCount() - start_time)); pResponse->SetFieldAt(3,"E"); conn->Close(); delete conn; conn = NULL; pResponse->Send(pRequest->GetCmd(),CR_ACK); return CONTINUE_SCRIPT; } pResponse->Addnew(); pResponse->SetFieldAt(1,"Send command [STREAM] o.k"); pResponse->SetFieldAt(2,this->Format("%d",this->GetTickCount() - start_time)); pResponse->SetFieldAt(3,"O"); start_time = this->GetTickCount(); res = GetLine(conn); if (res == "") { pResponse->Addnew(); pResponse->SetFieldAt(1,"the server did not respond !!!"); pResponse->SetFieldAt(2,this->Format("%d",this->GetTickCount() - start_time)); pResponse->SetFieldAt(3,"E"); conn->Close(); delete conn; conn = NULL; pResponse->Send(pRequest->GetCmd(),CR_ACK); return CONTINUE_SCRIPT; } pResponse->Addnew(); pResponse->SetFieldAt(1,res); pResponse->SetFieldAt(2,this->Format("%d",this->GetTickCount() - start_time)); pResponse->SetFieldAt(3,"N"); ///////// start_time = this->GetTickCount(); if (!SendMsg(conn,"QUIT\n")) { pResponse->Addnew(); pResponse->SetFieldAt(1,"sending the command [QUIT] failed"); pResponse->SetFieldAt(2,this->Format("%d",this->GetTickCount() - start_time)); pResponse->SetFieldAt(3,"E"); conn->Close(); delete conn; conn = NULL; pResponse->Send(pRequest->GetCmd(),CR_ACK); return CONTINUE_SCRIPT; } pResponse->Addnew(); pResponse->SetFieldAt(1,"Send command [QUIT] o.k"); pResponse->SetFieldAt(2,this->Format("%d",this->GetTickCount() - start_time)); pResponse->SetFieldAt(3,"O"); conn->Close(); delete conn; conn = NULL; } pResponse->Send(pRequest->GetCmd(),CR_ACK); } return CONTINUE_SCRIPT; }
Tutto questo per verificare se il nostro Clamav Antivirus sta correndo e se funziona correttamente con le funzioni interne di Caronte Antispam.
Da notare la funzione "main" di questa procedura:
int Main(CAdminRequest pRequest, CAdminResponse pResponse) { ...
Le classi CAdminRequest e
CAdminResponse sono intrinseche della procedura di ADMIN e Caronte le passa già come argomenti di funzione indicandoci che c'è sì una "richiesta" con i relativi dati ma occorre anche "rispondere" a tale richiesta.
Siamo arrivati alla fine ! Manca solamente l'installazione con il suo "setup".
Anche qui ci occorre un file XML e uno script.
Il file XML riporta le "informazioni" base che l'engine di installazione di Caronte Antispam usa per riconoscere la plug-in e si deve chiamare
OBBLIGATORIAMENTE "info.xml" con sempre l'obbligo di trovarsi all'interno della directory della plug-in (es /scritps/admin/plugin/clamav/info.xml )
:
<?xml version="1.0" encoding="UTF-8" ?>
<info>
<plugin>
<uniqueID>ClamAV_Antivirus_by_ceg</uniqueID>
<pluginname>ClamAV Antivirus</pluginname>
<authorname>Alessandro Cappellini</authorname>
<companyname>C&G Servizi web s.r.l.</companyname>
<description>ClamAV Antivirus plugin for Caronte Antispam</description>
<version>1.0.0</version>
<copyright>Copyright (C) 2008</copyright>
<comments>http://www.caronteantispam.it</comments>
<install_unistall_script>install.cs</install_unistall_script>
</plugin>
</info>
Il file contiene informazioni di titolo generale, ma anche tag come
"uniqueID" e "install_unistall_script"
questi due tag particolari servono per "identificare" la plug-in e sapere qual'e' lo script di installazione/disistallazione della plug.
Se l'utente decide di installare la plug-in, l'engine di Caronte farà correre il nostro script di installazione indicato in questi TAG e cosi strutturato per la nostra plugin:
#import( class , HashArray ) #import( class , CS_FileSystem )
CS_ADMIN_SCRIPT this = new CS_ADMIN_SCRIPT($_this); string filedes[14]; string filesrc[14]; filedes[0] = "{ROOT}/scripts/antispam/clamav.cs"; filedes[1] = "{ROOT}/scripts/admin/8001.cs"; filedes[2] = "{ROOT_WWW}/img/clamav_ico.gif"; filedes[3] = "{ROOT_WWW}/img/clamav-logo.png"; filedes[4] = "{ROOT_WWW}/ajax_stats_virus.htmcc"; filedes[5] = "{ROOT_WWW}/clamav_antivirus.htmcc"; filedes[6] = "{ROOT_WWW}/ajax_test_clamav.htmcc"; filedes[7] = "{ROOT_WWW}/include/stats/STATSf1_7a.xml"; filedes[8] = "{ROOT_WWW}/include/language/it/clamav.xml"; filedes[9] = "{ROOT_WWW}/include/language/en/clamav.xml"; filedes[10] = "{ROOT_WWW}/include/user_menu/clamav.xml"; filedes[11] = "{ROOT_WWW}/include/admin_menu/clamav.xml"; filedes[12] = "{ROOT_WWW}/include/template/clamav.htmch"; filedes[13] = "{ROOT_WWW}/include/template/js_clamav.htmch"; filesrc[0] = "{plugin_path}/clamav.cs"; filesrc[1] = "{plugin_path}/8001.cs"; filesrc[2] = "{plugin_path}/clamav_ico.gif"; filesrc[3] = "{plugin_path}/clamav-logo.png"; filesrc[4] = "{plugin_path}/ajax_stats_virus.htmcc"; filesrc[5] = "{plugin_path}/clamav_antivirus.htmcc"; filesrc[6] = "{plugin_path}/ajax_test_clamav.htmcc"; filesrc[7] = "{plugin_path}/include/stats/STATSf1_7a.xml"; filesrc[8] = "{plugin_path}/include/it/clamav.xml"; filesrc[9] = "{plugin_path}/include/en/clamav.xml"; filesrc[10] = "{plugin_path}/include/user_menu/clamav.xml"; filesrc[11] = "{plugin_path}/include/admin_menu/clamav.xml"; filesrc[12] = "{plugin_path}/include/template/clamav.htmch"; filesrc[13] = "{plugin_path}/include/template/js_clamav.htmch"; void install(string dir, string cid) { CS_FileSystem sys = new CS_FileSystem(); string ROOT_WWW = this->GetConfig("path","WEBGUI"); for (int i = 0; i < 14; i++) { filedes[i] = this->Replace(filedes[i],"{ROOT}",sys->AppPath()); filedes[i] = this->Replace(filedes[i],"{ROOT_WWW}",ROOT_WWW); filesrc[i] = this->Replace(filesrc[i],"{plugin_path}",dir); sys->CopyFile(filesrc[i],filedes[i],1); //overwrite } delete sys; HashArray myconfig = new HashArray(); if (this->GetConfigToArray(myconfig,"CS_SCRIPT") == 1) { for (int i = 0; i < myconfig->GetRecordCount(); i++) { if (this->REeq(myconfig->GetKeyByIndex(i),"cs_(\\d+?)",0) == 1) { if (this->Split(myconfig->GetS(myconfig->GetKeyByIndex(i)),'|',1) == "clamav.cs") { //reinstall !!!!!! delete myconfig; return; } } } this->SetConfig("CLAMAV","enable","0"); this->AddAntispamScript("clamav.cs",-1); this->WaitForReplaceConfig(); this->SaveConfig(); this->SetLevelReBootConfig(0); this->SetRebootConfig(1); } } void uninstall(string dir, string cid) { this->DeleteAntispamScript("clamav.cs"); this->WaitForReplaceConfig(); this->SaveConfig(); this->SetLevelReBootConfig(0); CS_FileSystem sys = new CS_FileSystem(); string ROOT_WWW = this->GetConfig("path","WEBGUI"); for (int i = 0; i < 14; i++) { filedes[i] = this->Replace(filedes[i],"{ROOT}",sys->AppPath()); filedes[i] = this->Replace(filedes[i],"{ROOT_WWW}",ROOT_WWW); sys->UnLink(filedes[i]); } delete sys; this->SetRebootConfig(1); }