2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 @implementation NSData(MimeQPHeaderFieldDecoding)
27 static Class NSStringClass = Nil;
28 static Class NGMimeTypeClass = Nil;
30 static int UseFoundationStringEncodingForMimeHeader = -1;
32 - (id)decodeQuotedPrintableValueOfMIMEHeaderField:(NSString *)_name {
33 // check data for 8-bit headerfields (RFC 2047 (MIME PART III))
37 This method returns an NSString or an NSData object (or nil).
40 NGMimeMessageParser_quoted_start = 1,
41 NGMimeMessageParser_quoted_charSet = 2,
42 NGMimeMessageParser_quoted_qpData = 3,
43 NGMimeMessageParser_quoted_end = 4
44 } status = NGMimeMessageParser_quoted_start;
46 const unsigned char *bytes, *firstEq;
51 if (UseFoundationStringEncodingForMimeHeader == -1) {
52 UseFoundationStringEncodingForMimeHeader
53 = [[NSUserDefaults standardUserDefaults]
54 boolForKey:@"UseFoundationStringEncodingForMimeHeader"]
58 if (NSStringClass == Nil) NSStringClass = [NSString class];
59 if (NGMimeTypeClass == Nil) NGMimeTypeClass = [NGMimeType class];
64 length = [self length];
66 /* check whether the string is long enough to be quoted etc */
70 /* check whether the string contains QP tokens ... */
73 if ((firstEq = memchr(bytes, '=', length)) == NULL)
76 /* process data ... (quoting etc) */
79 unsigned int bufLen, maxBufLen;
83 unsigned char encoding;
85 buffer = calloc(length + 13, sizeof(unichar));
87 maxBufLen = length + 3;
88 buffer[maxBufLen - 1] = '\0';
95 status = NGMimeMessageParser_quoted_start;
97 /* copy data up to first '=' sign */
98 if ((cnt = (firstEq - bytes)) > 0) {
99 for (; bufLen < cnt; bufLen++)
100 buffer[bufLen] = bytes[bufLen];
103 for (; cnt < (length - 1); cnt++) {
106 if (status == NGMimeMessageParser_quoted_start) {
107 if ((bytes[cnt] == '=') && (bytes[cnt + 1] == '?')) { // found begin
109 status = NGMimeMessageParser_quoted_charSet;
112 if (bytes[cnt + 1] != '=') {
113 buffer[bufLen++] = bytes[cnt];
114 buffer[bufLen++] = bytes[cnt+1];
116 if (cnt >= length - 1)
120 buffer[bufLen++] = bytes[cnt];
124 else if (status == NGMimeMessageParser_quoted_charSet) {
128 if (bytes[cnt] == '?') {
130 [NSStringClass stringWithCString:(char *)(bytes + tmp)
134 if ((length - cnt) > 2) {
135 // set encoding (eg 'q' for quoted printable)
137 encoding = bytes[cnt];
138 cnt++; // skip encoding
139 status = NGMimeMessageParser_quoted_qpData;
141 else { // unexpected end
142 NSLog(@"WARNING: unexpected end of header");
148 else if (status == NGMimeMessageParser_quoted_qpData) {
152 if ((bytes[cnt] == '?') && (bytes[cnt + 1] == '=')) {
157 tmpData = _rfc2047Decoding(encoding, (char *)bytes + tmp, cnt - tmp);
161 create a temporary string for charset conversion ...
162 Note: the headerfield is currently held in ISO Latin 1
166 if (!UseFoundationStringEncodingForMimeHeader) {
167 tmpStr = [NSStringClass stringWithData:tmpData
168 usingEncodingNamed:charset];
171 NSStringEncoding enc;
173 enc = [NGMimeTypeClass stringEncodingForCharset:charset];
174 tmpStr = [[[NSStringClass alloc] initWithData:tmpData encoding:enc]
177 tmpLen = [tmpStr length];
179 if ((tmpLen + bufLen) < maxBufLen) {
180 [tmpStr getCharacters:(buffer + bufLen)];
184 [self errorWithFormat:@"%s: quoted data to large --> ignored %@",
185 __PRETTY_FUNCTION__, tmpStr];
190 status = NGMimeMessageParser_quoted_start;
196 buffer[bufLen] = bytes[cnt];
200 buffer[bufLen] = '\0';
206 if (buffer && foundQP) {
207 data = [[[NSStringClass alloc] initWithCharacters:buffer length:bufLen]
210 [self warnWithFormat:
211 @"%s: got no string for buffer '%s', length '%i' !",
212 __PRETTY_FUNCTION__, buffer, bufLen];
217 data = self; /* we return an NSData */
219 if (buffer != NULL) free(buffer); buffer = NULL;
226 @end /* NSData(MimeQPHeaderFieldDecoding) */