2 Copyright (C) 2000-2007 SKYRIX Software AG
3 Copyright (C) 2007 Helge Hess
5 This file is part of SOPE.
7 SOPE is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with SOPE; see the file COPYING. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include <NGImap4/NSString+Imap4.h>
26 /* TODO: NOT UNICODE SAFE (uses cString) */
28 static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen,
29 unsigned char **result_,
30 unsigned int *cntRes_);
31 static int _decodeOfModifiedUTF7(unsigned char *_target, unsigned _targetLen,
32 unsigned *usedBytes_ ,
33 unsigned char **buffer_,
34 int *bufLen_, int maxBuf);
36 @implementation NSString(Imap4)
38 - (NSString *)stringByEncodingImap4FolderName {
39 // TBD: this is restricted to Latin1, should be fixed to UTF-8
40 /* dude.d& --> dude.d&- */
41 unsigned char *buf = NULL;
42 unsigned char *res = NULL;
45 unsigned int cntRes = 0;
46 NSString *result = nil;
49 len = [self cStringLength];
50 buf = calloc(len + 3, sizeof(char));
51 res = calloc((len * 6) + 3, sizeof(char));
54 [self getCString:(char *)buf];
58 if (((c > 31) && (c < 38)) ||
59 ((c > 38) && (c < 127))) {
74 while (cnt < (len - 1)) {
76 if (((c > 31) && (c < 38)) ||
77 ((c > 38) && (c < 127)) ||
90 length = cnt - start + 1;
92 _encodeToModifiedUTF7(buf + start, length, &res, &cntRes);
101 if (buf != NULL) free(buf); buf = NULL;
103 data = [[NSData alloc] initWithBytesNoCopy:res length:cntRes
105 result = [[NSString alloc] initWithData:data
106 encoding:NSISOLatin1StringEncoding];
107 [data release]; data = nil;
109 return [result autorelease];
112 - (NSString *)stringByDecodingImap4FolderName {
113 // TBD: this is restricted to Latin1, should be fixed to UTF-8
114 /* dude/d&- --> dude/d& */
118 unsigned int cnt = 0;
119 unsigned int cntRes = 0;
120 NSString *result = nil;
123 if ((len = [self cStringLength]) == 0)
126 buf = calloc(len + 3, sizeof(unsigned char));
127 res = calloc(len + 3, sizeof(unsigned char));
131 [self getCString:(char *)buf];
133 while (cnt < (len - 1)) { /* &- */
139 if (buf[cnt + 1] == '-') {
144 unsigned usedBytes = 0;
145 unsigned char *buffer;
151 buffer = calloc(maxBuf + 3, sizeof(char));
153 if (_decodeOfModifiedUTF7(buf + cnt, len - cnt, &usedBytes , &buffer,
154 &bufLen, maxBuf) == 0) {
158 while (cnt1 < bufLen) {
159 res[cntRes++] = buffer[cnt1++];
164 NSCAssert(NO, @"couldn't decode UTF-7 ..");
166 free(buffer); buffer = NULL;
175 res[cntRes++] = buf[cnt++];
177 if (buf != NULL) free(buf); buf = NULL;
179 data = [[NSData alloc] initWithBytesNoCopy:res length:cntRes
181 result = [[NSString alloc] initWithData:data
182 encoding:NSISOLatin1StringEncoding];
183 [data release]; data = nil;
185 return [result autorelease];
188 - (NSString *)stringByEscapingImap4Password {
196 chars = calloc(len + 2, sizeof(unichar));
197 [self getCharacters:chars];
199 buffer = calloc(len * 2 + 2, sizeof(unichar));
200 buffer[len * 2] = '\0';
202 for (i = 0, j = 0; i < len; i++, j++) {
205 if (chars[i] <= 0x1F || chars[i] > 0x7F) {
208 else switch (chars[i]) {
225 buffer[j] = chars[i];
227 if (chars != NULL) free(chars); chars = NULL;
229 s = [NSString stringWithCharacters:buffer length:j];
230 if (buffer != NULL) free(buffer); buffer = NULL;
234 @end /* NSString(Imap4) */
236 static void writeChunk(int _c1, int _c2, int _c3, int _pads,
237 unsigned char **result_,
238 unsigned int *cntRes_);
240 static int getChar(int _cnt, int *cnt_, unsigned char *_buf) {
244 result = _buf[*cnt_];
252 static void _encodeToModifiedUTF7(unsigned char *_buf, int encLen,
253 unsigned char **result_, unsigned int *cntRes_)
261 while (cnt < encLen) {
262 c1 = getChar(cntAll++, &cnt, _buf);
264 writeChunk(c1, 0, 0, 2, result_, cntRes_);
267 c2 = getChar(cntAll++, &cnt, _buf);
269 writeChunk(c1, c2, 0, 1, result_, cntRes_);
272 c3 = getChar(cntAll++, &cnt, _buf);
273 writeChunk(c1, c2, c3, 0, result_, cntRes_);
279 /* check metamail output for correctness */
281 static unsigned char basis_64[] =
282 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
284 static void writeChunk(int c1, int c2, int c3, int pads, unsigned char **result_,
285 unsigned int *cntRes_) {
289 (*result_)[*cntRes_] = c;
292 c = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
294 (*result_)[*cntRes_] = c;
302 c = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
303 (*result_)[*cntRes_] = c;
307 c = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
309 (*result_)[*cntRes_] = c;
312 c = basis_64[c3 & 0x3F];
313 (*result_)[*cntRes_] = c;
318 static char index_64[128] = {
319 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
320 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
321 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
322 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
323 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
324 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
325 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
326 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
329 #define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
331 static int _decodeOfModifiedUTF7(unsigned char *_target, unsigned _targetLen,
332 unsigned *usedBytes_ , unsigned char **buffer_,
333 int *bufLen_, int maxBuf)
338 for (cnt = 0; cnt < _targetLen; ) {
350 if (cnt < _targetLen)
360 if (cnt < _targetLen) {
365 if (cnt < _targetLen) {
371 if (c2 == -1 || c3 == -1 || c4 == -1) {
372 fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n");
376 if (c1 == '=' || c2 == '=') {
383 if (*bufLen_ < maxBuf) {
386 c = ((c1<<2) | ((c2&0x30)>>4));
389 (*buffer_)[*bufLen_] = c;
390 *bufLen_ = *bufLen_ + 1;
396 else if (c3 == '=') {
402 if (*bufLen_ < maxBuf) {
404 c = (((c2&0XF) << 4) | ((c3&0x3C) >> 2));
406 (*buffer_)[*bufLen_] = c;
407 *bufLen_ = *bufLen_ + 1;
414 else if (c4 == '=') {
419 if (*bufLen_ < maxBuf) {
422 c = (((c3&0x03) <<6) | c4);
424 (*buffer_)[*bufLen_] = c;
425 (*bufLen_) = (*bufLen_) + 1;