summaryrefslogtreecommitdiffstats
path: root/mimelib/dw_cte.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /mimelib/dw_cte.cpp
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'mimelib/dw_cte.cpp')
-rw-r--r--mimelib/dw_cte.cpp901
1 files changed, 901 insertions, 0 deletions
diff --git a/mimelib/dw_cte.cpp b/mimelib/dw_cte.cpp
new file mode 100644
index 000000000..6ebf07f50
--- /dev/null
+++ b/mimelib/dw_cte.cpp
@@ -0,0 +1,901 @@
+//=============================================================================
+// File: dw_cte.cpp
+// Contents: Function definitions for content transfer encodings
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <string.h>
+#include <mimelib/string.h>
+#include <mimelib/utility.h>
+
+#define MAXLINE 76
+
+static size_t calc_crlf_buff_size(const char* srcBuf, size_t srcLen);
+static int to_crlf(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen);
+static int to_lf(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen);
+static int to_cr(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen);
+static int encode_base64(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen);
+static int decode_base64(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen);
+static int encode_qp(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen);
+static int decode_qp(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen);
+static size_t calc_qp_buff_size(const char* aIn, size_t aInLen);
+
+
+int DwToCrLfEol(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Estimate required destination buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = calc_crlf_buff_size(srcBuf, srcLen);
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ to_crlf(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return 0;
+}
+
+
+int DwToLfEol(const DwString& aSrcStr, DwString& aDestStr)
+{
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = srcLen;
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ to_lf(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return 0;
+}
+
+
+int DwToCrEol(const DwString& aSrcStr, DwString& aDestStr)
+{
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = srcLen;
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ to_cr(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return 0;
+}
+
+
+int DwToLocalEol(const DwString& aSrcStr, DwString& aDestStr)
+{
+#if defined(DW_EOL_CRLF)
+ return DwToCrLfEol(aSrcStr, aDestStr);
+#elif defined(DW_EOL_LF)
+ return DwToLfEol(aSrcStr, aDestStr);
+#else
+# error "Must define DW_EOL_CRLF, DW_EOL_LF"
+#endif
+}
+
+
+int DwEncodeBase64(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Estimate required destination buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = (srcLen+2)/3*4;
+ destSize += strlen(DW_EOL)*destSize/72 + 2;
+ destSize += 64; // a little extra room
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ int result =
+ encode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return result;
+}
+
+
+int DwDecodeBase64(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Set destination buffer size same as source buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = srcLen;
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ int result =
+ decode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return result;
+}
+
+
+int DwEncodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Estimate required destination buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = calc_qp_buff_size(srcBuf, srcLen);
+ destSize += 64; // a little extra room
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ int result =
+ encode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return result;
+}
+
+
+int DwDecodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Set destination buffer size same as source buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = srcLen;
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ int result =
+ decode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return result;
+}
+
+
+//============================================================================
+// Everything below this line is private to this file (static)
+//============================================================================
+
+
+static size_t calc_crlf_buff_size(const char* srcBuf, size_t srcLen)
+{
+ size_t i, extra;
+
+ if (!srcBuf) return 0;
+ extra = 0;
+ for (i=0; i < srcLen; ) {
+ switch (srcBuf[i]) {
+ /* Bare LF (UNIX or C text) */
+ case '\n':
+ ++extra;
+ ++i;
+ break;
+ case '\r':
+ /* CR LF (DOS, Windows, or MIME text) */
+ if (i+1 < srcLen && srcBuf[i+1] == '\n') {
+ i += 2;
+ }
+ /* Bare CR (Macintosh text) */
+ else {
+ ++extra;
+ ++i;
+ }
+ break;
+ default:
+ ++i;
+ }
+ }
+ return srcLen + extra;
+}
+
+
+static int to_crlf(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen)
+{
+ size_t iSrc, iDest;
+
+ if (!srcBuf || !destBuf || !destLen) return -1;
+ iSrc = iDest = 0;
+ while (iSrc < srcLen && iDest < destSize) {
+ switch (srcBuf[iSrc]) {
+ /* Bare LF (UNIX or C text) */
+ case '\n':
+ destBuf[iDest++] = '\r';
+ if (iDest < destSize) {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ break;
+ case '\r':
+ /* CR LF (DOS, Windows, or MIME text) */
+ if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ if (iDest < destSize) {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ }
+ /* Bare CR (Macintosh text) */
+ else {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ if (iDest < destSize) {
+ destBuf[iDest++] = '\n';
+ }
+ }
+ break;
+ default:
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ }
+ *destLen = iDest;
+ if (iDest < destSize) {
+ destBuf[iDest] = 0;
+ }
+ return 0;
+}
+
+
+static int to_lf(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen)
+{
+ size_t iSrc, iDest;
+
+ if (!srcBuf || !destBuf || !destLen) return -1;
+ iSrc = iDest = 0;
+ while (iSrc < srcLen && iDest < destSize) {
+ switch (srcBuf[iSrc]) {
+ /* Bare LF (UNIX or C text) */
+ case '\n':
+ destBuf[iDest++] = srcBuf[iSrc++];
+ break;
+ case '\r':
+ /* CR LF (DOS, Windows, or MIME text) */
+ if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
+ ++iSrc;
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ /* Bare CR (Macintosh text) */
+ else {
+ destBuf[iDest++] = '\n';
+ ++iSrc;
+ }
+ break;
+ default:
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ }
+ *destLen = iDest;
+ if (iDest < destSize) {
+ destBuf[iDest] = 0;
+ }
+ return 0;
+}
+
+
+static int to_cr(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen)
+{
+ size_t iSrc, iDest;
+
+ if (!srcBuf || !destBuf || !destLen) return -1;
+ iSrc = iDest = 0;
+ while (iSrc < srcLen && iDest < destSize) {
+ switch (srcBuf[iSrc]) {
+ /* Bare LF (UNIX or C text) */
+ case '\n':
+ destBuf[iDest++] = '\r';
+ ++iSrc;
+ break;
+ case '\r':
+ /* CR LF (DOS, Windows, or MIME text) */
+ if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ ++iSrc;
+ }
+ /* Bare CR (Macintosh text) */
+ else {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ break;
+ default:
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ }
+ *destLen = iDest;
+ if (iDest < destSize) {
+ destBuf[iDest] = 0;
+ }
+ return 0;
+}
+
+
+static char base64tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static char base64idx[128] = {
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377', 62,'\377','\377','\377', 63,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61,'\377','\377','\377','\377','\377','\377',
+ '\377', 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25,'\377','\377','\377','\377','\377',
+ '\377', 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51,'\377','\377','\377','\377','\377'
+};
+
+static char hextab[] = "0123456789ABCDEF";
+
+#ifdef __cplusplus
+inline int isbase64(int a) {
+ return ('A' <= a && a <= 'Z')
+ || ('a' <= a && a <= 'z')
+ || ('0' <= a && a <= '9')
+ || a == '+' || a == '/';
+}
+#else
+#define isbase64(a) ( ('A' <= (a) && (a) <= 'Z') \
+ || ('a' <= (a) && (a) <= 'z') \
+ || ('0' <= (a) && (a) <= '9') \
+ || (a) == '+' || (a) == '/' )
+#endif
+
+
+static int encode_base64(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen)
+{
+ if (!aIn || !aOut || !aOutLen)
+ return -1;
+ size_t inLen = aInLen;
+ char* out = aOut;
+ size_t outSize = (inLen+2)/3*4; /* 3:4 conversion ratio */
+ outSize += strlen(DW_EOL)*outSize/MAXLINE + 2; /* Space for newlines and NUL */
+ if (aOutSize < outSize)
+ return -1;
+ size_t inPos = 0;
+ size_t outPos = 0;
+ int c1, c2, c3;
+ int lineLen = 0;
+ /* Get three characters at a time and encode them. */
+ for (size_t i=0; i < inLen/3; ++i) {
+ c1 = aIn[inPos++] & 0xFF;
+ c2 = aIn[inPos++] & 0xFF;
+ c3 = aIn[inPos++] & 0xFF;
+ out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+ out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
+ out[outPos++] = base64tab[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)];
+ out[outPos++] = base64tab[c3 & 0x3F];
+ lineLen += 4;
+ if (lineLen >= MAXLINE-3) {
+ const char* cp = DW_EOL;
+ out[outPos++] = *cp++;
+ if (*cp) {
+ out[outPos++] = *cp;
+ }
+ lineLen = 0;
+ }
+ }
+ /* Encode the remaining one or two characters. */
+ const char* cp;
+ switch (inLen % 3) {
+ case 0:
+ cp = DW_EOL;
+ out[outPos++] = *cp++;
+ if (*cp) {
+ out[outPos++] = *cp;
+ }
+ break;
+ case 1:
+ c1 = aIn[inPos] & 0xFF;
+ out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+ out[outPos++] = base64tab[((c1 & 0x03) << 4)];
+ out[outPos++] = '=';
+ out[outPos++] = '=';
+ cp = DW_EOL;
+ out[outPos++] = *cp++;
+ if (*cp) {
+ out[outPos++] = *cp;
+ }
+ break;
+ case 2:
+ c1 = aIn[inPos++] & 0xFF;
+ c2 = aIn[inPos] & 0xFF;
+ out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+ out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
+ out[outPos++] = base64tab[((c2 & 0x0F) << 2)];
+ out[outPos++] = '=';
+ cp = DW_EOL;
+ out[outPos++] = *cp++;
+ if (*cp) {
+ out[outPos++] = *cp;
+ }
+ break;
+ }
+ out[outPos] = 0;
+ *aOutLen = outPos;
+ return 0;
+}
+
+
+static int decode_base64(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen)
+{
+ if (!aIn || !aOut || !aOutLen)
+ return -1;
+ size_t inLen = aInLen;
+ char* out = aOut;
+ size_t outSize = ( ( inLen + 3 ) / 4 ) * 3;
+ if (aOutSize < outSize)
+ return -1;
+ /* Get four input chars at a time and decode them. Ignore white space
+ * chars (CR, LF, SP, HT). If '=' is encountered, terminate input. If
+ * a char other than white space, base64 char, or '=' is encountered,
+ * flag an input error, but otherwise ignore the char.
+ */
+ int isErr = 0;
+ int isEndSeen = 0;
+ int b1, b2, b3;
+ int a1, a2, a3, a4;
+ size_t inPos = 0;
+ size_t outPos = 0;
+ while (inPos < inLen) {
+ a1 = a2 = a3 = a4 = 0;
+ while (inPos < inLen) {
+ a1 = aIn[inPos++] & 0xFF;
+ if (isbase64(a1)) {
+ break;
+ }
+ else if (a1 == '=') {
+ isEndSeen = 1;
+ break;
+ }
+ else if (a1 != '\r' && a1 != '\n' && a1 != ' ' && a1 != '\t') {
+ isErr = 1;
+ }
+ }
+ while (inPos < inLen) {
+ a2 = aIn[inPos++] & 0xFF;
+ if (isbase64(a2)) {
+ break;
+ }
+ else if (a2 == '=') {
+ isEndSeen = 1;
+ break;
+ }
+ else if (a2 != '\r' && a2 != '\n' && a2 != ' ' && a2 != '\t') {
+ isErr = 1;
+ }
+ }
+ while (inPos < inLen) {
+ a3 = aIn[inPos++] & 0xFF;
+ if (isbase64(a3)) {
+ break;
+ }
+ else if (a3 == '=') {
+ isEndSeen = 1;
+ break;
+ }
+ else if (a3 != '\r' && a3 != '\n' && a3 != ' ' && a3 != '\t') {
+ isErr = 1;
+ }
+ }
+ while (inPos < inLen) {
+ a4 = aIn[inPos++] & 0xFF;
+ if (isbase64(a4)) {
+ break;
+ }
+ else if (a4 == '=') {
+ isEndSeen = 1;
+ break;
+ }
+ else if (a4 != '\r' && a4 != '\n' && a4 != ' ' && a4 != '\t') {
+ isErr = 1;
+ }
+ }
+ if (isbase64(a1) && isbase64(a2) && isbase64(a3) && isbase64(a4)) {
+ a1 = base64idx[a1] & 0xFF;
+ a2 = base64idx[a2] & 0xFF;
+ a3 = base64idx[a3] & 0xFF;
+ a4 = base64idx[a4] & 0xFF;
+ b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+ b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
+ b3 = ((a3 << 6) & 0xC0) | ( a4 & 0x3F);
+ out[outPos++] = char(b1);
+ out[outPos++] = char(b2);
+ out[outPos++] = char(b3);
+ }
+ else if (isbase64(a1) && isbase64(a2) && isbase64(a3) && a4 == '=') {
+ a1 = base64idx[a1] & 0xFF;
+ a2 = base64idx[a2] & 0xFF;
+ a3 = base64idx[a3] & 0xFF;
+ b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+ b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
+ out[outPos++] = char(b1);
+ out[outPos++] = char(b2);
+ break;
+ }
+ else if (isbase64(a1) && isbase64(a2) && a3 == '=' && a4 == '=') {
+ a1 = base64idx[a1] & 0xFF;
+ a2 = base64idx[a2] & 0xFF;
+ b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+ out[outPos++] = char(b1);
+ break;
+ }
+ else {
+ break;
+ }
+ if (isEndSeen) {
+ break;
+ }
+ } /* end while loop */
+ *aOutLen = outPos;
+ return (isErr) ? -1 : 0;
+}
+
+
+/***** Warning: calc_qp_buff_size must stay in sync with encode_qp ******/
+
+static int encode_qp(const char* aIn, size_t aInLen, char* aOut,
+ size_t /*aOutSize */, size_t* aOutLen)
+{
+ size_t inPos, outPos, lineLen;
+ int ch;
+
+ if (!aIn || !aOut || !aOutLen) {
+ return -1;
+ }
+ inPos = 0;
+ outPos = 0;
+ lineLen = 0;
+ while (inPos < aInLen) {
+ ch = aIn[inPos++] & 0xFF;
+ /* '.' at beginning of line (confuses some SMTPs) */
+ if (lineLen == 0 && ch == '.') {
+ aOut[outPos++] = '=';
+ aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
+ aOut[outPos++] = hextab[ch & 0x0F];
+ lineLen += 3;
+ }
+ /* "From " at beginning of line (gets mangled in mbox folders) */
+ else if (lineLen == 0 && inPos+3 < aInLen && ch == 'F'
+ && aIn[inPos ] == 'r' && aIn[inPos+1] == 'o'
+ && aIn[inPos+2] == 'm' && aIn[inPos+3] == ' ') {
+ aOut[outPos++] = '=';
+ aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
+ aOut[outPos++] = hextab[ch & 0x0F];
+ lineLen += 3;
+ }
+ /* Normal printable char */
+ else if ((62 <= ch && ch <= 126) || (33 <= ch && ch <= 60)) {
+ aOut[outPos++] = (char) ch;
+ ++lineLen;
+ }
+ /* Space */
+ else if (ch == ' ') {
+ /* Space at end of line or end of input must be encoded */
+#if defined(DW_EOL_LF)
+ if (inPos >= aInLen /* End of input? */
+ || aIn[inPos] == '\n') { /* End of line? */
+
+ aOut[outPos++] = '=';
+ aOut[outPos++] = '2';
+ aOut[outPos++] = '0';
+ lineLen += 3;
+ }
+#elif defined(DW_EOL_CRLF)
+ if (inPos >= aInLen /* End of input? */
+ || (inPos < aInLen-1 /* End of line? */
+ && aIn[inPos ] == '\r'
+ && aIn[inPos+1] == '\n') ) {
+
+ aOut[outPos++] = '=';
+ aOut[outPos++] = '2';
+ aOut[outPos++] = '0';
+ lineLen += 3;
+ }
+#else
+# error Must define DW_EOL_LF or DW_EOL_CRLF
+#endif
+ else {
+ aOut[outPos++] = ' ';
+ ++lineLen;
+ }
+ }
+ /* Hard line break */
+#if defined(DW_EOL_LF)
+ else if (ch == '\n') {
+ aOut[outPos++] = '\n';
+ lineLen = 0;
+ }
+#elif defined(DW_EOL_CRLF)
+ else if (inPos < aInLen && ch == '\r' && aIn[inPos] == '\n') {
+ ++inPos;
+ aOut[outPos++] = '\r';
+ aOut[outPos++] = '\n';
+ lineLen = 0;
+ }
+#endif
+ /* Non-printable char */
+ else if (ch & 0x80 /* 8-bit char */
+ || !(ch & 0xE0) /* control char */
+ || ch == 0x7F /* DEL */
+ || ch == '=') { /* special case */
+ aOut[outPos++] = '=';
+ aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
+ aOut[outPos++] = hextab[ch & 0x0F];
+ lineLen += 3;
+ }
+ /* Soft line break */
+#if defined(DW_EOL_LF)
+ if (lineLen >= MAXLINE-3 && inPos < aInLen && aIn[inPos] != '\n') {
+ aOut[outPos++] = '=';
+ aOut[outPos++] = '\n';
+ lineLen = 0;
+ }
+#elif defined(DW_EOL_CRLF)
+ if (lineLen >= MAXLINE-3 && !(inPos < aInLen-1 &&
+ aIn[inPos] == '\r' && aIn[inPos+1] == '\n')) {
+
+ aOut[outPos++] = '=';
+ aOut[outPos++] = '\r';
+ aOut[outPos++] = '\n';
+ lineLen = 0;
+ }
+#endif
+ }
+ aOut[outPos] = 0;
+ *aOutLen = outPos;
+ return 0;
+}
+
+
+static int decode_qp(const char* aIn, size_t aInLen, char* aOut,
+ size_t /* aOutSize */, size_t* aOutLen)
+{
+ size_t i, inPos, outPos, lineLen, nextLineStart, numChars, charsEnd;
+ int isEolFound, softLineBrk, isError;
+ int ch, c1, c2;
+
+ if (!aIn || !aOut || !aOutLen)
+ return -1;
+ isError = 0;
+ inPos = 0;
+ outPos = 0;
+ for (i=0; i < aInLen; ++i) {
+ if (aIn[i] == 0) {
+ aInLen = i;
+ break;
+ }
+ }
+ if (aInLen == 0) {
+ aOut[0] = 0;
+ *aOutLen = 0;
+ return 0;
+ }
+ while (inPos < aInLen) {
+ /* Get line */
+ lineLen = 0;
+ isEolFound = 0;
+ while (!isEolFound && lineLen < aInLen - inPos) {
+ ch = aIn[inPos+lineLen];
+ ++lineLen;
+ if (ch == '\n') {
+ isEolFound = 1;
+ }
+ }
+ nextLineStart = inPos + lineLen;
+ numChars = lineLen;
+ /* Remove white space from end of line */
+ while (numChars > 0) {
+ ch = aIn[inPos+numChars-1] & 0x7F;
+ if (ch != '\n' && ch != '\r' && ch != ' ' && ch != '\t') {
+ break;
+ }
+ --numChars;
+ }
+ charsEnd = inPos + numChars;
+ /* Decode line */
+ softLineBrk = 0;
+ while (inPos < charsEnd) {
+ ch = aIn[inPos++] & 0x7F;
+ if (ch != '=') {
+ /* Normal printable char */
+ aOut[outPos++] = (char) ch;
+ }
+ else /* if (ch == '=') */ {
+ /* Soft line break */
+ if (inPos >= charsEnd) {
+ softLineBrk = 1;
+ break;
+ }
+ /* Non-printable char */
+ else if (inPos < charsEnd-1) {
+ c1 = aIn[inPos++] & 0x7F;
+ if ('0' <= c1 && c1 <= '9')
+ c1 -= '0';
+ else if ('A' <= c1 && c1 <= 'F')
+ c1 = c1 - 'A' + 10;
+ else if ('a' <= c1 && c1 <= 'f')
+ c1 = c1 - 'a' + 10;
+ else
+ isError = 1;
+ c2 = aIn[inPos++] & 0x7F;
+ if ('0' <= c2 && c2 <= '9')
+ c2 -= '0';
+ else if ('A' <= c2 && c2 <= 'F')
+ c2 = c2 - 'A' + 10;
+ else if ('a' <= c2 && c2 <= 'f')
+ c2 = c2 - 'a' + 10;
+ else
+ isError = 1;
+ aOut[outPos++] = (char) ((c1 << 4) + c2);
+ }
+ else /* if (inPos == charsEnd-1) */ {
+ isError = 1;
+ }
+ }
+ }
+ if (isEolFound && !softLineBrk) {
+ const char* cp = DW_EOL;
+ aOut[outPos++] = *cp++;
+ if (*cp) {
+ aOut[outPos++] = *cp;
+ }
+ }
+ inPos = nextLineStart;
+ }
+ aOut[outPos] = 0;
+ *aOutLen = outPos;
+ return (isError) ? -1 : 0;
+}
+
+
+/***** Warning: calc_qp_buff_size must stay in sync with encode_qp ******/
+
+static size_t calc_qp_buff_size(const char* aIn, size_t aInLen)
+{
+ size_t inPos, outLen, lineLen;
+ int ch;
+
+ if (!aIn || aInLen == 0) {
+ return 0;
+ }
+ inPos = 0;
+ outLen = 0;
+ lineLen = 0;
+ while (inPos < aInLen) {
+ ch = aIn[inPos++] & 0xFF;
+ /* '.' at beginning of line (confuses some SMTPs) */
+ if (lineLen == 0 && ch == '.') {
+ outLen += 3;
+ lineLen += 3;
+ }
+ /* "From " at beginning of line (gets mangled in mbox folders) */
+ else if (lineLen == 0 && inPos+3 < aInLen && ch == 'F'
+ && aIn[inPos ] == 'r' && aIn[inPos+1] == 'o'
+ && aIn[inPos+2] == 'm' && aIn[inPos+3] == ' ') {
+ outLen += 3;
+ lineLen += 3;
+ }
+ /* Normal printable char */
+ else if ((62 <= ch && ch <= 126) || (33 <= ch && ch <= 60)) {
+ ++outLen;
+ ++lineLen;
+ }
+ /* Space */
+ else if (ch == ' ') {
+ /* Space at end of line or end of input must be encoded */
+#if defined(DW_EOL_LF)
+ if (inPos >= aInLen /* End of input? */
+ || aIn[inPos] == '\n') { /* End of line? */
+
+ outLen += 3;
+ lineLen += 3;
+ }
+#elif defined(DW_EOL_CRLF)
+ if (inPos >= aInLen /* End of input? */
+ || (inPos < aInLen-1 /* End of line? */
+ && aIn[inPos ] == '\r'
+ && aIn[inPos+1] == '\n') ) {
+
+ outLen += 3;
+ lineLen += 3;
+ }
+#else
+# error Must define DW_EOL_LF or DW_EOL_CRLF
+#endif
+ else {
+ ++outLen;
+ ++lineLen;
+ }
+ }
+ /* Hard line break */
+#if defined(DW_EOL_LF)
+ else if (ch == '\n') {
+ ++outLen;
+ lineLen = 0;
+ }
+#elif defined(DW_EOL_CRLF)
+ else if (inPos < aInLen && ch == '\r' && aIn[inPos] == '\n') {
+ ++inPos;
+ outLen += 2;
+ lineLen = 0;
+ }
+#endif
+ /* Non-printable char */
+ else if (ch & 0x80 /* 8-bit char */
+ || !(ch & 0xE0) /* control char */
+ || ch == 0x7F /* DEL */
+ || ch == '=') { /* special case */
+ outLen += 3;
+ lineLen += 3;
+ }
+ /* Soft line break */
+#if defined(DW_EOL_LF)
+ if (lineLen >= MAXLINE-3 && inPos < aInLen && aIn[inPos] != '\n') {
+ outLen += 2;
+ lineLen = 0;
+ }
+#elif defined(DW_EOL_CRLF)
+ if (lineLen >= MAXLINE-3 && !(inPos < aInLen-1 &&
+ aIn[inPos] == '\r' && aIn[inPos+1] == '\n')) {
+
+ outLen += 3;
+ lineLen = 0;
+ }
+#endif
+ }
+ return outLen;
+}
+