diff -ru zarafa-7.1.4/provider/libserver/ZarafaCmd.cpp zarafa-7.1.4.spamhook/provider/libserver/ZarafaCmd.cpp --- zarafa-7.1.4/provider/libserver/ZarafaCmd.cpp 2013-02-28 17:13:17.000000000 +0100 +++ zarafa-7.1.4.spamhook/provider/libserver/ZarafaCmd.cpp 2013-04-15 11:34:45.018632455 +0200 @@ -84,6 +84,7 @@ #include "StreamUtil.h" #include "CommonUtil.h" #include "StorageUtil.h" +#include "UnixUtil.h" #include "ZarafaICS.h" @@ -7655,6 +7656,179 @@ bool bMoved; }COPYITEM; +//SPAM HOOK +//This function parses an e-mail to the /etc/zarafa/userscripts/junklearn script. With 2 arguments: +//ham or spam +//message id +//and pipes the mail header to the script. +//This script wil be inhaled by MoveObjects(); +///////////////////////////////////////////////////////////////////////////////////////////////// +int SpamHook(ECDatabase *lpDatabase,int ulId, unsigned int ulDestFolderId) +{ + + ALLOC_DBRESULT(); + ECRESULT er = erSuccess; + std::string shScriptPath = g_lpSessionManager->GetConfig()->GetSetting("junklearn_script"); + string shMailStatus; + entryId* junkFolderEntryId; + entryId* wasteBucketEntryId; + int shNumRows; + + //dont do anything if the junklearn script doesnt exist: + int fCheck=open(shScriptPath.c_str(), O_RDONLY); + if (fCheck==0) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_INFO,"SpamHook: skipping, script "+shScriptPath+" not found"); + er=erSuccess; + goto exit; + } + close(fCheck); + + //Get store object ID via message object id + unsigned int storeId; + er = g_lpSessionManager->GetCacheManager()->GetStore(ulId,&storeId,NULL); + if(er != erSuccess) + { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error while retrieve source folder."); + goto exit; + } + + //get deleted items folder entry id + strQuery="SELECT val_binary FROM properties WHERE hierarchyid="+stringify(storeId)+" AND tag="+stringify(PROP_ID(PR_IPM_WASTEBASKET_ENTRYID)); + er = lpDatabase->DoSelect(strQuery, &lpDBResult); + if(er != erSuccess) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error while retrieve wastebasket entryid from DB."); + goto exit; + } + lpDBRow = lpDatabase->FetchRow(lpDBResult); + lpDBLen = lpDatabase->FetchRowLengths(lpDBResult); + shNumRows=lpDatabase->GetNumRows(lpDBResult); + if(shNumRows<1) + { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error while retrieve wastebasket entryid, empty DB result."); + goto exit; + } + + //Convert 'deleted items' entryid to objectid. + wasteBucketEntryId = new entryId[0]; + wasteBucketEntryId->__ptr=(unsigned char*)lpDBRow[0]; + wasteBucketEntryId->__size=lpDBLen[0]; + unsigned int wasteBucketFolderId; + er=g_lpSessionManager->GetCacheManager()->GetObjectFromEntryId(wasteBucketEntryId,&wasteBucketFolderId); + delete wasteBucketEntryId; + if(er!=erSuccess) + { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error while retrieve wastebasket entryid, converting to objectID."); + goto exit; + } + + //Get 'junk folder' entryId. + FREE_DBRESULT(); + strQuery="SELECT val_binary FROM receivefolder LEFT JOIN mvproperties ON receivefolder.objid=mvproperties.hierarchyid WHERE receivefolder.storeid="+stringify(storeId)+" AND receivefolder.messageclass='IPC' AND mvproperties.tag="+stringify(PROP_ID(PR_ADDITIONAL_REN_ENTRYIDS))+" AND mvproperties.orderid=4"; + er = lpDatabase->DoSelect(strQuery, &lpDBResult); + if(er != erSuccess) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error while retrieve junkfolder entryids from DB."); + goto exit; + } + lpDBRow = lpDatabase->FetchRow(lpDBResult); + lpDBLen = lpDatabase->FetchRowLengths(lpDBResult); + shNumRows=lpDatabase->GetNumRows(lpDBResult); + if(shNumRows<1) + { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error while retrieve junkfolder entryid, empty DB result."); + goto exit; + } + + //Convert 'junk folder' entryid to objectid. + junkFolderEntryId = new entryId[0]; + junkFolderEntryId->__ptr=(unsigned char*)lpDBRow[0]; + junkFolderEntryId->__size=lpDBLen[0]; + unsigned int junkFolderId; + er=g_lpSessionManager->GetCacheManager()->GetObjectFromEntryId(junkFolderEntryId,&junkFolderId); + delete junkFolderEntryId; + if(er!=erSuccess) + { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error while retrieve junkfolder entryid, converting to objectID."); + goto exit; + } + + //Get source folder object ID. (Actually we should check if mail came from subfolders in the 'deleted items folder', which I think never happens.) + unsigned int srcFolderId; + er=g_lpSessionManager->GetCacheManager()->GetParent(ulId,&srcFolderId); + if(er!=erSuccess) + { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error while retrieve src folder id."); + goto exit; + } + + //now we can determine if object being moved from or to the junkfolder + //if destination folder is junk, mark as spam + if(ulDestFolderId==junkFolderId) + shMailStatus="spam"; + else + { + //if destination folder is not TRASH and de source folder is JUNK, mark as ham + if(ulDestFolderId!=wasteBucketFolderId && srcFolderId==junkFolderId) + shMailStatus="ham"; + else + //its just a normal movement, so do nothing. + goto exit; + } + + //Get the mail from the DB. + FREE_DBRESULT(); + strQuery="SELECT val_string FROM properties WHERE tag="+stringify(PROP_ID(PR_TRANSPORT_MESSAGE_HEADERS))+" AND hierarchyid= "+stringify(ulId); + er = lpDatabase->DoSelect(strQuery, &lpDBResult); + if(er != erSuccess) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: db error while retrieve mail header."); + goto exit; + } + + lpDBRow = lpDatabase->FetchRow(lpDBResult); + shNumRows=lpDatabase->GetNumRows(lpDBResult); + + if(shNumRows<=0) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: warning mail header empty or this object is no e-mail"); + goto exit; + } + + { + //now its time to open the spamhook script and pass the mail to it: + shScriptPath=shScriptPath+" "+shMailStatus+" "+stringify(ulId); + int ulFpWrite = -1; + int ulFpRead = -1; + int ulCommandRetval; + + //we asume failure, unless we make it all the way though the script + er=ZARAFA_E_UNKNOWN; + + pid_t ulCommandPid = unix_popen_rw(g_lpSessionManager->GetLogger(), shScriptPath.c_str(), &ulFpWrite, &ulFpRead, NULL, NULL, true, false); + if (ulCommandPid <= 0) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error opening subprocess."); + goto exit; + } + + //pass the data to the subprocess: + write(ulFpWrite, lpDBRow[0], strlen(lpDBRow[0])); + ulCommandRetval=unix_pclose(ulFpRead, ulFpWrite, ulCommandPid); + + //subprocess is done, check results + if (ulCommandRetval<0) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error "+shScriptPath+" exits with: "+stringify(WEXITSTATUS(ulCommandRetval))); + goto exit; + } + } + + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_INFO,"SpamHook: "+shScriptPath+" successfully executed."); + er=erSuccess; + + exit: + // Free database results + FREE_DBRESULT(); + + return er; +} + + // Move one or more messages and/or moved a softdeleted message to a normal message ECRESULT MoveObjects(ECSession *lpSession, ECDatabase *lpDatabase, ECListInt* lplObjectIds, unsigned int ulDestFolderId, unsigned int ulSyncId) { @@ -8641,6 +8815,16 @@ // @note The object type checking wille be done in MoveObjects or CopyObject +//SPAMHOOK +///////////////////////////////////// + //Iterate over all mail ids and initiate spamhook. + for(iObjectId = lObjectIds.begin(); iObjectId != lObjectIds.end(); iObjectId++) + { + SpamHook(lpDatabase,*iObjectId,ulDestFolderId); + } +//SPAMHOOK END +//////////////////////////////////// + //check copy or a move if(ulFlags & FOLDER_MOVE ) { // A move er = MoveObjects(lpecSession, lpDatabase, &lObjectIds, ulDestFolderId, ulSyncId); diff -ru zarafa-7.1.4/provider/server/ECServer.cpp zarafa-7.1.4.spamhook/provider/server/ECServer.cpp --- zarafa-7.1.4/provider/server/ECServer.cpp 2013-02-28 17:13:17.000000000 +0100 +++ zarafa-7.1.4.spamhook/provider/server/ECServer.cpp 2013-04-15 11:14:40.000000000 +0200 @@ -963,6 +963,7 @@ { "deletegroup_script", "/etc/zarafa/userscripts/deletegroup", CONFIGSETTING_RELOADABLE}, { "createcompany_script", "/etc/zarafa/userscripts/createcompany", CONFIGSETTING_RELOADABLE }, { "deletecompany_script", "/etc/zarafa/userscripts/deletecompany", CONFIGSETTING_RELOADABLE }, + { "junklearn_script", "/etc/zarafa/userscripts/junklearn", CONFIGSETTING_RELOADABLE }, { "user_safe_mode", "no", CONFIGSETTING_RELOADABLE }, // Storename format