From: helge Date: Sun, 28 Nov 2004 17:58:43 +0000 (+0000) Subject: improved Sieve client X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee98932fdc6c01298d281579dbbb9001504b224d;p=sope improved Sieve client git-svn-id: http://svn.opengroupware.org/SOPE/trunk@418 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- diff --git a/sope-mime/ChangeLog b/sope-mime/ChangeLog index a1c8175a..375acd26 100644 --- a/sope-mime/ChangeLog +++ b/sope-mime/ChangeLog @@ -1,3 +1,7 @@ +2004-11-28 Helge Hess + + * NGImap4: improvements in the Sieve client (v4.5.201) + 2004-11-19 Helge Hess * NGImap4: minor code cleanups (v4.5.200) diff --git a/sope-mime/NGImap4/ChangeLog b/sope-mime/NGImap4/ChangeLog index 141136db..502f05d7 100644 --- a/sope-mime/NGImap4/ChangeLog +++ b/sope-mime/NGImap4/ChangeLog @@ -1,3 +1,13 @@ +2004-11-28 Helge Hess + + * NGSieveClient.m: can init using a URL, prepared some parsing methods, + open connection on demand when login:password: is called, added + support for -listScripts and -getScript: + + * NGSieveClient.m: added a buffered stream for raw IO, added proper + error handling in some methods, added support for 'NSData commands', + properly convert commands to UTF-8 + 2004-11-19 Helge Hess * NGSieveClient.m, NGImap4Client.m: minor code cleanups diff --git a/sope-mime/NGImap4/NGImap4ResponseParser.h b/sope-mime/NGImap4/NGImap4ResponseParser.h index f716852f..75c426f5 100644 --- a/sope-mime/NGImap4/NGImap4ResponseParser.h +++ b/sope-mime/NGImap4/NGImap4ResponseParser.h @@ -1,7 +1,7 @@ /* Copyright (C) 2000-2004 SKYRIX Software AG - This file is part of OGo + This file is part of OpenGroupware.org. OGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #ifndef __OGo_NGImap4_NGImap4ResponseParser_H__ #define __OGo_NGImap4_NGImap4ResponseParser_H__ diff --git a/sope-mime/NGImap4/NGSieveClient.h b/sope-mime/NGImap4/NGSieveClient.h index 2545ce5e..25192d7a 100644 --- a/sope-mime/NGImap4/NGSieveClient.h +++ b/sope-mime/NGImap4/NGSieveClient.h @@ -28,8 +28,17 @@ #include #include -@class NSMutableArray, NSString, NSNumber, NSDictionary, NSArray; -@class NGSieveResponseParser, EOQualifier, NGHashMap; +/* + NGSieveClient + + This implements a client for server stored Sieve scripts as supported by + the Cyrus IMAP server. +*/ + +@class NSMutableArray, NSString, NSNumber, NSDictionary, NSArray, NSException; +@class EOQualifier; +@class NGHashMap; +@class NGBufferedStream; typedef enum { UnConnected_NGSieveState = 1, @@ -40,10 +49,11 @@ typedef enum { @interface NGSieveClient : NSObject { @protected - id socket; - id text; - id address; - NGImap4ResponseParser *parser; + id socket; + NGBufferedStream *io; + id address; + NGImap4ResponseParser *parser; + NSException *lastException; BOOL isLogin; @@ -53,9 +63,11 @@ typedef enum { BOOL debug; } ++ (id)clientWithURL:(id)_url; + (id)clientWithAddress:(id)_address; + (id)clientWithHost:(id)_host; +- (id)initWithURL:(id)_url; - (id)initWithHost:(id)_host; - (id)initWithAddress:(id)_address; @@ -64,6 +76,11 @@ typedef enum { - (id)socket; - (id)address; +/* exceptions */ + +- (NSException *)lastException; +- (void)resetLastException; + /* connection */ - (NSDictionary *)openConnection; @@ -76,11 +93,11 @@ typedef enum { - (NSDictionary *)login:(NSString *)_login password:(NSString *)_passwd; - (NSDictionary *)logout; -- (NSDictionary *)getScript:(NSString *)_scriptName; +- (NSString *)getScript:(NSString *)_scriptName; - (NSDictionary *)putScript:(NSString *)_name script:(NSString *)_script; - (NSDictionary *)setActiveScript:(NSString *)_name; - (NSDictionary *)deleteScript:(NSString *)_script; -- (NSDictionary *)listScript:(NSString *)_script; +- (NSDictionary *)listScripts; /* equality */ diff --git a/sope-mime/NGImap4/NGSieveClient.m b/sope-mime/NGImap4/NGSieveClient.m index 4d4a8d43..d3478d61 100644 --- a/sope-mime/NGImap4/NGSieveClient.m +++ b/sope-mime/NGImap4/NGSieveClient.m @@ -30,16 +30,22 @@ @interface NGSieveClient(Private) -- (NGHashMap *)processCommand:(NSString *)_command; -- (NGHashMap *)processCommand:(NSString *)_command logText:(NSString *)_txt; +- (NGHashMap *)processCommand:(id)_command; +- (NGHashMap *)processCommand:(id)_command logText:(id)_txt; -- (void)sendCommand:(NSString *)_command; -- (void)sendCommand:(NSString *)_command logText:(NSString *)_txt; +- (NSException *)sendCommand:(id)_command; +- (NSException *)sendCommand:(id)_command logText:(id)_txt; +- (NSException *)sendCommand:(id)_command logText:(id)_txt attempts:(int)_c; - (NSMutableDictionary *)normalizeResponse:(NGHashMap *)_map; - (NSMutableDictionary *)normalizeOpenConnectionResponse:(NGHashMap *)_map; - (NSDictionary *)login; +/* parsing */ + +- (NSString *)readStringToCRLF; +- (NSString *)readString; + @end /* @@ -85,15 +91,48 @@ static BOOL debugImap4 = NO; NoNumber = [[NSNumber numberWithBool:NO] retain]; } ++ (id)clientWithURL:(id)_url { + return [[[self alloc] initWithURL:_url] autorelease]; +} + + (id)clientWithAddress:(id)_address { - return - [[(NGSieveClient *)[self alloc] initWithAddress:_address] autorelease]; + NGSieveClient *client; + + client = [self alloc]; + return [[client initWithAddress:_address] autorelease]; } + (id)clientWithHost:(id)_host { return [[[self alloc] initWithHost:_host] autorelease]; } +- (id)initWithNSURL:(NSURL *)_url { + NGInternetSocketAddress *a; + int port; + + if ((port = [[_url port] intValue]) == 0) + port = defaultSievePort; + + a = [NGInternetSocketAddress addressWithPort:port + onHost:[_url host]]; + if ((self = [self initWithAddress:a])) { + self->login = [[_url user] copy]; + self->password = [[_url password] copy]; + } + return self; +} +- (id)initWithURL:(id)_url { + if (_url == nil) { + [self release]; + return nil; + } + + if (![_url isKindOfClass:[NSURL class]]) + _url = [NSURL URLWithString:[_url stringValue]]; + + return [self initWithNSURL:_url]; +} + - (id)initWithHost:(id)_host { NGInternetSocketAddress *a; @@ -104,14 +143,15 @@ static BOOL debugImap4 = NO; - (id)initWithAddress:(id)_address { // di if ((self = [super init])) { self->address = [_address retain]; - self->debug = debugImap4; + self->debug = debugImap4; } return self; } - (void)dealloc { - [self->text release]; + [self->lastException release]; [self->address release]; + [self->io release]; [self->socket release]; [self->parser release]; [self->login release]; @@ -145,9 +185,26 @@ static BOOL debugImap4 = NO; return self->address; } +/* exceptions */ + +- (void)setLastException:(NSException *)_ex { + ASSIGN(self->lastException, _ex); +} +- (NSException *)lastException { + return self->lastException; +} +- (void)resetLastException { + [self->lastException release]; + self->lastException = nil; +} + /* connection */ -/* Opens a connection to given Host. */ +- (void)resetStreams { + [self->socket release]; self->socket = nil; + [self->io release]; self->io = nil; + [self->parser release]; self->parser = nil; +} - (NSDictionary *)openConnection { struct timeval tv; @@ -157,15 +214,17 @@ static BOOL debugImap4 = NO; gettimeofday(&tv, NULL); ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0); } - - [self->socket release]; self->socket = nil; - [self->parser release]; self->parser = nil; - [self->text release]; self->text = nil; + + [self resetStreams]; self->socket = [[NGActiveSocket socketConnectedToAddress:self->address] retain]; - self->text = - [(NGCTextStream *)[NGCTextStream alloc] initWithSource:self->socket]; + if (self->socket == nil) { + [self logWithFormat:@"ERROR: could not connect: %@", self->address]; + return nil; + } + + self->io = [[NGBufferedStream alloc] initWithSource:self->socket]; self->parser = [[NGImap4ResponseParser alloc] initWithStream:self->socket]; /* receive greeting from server without tag-id */ @@ -180,30 +239,26 @@ static BOOL debugImap4 = NO; [self->parser parseSieveResponse]]; } -/*" -** Check whether stream is already open (could be closed because server-timeout) -"*/ - - (NSNumber *)isConnected { + // TODO: why does this return a number?! + /* + Check whether stream is already open (could be closed because + server-timeout + */ return [NSNumber numberWithBool: (self->socket == nil) ? NO : [(NGActiveSocket *)self->socket isAlive]]; } -/*" -** Close a consisting connection. -"*/ - - (void)closeConnection { [self->socket close]; [self->socket release]; self->socket = nil; - [self->text release]; self->text = nil; [self->parser release]; self->parser = nil; } -/* login with plaintext password authenticating */ - - (NSDictionary *)login:(NSString *)_login password:(NSString *)_passwd { + /* login with plaintext password authenticating */ + if ((_login == nil) || (_passwd == nil)) return nil; @@ -226,13 +281,21 @@ static BOOL debugImap4 = NO; NSData *auth; char *buf; int bufLen, logLen; - - + + if (![self->socket isConnected]) { + id con; + + if ((con = [self openConnection]) == nil) + return nil; + if (![[con objectForKey:@"result"] boolValue]) + return con; + } + logLen = [self->login cStringLength]; bufLen = (logLen * 2) + [self->password cStringLength] +2; - buf = calloc(sizeof(char), bufLen); - + buf = calloc(bufLen + 2, sizeof(char)); + sprintf(buf, "%s %s %s", [self->login cString], [self->login cString], [self->password cString]); @@ -245,7 +308,7 @@ static BOOL debugImap4 = NO; if (LOG_PASSWORD == 1) { NSString *s; - + s = [NSString stringWithFormat:@"AUTHENTICATE \"PLAIN\" {%d+}\r\n%s", [auth length], [auth bytes]]; map = [self processCommand:s]; @@ -258,7 +321,7 @@ static BOOL debugImap4 = NO; map = [self processCommand:s logText:@"AUTHENTICATE \"PLAIN\" {%d+}\r\nLOGIN:PASSWORD\r\n"]; } - return [self normalizeResponse:map]; + return map ? [self normalizeResponse:map] : nil; } /* logout from the connected host and close the connection */ @@ -271,10 +334,46 @@ static BOOL debugImap4 = NO; return [self normalizeResponse:map]; } -- (NSDictionary *)getScript:(NSString *)_scriptName { - // TODO: implement - [self notImplemented:_cmd]; - return nil; +- (NSString *)getScript:(NSString *)_scriptName { + NSException *ex; + NSString *script, *s; + + s = [@"GETSCRIPT \"" stringByAppendingString:_scriptName]; + s = [s stringByAppendingString:@"\""]; + ex = [self sendCommand:s logText:s attempts:3]; + if (ex != nil) { + [self logWithFormat:@"ERROR: could not get script: %@", ex]; + [self setLastException:ex]; + return nil; + } + + /* read script string */ + + if ((script = [[self readString] autorelease]) == nil) + return nil; + + /* read response code */ + + if ((s = [self readStringToCRLF]) == nil) { + [self logWithFormat:@"ERROR: could not parse status line."]; + return nil; + } + if ([s length] == 0) { // remainder of previous string + [s release]; + if ((s = [self readStringToCRLF]) == nil) { + [self logWithFormat:@"ERROR: could not parse status line."]; + return nil; + } + } + + if (![s hasPrefix:@"OK"]) { + [self logWithFormat:@"ERROR: status line reports: '%@'", s]; + [s release]; + return nil; + } + [s release]; + + return script; } - (BOOL)isValidScriptName:(NSString *)_name { @@ -324,24 +423,79 @@ static BOOL debugImap4 = NO; NSLog(@"%s: missing script-name", __PRETTY_FUNCTION__); return nil; } - + s = [NSString stringWithFormat:@"DELETESCRIPT \"%@\"\r\n", _name]; map = [self processCommand:s]; return [self normalizeResponse:map]; } -- (NSDictionary *)listScript:(NSString *)_script { - [self notImplemented:_cmd]; - return nil; + +- (NSDictionary *)listScripts { + NSMutableDictionary *md; + NSException *ex; + NSString *line; + + ex = [self sendCommand:@"LISTSCRIPTS" logText:@"LISTSCRIPTS" attempts:3]; + if (ex != nil) { + [self logWithFormat:@"ERROR: could not list scripts: %@", ex]; + [self setLastException:ex]; + return nil; + } + + /* read response */ + + md = [NSMutableDictionary dictionaryWithCapacity:16]; + while ((line = [self readStringToCRLF]) != nil) { + if ([line hasPrefix:@"OK"]) + break; + + if ([line hasPrefix:@"NO"]) { + md = nil; + break; + } + + if ([line hasPrefix:@"{"]) { + [self logWithFormat:@"unsupported list response line: '%@'", line]; + } + else if ([line hasPrefix:@"\""]) { + NSString *s; + NSRange r; + BOOL isActive; + + s = [line substringFromIndex:1]; + r = [s rangeOfString:@"\""]; + + if (r.length == 0) { + [self logWithFormat:@"missing closing quote in line: '%@'", line]; + [line release]; line = nil; + continue; + } + + s = [s substringToIndex:r.location]; + isActive = [line rangeOfString:@"ACTIVE"].length == 0 ? NO : YES; + + [md setObject:isActive ? @"ACTIVE" : @"" forKey:s]; + } + else { + [self logWithFormat:@"unexpected list response line (%d): '%@'", + [line length], line]; + } + + [line release]; line = nil; + } + + [line release]; line = nil; + + return md; } /* -** Filter for all responses -** result : NSNumber (response result) -** exists : NSNumber (number of exists mails in selectet folder -** recent : NSNumber (number of recent mails in selectet folder -** expunge : NSArray (message sequence number of expunged mails - in selectet folder) + Filter for all responses + result : NSNumber (response result) + exists : NSNumber (number of exists mails in selectet folder + recent : NSNumber (number of recent mails in selectet folder + expunge : NSArray (message sequence number of expunged mails + in selectet folder) */ - (NSMutableDictionary *)normalizeResponse:(NGHashMap *)_map { @@ -355,14 +509,12 @@ static BOOL debugImap4 = NO; forKeys:keys count:2]; } -/* -** filter for open connection -*/ - (NSDictionary *)normalizeOpenConnectionResponse:(NGHashMap *)_map { + /* filter for open connection */ NSMutableDictionary *result; NSString *tmp; - + result = [self normalizeResponse:_map]; if (![[[_map objectEnumeratorForKey:@"ok"] nextObject] boolValue]) @@ -375,18 +527,6 @@ static BOOL debugImap4 = NO; return result; } - - -/* -** filter for list -** list : NSDictionary (folder name as key and flags as value) -*/ - -- (NSString *)description { - return [NSString stringWithFormat:@"", - (unsigned)self, [self socket]]; -} - /* Private Methods */ - (BOOL)handleProcessException:(NSException *)_exception @@ -424,13 +564,13 @@ static BOOL debugImap4 = NO; [self logWithFormat:@"reconnect ..."]; } -- (NGHashMap *)processCommand:(NSString *)_command logText:(NSString *)_txt { +- (NGHashMap *)processCommand:(id)_command logText:(id)_txt { NGHashMap *map = nil; BOOL repeatCommand = NO; int repeatCnt = 0; struct timeval tv; double ti = 0.0; - + if (ProfileImapEnabled) { gettimeofday(&tv, NULL); ti = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0); @@ -447,8 +587,14 @@ static BOOL debugImap4 = NO; } NS_DURING { - [self sendCommand:_command logText:_txt]; - map = [self->parser parseSieveResponse]; + NSException *ex; + + if ((ex = [self sendCommand:_command logText:_txt]) != nil) { + repeatCommand = [self handleProcessException:ex + repetitionCount:repeatCnt]; + } + else + map = [self->parser parseSieveResponse]; } NS_HANDLER { repeatCommand = [self handleProcessException:localException @@ -468,26 +614,233 @@ static BOOL debugImap4 = NO; return map; } -- (NGHashMap *)processCommand:(NSString *)_command { +- (NGHashMap *)processCommand:(id)_command { return [self processCommand:_command logText:_command]; } -- (void)sendCommand:(NSString *)_command logText:(NSString *)_txt { - // TODO: should accept 'NSData' commands +- (NSException *)sendCommand:(id)_command logText:(id)_txt { NSString *command = nil; - command = _command; + if ((command = _command) == nil) /* missing command */ + return nil; // TODO: return exception? + + /* log */ + + if (self->debug) { + if ([_txt isKindOfClass:[NSData class]]) { + fprintf(stderr, "C: "); + fwrite([_txt bytes], [_txt length], 1, stderr); + fputc('\n', stderr); + } + else + fprintf(stderr, "C: %s\n", [_txt cString]); + } + + /* write */ + + if (![_command isKindOfClass:[NSData class]]) + _command = [command dataUsingEncoding:NSUTF8StringEncoding]; + + if (![self->io safeWriteData:_command]) + return [self->io lastException]; + if (![self->io writeBytes:"\r\n" count:2]) + return [self->io lastException]; + if (![self->io flush]) + return [self->io lastException]; + + return nil; +} + +- (NSException *)sendCommand:(id)_command { + return [self sendCommand:_command logText:_command]; +} + +- (NSException *)sendCommand:(id)_command logText:(id)_txt attempts:(int)_c { + NSException *ex; + BOOL tryAgain; + int repeatCnt; + + for (tryAgain = YES, repeatCnt = 0, ex = nil; tryAgain; repeatCnt++) { + if (repeatCnt > 0) { + if (repeatCnt > 1) /* one repeat goes without delay */ + [self waitPriorReconnectWithRepetitionCount:repeatCnt]; + [self reconnect]; + tryAgain = NO; + } + + NS_DURING + ex = [self sendCommand:_command logText:_txt]; + NS_HANDLER + ex = [localException retain]; + NS_ENDHANDLER; + + if (ex == nil) /* everything is fine */ + break; + + if (repeatCnt > _c) /* reached max attempts */ + break; + + /* try again for certain exceptions */ + tryAgain = [self handleProcessException:ex repetitionCount:repeatCnt]; + } + + return ex; +} + +/* low level */ + +- (int)readByte { + unsigned char c; + + if (![self->io readBytes:&c count:1]) { + [self setLastException:[self->io lastException]]; + return -1; + } + return c; +} + +- (NSString *)readLiteral { + /* + Assumes 1st char is consumed, returns a retained string. + + Parses: "{" number [ "+" ] "}" CRLF *OCTET + */ + unsigned char countBuf[16]; + int i; + unsigned byteCount; + unsigned char *octets; + + /* read count */ - if (self->debug) - fprintf(stderr, "C: %s\n", [_txt cString]); + for (i = 0; i < 14; i++) { + int c; + + if ((c = [self readByte]) == -1) + return nil; + if (c == '}') + break; + + countBuf[i] = c; + } + countBuf[i] = '\0'; + byteCount = i > 0 ? atoi(countBuf) : 0; + + /* read CRLF */ + + i = [self readByte]; + if (i != '\n') { + if (i == '\r' && i != -1) + i = [self readByte]; + if (i == -1) + return nil; + } + + /* read octet */ + + if (byteCount == 0) + return @""; + + octets = malloc(byteCount + 4); + if (![self->io safeReadBytes:octets count:byteCount]) { + [self setLastException:[self->io lastException]]; + return nil; + } + octets[byteCount] = '\0'; - [self->text writeString:command]; - [self->text writeString:@"\r\n"]; - [self->text flush]; + return [[NSString alloc] initWithUTF8String:octets]; } -- (void)sendCommand:(NSString *)_command { - [self sendCommand:_command logText:_command]; +- (NSString *)readQuoted { + /* + assumes 1st char is consumed, returns a retained string + + Note: quoted strings are limited to 1KB! + */ + unsigned char buf[1032]; + int i, c; + + i = 0; + do { + c = [self readByte]; + buf[i] = c; + i++; + } + while ((c != -1) && (c != '"')); + buf[i] = '\0'; + + if (c == -1) + return nil; + + return [[NSString alloc] initWithUTF8String:buf]; +} + +- (NSString *)readStringToCRLF { + unsigned char buf[1032]; + int i, c; + + i = 0; + do { + c = [self readByte]; + if (c == '\n' || c == '\r') + break; + + buf[i] = c; + i++; + } + while ((c != -1) && (c != '\r') && (c != '\n') && (i < 1024)); + buf[i] = '\0'; + + if (c == -1) + return nil; + + /* consume CRLF */ + if (c == '\r') { + if ((c = [self readByte]) != '\n') { + if (c == -1) + return nil; + [self logWithFormat:@"WARNING(%s): expected LF after CR, got: '%c'", + __PRETTY_FUNCTION__, c]; + return nil; + } + } + + return [[NSString alloc] initWithUTF8String:buf]; +} + +- (NSString *)readString { + /* Note: returns a retained string */ + int c1; + + if ((c1 = [self readByte]) == -1) + return nil; + + if (c1 == '"') + return [self readQuoted]; + if (c1 == '{') + return [self readLiteral]; + + return [self readStringToCRLF]; +} + +- (NSString *)readSieveName { + return [self readString]; +} + +/* description */ + +- (NSString *)description { + NSMutableString *ms; + + ms = [NSMutableString stringWithCapacity:128]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + + if (self->socket != nil) + [ms appendFormat:@" socket=%@", [self socket]]; + else + [ms appendFormat:@" address=%@", self->address]; + + [ms appendString:@">"]; + return ms; } @end /* NGSieveClient */ diff --git a/sope-mime/Version b/sope-mime/Version index 31c4d5bd..51cb919c 100644 --- a/sope-mime/Version +++ b/sope-mime/Version @@ -2,6 +2,6 @@ MAJOR_VERSION:=4 MINOR_VERSION:=5 -SUBMINOR_VERSION:=200 +SUBMINOR_VERSION:=201 # v4.2.149 requires libNGStreams v4.2.34 diff --git a/sope-mime/samples/GNUmakefile b/sope-mime/samples/GNUmakefile index 8eeceeb2..08a12f41 100644 --- a/sope-mime/samples/GNUmakefile +++ b/sope-mime/samples/GNUmakefile @@ -8,7 +8,8 @@ TOOL_NAME = \ imapls \ test_qpdecode \ imapquota \ - imap_tool + imap_tool \ + sievetool imapquota_OBJC_FILES = ImapQuotaTool.m ImapTool.m imapquota.m imapget_OBJC_FILES = ImapTool.m imapget.m @@ -16,6 +17,7 @@ imap_tool_OBJC_FILES = imap_tool.m mime2xml_OBJC_FILES = Mime2XmlTool.m mime2xml.m imapls_OBJC_FILES = ImapTool.m ImapListTool.m imapls.m test_qpdecode_OBJC_FILES = test_qpdecode.m +sievetool_OBJC_FILES = sievetool.m -include GNUmakefile.preamble include $(GNUSTEP_MAKEFILES)/tool.make diff --git a/sope-mime/samples/ImapTool.h b/sope-mime/samples/ImapTool.h index 0181b3a9..6fef3031 100644 --- a/sope-mime/samples/ImapTool.h +++ b/sope-mime/samples/ImapTool.h @@ -1,7 +1,7 @@ /* - Copyright (C) 2000-2003 SKYRIX Software AG + Copyright (C) 2000-2004 SKYRIX Software AG - This file is part of OGo + This file is part of OpenGroupware.org. OGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the @@ -30,7 +30,13 @@ { NGImap4FileManager *fileManager; } + +/* operations */ + - (void)flush; + +/* accessors */ + - (NGImap4FileManager *)fileManager; @end diff --git a/sope-mime/samples/Mime2XmlTool.h b/sope-mime/samples/Mime2XmlTool.h index 30c8d11d..d5a169b0 100644 --- a/sope-mime/samples/Mime2XmlTool.h +++ b/sope-mime/samples/Mime2XmlTool.h @@ -1,7 +1,7 @@ /* - Copyright (C) 2000-2003 SKYRIX Software AG + Copyright (C) 2000-2004 SKYRIX Software AG - This file is part of OGo + This file is part of OpenGroupware.org. OGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #import diff --git a/sope-mime/samples/sievetool.m b/sope-mime/samples/sievetool.m new file mode 100644 index 00000000..1fde51fa --- /dev/null +++ b/sope-mime/samples/sievetool.m @@ -0,0 +1,95 @@ +/* + Copyright (C) 2004 Helge Hess + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo 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 Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include +#include "common.h" + +static NSURL *getDefaultsURL(void) { + NSUserDefaults *ud; + NSString *pwd, *user, *host; + NSString *url; + + ud = [NSUserDefaults standardUserDefaults]; + + if ((url = [ud stringForKey:@"url"]) != nil) + return [NSURL URLWithString:url]; + + user = [ud stringForKey:@"user"]; + pwd = [ud stringForKey:@"password"]; + host = [ud stringForKey:@"host"]; + + url = [@"http://" stringByAppendingString:user]; + url = [url stringByAppendingString:@":"]; + url = [url stringByAppendingString:pwd]; + url = [url stringByAppendingString:@"@"]; + url = [url stringByAppendingString:host]; + url = [url stringByAppendingString:@":2000/"]; + return [NSURL URLWithString:url]; +} + +static int test(NSArray *args) { + NSUserDefaults *ud; + NGSieveClient *client; + NSURL *url; + id res; + + ud = [NSUserDefaults standardUserDefaults]; + + url = getDefaultsURL(); + NSLog(@"check URL: %@", url); + + client = [[NGSieveClient alloc] initWithURL:url]; + NSLog(@" client: %@", client); + + if ((res = [client login:[url user] password:[url password]]) == nil) { + NSLog(@"could not login %@: %@", [url user], client); + return 1; + } + + NSLog(@" login %@: %@", [url user], res); + NSLog(@" client: %@", client); + + res = [client listScripts]; + NSLog(@" list: %@", res); + + res = [client getScript:@"ogo"]; + NSLog(@" get 'ogo': %@", res); + + return 0; +} + +int main(int argc, char **argv, char **env) { + NSAutoreleasePool *pool; + int res; + + pool = [NSAutoreleasePool new]; +#if LIB_FOUNDATION_LIBRARY + [NSProcessInfo initializeWithArguments:argv count:argc environment:env]; +#endif + + res = test([[NSProcessInfo processInfo] argumentsWithoutDefaults]); + + [pool release]; + exit(0); + /* static linking */ + [NGExtensions class]; + return 0; +}