From 5a4070d4464dc019467a9480365211f75ad14273 Mon Sep 17 00:00:00 2001 From: helge Date: Tue, 13 Dec 2005 15:45:43 +0000 Subject: [PATCH] some code cleanups git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1198 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- sope-mime/ChangeLog | 2 + sope-mime/NGMail/ChangeLog | 5 + sope-mime/NGMail/GNUmakefile | 1 + sope-mime/NGMail/NGMimeMessageParser.m | 193 +-------------------- sope-mime/NGMail/NSData+MimeQP.m | 226 +++++++++++++++++++++++++ sope-mime/NGMime/NGMimeUtilities.h | 7 +- sope-mime/Version | 2 +- 7 files changed, 241 insertions(+), 195 deletions(-) create mode 100644 sope-mime/NGMail/NSData+MimeQP.m diff --git a/sope-mime/ChangeLog b/sope-mime/ChangeLog index fe348fcd..ad71a4f2 100644 --- a/sope-mime/ChangeLog +++ b/sope-mime/ChangeLog @@ -1,5 +1,7 @@ 2005-12-13 Helge Hess + * NGMail: some code cleanups / reorgs (v4.5.239) + * v4.5.238 * NGImap4: fixed QP handling in IMAP4 envelopes (#1587) diff --git a/sope-mime/NGMail/ChangeLog b/sope-mime/NGMail/ChangeLog index 1e280cdc..56a78242 100644 --- a/sope-mime/NGMail/ChangeLog +++ b/sope-mime/NGMail/ChangeLog @@ -1,3 +1,8 @@ +2005-12-13 Helge Hess + + * NGMimeMessageParser.m: moved NSData QP category to own file + (NSData+MimeQP.m) + 2005-07-20 Helge Hess * NGMimeMessage.m: added some convinience methods to access the header diff --git a/sope-mime/NGMail/GNUmakefile b/sope-mime/NGMail/GNUmakefile index 20530556..fa2efbfa 100644 --- a/sope-mime/NGMail/GNUmakefile +++ b/sope-mime/NGMail/GNUmakefile @@ -52,6 +52,7 @@ NGMail_OBJC_FILES = \ NGMimeMessageTextBodyGenerator.m \ \ NGMailBase64Encoding.m \ + NSData+MimeQP.m \ -include GNUmakefile.preamble ifneq ($(frameworks),yes) diff --git a/sope-mime/NGMail/NGMimeMessageParser.m b/sope-mime/NGMail/NGMimeMessageParser.m index b21cef1c..d3f3afc3 100644 --- a/sope-mime/NGMail/NGMimeMessageParser.m +++ b/sope-mime/NGMail/NGMimeMessageParser.m @@ -24,26 +24,16 @@ #include "common.h" #include - - @interface NGMimeMessageParserDelegate : NSObject @end @implementation NGMimeMessageParserDelegate -static int UseFoundationStringEncodingForMimeHeader = -1; -static Class NGMimeMessageParserClass = NULL; +static Class NGMimeMessageParserClass = Nil; + (void)initialize { - if (UseFoundationStringEncodingForMimeHeader == -1) { - UseFoundationStringEncodingForMimeHeader - = [[NSUserDefaults standardUserDefaults] - boolForKey:@"UseFoundationStringEncodingForMimeHeader"] - ? 1 : 0; - } - if (NGMimeMessageParserClass == NULL) { + if (NGMimeMessageParserClass == Nil) NGMimeMessageParserClass = [NGMimeMessageParser class]; - } } - (id)parser:(NGMimePartParser *)_p parseHeaderField:(NSString *)_field @@ -128,186 +118,7 @@ static Class NSStringClass = Nil; @end /* NGMimeMessageParser */ -@implementation NSData(MimeQPHeaderFieldDecoding) - -- (id)decodeQuotedPrintableValueOfMIMEHeaderField:(NSString *)_name { - // check data for 8-bit headerfields (RFC 2047 (MIME PART III)) - static Class NGMimeTypeClass = Nil; - enum { - NGMimeMessageParser_quoted_start = 1, - NGMimeMessageParser_quoted_charSet = 2, - NGMimeMessageParser_quoted_qpData = 3, - NGMimeMessageParser_quoted_end = 4 - } status = NGMimeMessageParser_quoted_start; - unsigned int length; - const unsigned char *bytes, *firstEq; - BOOL foundQP = NO; - - if (NSStringClass == Nil) NSStringClass = [NSString class]; - if (NGMimeTypeClass == Nil) NGMimeTypeClass = [NGMimeType class]; - - length = [self length]; - - /* check whether the string is long enough to be quoted etc */ - if (length <= 6) - return self; - - /* check whether the string contains QP tokens ... */ - bytes = [self bytes]; - - if ((firstEq = memchr(bytes, '=', length)) == NULL) - return self; - - /* process data ... (quoting etc) */ - { - unichar *buffer; - unsigned int bufLen, maxBufLen; - NSString *charset; - BOOL appendLC; - int cnt, tmp; - unsigned char encoding; - - buffer = calloc(length + 13, sizeof(unichar)); - - maxBufLen = length + 3; - buffer[maxBufLen - 1] = '\0'; - bufLen = 0; - - encoding = 0; - tmp = -1; - appendLC = YES; - charset = nil; - status = NGMimeMessageParser_quoted_start; - - /* copy data up to first '=' sign */ - if ((cnt = (firstEq - bytes)) > 0) { - for (; bufLen < cnt; bufLen++) - buffer[bufLen] = bytes[bufLen]; - } - - for (; cnt < (length-1); cnt++) { - appendLC = YES; - - if (status == NGMimeMessageParser_quoted_start) { - if ((bytes[cnt] == '=') && (bytes[cnt + 1] == '?')) { // found begin - cnt++; - status = NGMimeMessageParser_quoted_charSet; - } - else { // other char - if (bytes[cnt + 1] != '=') { - buffer[bufLen++] = bytes[cnt]; - buffer[bufLen++] = bytes[cnt+1]; - cnt++; - if (cnt >= length - 1) - appendLC = NO; - } - else { - buffer[bufLen++] = bytes[cnt]; - } - } - } - else if (status == NGMimeMessageParser_quoted_charSet) { - if (tmp == -1) - tmp = cnt; - - if (bytes[cnt] == '?') { - charset = - [NSStringClass stringWithCString:(char *)(bytes + tmp) - length:(cnt - tmp)]; - tmp = -1; - - if ((length - cnt) > 2) { - // set encoding (eg 'q' for quoted printable) - cnt++; // skip '?' - encoding = bytes[cnt]; - cnt++; // skip encoding - status = NGMimeMessageParser_quoted_qpData; - } - else { // unexpected end - NSLog(@"WARNING: unexpected end of header"); - appendLC = NO; - break; - } - } - } - else if (status == NGMimeMessageParser_quoted_qpData) { - if (tmp == -1) - tmp = cnt; - - if ((bytes[cnt] == '?') && (bytes[cnt + 1] == '=')) { - NSData *tmpData; - NSString *tmpStr; - unsigned int tmpLen; - - tmpData = _rfc2047Decoding(encoding, (char *)bytes + tmp, cnt - tmp); - foundQP = YES; - - /* - create a temporary string for charset conversion ... - Note: the headerfield is currently held in ISO Latin 1 - */ - tmpStr = nil; - - if (!UseFoundationStringEncodingForMimeHeader) { - tmpStr = [NSStringClass stringWithData:tmpData - usingEncodingNamed:charset]; - } - if (tmpStr == nil) { - NSStringEncoding enc; - - enc = [NGMimeTypeClass stringEncodingForCharset:charset]; - tmpStr = [[[NSStringClass alloc] initWithData:tmpData encoding:enc] - autorelease]; - } - tmpLen = [tmpStr length]; - - if ((tmpLen + bufLen) < maxBufLen) { - [tmpStr getCharacters:(buffer + bufLen)]; - bufLen += tmpLen; - } - else { - NSLog(@"ERROR[%s]: quoted data to large --> ignored %@", - __PRETTY_FUNCTION__, tmpStr); - } - tmp = -1; - cnt++; - appendLC = YES; - status = NGMimeMessageParser_quoted_start; - } - } - } - if (appendLC) { - if (cnt < length) { - buffer[bufLen] = bytes[cnt]; - bufLen++; - } - } - buffer[bufLen] = '\0'; - { - id data; - - data = nil; - - if (buffer && foundQP) { - data = [[[NSString alloc] initWithCharacters:buffer length:bufLen] - autorelease]; - if (data == nil) { - NSLog(@"%s: got no string for buffer '%s', length '%i' !", - __PRETTY_FUNCTION__, - buffer, bufLen); - } - } - if (!data) { - data = self; - } - free(buffer); buffer = NULL; - return data; - } - } - return self; -} -@end /* NSData(MimeQPHeaderFieldDecoding) */ @implementation NGMimeRfc822BodyParser diff --git a/sope-mime/NGMail/NSData+MimeQP.m b/sope-mime/NGMail/NSData+MimeQP.m new file mode 100644 index 00000000..ddaee465 --- /dev/null +++ b/sope-mime/NGMail/NSData+MimeQP.m @@ -0,0 +1,226 @@ +/* + Copyright (C) 2000-2005 SKYRIX Software AG + + This file is part of SOPE. + + SOPE 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. + + SOPE 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 SOPE; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "common.h" +#include + +@implementation NSData(MimeQPHeaderFieldDecoding) + +static Class NSStringClass = Nil; +static Class NGMimeTypeClass = Nil; + +static int UseFoundationStringEncodingForMimeHeader = -1; + +- (id)decodeQuotedPrintableValueOfMIMEHeaderField:(NSString *)_name { + // check data for 8-bit headerfields (RFC 2047 (MIME PART III)) + /* + TODO: document + + This method returns an NSString or an NSData object (or nil). + */ + enum { + NGMimeMessageParser_quoted_start = 1, + NGMimeMessageParser_quoted_charSet = 2, + NGMimeMessageParser_quoted_qpData = 3, + NGMimeMessageParser_quoted_end = 4 + } status = NGMimeMessageParser_quoted_start; + unsigned int length; + const unsigned char *bytes, *firstEq; + BOOL foundQP = NO; + + /* setup statics */ + + if (UseFoundationStringEncodingForMimeHeader == -1) { + UseFoundationStringEncodingForMimeHeader + = [[NSUserDefaults standardUserDefaults] + boolForKey:@"UseFoundationStringEncodingForMimeHeader"] + ? 1 : 0; + } + + if (NSStringClass == Nil) NSStringClass = [NSString class]; + if (NGMimeTypeClass == Nil) NGMimeTypeClass = [NGMimeType class]; + + + /* begin */ + + length = [self length]; + + /* check whether the string is long enough to be quoted etc */ + if (length <= 6) + return self; + + /* check whether the string contains QP tokens ... */ + bytes = [self bytes]; + + if ((firstEq = memchr(bytes, '=', length)) == NULL) + return self; + + /* process data ... (quoting etc) */ + { + unichar *buffer; + unsigned int bufLen, maxBufLen; + NSString *charset; + BOOL appendLC; + int cnt, tmp; + unsigned char encoding; + + buffer = calloc(length + 13, sizeof(unichar)); + + maxBufLen = length + 3; + buffer[maxBufLen - 1] = '\0'; + bufLen = 0; + + encoding = 0; + tmp = -1; + appendLC = YES; + charset = nil; + status = NGMimeMessageParser_quoted_start; + + /* copy data up to first '=' sign */ + if ((cnt = (firstEq - bytes)) > 0) { + for (; bufLen < cnt; bufLen++) + buffer[bufLen] = bytes[bufLen]; + } + + for (; cnt < (length - 1); cnt++) { + appendLC = YES; + + if (status == NGMimeMessageParser_quoted_start) { + if ((bytes[cnt] == '=') && (bytes[cnt + 1] == '?')) { // found begin + cnt++; + status = NGMimeMessageParser_quoted_charSet; + } + else { // other char + if (bytes[cnt + 1] != '=') { + buffer[bufLen++] = bytes[cnt]; + buffer[bufLen++] = bytes[cnt+1]; + cnt++; + if (cnt >= length - 1) + appendLC = NO; + } + else { + buffer[bufLen++] = bytes[cnt]; + } + } + } + else if (status == NGMimeMessageParser_quoted_charSet) { + if (tmp == -1) + tmp = cnt; + + if (bytes[cnt] == '?') { + charset = + [NSStringClass stringWithCString:(char *)(bytes + tmp) + length:(cnt - tmp)]; + tmp = -1; + + if ((length - cnt) > 2) { + // set encoding (eg 'q' for quoted printable) + cnt++; // skip '?' + encoding = bytes[cnt]; + cnt++; // skip encoding + status = NGMimeMessageParser_quoted_qpData; + } + else { // unexpected end + NSLog(@"WARNING: unexpected end of header"); + appendLC = NO; + break; + } + } + } + else if (status == NGMimeMessageParser_quoted_qpData) { + if (tmp == -1) + tmp = cnt; + + if ((bytes[cnt] == '?') && (bytes[cnt + 1] == '=')) { + NSData *tmpData; + NSString *tmpStr; + unsigned int tmpLen; + + tmpData = _rfc2047Decoding(encoding, (char *)bytes + tmp, cnt - tmp); + foundQP = YES; + + /* + create a temporary string for charset conversion ... + Note: the headerfield is currently held in ISO Latin 1 + */ + tmpStr = nil; + + if (!UseFoundationStringEncodingForMimeHeader) { + tmpStr = [NSStringClass stringWithData:tmpData + usingEncodingNamed:charset]; + } + if (tmpStr == nil) { + NSStringEncoding enc; + + enc = [NGMimeTypeClass stringEncodingForCharset:charset]; + tmpStr = [[[NSStringClass alloc] initWithData:tmpData encoding:enc] + autorelease]; + } + tmpLen = [tmpStr length]; + + if ((tmpLen + bufLen) < maxBufLen) { + [tmpStr getCharacters:(buffer + bufLen)]; + bufLen += tmpLen; + } + else { + [self errorWithFormat:@"%s: quoted data to large --> ignored %@", + __PRETTY_FUNCTION__, tmpStr]; + } + tmp = -1; + cnt++; + appendLC = YES; + status = NGMimeMessageParser_quoted_start; + } + } + } + if (appendLC) { + if (cnt < length) { + buffer[bufLen] = bytes[cnt]; + bufLen++; + } + } + buffer[bufLen] = '\0'; + { + id data; + + data = nil; + + if (buffer && foundQP) { + data = [[[NSStringClass alloc] initWithCharacters:buffer length:bufLen] + autorelease]; + if (data == nil) { + [self warnWithFormat: + @"%s: got no string for buffer '%s', length '%i' !", + __PRETTY_FUNCTION__, buffer, bufLen]; + } + } + + if (data == nil) + data = self; /* we return an NSData */ + + if (buffer != NULL) free(buffer); buffer = NULL; + return data; + } + } + return self; +} + +@end /* NSData(MimeQPHeaderFieldDecoding) */ diff --git a/sope-mime/NGMime/NGMimeUtilities.h b/sope-mime/NGMime/NGMimeUtilities.h index d5df2bdf..a6975bc2 100644 --- a/sope-mime/NGMime/NGMimeUtilities.h +++ b/sope-mime/NGMime/NGMimeUtilities.h @@ -170,11 +170,12 @@ static inline NSData *_rfc2047Decoding(char _enc, const char *_bytes, NSData *data = nil; if ((_enc == 'b') || (_enc == 'B')) { // use BASE64 decoding + // TODO: improve efficiency (directly decode buffers w/o NSData) NSData *tmp; tmp = [[NSData alloc] initWithBytes:_bytes length:_length]; data = [tmp dataByDecodingBase64]; - RELEASE(tmp); + [tmp release]; tmp = nil; } else if ((_enc == 'q') || (_enc == 'Q')) { // use quoted-printable decoding char *dest = NULL; @@ -182,7 +183,7 @@ static inline NSData *_rfc2047Decoding(char _enc, const char *_bytes, size_t resSize = 0; destSize = _length; - dest = NGMallocAtomic(destSize * sizeof(char)); + dest = calloc(destSize + 2, sizeof(char)); resSize = NGDecodeQuotedPrintable(_bytes, _length, dest, destSize); if ((int)resSize != -1) { data = [NSData dataWithBytesNoCopy:dest length:resSize]; @@ -190,7 +191,7 @@ static inline NSData *_rfc2047Decoding(char _enc, const char *_bytes, else { NSLog(@"WARNING(%s): An error occour during quoted-printable decoding", __PRETTY_FUNCTION__); - NGFree(dest); dest = NULL; + if (dest != NULL) free(dest); dest = NULL; data = [NSData dataWithBytes:_bytes length:_length]; } } diff --git a/sope-mime/Version b/sope-mime/Version index 662bf876..bd8bd08a 100644 --- a/sope-mime/Version +++ b/sope-mime/Version @@ -2,7 +2,7 @@ MAJOR_VERSION:=4 MINOR_VERSION:=5 -SUBMINOR_VERSION:=238 +SUBMINOR_VERSION:=239 # v4.5.214 requires libNGExtensions v4.5.146 # v4.2.149 requires libNGStreams v4.2.34 -- 2.39.5