1 //=============================================================================
2 // File: dw_cte.cpp
3 // Contents: Function definitions for content transfer encodings
4 // Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
5 // WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
6 // $Revision: 1.6 $
7 // $Date: 1997/09/27 11:53:43 $
8 //
9 // Copyright (c) 1996, 1997 Douglas W. Sauder
10 // All rights reserved.
11 //
12 // IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
13 // INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
14 // THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
15 // HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 //
17 // DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
18 // NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 // PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
20 // BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
21 // SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
22 //
23 //=============================================================================
24
25 #define DW_IMPLEMENTATION
26
27 #include <mimelib/config.h>
28 #include <mimelib/debug.h>
29 #include <string.h>
30 #include <mimelib/string.h>
31 #include <mimelib/utility.h>
32
33 #define MAXLINE 76
34
35 static size_t calc_crlf_buff_size(const char* srcBuf, size_t srcLen);
36 static int to_crlf(const char* srcBuf, size_t srcLen, char* destBuf,
37 size_t destSize, size_t* destLen);
38 static int to_lf(const char* srcBuf, size_t srcLen, char* destBuf,
39 size_t destSize, size_t* destLen);
40 static int to_cr(const char* srcBuf, size_t srcLen, char* destBuf,
41 size_t destSize, size_t* destLen);
42 static int encode_base64(const char* aIn, size_t aInLen, char* aOut,
43 size_t aOutSize, size_t* aOutLen);
44 static int decode_base64(const char* aIn, size_t aInLen, char* aOut,
45 size_t aOutSize, size_t* aOutLen);
46 static int encode_qp(const char* aIn, size_t aInLen, char* aOut,
47 size_t aOutSize, size_t* aOutLen);
48 static int decode_qp(const char* aIn, size_t aInLen, char* aOut,
49 size_t aOutSize, size_t* aOutLen);
50 static size_t calc_qp_buff_size(const char* aIn, size_t aInLen);
51
52
DwToCrLfEol(const DwString & aSrcStr,DwString & aDestStr)53 int DwToCrLfEol(const DwString& aSrcStr, DwString& aDestStr)
54 {
55 // Estimate required destination buffer size
56 size_t srcLen = aSrcStr.length();
57 const char* srcBuf = aSrcStr.data();
58 size_t destSize = calc_crlf_buff_size(srcBuf, srcLen);
59
60 // Allocate destination buffer
61 DwString destStr(destSize, (char)0);
62 char* destBuf = (char*) destStr.data();
63
64 // Encode source to destination
65 size_t destLen;
66 to_crlf(srcBuf, srcLen, destBuf, destSize, &destLen);
67 aDestStr.assign(destStr, 0, destLen);
68 return 0;
69 }
70
71
DwToLfEol(const DwString & aSrcStr,DwString & aDestStr)72 int DwToLfEol(const DwString& aSrcStr, DwString& aDestStr)
73 {
74 size_t srcLen = aSrcStr.length();
75 const char* srcBuf = aSrcStr.data();
76 size_t destSize = srcLen;
77
78 // Allocate destination buffer
79 DwString destStr(destSize, (char)0);
80 char* destBuf = (char*) destStr.data();
81
82 // Encode source to destination
83 size_t destLen;
84 to_lf(srcBuf, srcLen, destBuf, destSize, &destLen);
85 aDestStr.assign(destStr, 0, destLen);
86 return 0;
87 }
88
89
DwToCrEol(const DwString & aSrcStr,DwString & aDestStr)90 int DwToCrEol(const DwString& aSrcStr, DwString& aDestStr)
91 {
92 size_t srcLen = aSrcStr.length();
93 const char* srcBuf = aSrcStr.data();
94 size_t destSize = srcLen;
95
96 // Allocate destination buffer
97 DwString destStr(destSize, (char)0);
98 char* destBuf = (char*) destStr.data();
99
100 // Encode source to destination
101 size_t destLen;
102 to_cr(srcBuf, srcLen, destBuf, destSize, &destLen);
103 aDestStr.assign(destStr, 0, destLen);
104 return 0;
105 }
106
107
DwToLocalEol(const DwString & aSrcStr,DwString & aDestStr)108 int DwToLocalEol(const DwString& aSrcStr, DwString& aDestStr)
109 {
110 #if defined(DW_EOL_CRLF)
111 return DwToCrLfEol(aSrcStr, aDestStr);
112 #elif defined(DW_EOL_LF)
113 return DwToLfEol(aSrcStr, aDestStr);
114 #else
115 # error "Must define DW_EOL_CRLF, DW_EOL_LF"
116 #endif
117 }
118
119
DwEncodeBase64(const DwString & aSrcStr,DwString & aDestStr)120 int DwEncodeBase64(const DwString& aSrcStr, DwString& aDestStr)
121 {
122 // Estimate required destination buffer size
123 size_t srcLen = aSrcStr.length();
124 const char* srcBuf = aSrcStr.data();
125 size_t destSize = (srcLen+2)/3*4;
126 destSize += strlen(DW_EOL)*destSize/72 + 2;
127 destSize += 64; // a little extra room
128
129 // Allocate destination buffer
130 DwString destStr(destSize, (char)0);
131 char* destBuf = (char*) destStr.data();
132
133 // Encode source to destination
134 size_t destLen;
135 int result =
136 encode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
137 aDestStr.assign(destStr, 0, destLen);
138 return result;
139 }
140
141
DwDecodeBase64(const DwString & aSrcStr,DwString & aDestStr)142 int DwDecodeBase64(const DwString& aSrcStr, DwString& aDestStr)
143 {
144 // Set destination buffer size same as source buffer size
145 size_t srcLen = aSrcStr.length();
146 const char* srcBuf = aSrcStr.data();
147 size_t destSize = srcLen;
148
149 // Allocate destination buffer
150 DwString destStr(destSize, (char)0);
151 char* destBuf = (char*) destStr.data();
152
153 // Encode source to destination
154 size_t destLen;
155 int result =
156 decode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
157 aDestStr.assign(destStr, 0, destLen);
158 return result;
159 }
160
161
DwEncodeQuotedPrintable(const DwString & aSrcStr,DwString & aDestStr)162 int DwEncodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
163 {
164 // Estimate required destination buffer size
165 size_t srcLen = aSrcStr.length();
166 const char* srcBuf = aSrcStr.data();
167 size_t destSize = calc_qp_buff_size(srcBuf, srcLen);
168 destSize += 64; // a little extra room
169
170 // Allocate destination buffer
171 DwString destStr(destSize, (char)0);
172 char* destBuf = (char*) destStr.data();
173
174 // Encode source to destination
175 size_t destLen;
176 int result =
177 encode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
178 aDestStr.assign(destStr, 0, destLen);
179 return result;
180 }
181
182
DwDecodeQuotedPrintable(const DwString & aSrcStr,DwString & aDestStr)183 int DwDecodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
184 {
185 // Set destination buffer size same as source buffer size
186 size_t srcLen = aSrcStr.length();
187 const char* srcBuf = aSrcStr.data();
188 size_t destSize = srcLen;
189
190 // Allocate destination buffer
191 DwString destStr(destSize, (char)0);
192 char* destBuf = (char*) destStr.data();
193
194 // Encode source to destination
195 size_t destLen;
196 int result =
197 decode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
198 aDestStr.assign(destStr, 0, destLen);
199 return result;
200 }
201
202
203 //============================================================================
204 // Everything below this line is private to this file (static)
205 //============================================================================
206
207
calc_crlf_buff_size(const char * srcBuf,size_t srcLen)208 static size_t calc_crlf_buff_size(const char* srcBuf, size_t srcLen)
209 {
210 size_t i, extra;
211
212 if (!srcBuf) return 0;
213 extra = 0;
214 for (i=0; i < srcLen; ) {
215 switch (srcBuf[i]) {
216 /* Bare LF (UNIX or C text) */
217 case '\n':
218 ++extra;
219 ++i;
220 break;
221 case '\r':
222 /* CR LF (DOS, Windows, or MIME text) */
223 if (i+1 < srcLen && srcBuf[i+1] == '\n') {
224 i += 2;
225 }
226 /* Bare CR (Macintosh text) */
227 else {
228 ++extra;
229 ++i;
230 }
231 break;
232 default:
233 ++i;
234 }
235 }
236 return srcLen + extra;
237 }
238
239
to_crlf(const char * srcBuf,size_t srcLen,char * destBuf,size_t destSize,size_t * destLen)240 static int to_crlf(const char* srcBuf, size_t srcLen, char* destBuf,
241 size_t destSize, size_t* destLen)
242 {
243 size_t iSrc, iDest;
244
245 if (!srcBuf || !destBuf || !destLen) return -1;
246 iSrc = iDest = 0;
247 while (iSrc < srcLen && iDest < destSize) {
248 switch (srcBuf[iSrc]) {
249 /* Bare LF (UNIX or C text) */
250 case '\n':
251 destBuf[iDest++] = '\r';
252 if (iDest < destSize) {
253 destBuf[iDest++] = srcBuf[iSrc++];
254 }
255 break;
256 case '\r':
257 /* CR LF (DOS, Windows, or MIME text) */
258 if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
259 destBuf[iDest++] = srcBuf[iSrc++];
260 if (iDest < destSize) {
261 destBuf[iDest++] = srcBuf[iSrc++];
262 }
263 }
264 /* Bare CR (Macintosh text) */
265 else {
266 destBuf[iDest++] = srcBuf[iSrc++];
267 if (iDest < destSize) {
268 destBuf[iDest++] = '\n';
269 }
270 }
271 break;
272 default:
273 destBuf[iDest++] = srcBuf[iSrc++];
274 }
275 }
276 *destLen = iDest;
277 if (iDest < destSize) {
278 destBuf[iDest] = 0;
279 }
280 return 0;
281 }
282
283
to_lf(const char * srcBuf,size_t srcLen,char * destBuf,size_t destSize,size_t * destLen)284 static int to_lf(const char* srcBuf, size_t srcLen, char* destBuf,
285 size_t destSize, size_t* destLen)
286 {
287 size_t iSrc, iDest;
288
289 if (!srcBuf || !destBuf || !destLen) return -1;
290 iSrc = iDest = 0;
291 while (iSrc < srcLen && iDest < destSize) {
292 switch (srcBuf[iSrc]) {
293 /* Bare LF (UNIX or C text) */
294 case '\n':
295 destBuf[iDest++] = srcBuf[iSrc++];
296 break;
297 case '\r':
298 /* CR LF (DOS, Windows, or MIME text) */
299 if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
300 ++iSrc;
301 destBuf[iDest++] = srcBuf[iSrc++];
302 }
303 /* Bare CR (Macintosh text) */
304 else {
305 destBuf[iDest++] = '\n';
306 ++iSrc;
307 }
308 break;
309 default:
310 destBuf[iDest++] = srcBuf[iSrc++];
311 }
312 }
313 *destLen = iDest;
314 if (iDest < destSize) {
315 destBuf[iDest] = 0;
316 }
317 return 0;
318 }
319
320
to_cr(const char * srcBuf,size_t srcLen,char * destBuf,size_t destSize,size_t * destLen)321 static int to_cr(const char* srcBuf, size_t srcLen, char* destBuf,
322 size_t destSize, size_t* destLen)
323 {
324 size_t iSrc, iDest;
325
326 if (!srcBuf || !destBuf || !destLen) return -1;
327 iSrc = iDest = 0;
328 while (iSrc < srcLen && iDest < destSize) {
329 switch (srcBuf[iSrc]) {
330 /* Bare LF (UNIX or C text) */
331 case '\n':
332 destBuf[iDest++] = '\r';
333 ++iSrc;
334 break;
335 case '\r':
336 /* CR LF (DOS, Windows, or MIME text) */
337 if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
338 destBuf[iDest++] = srcBuf[iSrc++];
339 ++iSrc;
340 }
341 /* Bare CR (Macintosh text) */
342 else {
343 destBuf[iDest++] = srcBuf[iSrc++];
344 }
345 break;
346 default:
347 destBuf[iDest++] = srcBuf[iSrc++];
348 }
349 }
350 *destLen = iDest;
351 if (iDest < destSize) {
352 destBuf[iDest] = 0;
353 }
354 return 0;
355 }
356
357
358 static char base64tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
359 "abcdefghijklmnopqrstuvwxyz0123456789+/";
360
361 static char base64idx[128] = {
362 '\377','\377','\377','\377','\377','\377','\377','\377',
363 '\377','\377','\377','\377','\377','\377','\377','\377',
364 '\377','\377','\377','\377','\377','\377','\377','\377',
365 '\377','\377','\377','\377','\377','\377','\377','\377',
366 '\377','\377','\377','\377','\377','\377','\377','\377',
367 '\377','\377','\377', 62,'\377','\377','\377', 63,
368 52, 53, 54, 55, 56, 57, 58, 59,
369 60, 61,'\377','\377','\377','\377','\377','\377',
370 '\377', 0, 1, 2, 3, 4, 5, 6,
371 7, 8, 9, 10, 11, 12, 13, 14,
372 15, 16, 17, 18, 19, 20, 21, 22,
373 23, 24, 25,'\377','\377','\377','\377','\377',
374 '\377', 26, 27, 28, 29, 30, 31, 32,
375 33, 34, 35, 36, 37, 38, 39, 40,
376 41, 42, 43, 44, 45, 46, 47, 48,
377 49, 50, 51,'\377','\377','\377','\377','\377'
378 };
379
380 static char hextab[] = "0123456789ABCDEF";
381
382 #ifdef __cplusplus
isbase64(int a)383 inline int isbase64(int a) {
384 return ('A' <= a && a <= 'Z')
385 || ('a' <= a && a <= 'z')
386 || ('0' <= a && a <= '9')
387 || a == '+' || a == '/';
388 }
389 #else
390 #define isbase64(a) ( ('A' <= (a) && (a) <= 'Z') \
391 || ('a' <= (a) && (a) <= 'z') \
392 || ('0' <= (a) && (a) <= '9') \
393 || (a) == '+' || (a) == '/' )
394 #endif
395
396
encode_base64(const char * aIn,size_t aInLen,char * aOut,size_t aOutSize,size_t * aOutLen)397 static int encode_base64(const char* aIn, size_t aInLen, char* aOut,
398 size_t aOutSize, size_t* aOutLen)
399 {
400 if (!aIn || !aOut || !aOutLen)
401 return -1;
402 size_t inLen = aInLen;
403 char* out = aOut;
404 size_t outSize = (inLen+2)/3*4; /* 3:4 conversion ratio */
405 outSize += strlen(DW_EOL)*outSize/MAXLINE + 2; /* Space for newlines and NUL */
406 if (aOutSize < outSize)
407 return -1;
408 size_t inPos = 0;
409 size_t outPos = 0;
410 int c1, c2, c3;
411 int lineLen = 0;
412 /* Get three characters at a time and encode them. */
413 for (size_t i=0; i < inLen/3; ++i) {
414 c1 = aIn[inPos++] & 0xFF;
415 c2 = aIn[inPos++] & 0xFF;
416 c3 = aIn[inPos++] & 0xFF;
417 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
418 out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
419 out[outPos++] = base64tab[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)];
420 out[outPos++] = base64tab[c3 & 0x3F];
421 lineLen += 4;
422 if (lineLen >= MAXLINE-3) {
423 char* cp = DW_EOL;
424 out[outPos++] = *cp++;
425 if (*cp) {
426 out[outPos++] = *cp;
427 }
428 lineLen = 0;
429 }
430 }
431 /* Encode the remaining one or two characters. */
432 char* cp;
433 switch (inLen % 3) {
434 case 0:
435 cp = DW_EOL;
436 out[outPos++] = *cp++;
437 if (*cp) {
438 out[outPos++] = *cp;
439 }
440 break;
441 case 1:
442 c1 = aIn[inPos] & 0xFF;
443 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
444 out[outPos++] = base64tab[((c1 & 0x03) << 4)];
445 out[outPos++] = '=';
446 out[outPos++] = '=';
447 cp = DW_EOL;
448 out[outPos++] = *cp++;
449 if (*cp) {
450 out[outPos++] = *cp;
451 }
452 break;
453 case 2:
454 c1 = aIn[inPos++] & 0xFF;
455 c2 = aIn[inPos] & 0xFF;
456 out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
457 out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
458 out[outPos++] = base64tab[((c2 & 0x0F) << 2)];
459 out[outPos++] = '=';
460 cp = DW_EOL;
461 out[outPos++] = *cp++;
462 if (*cp) {
463 out[outPos++] = *cp;
464 }
465 break;
466 }
467 out[outPos] = 0;
468 *aOutLen = outPos;
469 return 0;
470 }
471
472
decode_base64(const char * aIn,size_t aInLen,char * aOut,size_t aOutSize,size_t * aOutLen)473 static int decode_base64(const char* aIn, size_t aInLen, char* aOut,
474 size_t aOutSize, size_t* aOutLen)
475 {
476 if (!aIn || !aOut || !aOutLen)
477 return -1;
478 size_t inLen = aInLen;
479 char* out = aOut;
480 size_t outSize = (inLen/4+1)*3+1;
481 if (aOutSize < outSize)
482 return -1;
483 /* Get four input chars at a time and decode them. Ignore white space
484 * chars (CR, LF, SP, HT). If '=' is encountered, terminate input. If
485 * a char other than white space, base64 char, or '=' is encountered,
486 * flag an input error, but otherwise ignore the char.
487 */
488 int isErr = 0;
489 int isEndSeen = 0;
490 int b1, b2, b3;
491 int a1, a2, a3, a4;
492 size_t inPos = 0;
493 size_t outPos = 0;
494 while (inPos < inLen) {
495 a1 = a2 = a3 = a4 = 0;
496 while (inPos < inLen) {
497 a1 = aIn[inPos++] & 0xFF;
498 if (isbase64(a1)) {
499 break;
500 }
501 else if (a1 == '=') {
502 isEndSeen = 1;
503 break;
504 }
505 else if (a1 != '\r' && a1 != '\n' && a1 != ' ' && a1 != '\t') {
506 isErr = 1;
507 }
508 }
509 while (inPos < inLen) {
510 a2 = aIn[inPos++] & 0xFF;
511 if (isbase64(a2)) {
512 break;
513 }
514 else if (a2 == '=') {
515 isEndSeen = 1;
516 break;
517 }
518 else if (a2 != '\r' && a2 != '\n' && a2 != ' ' && a2 != '\t') {
519 isErr = 1;
520 }
521 }
522 while (inPos < inLen) {
523 a3 = aIn[inPos++] & 0xFF;
524 if (isbase64(a3)) {
525 break;
526 }
527 else if (a3 == '=') {
528 isEndSeen = 1;
529 break;
530 }
531 else if (a3 != '\r' && a3 != '\n' && a3 != ' ' && a3 != '\t') {
532 isErr = 1;
533 }
534 }
535 while (inPos < inLen) {
536 a4 = aIn[inPos++] & 0xFF;
537 if (isbase64(a4)) {
538 break;
539 }
540 else if (a4 == '=') {
541 isEndSeen = 1;
542 break;
543 }
544 else if (a4 != '\r' && a4 != '\n' && a4 != ' ' && a4 != '\t') {
545 isErr = 1;
546 }
547 }
548 if (isbase64(a1) && isbase64(a2) && isbase64(a3) && isbase64(a4)) {
549 a1 = base64idx[a1] & 0xFF;
550 a2 = base64idx[a2] & 0xFF;
551 a3 = base64idx[a3] & 0xFF;
552 a4 = base64idx[a4] & 0xFF;
553 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
554 b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
555 b3 = ((a3 << 6) & 0xC0) | ( a4 & 0x3F);
556 out[outPos++] = char(b1);
557 out[outPos++] = char(b2);
558 out[outPos++] = char(b3);
559 }
560 else if (isbase64(a1) && isbase64(a2) && isbase64(a3) && a4 == '=') {
561 a1 = base64idx[a1] & 0xFF;
562 a2 = base64idx[a2] & 0xFF;
563 a3 = base64idx[a3] & 0xFF;
564 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
565 b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
566 out[outPos++] = char(b1);
567 out[outPos++] = char(b2);
568 break;
569 }
570 else if (isbase64(a1) && isbase64(a2) && a3 == '=' && a4 == '=') {
571 a1 = base64idx[a1] & 0xFF;
572 a2 = base64idx[a2] & 0xFF;
573 b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
574 out[outPos++] = char(b1);
575 break;
576 }
577 else {
578 break;
579 }
580 if (isEndSeen) {
581 break;
582 }
583 } /* end while loop */
584 *aOutLen = outPos;
585 return (isErr) ? -1 : 0;
586 }
587
588
589 /***** Warning: calc_qp_buff_size must stay in sync with encode_qp ******/
590
encode_qp(const char * aIn,size_t aInLen,char * aOut,size_t,size_t * aOutLen)591 static int encode_qp(const char* aIn, size_t aInLen, char* aOut,
592 size_t /*aOutSize */, size_t* aOutLen)
593 {
594 size_t inPos, outPos, lineLen;
595 int ch;
596
597 if (!aIn || !aOut || !aOutLen) {
598 return -1;
599 }
600 inPos = 0;
601 outPos = 0;
602 lineLen = 0;
603 while (inPos < aInLen) {
604 ch = aIn[inPos++] & 0xFF;
605 /* '.' at beginning of line (confuses some SMTPs) */
606 if (lineLen == 0 && ch == '.') {
607 aOut[outPos++] = '=';
608 aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
609 aOut[outPos++] = hextab[ch & 0x0F];
610 lineLen += 3;
611 }
612 /* "From " at beginning of line (gets mangled in mbox folders) */
613 else if (lineLen == 0 && inPos+3 < aInLen && ch == 'F'
614 && aIn[inPos ] == 'r' && aIn[inPos+1] == 'o'
615 && aIn[inPos+2] == 'm' && aIn[inPos+3] == ' ') {
616 aOut[outPos++] = '=';
617 aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
618 aOut[outPos++] = hextab[ch & 0x0F];
619 lineLen += 3;
620 }
621 /* Normal printable char */
622 else if ((62 <= ch && ch <= 126) || (33 <= ch && ch <= 60)) {
623 aOut[outPos++] = (char) ch;
624 ++lineLen;
625 }
626 /* Space */
627 else if (ch == ' ') {
628 /* Space at end of line or end of input must be encoded */
629 #if defined(DW_EOL_LF)
630 if (inPos >= aInLen /* End of input? */
631 || aIn[inPos] == '\n') { /* End of line? */
632
633 aOut[outPos++] = '=';
634 aOut[outPos++] = '2';
635 aOut[outPos++] = '0';
636 lineLen += 3;
637 }
638 #elif defined(DW_EOL_CRLF)
639 if (inPos >= aInLen /* End of input? */
640 || (inPos < aInLen-1 /* End of line? */
641 && aIn[inPos ] == '\r'
642 && aIn[inPos+1] == '\n') ) {
643
644 aOut[outPos++] = '=';
645 aOut[outPos++] = '2';
646 aOut[outPos++] = '0';
647 lineLen += 3;
648 }
649 #else
650 # error Must define DW_EOL_LF or DW_EOL_CRLF
651 #endif
652 else {
653 aOut[outPos++] = ' ';
654 ++lineLen;
655 }
656 }
657 /* Hard line break */
658 #if defined(DW_EOL_LF)
659 else if (ch == '\n') {
660 aOut[outPos++] = '\n';
661 lineLen = 0;
662 }
663 #elif defined(DW_EOL_CRLF)
664 else if (inPos < aInLen && ch == '\r' && aIn[inPos] == '\n') {
665 ++inPos;
666 aOut[outPos++] = '\r';
667 aOut[outPos++] = '\n';
668 lineLen = 0;
669 }
670 #endif
671 /* Non-printable char */
672 else if (ch & 0x80 /* 8-bit char */
673 || !(ch & 0xE0) /* control char */
674 || ch == 0x7F /* DEL */
675 || ch == '=') { /* special case */
676 aOut[outPos++] = '=';
677 aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
678 aOut[outPos++] = hextab[ch & 0x0F];
679 lineLen += 3;
680 }
681 /* Soft line break */
682 #if defined(DW_EOL_LF)
683 if (lineLen >= MAXLINE-3 && inPos < aInLen && aIn[inPos] != '\n') {
684 aOut[outPos++] = '=';
685 aOut[outPos++] = '\n';
686 lineLen = 0;
687 }
688 #elif defined(DW_EOL_CRLF)
689 if (lineLen >= MAXLINE-3 && !(inPos < aInLen-1 &&
690 aIn[inPos] == '\r' && aIn[inPos+1] == '\n')) {
691
692 aOut[outPos++] = '=';
693 aOut[outPos++] = '\r';
694 aOut[outPos++] = '\n';
695 lineLen = 0;
696 }
697 #endif
698 }
699 aOut[outPos] = 0;
700 *aOutLen = outPos;
701 return 0;
702 }
703
704
decode_qp(const char * aIn,size_t aInLen,char * aOut,size_t,size_t * aOutLen)705 static int decode_qp(const char* aIn, size_t aInLen, char* aOut,
706 size_t /* aOutSize */, size_t* aOutLen)
707 {
708 size_t i, inPos, outPos, lineLen, nextLineStart, numChars, charsEnd;
709 int isEolFound, softLineBrk, isError;
710 int ch, c1, c2;
711
712 if (!aIn || !aOut || !aOutLen)
713 return -1;
714 isError = 0;
715 inPos = 0;
716 outPos = 0;
717 for (i=0; i < aInLen; ++i) {
718 if (aIn[i] == 0) {
719 aInLen = i;
720 break;
721 }
722 }
723 if (aInLen == 0) {
724 aOut[0] = 0;
725 *aOutLen = 0;
726 return 0;
727 }
728 while (inPos < aInLen) {
729 /* Get line */
730 lineLen = 0;
731 isEolFound = 0;
732 while (!isEolFound && lineLen < aInLen - inPos) {
733 ch = aIn[inPos+lineLen];
734 ++lineLen;
735 if (ch == '\n') {
736 isEolFound = 1;
737 }
738 }
739 nextLineStart = inPos + lineLen;
740 numChars = lineLen;
741 /* Remove white space from end of line */
742 while (numChars > 0) {
743 ch = aIn[inPos+numChars-1] & 0x7F;
744 if (ch != '\n' && ch != '\r' && ch != ' ' && ch != '\t') {
745 break;
746 }
747 --numChars;
748 }
749 charsEnd = inPos + numChars;
750 /* Decode line */
751 softLineBrk = 0;
752 while (inPos < charsEnd) {
753 ch = aIn[inPos++] & 0x7F;
754 if (ch != '=') {
755 /* Normal printable char */
756 aOut[outPos++] = (char) ch;
757 }
758 else /* if (ch == '=') */ {
759 /* Soft line break */
760 if (inPos >= charsEnd) {
761 softLineBrk = 1;
762 break;
763 }
764 /* Non-printable char */
765 else if (inPos < charsEnd-1) {
766 c1 = aIn[inPos++] & 0x7F;
767 if ('0' <= c1 && c1 <= '9')
768 c1 -= '0';
769 else if ('A' <= c1 && c1 <= 'F')
770 c1 = c1 - 'A' + 10;
771 else if ('a' <= c1 && c1 <= 'f')
772 c1 = c1 - 'a' + 10;
773 else
774 isError = 1;
775 c2 = aIn[inPos++] & 0x7F;
776 if ('0' <= c2 && c2 <= '9')
777 c2 -= '0';
778 else if ('A' <= c2 && c2 <= 'F')
779 c2 = c2 - 'A' + 10;
780 else if ('a' <= c2 && c2 <= 'f')
781 c2 = c2 - 'a' + 10;
782 else
783 isError = 1;
784 aOut[outPos++] = (char) ((c1 << 4) + c2);
785 }
786 else /* if (inPos == charsEnd-1) */ {
787 isError = 1;
788 }
789 }
790 }
791 if (isEolFound && !softLineBrk) {
792 const char* cp = DW_EOL;
793 aOut[outPos++] = *cp++;
794 if (*cp) {
795 aOut[outPos++] = *cp;
796 }
797 }
798 inPos = nextLineStart;
799 }
800 aOut[outPos] = 0;
801 *aOutLen = outPos;
802 return (isError) ? -1 : 0;
803 }
804
805
806 /***** Warning: calc_qp_buff_size must stay in sync with encode_qp ******/
807
calc_qp_buff_size(const char * aIn,size_t aInLen)808 static size_t calc_qp_buff_size(const char* aIn, size_t aInLen)
809 {
810 size_t inPos, outLen, lineLen;
811 int ch;
812
813 if (!aIn || aInLen == 0) {
814 return 0;
815 }
816 inPos = 0;
817 outLen = 0;
818 lineLen = 0;
819 while (inPos < aInLen) {
820 ch = aIn[inPos++] & 0xFF;
821 /* '.' at beginning of line (confuses some SMTPs) */
822 if (lineLen == 0 && ch == '.') {
823 outLen += 3;
824 lineLen += 3;
825 }
826 /* "From " at beginning of line (gets mangled in mbox folders) */
827 else if (lineLen == 0 && inPos+3 < aInLen && ch == 'F'
828 && aIn[inPos ] == 'r' && aIn[inPos+1] == 'o'
829 && aIn[inPos+2] == 'm' && aIn[inPos+3] == ' ') {
830 outLen += 3;
831 lineLen += 3;
832 }
833 /* Normal printable char */
834 else if ((62 <= ch && ch <= 126) || (33 <= ch && ch <= 60)) {
835 ++outLen;
836 ++lineLen;
837 }
838 /* Space */
839 else if (ch == ' ') {
840 /* Space at end of line or end of input must be encoded */
841 #if defined(DW_EOL_LF)
842 if (inPos >= aInLen /* End of input? */
843 || aIn[inPos] == '\n') { /* End of line? */
844
845 outLen += 3;
846 lineLen += 3;
847 }
848 #elif defined(DW_EOL_CRLF)
849 if (inPos >= aInLen /* End of input? */
850 || (inPos < aInLen-1 /* End of line? */
851 && aIn[inPos ] == '\r'
852 && aIn[inPos+1] == '\n') ) {
853
854 outLen += 3;
855 lineLen += 3;
856 }
857 #else
858 # error Must define DW_EOL_LF or DW_EOL_CRLF
859 #endif
860 else {
861 ++outLen;
862 ++lineLen;
863 }
864 }
865 /* Hard line break */
866 #if defined(DW_EOL_LF)
867 else if (ch == '\n') {
868 ++outLen;
869 lineLen = 0;
870 }
871 #elif defined(DW_EOL_CRLF)
872 else if (inPos < aInLen && ch == '\r' && aIn[inPos] == '\n') {
873 ++inPos;
874 outLen += 2;
875 lineLen = 0;
876 }
877 #endif
878 /* Non-printable char */
879 else if (ch & 0x80 /* 8-bit char */
880 || !(ch & 0xE0) /* control char */
881 || ch == 0x7F /* DEL */
882 || ch == '=') { /* special case */
883 outLen += 3;
884 lineLen += 3;
885 }
886 /* Soft line break */
887 #if defined(DW_EOL_LF)
888 if (lineLen >= MAXLINE-3 && inPos < aInLen && aIn[inPos] != '\n') {
889 outLen += 2;
890 lineLen = 0;
891 }
892 #elif defined(DW_EOL_CRLF)
893 if (lineLen >= MAXLINE-3 && !(inPos < aInLen-1 &&
894 aIn[inPos] == '\r' && aIn[inPos+1] == '\n')) {
895
896 outLen += 3;
897 lineLen = 0;
898 }
899 #endif
900 }
901 return outLen;
902 }
903
904