#
# old_revision [6573eb6d5779706b5935161822c561cf325f7fa6]
#
# patch "SoObjects/SOGo/SOGoDomainDefaults.h"
#  from [0b2be24987ff61077a11ffe0bf02116625d782d1]
#    to [88b910b96713c21a9d0710066a0f569e8e3eefa7]
# 
# patch "SoObjects/SOGo/SOGoDomainDefaults.m"
#  from [fa3475a65ccea244b1223c960aa0dbd8dd990be4]
#    to [f380c5be1577fe21a0e2c27d1944b3e124623e9c]
# 
# patch "SoObjects/SOGo/SOGoSieveManager.h"
#  from [d3a6cf989982a7dc20ef92ffc786f2e278742951]
#    to [8bc04ad0515f258519b08969699eb3374e24ae2c]
# 
# patch "SoObjects/SOGo/SOGoSieveManager.m"
#  from [3d8e3ce324744a5bb8ebfe9d8fdb738a26bd6b92]
#    to [03246493ff500bf6224324f1820ca235a24972fc]
# 
# patch "UI/PreferencesUI/UIxPreferences.m"
#  from [118f6316688e83962d53584288dd47e498270881]
#    to [495102cb29027e04b934358bd6c3ffbd0cf4f0c2]
#
============================================================
--- SoObjects/SOGo/SOGoDomainDefaults.h	0b2be24987ff61077a11ffe0bf02116625d782d1
+++ SoObjects/SOGo/SOGoDomainDefaults.h	88b910b96713c21a9d0710066a0f569e8e3eefa7
@@ -47,7 +47,17 @@
 - (NSString *) imapFolderSeparator;
 - (BOOL) imapAclConformsToIMAPExt;
 - (BOOL) forceIMAPLoginWithEmail;
+
+
+- (NSString *) sievePrependFilterName;
+- (NSString *) sieveAppendFilterName;
+- (NSString *) sievePrependGlobalFilterName;
+- (NSString *) sieveAppendGlobalFilterName;
+- (BOOL) sieveInsertServerFilter;
 - (BOOL) sieveScriptsEnabled;
+- (BOOL) sieveDebugEnabled;
+
+
 - (BOOL) forwardEnabled;
 - (BOOL) vacationEnabled;
 - (NSString *) mailingMechanism;
============================================================
--- SoObjects/SOGo/SOGoDomainDefaults.m	fa3475a65ccea244b1223c960aa0dbd8dd990be4
+++ SoObjects/SOGo/SOGoDomainDefaults.m	f380c5be1577fe21a0e2c27d1944b3e124623e9c
@@ -176,6 +176,39 @@
   return [self boolForKey: @"SOGoSieveScriptsEnabled"];
 }
 
+
+
+- (NSString *) sievePrependFilterName
+{
+  return [self stringForKey: @"SOGoSievePrependFilterName"];
+}
+
+- (NSString *) sieveAppendFilterName
+{
+  return [self stringForKey: @"SOGoSieveAppendFilterName"];
+}
+
+- (NSString *) sievePrependGlobalFilterName
+{
+  return [self stringForKey: @"SOGoSievePrependGlobalFilterName"];
+}
+
+- (NSString *) sieveAppendGlobalFilterName
+{
+  return [self stringForKey: @"SOGoSieveAppendGlobalFilterName"];
+}
+
+- (BOOL) sieveInsertServerFilter
+{
+  return [self boolForKey: @"SOGoSieveInsertServerFilter"];
+}
+
+- (BOOL) sieveDebugEnabled
+{
+  return [self boolForKey: @"SOGoSieveDebugEnabled"];
+}
+
+
 - (BOOL) forwardEnabled
 {
   return [self boolForKey: @"SOGoForwardEnabled"];
@@ -186,6 +219,10 @@
   return [self boolForKey: @"SOGoVacationEnabled"];
 }
 
+
+
+
+
 - (NSString *) mailingMechanism
 {
   NSString *mailingMechanism;
============================================================
--- SoObjects/SOGo/SOGoSieveManager.h	d3a6cf989982a7dc20ef92ffc786f2e278742951
+++ SoObjects/SOGo/SOGoSieveManager.h	8bc04ad0515f258519b08969699eb3374e24ae2c
@@ -31,6 +31,7 @@
 @class NSString;
 @class SOGoMailAccount;
 @class SOGoUser;
+@class NGSieveClient;
 
 @interface SOGoSieveManager : NSObject
 {
@@ -45,11 +46,24 @@
 - (NSString *) sieveScriptWithRequirements: (NSMutableArray *) newRequirements;
 - (NSString *) lastScriptError;
 
+
 - (BOOL) updateFiltersForLogin: (NSString *) theLogin
 		      authname: (NSString *) theAuthName
 		      password: (NSString *) thePassword
 		       account: (SOGoMailAccount *) theAccount;
 
+- (NSString *) makeScriptEntryWithScript:(NSString*)scriptName 
+				withContent:(BOOL)retrieveContent  
+				  andClient:(NGSieveClient *)client;
+					
+- (NSString *) makeScriptEntryWithScript:(NSString*)scriptName 
+				withContent:(BOOL)retrieveContent 
+				  andClient:(NGSieveClient *)client 
+				   asGlobal:(BOOL) isGlobal;			  	  
+				  	  
+- (NSDictionary *) loadScriptList: (NGSieveClient *) sieveClient;
+
+
 @end
 
 #endif /* SOGOSIEVEMANAGER_H */
============================================================
--- SoObjects/SOGo/SOGoSieveManager.m	3d8e3ce324744a5bb8ebfe9d8fdb738a26bd6b92
+++ SoObjects/SOGo/SOGoSieveManager.m	03246493ff500bf6224324f1820ca235a24972fc
@@ -26,6 +26,7 @@
 #import <Foundation/NSString.h>
 #import <Foundation/NSURL.h>
 #import <Foundation/NSValue.h>
+#import <NGExtensions/NSString+Ext.h>
 
 #import <SOGo/NSArray+Utilities.h>
 #import <SOGo/NSDictionary+Utilities.h>
@@ -618,10 +619,10 @@ static NSString *sieveScriptName = @"sog
 - (BOOL) updateFiltersForLogin: (NSString *) theLogin
 		      authname: (NSString *) theAuthName
 		      password: (NSString *) thePassword
-		       account: (SOGoMailAccount *) theAccount
+		      account: (SOGoMailAccount *) theAccount
 {
   NSMutableArray *req;
-  NSMutableString *script, *header;
+  NSMutableString *script, *header, *appendScriptStr, *prependScriptStr;
   NGInternetSocketAddress *address;
   NSDictionary *result, *values;
   SOGoUserDefaults *ud;
@@ -640,6 +641,8 @@ static NSString *sieveScriptName = @"sog
   b = NO;
 
   script = [NSMutableString string];
+  appendScriptStr = [NSMutableString string]; // needed for include
+  prependScriptStr = [NSMutableString string]; // needed for include
 
   // Right now, we handle Sieve filters here and only for vacation
   // and forwards. Traditional filters support (for fileinto, for
@@ -713,6 +716,9 @@ static NSString *sieveScriptName = @"sog
       if ([[values objectForKey: @"keepCopy"] boolValue])
 	[script appendString: @"keep;\r\n"];
     }
+    
+    
+
   
   filterScript = [self sieveScriptWithRequirements: req];
   if (filterScript)
@@ -729,13 +735,8 @@ static NSString *sieveScriptName = @"sog
       return NO;
     }
 
-  if ([req count])
-    {
-      header = [NSString stringWithFormat: @"require [\"%@\"];\r\n",
-                         [req componentsJoinedByString: @"\",\""]];
-      [script insertString: header  atIndex: 0];
-    }
 
+    
   // We connect to our Sieve server and upload the script.
   //
   // sieveServer might have the following format:
@@ -793,6 +794,9 @@ static NSString *sieveScriptName = @"sog
     [client closeConnection];
     return NO;
   }
+
+  
+  
   result = [client login: theLogin  authname: theAuthName  password: thePassword];
   if (![[result valueForKey:@"result"] boolValue]) {
     NSLog(@"failure. Attempting with a renewed password (no authname supported)");
@@ -807,14 +811,164 @@ static NSString *sieveScriptName = @"sog
     return NO;
   }
 
+  
+  // Handle external scripts for inclusion in sogo.sieve
+  BOOL useExternalScripts = [dd sieveInsertServerFilter]
+  			|| [dd sievePrependFilterName]
+			|| [dd sieveAppendFilterName]
+			|| [dd sievePrependGlobalFilterName]
+			|| [dd sieveAppendGlobalFilterName];
+
+			
+  if(useExternalScripts)
+  {
+	NSMutableDictionary *serverscripts = [NSMutableDictionary dictionary];
+
+	NSMutableArray *_preFiles = [NSMutableArray array];
+	NSMutableArray *_postFiles = [NSMutableArray array];
+	NSMutableArray *_preGlobalFiles = [NSMutableArray array];
+	NSMutableArray *_postGlobalFiles = [NSMutableArray array];		
+
+	// Check for an available 'include' sieve plugin.
+	// When the plugin is not available,
+	// - the script/s will be included directly as source (read from server, lasts some microseconds longer ;-) )
+	// - global scripts not possible (they are only possible, too, when configured in dovecot)
+	//
+  	BOOL withScriptContent = ![client hasCapability: @"include"];
+ 
+  	if(withScriptContent)
+  	{
+  		NSLog(@"WARNING! Configured managesieve server does not support the 'include' plugin. Including scripts directly.");
+  	}
+  	else
+	{		
+		// Usefull if available - so you do not need to include all the stuff in one file
+		[req addObjectUniquely: @"include"];	  
+	}	
+			
+	if([dd sieveInsertServerFilter]) // Insert all current filters on and from the Server, but without sogo.sieve
+	{
+		// Read all current scripts from server, but they must be sorted by a prefix 'pre_' and/or 'post_'
+		// Sorting with number after the prefix will help ...
+		serverscripts = [self loadScriptList: client];
+	}
+	else  // Std case: pre-configured scriptnames for pre-run and post-run
+	{
+		// prepend an external script, name is configured in sievePrependFilterName
+		if([dd sievePrependFilterName])
+		{
+			[_preFiles addObject: [dd sievePrependFilterName]];
+		}		
+		
+		if([dd sieveAppendFilterName])
+		{
+			[_postFiles addObject: [dd sieveAppendFilterName]];
+		}
+		
+		// prepend an global external script, name is configured in sievePrependGlobalFilterName
+		// This runs only when the 'include' sieve-plugin is available
+		if(!withScriptContent)
+		{
+			if([dd sievePrependGlobalFilterName])
+			{
+				[_preGlobalFiles addObject: [dd sievePrependGlobalFilterName]];
+			}	
+	
+			
+			if([dd sieveAppendGlobalFilterName])
+			{
+				[_postGlobalFiles addObject: [dd sieveAppendGlobalFilterName]];
+			}
+		}		
+		
+		[serverscripts setObject: _preFiles forKey: @"prefiles" ];
+		[serverscripts setObject: _preGlobalFiles forKey: @"globalPrefiles" ];		
+		
+		[serverscripts setObject: _postFiles forKey: @"postfiles" ];
+		[serverscripts setObject: _postGlobalFiles forKey: @"globalPostfiles" ];			
+	}
+
+	
+	// Now creating stuff from 'serverscripts' and make scripts
+	if([dd sieveDebugEnabled]) NSLog(@"SIEVE: Now creating stuff from 'serverscripts' and make sieve scripts");
+	NSString *_scriptName;
+	
+	if([[serverscripts objectForKey: @"prefiles"] count] > 0)
+	{
+		NSEnumerator *preFiles = [[serverscripts objectForKey: @"prefiles"] objectEnumerator];
+		
+		//while(_scriptName = (NSString *)[preFiles nextObject])
+		while(_scriptName = [preFiles nextObject])
+		{	
+			[prependScriptStr appendString: [self makeScriptEntryWithScript: _scriptName 
+					withContent:withScriptContent  
+					andClient: client]];
+		}
+	}
+	
+	if([[serverscripts objectForKey: @"postfiles"] count] > 0)
+	{
+		NSEnumerator *postFiles = [[serverscripts objectForKey: @"postfiles"] objectEnumerator];
+		
+		// while(_scriptName = (NSString *)[postFiles nextObject])
+		while(_scriptName = [postFiles nextObject])
+		{
+			[appendScriptStr appendString: [self makeScriptEntryWithScript: _scriptName 
+					withContent:withScriptContent  
+					andClient: client]];
+		}
+	}
+	
+	// Global
+	if(!withScriptContent) // Global scripts could only be used with the sieve-plugin 'include' AND server configuration (known in dovecot)
+	{
+		[prependScriptStr appendString: [self makeScriptEntryWithScript: _scriptName 
+							withContent:NO  
+							andClient: client
+							asGlobal: YES]];
+				
+		[appendScriptStr appendString: [self makeScriptEntryWithScript: _scriptName 
+							withContent:NO  
+							andClient: client
+							asGlobal: YES]];
+	}				
+		
+	
+	// sievePrepend*FilterName MUST be the first entry after file header
+	if([prependScriptStr length])
+	{
+		[script insertString: prependScriptStr atIndex: 0];  	  
+	}    
+	
+	// sieveAppend*FilterName MUST be the last entry
+	if([appendScriptStr length])
+	{
+		[script appendString: appendScriptStr];
+	}
+  }
+  
+  
+  // Creating require-string
+  if ([req count])
+    {
+      header = [NSString stringWithFormat: @"require [\"%@\"];\r\n",
+                         [req componentsJoinedByString: @"\",\""]];
+      [script insertString: header  atIndex: 0];
+    }
+
+  if([dd sieveDebugEnabled]) NSLog(@"SIEVE: Created sieve script:\r\n----\r\n%@", script);
+    
+    
   /* We ensure to deactive the current active script since it could prevent
      its deletion from the server. */
   result = [client setActiveScript: @""];
+  
   // We delete the existing Sieve script
   result = [client deleteScript: sieveScriptName];
   
-  if (![[result valueForKey:@"result"] boolValue]) {
-    NSLog(@"WARNING: Could not delete Sieve script - continuing...: %@", result);
+  if (![[result valueForKey:@"result"] boolValue]) 
+  {
+  	  NSLog(@"WARNING: Could not delete Sieve script - continuing...: %@", result);
   }
 
   // We put and activate the script only if we actually have a script
@@ -836,8 +990,129 @@ static NSString *sieveScriptName = @"sog
 	return NO;
       }
   }
+  
+  return YES;
+}
 
-  return YES;
+
+- (NSString *) makeScriptEntryWithScript:(NSString*)scriptName 
+				withContent:(BOOL)retrieveContent  
+				andClient:(NGSieveClient *)sieveClient
+{
+	return [self makeScriptEntryWithScript: scriptName 
+			withContent:retrieveContent 
+			andClient:sieveClient 
+			asGlobal:NO];
 }
 
+- (NSString *) makeScriptEntryWithScript:(NSString*)scriptName 
+				withContent:(BOOL)retrieveContent 
+				andClient:(NGSieveClient *)sieveClient 
+				asGlobal:(BOOL) isGlobal
+{
+	// Configdata
+	SOGoDomainDefaults *dd = [user domainDefaults];
+	
+	// when a content is given (!= NIL), a "global" file is not "reachable"
+	if(retrieveContent)
+	{
+		isGlobal = NO;
+	}
+	
+	NSString *sieveFileName = [scriptName stringWithoutSuffix:@".sieve"];
+	
+	// Check, if configures local/":personal" configured in 'sieve*FilterName' are on place.
+	// If not, create it
+	if(isGlobal == NO && ![sieveClient getScript: sieveFileName])
+	{
+		if([dd sieveDebugEnabled]) NSLog(@"SIEVE: Script '%@' not found, now creating it.", scriptName);
+		[sieveClient putScript: sieveFileName script:[NSString stringWithFormat: @"# Dummy file '%@' created by SOGo", scriptName]];
+	}
+	
+	
+	// when global, another include-string has to be created
+	if(isGlobal)
+	{
+		if(!scriptName)
+		{
+			return @"";
+		}
+		
+		// create include global configured '*FilterName'
+		return [NSString stringWithFormat: @"\r\ninclude :global \"%@\";\r\n\r\n", scriptName];
+	}
+	else
+	{
+		if(retrieveContent)
+		{
+			// get content of script and return it
+			if(![sieveClient getScript: sieveFileName])  // Create file if not available
+			{
+				if([dd sieveDebugEnabled]) NSLog(@"SIEVE: Script '%@' not found, now creating it as dummy.", scriptName);
+				[sieveClient putScript: sieveFileName script:[NSString stringWithFormat: @"# This file '%@' was created by SOGo", scriptName]];
+			}				
+				
+
+			NSString *loadedScript = [sieveClient getScript: sieveFileName];
+			if(!loadedScript)
+			{
+				if([dd sieveDebugEnabled]) NSLog(@"SIEVE: WARNING: Cannot include script content, script '%@' not found.", scriptName);
+				return nil; // No file, no string.
+			}
+			else
+			{
+				return [NSString stringWithFormat: @"\r\n##### included file content follows #####\r\n%@\r\n##### END OF included file content #####\r\n", loadedScript];
+			}			
+		}
+		else
+		{
+			// create include for personal 'sieve*FilterName'
+			return [NSString stringWithFormat: @"\r\ninclude :personal \"%@\";\r\n\r\n", scriptName];	
+		}
+	}
+}
+
+
+- (NSDictionary *) loadScriptList: (NGSieveClient *)sieveClient
+{
+	NSMutableArray *_preFiles = [NSMutableArray array];
+	NSMutableArray *_postFiles = [NSMutableArray array];
+	NSString *activeFile = @"";
+	
+	// Get list of scripts
+	NSDictionary *scriptList = [sieveClient listScripts];
+
+	if([scriptList count] > 0) // objectForKey
+	{
+		NSArray *keys = [scriptList allKeys];
+		NSArray *values = [scriptList allValues];	
+		
+		int i;
+		for(i=0; i< [keys count]; i++)
+		{
+			if([[keys objectAtIndex: i] hasPrefix: @"pre_"])
+			{
+				[_preFiles addObject: [keys objectAtIndex: i]];
+			}
+			else if([[keys objectAtIndex: i] hasPrefix: @"post_"])
+			{
+				[_postFiles addObject: [keys objectAtIndex: i]];
+			}
+			
+			if([[[values objectAtIndex: i] lowercaseString] isEqualToString: @"active"])
+			{
+				activeFile = [keys objectAtIndex: i];
+			}	
+		}
+	}
+	
+	// Packing results into structure
+	NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:4];
+	[dict setObject: [NSArray arrayWithArray:_preFiles ] forKey: @"prefiles"]; 
+	[dict setObject: [NSArray arrayWithArray:_postFiles ] forKey: @"postfiles" ];
+	[dict setObject: activeFile forKey: @"activeFile"];
+	
+	return dict;
+}
+
 @end
============================================================
--- UI/PreferencesUI/UIxPreferences.m	118f6316688e83962d53584288dd47e498270881
+++ UI/PreferencesUI/UIxPreferences.m	495102cb29027e04b934358bd6c3ffbd0cf4f0c2
@@ -975,6 +975,7 @@
       folder = [[self clientObject] mailAccountsFolder: @"Mail"
                                              inContext: context];
       account = [folder lookupName: @"0" inContext: context acquire: NO];
+
       [account updateFilters];
 
       if (hasChanged)
