See ChangeLog

Monotone-Parent: 178cf4e5311729ac333305676b5ad2aa35a7ca71
Monotone-Revision: d51bb1b592f986d2e34036c3dad0c70f43f0150a

Monotone-Author: ludovic@Sophos.ca
Monotone-Date: 2011-06-29T17:43:10
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Ludovic Marcotte
2011-06-29 17:43:10 +00:00
parent f44212f0e6
commit 7e720da571
11 changed files with 521 additions and 247 deletions
+6
View File
@@ -1,3 +1,9 @@
2011-06-29 Ludovic Marcotte <lmarcotte@inverse.ca>
* Added get/set/unset capabilities to sogo-tool to set
user's defaults/settings. Refactored some code to be
more cleanly structured.
2011-06-24 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/SOGo/SOGoSystemDefaults.m (-loginDomains): new method
-2
View File
@@ -33,8 +33,6 @@ Mailer_OBJC_FILES += \
SOGoMailForward.m \
SOGoMailReply.m \
\
SOGoSieveConverter.m \
\
EOQualifier+MailDAV.m \
NSData+Mail.m \
NSString+Mail.m \
+8 -224
View File
@@ -30,14 +30,12 @@
#import <NGObjWeb/SoHTTPAuthenticator.h>
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGStreams/NGInternetSocketAddress.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGImap4/NGImap4Connection.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NGImap4Context.h>
#import <NGImap4/NGSieveClient.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
@@ -45,13 +43,13 @@
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoSieveManager.h>
#import "SOGoDraftsFolder.h"
#import "SOGoMailFolder.h"
#import "SOGoMailManager.h"
#import "SOGoMailNamespace.h"
#import "SOGoSentFolder.h"
#import "SOGoSieveConverter.h"
#import "SOGoTrashFolder.h"
#import "SOGoUser+Mailer.h"
@@ -60,7 +58,6 @@
@implementation SOGoMailAccount
static NSString *inboxFolderName = @"INBOX";
static NSString *sieveScriptName = @"sogo";
- (id) init
{
@@ -283,228 +280,15 @@ static NSString *sieveScriptName = @"sogo";
- (BOOL) updateFilters
{
NSMutableArray *requirements;
NSMutableString *script, *header;
NGInternetSocketAddress *address;
NSDictionary *result, *values;
SOGoUserDefaults *ud;
SOGoDomainDefaults *dd;
NGSieveClient *client;
NSString *filterScript, *v, *password, *sieveServer;
SOGoSieveConverter *converter;
int sievePort;
BOOL b;
SOGoSieveManager *manager;
dd = [[context activeUser] domainDefaults];
if (!([dd sieveScriptsEnabled] || [dd vacationEnabled] || [dd forwardEnabled]))
return YES;
manager = [SOGoSieveManager sieveManagerForUser: [context activeUser]];
requirements = [NSMutableArray arrayWithCapacity: 15];
ud = [[context activeUser] userDefaults];
b = NO;
script = [NSMutableString string];
// Right now, we handle Sieve filters here and only for vacation
// and forwards. Traditional filters support (for fileinto, for
// example) will be added later.
values = [ud vacationOptions];
// We handle vacation messages.
// See http://ietfreport.isoc.org/idref/draft-ietf-sieve-vacation/
if (values && [[values objectForKey: @"enabled"] boolValue])
{
NSArray *addresses;
NSString *text;
BOOL ignore;
int days, i;
days = [[values objectForKey: @"daysBetweenResponse"] intValue];
addresses = [values objectForKey: @"autoReplyEmailAddresses"];
ignore = [[values objectForKey: @"ignoreLists"] boolValue];
text = [values objectForKey: @"autoReplyText"];
b = YES;
if (days == 0)
days = 7;
[requirements addObjectUniquely: @"vacation"];
// Skip mailing lists
if (ignore)
[script appendString: @"if allof ( not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"], not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"], not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\" ) {"];
[script appendFormat: @"vacation :days %d :addresses [", days];
for (i = 0; i < [addresses count]; i++)
{
[script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]];
if (i == [addresses count]-1)
[script appendString: @"] "];
else
[script appendString: @", "];
}
[script appendFormat: @"text:\r\n%@\r\n.\r\n;\r\n", text];
if (ignore)
[script appendString: @"}\r\n"];
}
// We handle mail forward
values = [ud forwardOptions];
if (values && [[values objectForKey: @"enabled"] boolValue])
{
id addresses;
int i;
b = YES;
addresses = [values objectForKey: @"forwardAddress"];
if ([addresses isKindOfClass: [NSString class]])
addresses = [NSArray arrayWithObject: addresses];
for (i = 0; i < [addresses count]; i++)
{
v = [addresses objectAtIndex: i];
if (v && [v length] > 0)
[script appendFormat: @"redirect \"%@\";\r\n", v];
}
if ([[values objectForKey: @"keepCopy"] boolValue])
[script appendString: @"keep;\r\n"];
}
converter = [SOGoSieveConverter sieveConverterForUser: [context activeUser]];
filterScript = [converter sieveScriptWithRequirements: requirements];
if (filterScript)
{
if ([filterScript length])
{
b = YES;
[script appendString: filterScript];
}
}
else
{
[self errorWithFormat: @"Sieve generation failure: %@",
[converter lastScriptError]];
return NO;
}
if ([requirements count])
{
header = [NSString stringWithFormat: @"require [\"%@\"];\r\n",
[requirements componentsJoinedByString: @"\",\""]];
[script insertString: header atIndex: 0];
}
// We connect to our Sieve server and upload the script.
//
// sieveServer might have the following format:
//
// sieve://localhost
// sieve://localhost:2000
//
// Values such as "localhost" or "localhost:2000" are NOT supported.
//
sieveServer = [dd sieveServer];
sievePort = 2000;
if (!sieveServer)
{
NSString *s;
sieveServer = @"localhost";
s = [dd imapServer];
if (s)
{
NSURL *url;
url = [NSURL URLWithString: s];
if ([url host])
sieveServer = [url host];
else
sieveServer = s;
}
}
else
{
NSURL *url;
url = [NSURL URLWithString: sieveServer];
if ([url host])
sieveServer = [url host];
if ([[url port] intValue] != 0)
sievePort = [[url port] intValue];
}
address = [NGInternetSocketAddress addressWithPort: sievePort onHost: sieveServer];
client = [NGSieveClient clientWithAddress: address];
if (!client) {
[self errorWithFormat: @"Sieve connection failed on %@", [address description]];
return NO;
}
password = [self imap4PasswordRenewed: NO];
if (!password) {
[client closeConnection];
return NO;
}
result = [client login: [[self imap4URL] user] password: password];
if (![[result valueForKey:@"result"] boolValue]) {
[self errorWithFormat: @"failure. Attempting with a renewed password."];
password = [self imap4PasswordRenewed: YES];
result = [client login: [[self imap4URL] user] password: password];
}
if (![[result valueForKey:@"result"] boolValue]) {
[self errorWithFormat: @"Could not login '%@' on Sieve server: %@: %@",
[[self imap4URL] user], client, result];
[client closeConnection];
return NO;
}
/* 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]) {
[self logWithFormat:@"WARNING: Could not delete Sieve script - continuing...: %@", result];
}
// We put and activate the script only if we actually have a script
// that does something...
if (b)
{
result = [client putScript: sieveScriptName script: script];
if (![[result valueForKey:@"result"] boolValue]) {
[self errorWithFormat:@"Could not upload Sieve script: %@", result];
[client closeConnection];
return NO;
}
result = [client setActiveScript: sieveScriptName];
if (![[result valueForKey:@"result"] boolValue]) {
[self errorWithFormat:@"Could not enable Sieve script: %@", result];
[client closeConnection];
return NO;
}
}
return YES;
return [manager updateFiltersForLogin: [[self imap4URL] user]
authname: [[self imap4URL] user]
password: [self imap4PasswordRenewed: NO]
account: self];
}
+4
View File
@@ -23,6 +23,8 @@ SOGo_HEADER_FILES = \
SOGoParentFolder.h \
SOGoUserFolder.h \
\
SOGoSieveManager.h \
\
SOGoUserManager.h \
LDAPSource.h \
SQLSource.h \
@@ -81,6 +83,8 @@ SOGo_OBJC_FILES = \
SOGoPublicBaseFolder.m \
SOGoUserFolder.m \
\
SOGoSieveManager.m \
\
SOGoDefaultsSource.m \
SOGoSystemDefaults.m \
SOGoDomainDefaults.m \
@@ -1,8 +1,9 @@
/* SOGoSieveConverter.h - this file is part of SOGo
/* SOGoSieveManager.h - this file is part of SOGo
*
* Copyright (C) 2010 Wolfgang Sourdeau
* Copyright (C) 2010-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Ludovic Marcotte <lmarcotte@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,30 +21,35 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef SOGOSIEVECONVERTER_H
#define SOGOSIEVECONVERTER_H
#ifndef SOGOSIEVEMANAGER_H
#define SOGOSIEVEMANAGER_H
#import <Foundation/NSObject.h>
@class NSDictionary;
@class NSMutableArray;
@class NSString;
@class SOGoMailAccount;
@class SOGoUser;
@interface SOGoSieveConverter : NSObject
@interface SOGoSieveManager : NSObject
{
SOGoUser *user;
NSMutableArray *requirements;
NSString *scriptError;
}
+ (id) sieveConverterForUser: (SOGoUser *) user;
+ (id) sieveManagerForUser: (SOGoUser *) user;
- (id) initForUser: (SOGoUser *) newUser;
- (NSString *) sieveScriptWithRequirements: (NSMutableArray *) newRequirements;
- (NSString *) lastScriptError;
- (BOOL) updateFiltersForLogin: (NSString *) theLogin
authname: (NSString *) theAuthName
password: (NSString *) thePassword
account: (SOGoMailAccount *) theAccount;
@end
#endif /* SOGOSIEVECONVERTER_H */
#endif /* SOGOSIEVEMANAGER_H */
@@ -1,8 +1,9 @@
/* SOGoSieveConverter.m - this file is part of SOGo
/* SOGoSieveManager.m - this file is part of SOGo
*
* Copyright (C) 2010 Wolfgang Sourdeau
* Copyright (C) 2010-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Ludovic Marcotte <lmarcotte@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +24,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
#import <SOGo/NSArray+Utilities.h>
@@ -30,9 +32,12 @@
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import "SOGoMailAccounts.h"
#import <NGStreams/NGInternetSocketAddress.h>
#import <NGImap4/NGSieveClient.h>
#import "SOGoSieveConverter.h"
#import "../Mailer/SOGoMailAccount.h"
#import "SOGoSieveManager.h"
typedef enum {
UIxFilterFieldTypeAddress,
@@ -47,6 +52,8 @@ static NSDictionary *sieveFields = nil;
static NSDictionary *sieveFlags = nil;
static NSDictionary *operatorRequirements = nil;
static NSDictionary *methodRequirements = nil;
static NSString *sieveScriptName = @"sogo";
@interface NSString (SOGoSieveExtension)
@@ -106,7 +113,7 @@ static NSDictionary *methodRequirements = nil;
@end
@implementation SOGoSieveConverter
@implementation SOGoSieveManager
+ (void) initialize
{
@@ -195,14 +202,14 @@ static NSDictionary *methodRequirements = nil;
}
}
+ (id) sieveConverterForUser: (SOGoUser *) newUser
+ (id) sieveManagerForUser: (SOGoUser *) newUser
{
SOGoSieveConverter *newConverter;
SOGoSieveManager *newManager;
newConverter = [[self alloc] initForUser: newUser];
[newConverter autorelease];
newManager = [[self alloc] initForUser: newUser];
[newManager autorelease];
return newConverter;
return newManager;
}
- (id) init
@@ -605,4 +612,232 @@ static NSDictionary *methodRequirements = nil;
return scriptError;
}
//
//
//
- (BOOL) updateFiltersForLogin: (NSString *) theLogin
authname: (NSString *) theAuthName
password: (NSString *) thePassword
account: (SOGoMailAccount *) theAccount
{
NSMutableArray *req;
NSMutableString *script, *header;
NGInternetSocketAddress *address;
NSDictionary *result, *values;
SOGoUserDefaults *ud;
SOGoDomainDefaults *dd;
NGSieveClient *client;
NSString *filterScript, *v, *sieveServer;
int sievePort;
BOOL b;
dd = [user domainDefaults];
if (!([dd sieveScriptsEnabled] || [dd vacationEnabled] || [dd forwardEnabled]))
return YES;
req = [NSMutableArray arrayWithCapacity: 15];
ud = [user userDefaults];
b = NO;
script = [NSMutableString string];
// Right now, we handle Sieve filters here and only for vacation
// and forwards. Traditional filters support (for fileinto, for
// example) will be added later.
values = [ud vacationOptions];
// We handle vacation messages.
// See http://ietfreport.isoc.org/idref/draft-ietf-sieve-vacation/
if (values && [[values objectForKey: @"enabled"] boolValue])
{
NSArray *addresses;
NSString *text;
BOOL ignore;
int days, i;
days = [[values objectForKey: @"daysBetweenResponse"] intValue];
addresses = [values objectForKey: @"autoReplyEmailAddresses"];
ignore = [[values objectForKey: @"ignoreLists"] boolValue];
text = [values objectForKey: @"autoReplyText"];
b = YES;
if (days == 0)
days = 7;
[req addObjectUniquely: @"vacation"];
// Skip mailing lists
if (ignore)
[script appendString: @"if allof ( not exists [\"list-help\", \"list-unsubscribe\", \"list-subscribe\", \"list-owner\", \"list-post\", \"list-archive\", \"list-id\", \"Mailing-List\"], not header :comparator \"i;ascii-casemap\" :is \"Precedence\" [\"list\", \"bulk\", \"junk\"], not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\" ) {"];
[script appendFormat: @"vacation :days %d :addresses [", days];
for (i = 0; i < [addresses count]; i++)
{
[script appendFormat: @"\"%@\"", [addresses objectAtIndex: i]];
if (i == [addresses count]-1)
[script appendString: @"] "];
else
[script appendString: @", "];
}
[script appendFormat: @"text:\r\n%@\r\n.\r\n;\r\n", text];
if (ignore)
[script appendString: @"}\r\n"];
}
// We handle mail forward
values = [ud forwardOptions];
if (values && [[values objectForKey: @"enabled"] boolValue])
{
id addresses;
int i;
b = YES;
addresses = [values objectForKey: @"forwardAddress"];
if ([addresses isKindOfClass: [NSString class]])
addresses = [NSArray arrayWithObject: addresses];
for (i = 0; i < [addresses count]; i++)
{
v = [addresses objectAtIndex: i];
if (v && [v length] > 0)
[script appendFormat: @"redirect \"%@\";\r\n", v];
}
if ([[values objectForKey: @"keepCopy"] boolValue])
[script appendString: @"keep;\r\n"];
}
filterScript = [self sieveScriptWithRequirements: req];
if (filterScript)
{
if ([filterScript length])
{
b = YES;
[script appendString: filterScript];
}
}
else
{
NSLog(@"Sieve generation failure: %@", [self lastScriptError]);
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:
//
// sieve://localhost
// sieve://localhost:2000
//
// Values such as "localhost" or "localhost:2000" are NOT supported.
//
sieveServer = [dd sieveServer];
sievePort = 2000;
if (!sieveServer)
{
NSString *s;
sieveServer = @"localhost";
s = [dd imapServer];
if (s)
{
NSURL *url;
url = [NSURL URLWithString: s];
if ([url host])
sieveServer = [url host];
else
sieveServer = s;
}
}
else
{
NSURL *url;
url = [NSURL URLWithString: sieveServer];
if ([url host])
sieveServer = [url host];
if ([[url port] intValue] != 0)
sievePort = [[url port] intValue];
}
address = [NGInternetSocketAddress addressWithPort: sievePort onHost: sieveServer];
client = [NGSieveClient clientWithAddress: address];
if (!client) {
NSLog(@"Sieve connection failed on %@", [address description]);
return NO;
}
if (!thePassword) {
[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)");
thePassword = [theAccount imap4PasswordRenewed: YES];
result = [client login: theLogin password: thePassword];
}
if (![[result valueForKey:@"result"] boolValue]) {
NSLog(@"Could not login '%@' on Sieve server: %@: %@",
theLogin, client, result);
[client closeConnection];
return NO;
}
/* 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);
}
// We put and activate the script only if we actually have a script
// that does something...
if (b)
{
result = [client putScript: sieveScriptName script: script];
if (![[result valueForKey:@"result"] boolValue]) {
NSLog(@"Could not upload Sieve script: %@", result);
[client closeConnection];
return NO;
}
result = [client setActiveScript: sieveScriptName];
if (![[result valueForKey:@"result"] boolValue]) {
NSLog(@"Could not enable Sieve script: %@", result);
[client closeConnection];
return NO;
}
}
return YES;
}
@end
+1 -1
View File
@@ -1,6 +1,6 @@
/* SOGoUserSettings.m - this file is part of SOGo
*
* Copyright (C) 2009-2010 Inverse inc.
* Copyright (C) 2009-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
+1
View File
@@ -16,6 +16,7 @@ $(SOGO_TOOL)_OBJC_FILES += \
SOGoToolRemoveDoubles.m \
SOGoToolRemove.m \
SOGoToolRenameUser.m \
SOGoToolUserPreferences.m
SOGO_SLAPD_SOCKD = sogo-slapd-sockd
$(SOGO_SLAPD_SOCKD)_INSTALL_DIR = $(SOGO_ADMIN_TOOLS)
+1 -1
View File
@@ -1,6 +1,6 @@
/* SOGoTool.h - this file is part of SOGo
*
* Copyright (C) 2009 Inverse inc.
* Copyright (C) 2009-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
+1 -1
View File
@@ -1,6 +1,6 @@
/* SOGoTool.m - this file is part of SOGo
*
* Copyright (C) 2009 Inverse inc.
* Copyright (C) 2009-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
+240
View File
@@ -0,0 +1,240 @@
/* SOGoToolUserPreferences.m - this file is part of SOGo
*
* Copyright (C) 2011 Inverse inc.
*
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/SOGoSieveManager.h>
#import "SOGoTool.h"
typedef enum
{
UserPreferencesUnknown = -1,
UserPreferencesGet = 0,
UserPreferencesSet = 1,
UserPreferencesUnset = 2,
} SOGoUserPreferencesCommand;
@interface SOGoToolUserPreferences : SOGoTool
@end
@implementation SOGoToolUserPreferences
+ (void) initialize
{
}
+ (NSString *) command
{
return @"user-preferences";
}
+ (NSString *) description
{
return @"set user defaults / settings in the database";
}
- (void) usage
{
fprintf (stderr, "user-preferences get|set|unset defaults|settings user [authname:authpassword] key value\n\n"
" user the user of whom to set the defaults/settings key/value\n");
}
//
// possible values are: get | set | unset
//
- (SOGoUserPreferencesCommand) _cmdFromString: (NSString *) theString
{
if ([theString length] > 2)
{
if ([theString caseInsensitiveCompare: @"get"] == NSOrderedSame)
return UserPreferencesGet;
else if ([theString caseInsensitiveCompare: @"set"] == NSOrderedSame)
return UserPreferencesSet;
else if ([theString caseInsensitiveCompare: @"unset"] == NSOrderedSame)
return UserPreferencesUnset; }
return UserPreferencesUnknown;
}
// If we got any of those keys for "defaults", we regenerate the Sieve script
//
// Forward
// SOGoSieveFilters
// Vacation
//
- (BOOL) _updateSieveScripsForkey: (NSString *) theKey
manager: (SOGoSieveManager *) theManager
login: (NSString *) theLogin
authname: (NSString *) theAuthName
password: (NSString *) thePassword
{
if ([theKey caseInsensitiveCompare: @"Forward"] == NSOrderedSame ||
[theKey caseInsensitiveCompare: @"SOGoSieveFilters"] == NSOrderedSame ||
[theKey caseInsensitiveCompare: @"Vacation"] == NSOrderedSame)
{
if ([theAuthName length] == 0 || [thePassword length] == 0)
{
NSLog(@"To update Sieve scripts, you must provide the \"authname:password\" parameter");
return NO;
}
return [theManager updateFiltersForLogin: theLogin
authname: theAuthName
password: thePassword
account: nil];
}
return YES;
}
- (BOOL) run
{
NSString *userId, *type, *key;
SOGoUserPreferencesCommand cmd;
id o;
NSRange r;
BOOL rc;
int max;
max = [arguments count];
rc = NO;
if (max > 3)
{
SOGoDefaultsSource *source;
SOGoSieveManager *manager;
SOGoUser *user;
cmd = [self _cmdFromString: [arguments objectAtIndex: 0]];
if (cmd != UserPreferencesUnknown)
{
type = [arguments objectAtIndex: 1];
userId = [arguments objectAtIndex: 2];
key = [arguments objectAtIndex: 3];
user = [SOGoUser userWithLogin: userId];
manager = [SOGoSieveManager sieveManagerForUser: user];
if ([type caseInsensitiveCompare: @"defaults"] == NSOrderedSame)
source = [user userDefaults];
else
source = [user userSettings];
if (cmd == UserPreferencesGet)
{
o = [source objectForKey: key];
if (o)
NSLog(@"value for key \"%@\": %@", key, [o jsonRepresentation]);
else
NSLog(@"Value for key \"%@\" not found in %@", key, type);
rc = YES;
}
else
{
NSString *authname, *authpwd, *value;
authname = @"";
authpwd = @"";
value = @"";
if (max > 4)
{
r = [[arguments objectAtIndex: 3] rangeOfString: @":"];
authname = [[arguments objectAtIndex: 3] substringToIndex: r.location];
authpwd = [[arguments objectAtIndex: 3] substringFromIndex: r.location+1];
key = [arguments objectAtIndex: 4];
if (max > 5)
value = [arguments objectAtIndex: 5];
}
else
{
key = [arguments objectAtIndex: 3];
value = [arguments objectAtIndex: 4];
}
if (cmd == UserPreferencesUnset)
[source removeObjectForKey: key];
else
{
o = [value objectFromJSONString];
//
// We support setting only "values" - for example, setting :
//
// SOGoDayStartTime to 9:00
//
// Values in JSON must be a dictionary so we must support passing:
//
// key == SOGoDayStartTime
// value == '{"SOGoDayStartTime": "09:00"}'
//
// to achieve what we want.
//
if (o && [o count] == 1)
{
[source setObject: [[o allValues] lastObject] forKey: key];
}
//
// We also support passing values that are already dictionaries so in this
// case, we simply set it to the passed key.
//
else if (o)
{
[source setObject: o forKey: key];
}
else
NSLog(@"Invalid JSON input - no changes performed in the database.");
}
[source synchronize];
rc = [self _updateSieveScripsForkey: key
manager: manager
login: userId
authname: authname
password: authpwd];
}
}
}
if (!rc)
{
[self usage];
}
return rc;
}
@end