From 5666149e37a519adb4373ea412d534b8b9ec2eea Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 25 Oct 2011 18:19:08 +0000 Subject: [PATCH] Monotone-Parent: 08c6872fb6a9c8bafc542d62b81e555faf5e1c05 Monotone-Revision: 07f66207968bbc8815cccf3c0b6d5147e13d8ab6 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-10-25T18:19:08 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 ++ OpenChange/GNUmakefile | 1 + OpenChange/MAPIStoreDraftsMessage.m | 16 ++- OpenChange/MAPIStoreMIME.h | 37 +++++++ OpenChange/MAPIStoreMIME.m | 154 ++++++++++++++++++++++++++++ 5 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 OpenChange/MAPIStoreMIME.h create mode 100644 OpenChange/MAPIStoreMIME.m diff --git a/ChangeLog b/ChangeLog index 911f7d29c..5a96d8b58 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2011-10-25 Wolfgang Sourdeau + * OpenChange/MAPIStoreDraftsMessage.m (_saveAttachment:): make use + of MAPIStoreMIME. + + * OpenChange/MAPIStoreMIME.[hm]: new class module implementing a + singleton helper that deduces mime types from file extensions, + based on the content of /etc/mime.types. + * OpenChange/MAPIStoreAttachment.m, OpenChange/MAPIStoreCalendarAttachment.m, OpenChange/MAPIStoreMailAttachment.m: replaced the diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 39d012e6f..86ad9ab7d 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -30,6 +30,7 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreActiveTables.m \ MAPIStoreAuthenticator.m \ MAPIStoreMapping.m \ + MAPIStoreMIME.m \ MAPIStoreTypes.m \ MAPIStorePropertySelectors.m \ \ diff --git a/OpenChange/MAPIStoreDraftsMessage.m b/OpenChange/MAPIStoreDraftsMessage.m index 14663ebf3..47f3fe57e 100644 --- a/OpenChange/MAPIStoreDraftsMessage.m +++ b/OpenChange/MAPIStoreDraftsMessage.m @@ -35,6 +35,7 @@ #import "MAPIStoreContext.h" #import "MAPIStoreMapping.h" +#import "MAPIStoreMIME.h" #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" #import "NSObject+MAPIStore.h" @@ -337,10 +338,6 @@ typedef void (*getMessageData_inMemCtx_) (MAPIStoreMessage *, SEL, attachment = [attachmentParts objectForKey: attachmentKey]; properties = [attachment newProperties]; - mimeType = [properties - objectForKey: MAPIPropertyKey (PR_ATTACH_MIME_TAG_UNICODE)]; - if (!mimeType) - mimeType = @"application/octet-stream"; filename = [properties objectForKey: MAPIPropertyKey (PR_ATTACH_LONG_FILENAME_UNICODE)]; @@ -353,6 +350,14 @@ typedef void (*getMessageData_inMemCtx_) (MAPIStoreMessage *, SEL, filename = @"untitled.bin"; } + mimeType = [properties + objectForKey: MAPIPropertyKey (PR_ATTACH_MIME_TAG_UNICODE)]; + if (!mimeType) + mimeType = [[MAPIStoreMIME sharedMAPIStoreMIME] + mimeTypeForExtension: [filename pathExtension]]; + if (!mimeType) + mimeType = @"application/octet-stream"; + content = [properties objectForKey: MAPIPropertyKey (PR_ATTACH_DATA_BIN)]; if (content) { @@ -614,7 +619,8 @@ e) [self logWithFormat: @"sending message"]; [self _commitProperties]; error = [(SOGoDraftObject *) sogoObject sendMailAndCopyToSent: NO]; - [self errorWithFormat: @"an exception occurred: %@", error]; + if (error) + [self errorWithFormat: @"an exception occurred: %@", error]; } else [self logWithFormat: @"ignored scheduling message"]; diff --git a/OpenChange/MAPIStoreMIME.h b/OpenChange/MAPIStoreMIME.h new file mode 100644 index 000000000..427868fca --- /dev/null +++ b/OpenChange/MAPIStoreMIME.h @@ -0,0 +1,37 @@ +/* MAPIStoreMIME.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 MAPISTOREMIME_H +#define MAPISTOREMIME_H + +@interface MAPIStoreMIME : NSObject +{ + NSMutableDictionary *mimeDict; +} + ++ (id) sharedMAPIStoreMIME; + +- (NSString *) mimeTypeForExtension: (NSString *) extension; + +@end + +#endif /* MAPISTOREMIME_H */ diff --git a/OpenChange/MAPIStoreMIME.m b/OpenChange/MAPIStoreMIME.m new file mode 100644 index 000000000..b23f660e2 --- /dev/null +++ b/OpenChange/MAPIStoreMIME.m @@ -0,0 +1,154 @@ +/* MAPIStoreMIME.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 "MAPIStoreMIME.h" + +/* Seems common to all distros ? */ +#define MAPIStoreMIMEFile @"/etc/mime.types" + +@implementation MAPIStoreMIME + ++ (id) sharedMAPIStoreMIME +{ + static MAPIStoreMIME *sharedInstance = nil; + + if (!sharedInstance) + sharedInstance = [self new]; + + return sharedInstance; +} + +- (void) _parseLine: (const char *) line + withLength: (NSUInteger) length +{ + NSUInteger count = 0, lastWord = 0; + NSString *mimeType = nil, *word; + NSData *wordData; + BOOL comment = NO; + + while (count < length && !comment) + { + while (count < length + && (line[count] == ' ' || line[count] == '\t')) + count++; + lastWord = count; + while (count < length + && line[count] != ' ' && line[count] != '\t' + && !comment) + { + if (line[count] == '#') + comment = YES; + else + count++; + } + if (count > lastWord) + { + wordData = [NSData dataWithBytes: line + lastWord + length: count - lastWord]; + word = [[NSString alloc] initWithData: wordData + encoding: NSASCIIStringEncoding]; + if (word) + { + if (mimeType) + { + [mimeDict setObject: mimeType forKey: word]; + [word release]; + } + else + mimeType = word; + } + } + } + + [mimeType release]; +} + +- (void) _parseContent: (NSData *) content +{ + const char *data; + NSUInteger lineStart = 0, bytesRead = 0, max; + + data = [content bytes]; + max = [content length]; + bytesRead = 0; + lineStart = 0; + + while (bytesRead < max) + { + if (data[bytesRead] == '\n') + { + [self _parseLine: data + lineStart withLength: bytesRead - lineStart]; + lineStart = bytesRead + 1; + } + else if (data[bytesRead] == '\r') + { + [self _parseLine: data + lineStart withLength: bytesRead - lineStart]; + if (bytesRead < (max - 1) && data[bytesRead] == '\n') + lineStart = bytesRead + 2; + else + lineStart = bytesRead + 1; + } + bytesRead++; + } + + if (bytesRead > (lineStart + 1)) + [self _parseLine: data + lineStart withLength: bytesRead - lineStart]; +} + +- (void) _readMIMEFile +{ + NSFileHandle *inH; + NSData *content; + + inH = [NSFileHandle fileHandleForReadingAtPath: MAPIStoreMIMEFile]; + content = [inH readDataToEndOfFile]; + [self _parseContent: content]; +} + +- (id) init +{ + if ((self = [super init])) + { + mimeDict = [NSMutableDictionary new]; + [self _readMIMEFile]; + } + + return self; +} + +- (void) dealloc +{ + [mimeDict release]; + [super dealloc]; +} + +- (NSString *) mimeTypeForExtension: (NSString *) extension +{ + return [mimeDict objectForKey: [extension lowercaseString]]; +} + +@end