diff -rupN zarafa-6.40.0-orig/provider/libserver/ZarafaCmd.cpp zarafa-6.40.0/provider/libserver/ZarafaCmd.cpp --- zarafa-6.40.0-orig/provider/libserver/ZarafaCmd.cpp 2010-05-31 19:28:59.000000000 +0200 +++ zarafa-6.40.0/provider/libserver/ZarafaCmd.cpp 2010-07-20 17:22:07.995625072 +0200 @@ -7244,6 +7244,166 @@ typedef struct{ SOURCEKEY sSourceKey; SOURCEKEY sParentSourceKey; }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,int ulDestFolderId) +{ + + ALLOC_DBRESULT(); + ECRESULT er = erSuccess; + std::string shScriptPath = g_lpSessionManager->GetConfig()->GetSetting("junklearn_script"); + + //If shScriptPath doesn't exist skip spam hook. + if(fopen(shScriptPath.c_str(),"r")) { + + //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); + int 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. + entryId* 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; + } + FREE_DBRESULT(); + + //Get 'junk folder' entryId. + 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. + entryId* 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; + } + FREE_DBRESULT(); + + //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; + } + + //Check if object is ham or spam + string shMailStatus; + //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"; + } + + //Only call hook script if the mail is marked as ham or spam. + if(!shMailStatus.empty()) { + + //Get the mail from the DB. + 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); + int shNumRows=lpDatabase->GetNumRows(lpDBResult); + + if(shNumRows>0) { + + // Execute the hook: + FILE *shFilePtr; + shScriptPath=shScriptPath+" "+shMailStatus+" "+stringify(ulId); + shFilePtr=popen(shScriptPath.c_str(),"w"); + fputs(lpDBRow[0],shFilePtr); + int shExitCode=pclose(shFilePtr); + if(!WIFEXITED(shExitCode)) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: "+shScriptPath+" was terminated abnormally."); + goto exit; + } + //If script exit with non 0, exit.. + if(WEXITSTATUS(shExitCode)!=0) { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: error "+shScriptPath+" exits with: "+stringify(shExitCode)); + er=ZARAFA_E_UNKNOWN; + goto exit; + } + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_INFO,"SpamHook: "+shScriptPath+" successfully executed."); + er=erSuccess; + } + else { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_WARNING,"SpamHook: warning mail header empty or this object is no e-mail"); + } + + // Free database results + FREE_DBRESULT(); + } + } + else { + g_lpSessionManager->GetLogger()->Log(EC_LOGLEVEL_INFO,"SpamHook: skipping, script "+shScriptPath+" not found"); + 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) @@ -8096,6 +8256,17 @@ SOAP_ENTRY_START5(copyObjects, *result, // @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++) + { + //Ignore the result + int shResult=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 -rupN zarafa-6.40.0-orig/provider/server/ECServer.cpp zarafa-6.40.0/provider/server/ECServer.cpp --- zarafa-6.40.0-orig/provider/server/ECServer.cpp 2010-05-31 19:28:59.000000000 +0200 +++ zarafa-6.40.0/provider/server/ECServer.cpp 2010-07-20 17:26:25.119624516 +0200 @@ -670,6 +670,7 @@ int running_server(char *szName, char *s { "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