Index: npl/mailserver/zarafa7/Datux-spamhook.patch
===================================================================
--- npl/mailserver/zarafa7/Datux-spamhook.patch	(revision c5c522c7ca74a4c1725ca5e3fe0bdcadff80e49a)
+++ npl/mailserver/zarafa7/Datux-spamhook.patch	(revision c5c522c7ca74a4c1725ca5e3fe0bdcadff80e49a)
@@ -0,0 +1,219 @@
+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
