From 3a357aaeb74a99eadc507389bd42441644a7e5d8 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Thu, 22 Sep 2011 23:45:33 +0000 Subject: [PATCH] Monotone-Parent: 657851bad9f402262a82eecf7afa3cedf45d780d Monotone-Revision: 25091cd75733e2785b3cd2550afa96d2cb4af894 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-09-22T23:45:33 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 11 + OpenChange/GNUmakefile | 4 + OpenChange/MAPIStoreMailFolder.m | 20 ++ OpenChange/MAPIStoreMemMailMessage.h | 32 +++ OpenChange/MAPIStoreMemMailMessage.m | 319 +++++++++++++++++++++++++++ OpenChange/SOGoMemMessage.h | 38 ++++ OpenChange/SOGoMemMessage.m | 56 +++++ 7 files changed, 480 insertions(+) create mode 100644 OpenChange/MAPIStoreMemMailMessage.h create mode 100644 OpenChange/MAPIStoreMemMailMessage.m create mode 100644 OpenChange/SOGoMemMessage.h create mode 100644 OpenChange/SOGoMemMessage.m diff --git a/ChangeLog b/ChangeLog index 26dd1567a..d5883804a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2011-09-22 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailFolder.m (-createMessage): return a MAPIStoreMemMailMessage. + + * OpenChange/SOGoMemMessage.m: new class that only provides a + temporary (memory-based) dictionary of Exchange attributes. + Similar to SOGoMAPIFSMessage except for the ability to save the + dictionary in question. + + * OpenChange/MAPIStoreMemMailMessage.m: new class that enables the + saving of composed mail messages, during the different copy + operations. + * OpenChange/MAPIStoreDraftsMessage.m (-getPrChangeKey) (-getPrPredecessorChangeList:inMemCtx:): return MAPISTORE_ERR_NOT_FOUND. diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 99088f3c6..6ad2e8d4b 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -112,6 +112,10 @@ $(SOGOBACKEND)_OBJC_FILES += \ \ EOBitmaskQualifier.m \ EOQualifier+MAPIFS.m \ + \ + SOGoMemMessage.m \ + MAPIStoreMemMailMessage.m \ + $(SOGOBACKEND)_RESOURCE_FILES += \ product.plist diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index f3dafe354..30072a219 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -57,6 +57,11 @@ #import "NSString+MAPIStore.h" #import "SOGoMAPIFSMessage.h" +/* Those are parts of a hack that enables creating mails to IMAP folders from + Exchange properties */ +#import "SOGoMemMessage.h" +#import "MAPIStoreMemMailMessage.h" + #import "MAPIStoreMailFolder.h" static Class MAPIStoreDraftsMessageK; @@ -966,6 +971,21 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) return MAPISTORE_SUCCESS; } +/* FIXME: this method makes use of the hacky MAPIStoreMemMailMessage */ +- (MAPIStoreMessage *) createMessage +{ + MAPIStoreDraftsMessage *newMessage; + SOGoMemMessage *newObject; + + newObject = [SOGoMemMessage + objectWithName: [SOGoObject globallyUniqueObjectId] + inContainer: sogoObject]; + newMessage + = [MAPIStoreMemMailMessage mapiStoreObjectWithSOGoObject: newObject + inContainer: self]; + + return newMessage; +} @end diff --git a/OpenChange/MAPIStoreMemMailMessage.h b/OpenChange/MAPIStoreMemMailMessage.h new file mode 100644 index 000000000..452959aa8 --- /dev/null +++ b/OpenChange/MAPIStoreMemMailMessage.h @@ -0,0 +1,32 @@ +/* MAPIStoreMemMailMessage.h - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 3, 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. + */ + +#ifndef MAPISTOREMEMMAILMESSAGE_H +#define MAPISTOREMEMMAILMESSAGE_H + +#import "MAPIStoreMessage.h" + +@interface MAPIStoreMemMailMessage : MAPIStoreMessage + +@end + +#endif /* MAPISTOREMEMMAILMESSAGE_H */ diff --git a/OpenChange/MAPIStoreMemMailMessage.m b/OpenChange/MAPIStoreMemMailMessage.m new file mode 100644 index 000000000..0cbb49265 --- /dev/null +++ b/OpenChange/MAPIStoreMemMailMessage.m @@ -0,0 +1,319 @@ +/* MAPIStoreMemMailMessage.m - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 3, 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 +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "MAPIStoreMapping.h" +#import "MAPIStoreContext.h" +#import "MAPIStoreTypes.h" +#import "NSObject+MAPIStore.h" +#import "NSString+MAPIStore.h" +#import "SOGoMemMessage.h" + +#import "MAPIStoreMemMailMessage.h" + +#undef DEBUG +#include +#include + +Class NSNumberK; + +@implementation MAPIStoreMemMailMessage + ++ (void) initialize +{ + NSNumberK = [NSNumber class]; +} + +- (int) setProperties: (struct SRow *) aRow +{ + int rc; + + rc = [super setProperties: aRow]; + if (rc == MAPISTORE_SUCCESS) + { + [sogoObject appendProperties: newProperties]; + [newProperties removeAllObjects]; + } + + return rc; +} + +- (int) getProperty: (void **) data + withTag: (enum MAPITAGS) propTag + inMemCtx: (TALLOC_CTX *) memCtx +{ + id value; + int rc; + + value = [[sogoObject properties] objectForKey: MAPIPropertyKey (propTag)]; + if (value) + rc = [value getMAPIValue: data forTag: propTag inMemCtx: memCtx]; + else + rc = [super getProperty: data withTag: propTag inMemCtx: memCtx]; + + return rc; +} + +- (int) getPrMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [@"IPM.Note" asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSArray *keys; + NSUInteger count, max; + NSString *key; + struct SPropTagArray *properties; + + keys = [[sogoObject properties] allKeys]; + max = [keys count]; + + properties = talloc_zero (NULL, struct SPropTagArray); + properties->cValues = max; + properties->aulPropTag = talloc_array (properties, enum MAPITAGS, max); + for (count = 0; count < max; count++) + { + key = [keys objectAtIndex: count]; + if ([key isKindOfClass: NSNumberK]) + { +#if (GS_SIZEOF_LONG == 4) + properties->aulPropTag[count] = [[keys objectAtIndex: count] unsignedLongValue]; +#elif (GS_SIZEOF_INT == 4) + properties->aulPropTag[count] = [[keys objectAtIndex: count] unsignedIntValue]; +#endif + } + } + + *propertiesP = properties; + + return MAPISTORE_SUCCESS; +} + +- (NSArray *) attachmentsKeysMatchingQualifier: (EOQualifier *) qualifier + andSortOrderings: (NSArray *) sortOrderings +{ + NSDictionary *attachments; + NSArray *keys; + NSString *key, *newKey; + NSUInteger count, max, aid; + MAPIStoreAttachment *attachment; + + attachments = [[sogoObject properties] objectForKey: @"attachments"]; + keys = [attachments allKeys]; + max = [keys count]; + if (max > 0) + { + aid = [keys count]; + for (count = 0; count < max; count++) + { + key = [keys objectAtIndex: count]; + attachment = [attachments objectForKey: key]; + newKey = [NSString stringWithFormat: @"%ul", (aid + count)]; + [attachmentParts setObject: attachment forKey: newKey]; + } + } + + return [super attachmentKeysMatchingQualifier: qualifier + andSortOrderings: sortOrderings]; +} + +/* FIXME: copied from SOGoDraftMessage... */ +- (NSString *) _quoteSpecials: (NSString *) address +{ + NSString *result, *part, *s2; + int i, len; + + // We want to correctly send mails to recipients such as : + // foo.bar + // foo (bar) + // bar, foo + if ([address indexOf: '('] >= 0 || [address indexOf: ')'] >= 0 + || [address indexOf: '<'] >= 0 || [address indexOf: '>'] >= 0 + || [address indexOf: '@'] >= 0 || [address indexOf: ','] >= 0 + || [address indexOf: ';'] >= 0 || [address indexOf: ':'] >= 0 + || [address indexOf: '\\'] >= 0 || [address indexOf: '"'] >= 0 + || [address indexOf: '.'] >= 0 + || [address indexOf: '['] >= 0 || [address indexOf: ']'] >= 0) + { + // We search for the first instance of < from the end + // and we quote what was before if we need to + len = [address length]; + i = -1; + while (len--) + if ([address characterAtIndex: len] == '<') + { + i = len; + break; + } + + if (i > 0) + { + part = [address substringToIndex: i - 1]; + s2 = [[part stringByReplacingString: @"\\" withString: @"\\\\"] + stringByReplacingString: @"\"" withString: @"\\\""]; + result = [NSString stringWithFormat: @"\"%@\" %@", s2, [address substringFromIndex: i]]; + } + else + { + s2 = [[address stringByReplacingString: @"\\" withString: @"\\\\"] + stringByReplacingString: @"\"" withString: @"\\\""]; + result = [NSString stringWithFormat: @"\"%@\"", s2]; + } + } + else + result = address; + + return result; +} + + +- (void) save +{ + NSDictionary *properties; + NSString *from, *to, *messageId, *subject, *body, *folderName, *flag, + *newIdString, *charset; + NSNumber *codePage; + NSCalendarDate *date; + NGMimeMessage *message; + NGMutableHashMap *map; + NGMimeMessageGenerator *generator; + NSData *htmlData, *messageData; + NGImap4Connection *connection; + NGImap4Client *client; + SOGoMailFolder *containerFolder; + NSDictionary *result, *responseResult; + MAPIStoreMapping *mapping; + uint64_t mid; + + properties = [sogoObject properties]; + + /* headers */ + from = [self _quoteSpecials: [properties objectForKey: MAPIPropertyKey (PR_SENT_REPRESENTING_EMAIL_ADDRESS_UNICODE)]]; + to = [self _quoteSpecials: [properties objectForKey: MAPIPropertyKey (PR_DISPLAY_TO_UNICODE)]]; + subject = [properties objectForKey: MAPIPropertyKey (PR_SUBJECT_UNICODE)]; + date = [properties objectForKey: MAPIPropertyKey (PR_CLIENT_SUBMIT_TIME)]; + messageId = [properties objectForKey: MAPIPropertyKey (PR_INTERNET_MESSAGE_ID_UNICODE)]; + + map = [[[NGMutableHashMap alloc] initWithCapacity:16] autorelease]; + if ([to length]) + [map setObject: to forKey: @"to"]; + if ([from length]) + [map setObject: from forKey: @"from"]; + if ([subject length]) + [map setObject: [subject asQPSubjectString: @"utf-8"] + forKey: @"subject"]; + if ([messageId length]) + [map setObject: messageId forKey: @"message-id"]; + if (date) + [map addObject: [date rfc822DateString] forKey: @"date"]; + [map addObject: @"1.0" forKey: @"MIME-Version"]; + + message = [[[NGMimeMessage alloc] initWithHeader: map] autorelease]; + + /* body */ + htmlData = [properties objectForKey: MAPIPropertyKey (PR_HTML)]; + if (htmlData) + { + /* charset */ + charset = @"us-ascii"; + codePage = [properties objectForKey: MAPIPropertyKey (PR_INTERNET_CPID)]; + switch ([codePage intValue]) + { + case 20127: + charset = @"us-ascii"; + break; + case 28605: + charset = @"iso-8859-15"; + break; + case 65001: + charset = @"utf-8"; + break; + case 28591: + default: + charset = @"iso-8859-1"; + } + + body = [NSString stringWithData: htmlData + usingEncodingNamed: charset]; + [map setObject: [NSString stringWithFormat: @"text/html; charset=%@", + charset] + forKey: @"content-type"]; + [message setBody: body]; + } + else + { + body = [properties objectForKey: MAPIPropertyKey (PR_BODY_UNICODE)]; + if (body) + { + [map setObject: @"text/plain; charset=utf-8" + forKey: @"content-type"]; + [message setBody: body]; + } + } + + /* mime message generation */ + generator = [NGMimeMessageGenerator new]; + messageData = [generator generateMimeFromPart: message]; + [generator release]; + + /* appending to imap folder */ + containerFolder = [container sogoObject]; + connection = [containerFolder imap4Connection]; + client = [connection client]; + folderName = [connection imap4FolderNameForURL: [containerFolder imap4URL]]; + result = [client append: messageData toFolder: folderName + withFlags: [NSArray arrayWithObjects: @"seen", nil]]; + if ([[result objectForKey: @"result"] boolValue]) + { + /* we reregister the new message URL with the id mapper */ + responseResult = [[result objectForKey: @"RawResponse"] + objectForKey: @"ResponseResult"]; + flag = [responseResult objectForKey: @"flag"]; + newIdString = [[flag componentsSeparatedByString: @" "] + objectAtIndex: 2]; + mid = [self objectId]; + mapping = [[self context] mapping]; + [mapping unregisterURLWithID: mid]; + [sogoObject setNameInContainer: [NSString stringWithFormat: @"%@.eml", newIdString]]; + [mapping registerURL: [self url] withID: mid]; + } +} + +@end diff --git a/OpenChange/SOGoMemMessage.h b/OpenChange/SOGoMemMessage.h new file mode 100644 index 000000000..a24892533 --- /dev/null +++ b/OpenChange/SOGoMemMessage.h @@ -0,0 +1,38 @@ +/* SOGoMemMessage.h - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 3, 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. + */ + +#ifndef SOGOMEMMESSAGE_H +#define SOGOMEMMESSAGE_H + +#import + +@interface SOGoMemMessage : SOGoObject +{ + NSMutableDictionary *properties; +} + +- (NSDictionary *) properties; +- (void) appendProperties: (NSDictionary *) newProperties; + +@end + +#endif /* SOGOMEMMESSAGE_H */ diff --git a/OpenChange/SOGoMemMessage.m b/OpenChange/SOGoMemMessage.m new file mode 100644 index 000000000..1ad26e3b1 --- /dev/null +++ b/OpenChange/SOGoMemMessage.m @@ -0,0 +1,56 @@ +/* SOGoMemMessage.m - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 3, 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 + +#import "SOGoMemMessage.h" + +@implementation SOGoMemMessage + +- (id) init +{ + if ((self = [super init])) + { + properties = [NSMutableDictionary new]; + } + + return self; +} + +- (void) dealloc +{ + [properties release]; + [super dealloc]; +} + +- (NSDictionary *) properties +{ + return properties; +} + +- (void) appendProperties: (NSDictionary *) newProperties +{ + [properties addEntriesFromDictionary: newProperties]; +} + + +@end