Removed the chunked-io stuff from libcitadel. Nothing was using it and it isn't...
[citadel.git] / libcitadel / lib / stringbuf.c
index 795dd604d734f881f0792d6398e44a3886cd3871..770cb3eb575893357592c83869fc68a543ab9ad8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1987-2011 by the citadel.org team
+ * Copyright (c) 1987-2018 by the citadel.org team
  *
  * This program is open source software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <sys/types.h>
 #define SHOW_ME_VAPPEND_PRINTF
 #include <stdarg.h>
-#ifndef LINUX_SENDFILE
-#include <sys/sendfile.h>
-#endif
+
 #include "libcitadel.h"
 
+#include "b64/cencode.h"
+#include "b64/cdecode.h"
+
 #ifdef HAVE_ICONV
 #include <iconv.h>
 #endif
@@ -42,8 +43,8 @@
 #include <execinfo.h>
 #endif
 
-#ifdef LINUX_SENDFILE
-#include <sys/sendfile.h>
+#ifdef UNDEF_MEMCPY
+#undef memcpy
 #endif
 
 #ifdef HAVE_ZLIB
@@ -52,6 +53,13 @@ int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen,
                           const Bytef * source, uLong sourceLen, int level);
 #endif
 int BaseStrBufSize = 64;
+int EnableSplice = 0;
+int ZLibCompressionRatio = -1; /* defaults to 6 */
+#ifdef HAVE_ZLIB
+#define DEF_MEM_LEVEL 8 /*< memlevel??? */
+#define OS_CODE 0x03   /*< unix */
+const int gz_magic[2] = { 0x1f, 0x8b };        /* gzip magic header */
+#endif
 
 const char *StrBufNOTNULL = ((char*) NULL) - 1;
 
@@ -248,7 +256,7 @@ void dbg_Init(StrBuf *Buf)
  * @param A First one
  * @param B second one
  */
-static inline void SwapBuffers(StrBuf *A, StrBuf *B)
+static inline void iSwapBuffers(StrBuf *A, StrBuf *B)
 {
        StrBuf C;
 
@@ -258,6 +266,12 @@ static inline void SwapBuffers(StrBuf *A, StrBuf *B)
 
 }
 
+void SwapBuffers(StrBuf *A, StrBuf *B)
+{
+       iSwapBuffers(A, B);
+}
+
+
 /** 
  * @ingroup StrBuf_Cast
  * @brief Cast operator to Plain String 
@@ -363,7 +377,12 @@ long StrBufShrinkToFit(StrBuf *Buf, int Force)
        if (Force || 
            (Buf->BufUsed + (Buf->BufUsed / 3) > Buf->BufSize))
        {
-               char *TmpBuf = (char*) malloc(Buf->BufUsed + 1);
+               char *TmpBuf;
+
+               TmpBuf = (char*) malloc(Buf->BufUsed + 1);
+               if (TmpBuf == NULL)
+                       return -1;
+
                memcpy (TmpBuf, Buf->buf, Buf->BufUsed + 1);
                Buf->BufSize = Buf->BufUsed + 1;
                free(Buf->buf);
@@ -382,7 +401,15 @@ StrBuf* NewStrBuf(void)
        StrBuf *NewBuf;
 
        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+       if (NewBuf == NULL)
+               return NULL;
+
        NewBuf->buf = (char*) malloc(BaseStrBufSize);
+       if (NewBuf->buf == NULL)
+       {
+               free(NewBuf);
+               return NULL;
+       }
        NewBuf->buf[0] = '\0';
        NewBuf->BufSize = BaseStrBufSize;
        NewBuf->BufUsed = 0;
@@ -407,7 +434,16 @@ StrBuf* NewStrBufDup(const StrBuf *CopyMe)
                return NewStrBuf();
 
        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+       if (NewBuf == NULL)
+               return NULL;
+
        NewBuf->buf = (char*) malloc(CopyMe->BufSize);
+       if (NewBuf->buf == NULL)
+       {
+               free(NewBuf);
+               return NULL;
+       }
+
        memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
        NewBuf->BufUsed = CopyMe->BufUsed;
        NewBuf->BufSize = CopyMe->BufSize;
@@ -480,7 +516,7 @@ void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, cons
                }
                else 
                        NewBuf = *CreateRelpaceMe;
-               SwapBuffers (NewBuf, CopyFlushMe);
+               iSwapBuffers (NewBuf, CopyFlushMe);
        }
        if (!KeepOriginal)
                FlushStrBuf(CopyFlushMe);
@@ -503,6 +539,9 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars)
        size_t CopySize;
 
        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+       if (NewBuf == NULL)
+               return NULL;
+
        if (nChars < 0)
                CopySize = strlen((ptr != NULL)?ptr:"");
        else
@@ -513,6 +552,7 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars)
 
        if (Siz == 0)
        {
+               free(NewBuf);
                return NULL;
        }
 
@@ -595,6 +635,8 @@ StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
        StrBuf *NewBuf;
 
        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+       if (NewBuf == NULL)
+               return NULL;
        NewBuf->buf = (char*) StringConstant;
        NewBuf->BufSize = SizeOfStrConstant;
        NewBuf->BufUsed = SizeOfStrConstant;
@@ -613,7 +655,7 @@ StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
  */
 int FlushStrBuf(StrBuf *buf)
 {
-       if (buf == NULL)
+       if ((buf == NULL) || (buf->buf == NULL))
                return -1;
        if (buf->ConstBuf)
                return -1;       
@@ -817,7 +859,8 @@ long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char Po
  */
 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, unsigned long Offset)
 {
-       if ((AppendBuf == NULL) || (Buf == NULL) || (AppendBuf->buf == NULL))
+       if ((AppendBuf == NULL) || (AppendBuf->buf == NULL) ||
+           (Buf == NULL) || (Buf->buf == NULL))
                return;
 
        if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed + 1)
@@ -1022,16 +1065,18 @@ int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t n
        }
        if (Offset + nChars < Source->BufUsed)
        {
-               if (nChars >= dest->BufSize)
-                       IncreaseBuf(dest, 0, nChars + 1);
+               if ((nChars >= dest->BufSize) && 
+                   (IncreaseBuf(dest, 0, nChars + 1) == -1))
+                       return 0;
                memcpy(dest->buf, Source->buf + Offset, nChars);
                dest->BufUsed = nChars;
                dest->buf[dest->BufUsed] = '\0';
                return nChars;
        }
        NCharsRemain = Source->BufUsed - Offset;
-       if (NCharsRemain  >= dest->BufSize)
-               IncreaseBuf(dest, 0, NCharsRemain + 1);
+       if ((NCharsRemain  >= dest->BufSize) && 
+           (IncreaseBuf(dest, 0, NCharsRemain + 1) == -1))
+               return 0;
        memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
        dest->BufUsed = NCharsRemain;
        dest->buf[dest->BufUsed] = '\0';
@@ -1064,7 +1109,9 @@ void StrBufCutLeft(StrBuf *Buf, int nChars)
  */
 void StrBufCutRight(StrBuf *Buf, int nChars)
 {
-       if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
+       if ((Buf == NULL) || (Buf->BufUsed == 0) || (Buf->buf == NULL))
+               return;
+
        if (nChars >= Buf->BufUsed) {
                FlushStrBuf(Buf);
                return;
@@ -1141,29 +1188,22 @@ void StrBufSpaceToBlank(StrBuf *Buf)
 
 void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
 {
-       const char *pBuff;
        const char *pLeft;
        const char *pRight;
 
-       if (Buf == NULL)
+       if ((Buf == NULL) || (Buf->buf == NULL)) {
                return;
-       pLeft = pBuff = Buf->buf;
-       while (pBuff != NULL) {
-               pLeft = pBuff;
-               pBuff = strchr(pBuff, leftboundary);
-               if (pBuff != NULL)
-                       pBuff++;
        }
-               
-       if (pLeft != NULL)
-               pBuff = pLeft;
-       else
-               pBuff = Buf->buf;
-       pRight = strchr(pBuff, rightboundary);
-       if (pRight != NULL)
+
+       pRight = strchr(Buf->buf, rightboundary);
+       if (pRight != NULL) {
                StrBufCutAt(Buf, 0, pRight);
-       if (pLeft != NULL)
-               StrBufCutLeft(Buf, pLeft - Buf->buf);
+       }
+
+       pLeft = strrchr(ChrPtr(Buf), leftboundary);
+       if (pLeft != NULL) {
+               StrBufCutLeft(Buf, pLeft - Buf->buf + 1);
+       }
 }
 
 
@@ -1343,6 +1383,23 @@ int StrBufRemove_token(StrBuf *Source, int parmnum, char separator)
        return ReducedBy;
 }
 
+int StrBufExtract_tokenFromStr(StrBuf *dest, const char *Source, long SourceLen, int parmnum, char separator)
+{
+       const StrBuf Temp = {
+               (char*)Source,
+               SourceLen,
+               SourceLen,
+               1
+#ifdef SIZE_DEBUG
+               ,
+               0,
+               "",
+               ""
+#endif
+       };
+
+       return StrBufExtract_token(dest, &Temp, parmnum, separator);
+}
 
 /**
  * @ingroup StrBuf_Tokenizer
@@ -1823,6 +1880,170 @@ void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
        *pt = '\0';
 }
 
+/** 
+ * @ingroup StrBuf_DeEnCoder
+ * @brief Escape a string for feeding out as a the username/password part of an URL while appending it to a Buffer
+ * @param OutBuf the output buffer
+ * @param In Buffer to encode
+ * @param PlainIn way in from plain old c strings
+ */
+void StrBufUrlescUPAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
+{
+       const char *pch, *pche;
+       char *pt, *pte;
+       int len;
+       
+       if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
+               return;
+       if (PlainIn != NULL) {
+               len = strlen(PlainIn);
+               pch = PlainIn;
+               pche = pch + len;
+       }
+       else {
+               pch = In->buf;
+               pche = pch + In->BufUsed;
+               len = In->BufUsed;
+       }
+
+       if (len == 0) 
+               return;
+
+       pt = OutBuf->buf + OutBuf->BufUsed;
+       pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
+
+       while (pch < pche) {
+               if (pt >= pte) {
+                       IncreaseBuf(OutBuf, 1, -1);
+                       pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
+                       pt = OutBuf->buf + OutBuf->BufUsed;
+               }
+
+               if((*pch >= 'a' && *pch <= 'z') ||
+                  (*pch >= 'A' && *pch <= 'Z') || /* A-Z */
+                  (*pch >= '0' && *pch <= ':') || /* 0-9 : */
+                  (*pch == '!') || (*pch == '_') || 
+                  (*pch == ',') || (*pch == '.'))
+               {
+                       *(pt++) = *(pch++);
+                       OutBuf->BufUsed++;
+               }                       
+               else {
+                       *pt = '%';
+                       *(pt + 1) = HexList[(unsigned char)*pch][0];
+                       *(pt + 2) = HexList[(unsigned char)*pch][1];
+                       pt += 3;
+                       OutBuf->BufUsed += 3;
+                       pch ++;
+               }
+       }
+       *pt = '\0';
+}
+
+/** 
+ * @ingroup StrBuf_DeEnCoder
+ * @brief append a string with characters having a special meaning in xml encoded to the buffer
+ * @param OutBuf the output buffer
+ * @param In Buffer to encode
+ * @param PlainIn way in from plain old c strings
+ * @param PlainInLen way in from plain old c strings; maybe you've got binary data or know the length?
+ * @param OverrideLowChars should chars < 0x20 be replaced by _ or escaped as xml entity?
+ */
+void StrBufXMLEscAppend(StrBuf *OutBuf,
+                       const StrBuf *In,
+                       const char *PlainIn,
+                       long PlainInLen,
+                       int OverrideLowChars)
+{
+       const char *pch, *pche;
+       char *pt, *pte;
+       int IsUtf8Sequence;
+       int len;
+
+       if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
+               return;
+       if (PlainIn != NULL) {
+               if (PlainInLen < 0)
+                       len = strlen((const char*)PlainIn);
+               else
+                       len = PlainInLen;
+               pch = PlainIn;
+               pche = pch + len;
+       }
+       else {
+               pch = (const char*)In->buf;
+               pche = pch + In->BufUsed;
+               len = In->BufUsed;
+       }
+
+       if (len == 0)
+               return;
+
+       pt = OutBuf->buf + OutBuf->BufUsed;
+       /**< we max append 6 chars at once plus the \0 */
+       pte = OutBuf->buf + OutBuf->BufSize - 6;
+
+       while (pch < pche) {
+               if (pt >= pte) {
+                       OutBuf->BufUsed = pt - OutBuf->buf;
+                       IncreaseBuf(OutBuf, 1, -1);
+                       pte = OutBuf->buf + OutBuf->BufSize - 6;
+                       /**< we max append 3 chars at once plus the \0 */
+
+                       pt = OutBuf->buf + OutBuf->BufUsed;
+               }
+
+               if (*pch == '<') {
+                       memcpy(pt, HKEY("&lt;"));
+                       pt += 4;
+                       pch ++;
+               }
+               else if (*pch == '>') {
+                       memcpy(pt, HKEY("&gt;"));
+                       pt += 4;
+                       pch ++;
+               }
+               else if (*pch == '&') {
+                       memcpy(pt, HKEY("&amp;"));
+                       pt += 5;
+                       pch++;
+               }
+               else if ((*pch >= 0x20) && (*pch <= 0x7F)) {
+                       *pt = *pch;
+                       pt++; pch++;
+               }
+               else {
+                       IsUtf8Sequence =  Ctdl_GetUtf8SequenceLength(pch, pche);
+                       if (IsUtf8Sequence)
+                       {
+                               while ((IsUtf8Sequence > 0) && 
+                                      (pch < pche))
+                               {
+                                       *pt = *pch;
+                                       pt ++;
+                                       pch ++;
+                                       --IsUtf8Sequence;
+                               }
+                       }
+                       else
+                       {
+                               *pt = '&';
+                               pt++;
+                               *pt = HexList[*(unsigned char*)pch][0];
+                               pt ++;
+                               *pt = HexList[*(unsigned char*)pch][1];
+                               pt ++; pch ++;
+                               *pt = '&';
+                               pt++;
+                               pch ++;
+                       }
+               }
+       }
+       *pt = '\0';
+       OutBuf->BufUsed = pt - OutBuf->buf;
+}
+
+
 /** 
  * @ingroup StrBuf_DeEnCoder
  * @brief append a string in hex encoding to the buffer
@@ -1874,6 +2095,45 @@ void StrBufHexEscAppend(StrBuf *OutBuf, const StrBuf *In, const unsigned char *P
        *pt = '\0';
 }
 
+void StrBufBase64Append(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn, long PlainInLen, int linebreaks)
+{
+       const char *pch;
+       char *pt;
+       int len;
+       long ExpectLen;
+       
+       if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
+               return;
+       if (PlainIn != NULL) {
+               if (PlainInLen < 0)
+                       len = strlen(PlainIn);
+               else
+                       len = PlainInLen;
+               pch = PlainIn;
+       }
+       else {
+               pch = In->buf;
+               len = In->BufUsed;
+       }
+
+       if (len == 0) 
+               return;
+
+       ExpectLen = ((len * 134) / 100) + OutBuf->BufUsed;
+
+       if (ExpectLen > OutBuf->BufSize)
+               if (IncreaseBuf(OutBuf, 1, ExpectLen) < ExpectLen)
+                       return;
+
+       pt = OutBuf->buf + OutBuf->BufUsed;
+
+       len = CtdlEncodeBase64(pt, pch, len, linebreaks);
+
+       pt += len;
+       OutBuf->BufUsed += len;
+       *pt = '\0';
+}
+
 /** 
  * @ingroup StrBuf_DeEnCoder
  * @brief append a string in hex encoding to the buffer
@@ -2431,6 +2691,23 @@ long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *Plai
        return Target->BufUsed;
 }
 
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief replace all non-Ascii characters by another
+ * @param Buf buffer to inspect
+ * @param repl charater to stamp over non ascii chars
+ */
+void StrBufAsciify(StrBuf *Buf, const char repl)
+{
+       long offset;
+
+       for (offset = 0; offset < Buf->BufUsed; offset ++)
+               if (!isascii(Buf->buf[offset]))
+                       Buf->buf[offset] = repl;
+       
+}
+
 /**
  * @ingroup StrBuf_DeEnCoder
  * @brief unhide special chars hidden to the HTML escaper
@@ -2442,14 +2719,14 @@ void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source)
        int a, b, len;
        char hex[3];
 
-       if (target != NULL)
-               FlushStrBuf(target);
-
-       if (source == NULL ||target == NULL)
+       if ((source == NULL) || (target == NULL) || (target->buf == NULL))
        {
                return;
        }
 
+       if (target != NULL)
+               FlushStrBuf(target);
+
        len = source->BufUsed;
        for (a = 0; a < len; ++a) {
                if (target->BufUsed >= target->BufSize)
@@ -2486,7 +2763,7 @@ void StrBufEUid_escapize(StrBuf *target, const StrBuf *source)
        if (target != NULL)
                FlushStrBuf(target);
 
-       if (source == NULL ||target == NULL)
+       if ((source == NULL) || (target == NULL) || (target->buf == NULL))
        {
                return;
        }
@@ -2524,9 +2801,14 @@ int StrBufDecodeBase64(StrBuf *Buf)
 {
        char *xferbuf;
        size_t siz;
-       if (Buf == NULL) return -1;
+
+       if (Buf == NULL)
+               return -1;
 
        xferbuf = (char*) malloc(Buf->BufSize);
+       if (xferbuf == NULL)
+               return -1;
+
        *xferbuf = '\0';
        siz = CtdlDecodeBase64(xferbuf,
                               Buf->buf,
@@ -2534,9 +2816,349 @@ int StrBufDecodeBase64(StrBuf *Buf)
        free(Buf->buf);
        Buf->buf = xferbuf;
        Buf->BufUsed = siz;
+
+       Buf->buf[Buf->BufUsed] = '\0';
        return siz;
 }
 
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief decode a buffer from base 64 encoding; expects targetbuffer
+ * @param BufIn Buffor to transform
+ * @param BufOut Buffer to put result into
+ */
+int StrBufDecodeBase64To(const StrBuf *BufIn, StrBuf *BufOut)
+{
+       if ((BufIn == NULL) || (BufOut == NULL))
+               return -1;
+
+       if (BufOut->BufSize < BufIn->BufUsed)
+               IncreaseBuf(BufOut, 0, BufIn->BufUsed);
+
+       BufOut->BufUsed = CtdlDecodeBase64(BufOut->buf,
+                                          BufIn->buf,
+                                          BufIn->BufUsed);
+       return BufOut->BufUsed;
+}
+
+typedef struct __z_enc_stream {
+       StrBuf OutBuf;
+       z_stream zstream;
+} z_enc_stream;
+
+vStreamT *StrBufNewStreamContext(eStreamType type, const char **Err)
+{
+       base64_decodestate *state;;
+       *Err = NULL;
+
+       switch (type)
+       {
+       case eBase64Decode:
+       case eBase64Encode:
+               state = (base64_decodestate*) malloc(sizeof(base64_decodestate));
+               base64_init_decodestate(state);
+               return (vStreamT*) state;
+               break;
+       case eZLibDecode:
+       {
+
+               z_enc_stream *stream;
+               int err;
+
+               stream = (z_enc_stream *) malloc(sizeof(z_enc_stream));
+               memset(stream, 0, sizeof(z_enc_stream));
+               stream->OutBuf.BufSize = 4*SIZ; /// TODO 64
+               stream->OutBuf.buf = (char*)malloc(stream->OutBuf.BufSize);
+
+               err = inflateInit(&stream->zstream);
+
+               if (err != Z_OK) {
+                       StrBufDestroyStreamContext(type, (vStreamT**) &stream, Err);
+                       *Err = zError(err);
+                       return NULL;
+               }
+               return (vStreamT*) stream;
+
+       }
+       case eZLibEncode:
+       {
+               z_enc_stream *stream;
+               int err;
+
+               stream = (z_enc_stream *) malloc(sizeof(z_enc_stream));
+               memset(stream, 0, sizeof(z_enc_stream));
+               stream->OutBuf.BufSize = 4*SIZ; /// todo 64
+               stream->OutBuf.buf = (char*)malloc(stream->OutBuf.BufSize);
+               /* write gzip header */
+               stream->OutBuf.BufUsed = snprintf
+                       (stream->OutBuf.buf,
+                        stream->OutBuf.BufSize, 
+                        "%c%c%c%c%c%c%c%c%c%c",
+                        gz_magic[0], gz_magic[1], Z_DEFLATED,
+                        0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
+                        OS_CODE);
+
+               err = deflateInit2(&stream->zstream,
+                                  ZLibCompressionRatio,
+                                  Z_DEFLATED,
+                                  -MAX_WBITS,
+                                  DEF_MEM_LEVEL,
+                                  Z_DEFAULT_STRATEGY);
+               if (err != Z_OK) {
+                       StrBufDestroyStreamContext(type, (vStreamT**) &stream, Err);
+                       *Err = zError(err);
+                       return NULL;
+               }
+               return (vStreamT*) stream;
+       }
+       case eEmtyCodec:
+               /// TODO
+
+               break;
+       }
+       return NULL;
+}
+
+int StrBufDestroyStreamContext(eStreamType type, vStreamT **vStream, const char **Err)
+{
+       int err;
+       int rc = 0;
+       *Err = NULL;
+       
+       if ((vStream == NULL) || (*vStream==NULL)) {
+               *Err = strerror(EINVAL);
+               return EINVAL;
+       }
+       switch (type)
+       {
+       case eBase64Encode:
+       case eBase64Decode:
+               free(*vStream);
+               *vStream = NULL;
+               break;
+       case eZLibDecode:
+       {
+               z_enc_stream *stream = (z_enc_stream *)*vStream;
+               (void)inflateEnd(&stream->zstream);
+               free(stream->OutBuf.buf);
+               free(stream);
+       }
+       case eZLibEncode:
+       {
+               z_enc_stream *stream = (z_enc_stream *)*vStream;
+               err = deflateEnd(&stream->zstream);
+               if (err != Z_OK) {
+                       *Err = zError(err);
+                       rc = -1;
+               }
+               free(stream->OutBuf.buf);
+               free(stream);
+               *vStream = NULL;
+               break;
+       }
+       case eEmtyCodec: 
+               break; /// TODO
+       }
+       return rc;
+}
+
+int StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, const char* pIn, long pInLen, vStreamT *vStream, int LastChunk, const char **Err)
+{
+       int rc = 0;
+       switch (type)
+       {
+       case eBase64Encode:
+       {
+               /// TODO
+/*
+               // base64_decodestate *state = (base64_decodestate*)vStream;
+               long ExpectLen;
+               
+               if (In != NULL)
+               {
+                       pIn = In->buf;
+                       pInLen = In->BufUsed;
+               }
+               if ((In == NULL) || (vStream == NULL))
+                       return;
+               
+               ExpectLen = (pInLen / 4) * 3;
+
+               if (Target->BufSize - Target->BufUsed < ExpectLen)
+               {
+                       IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1);
+               }
+
+               ////    ExpectLen = base64_encode_block(pIn, pInLen, Target->buf + Target->BufUsed, state);
+               Target->BufUsed += ExpectLen;
+               Target->buf[Target->BufUsed] = '\0';
+*/
+       }
+       break;
+       case eBase64Decode:
+       {
+/*
+               base64_decodestate *state = (base64_decodestate *)vStream;
+               long ExpectLen;
+               
+               if (In != NULL)
+               {
+                       pIn = In->buf;
+                       pInLen = In->BufUsed;
+               }
+               if ((pIn == NULL) || (vStream == NULL))
+                       return;
+               
+               ExpectLen = (pInLen / 4) * 3;
+
+               if (Target->BufSize - Target->BufUsed < ExpectLen)
+               {
+                       IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1);
+               }
+
+               ExpectLen = base64_decode_block(pIn, pInLen, Target->buf + Target->BufUsed, state);
+               Target->BufUsed += ExpectLen;
+               Target->buf[Target->BufUsed] = '\0';
+*/
+       }
+       break;
+       case eZLibEncode:
+       {
+               z_enc_stream *stream = (z_enc_stream *)vStream;
+               int org_outbuf_len = stream->OutBuf.BufUsed;
+               int err;
+               unsigned int chunkavail;
+
+               if (In->ReadWritePointer != NULL)
+               {
+                       stream->zstream.next_in = (Bytef *) In->ReadWritePointer;
+                       stream->zstream.avail_in = (uInt) In->Buf->BufUsed - 
+                               (In->ReadWritePointer - In->Buf->buf);
+               }
+               else
+               {
+                       stream->zstream.next_in = (Bytef *) In->Buf->buf;
+                       stream->zstream.avail_in = (uInt) In->Buf->BufUsed;
+               }
+               
+               stream->zstream.next_out = (unsigned char*)stream->OutBuf.buf + stream->OutBuf.BufUsed;
+               stream->zstream.avail_out = chunkavail = (uInt) stream->OutBuf.BufSize - stream->OutBuf.BufUsed;
+
+               err = deflate(&stream->zstream,  (LastChunk) ? Z_FINISH : Z_NO_FLUSH);
+
+               stream->OutBuf.BufUsed += (chunkavail - stream->zstream.avail_out);
+
+               if (Target && 
+                   (LastChunk ||
+                    (stream->OutBuf.BufUsed != org_outbuf_len)
+                           ))
+               {
+                       iSwapBuffers(Target->Buf, &stream->OutBuf);
+               }
+
+               if (stream->zstream.avail_in == 0)
+               {
+                       FlushStrBuf(In->Buf);
+                       In->ReadWritePointer = NULL;
+               }
+               else
+               {
+                       if (stream->zstream.avail_in < 64)
+                       {
+                               memmove(In->Buf->buf,
+                                       In->Buf->buf + In->Buf->BufUsed - stream->zstream.avail_in,
+                                       stream->zstream.avail_in);
+
+                               In->Buf->BufUsed = stream->zstream.avail_in;
+                               In->Buf->buf[In->Buf->BufUsed] = '\0';
+                       }
+                       else
+                       {
+                               
+                               In->ReadWritePointer = In->Buf->buf + 
+                                       (In->Buf->BufUsed - stream->zstream.avail_in);
+                       }
+               }
+               rc = (LastChunk && (err != Z_FINISH));
+               if (!rc && (err != Z_OK)) {
+                       *Err = zError(err);
+               }
+               
+       }
+       break;
+       case eZLibDecode: {
+               z_enc_stream *stream = (z_enc_stream *)vStream;
+               int org_outbuf_len = stream->zstream.total_out;
+               int err;
+
+               if ((stream->zstream.avail_out != 0) && (stream->zstream.next_in != NULL)) {
+                       if (In->ReadWritePointer != NULL)
+                       {
+                               stream->zstream.next_in = (Bytef *) In->ReadWritePointer;
+                               stream->zstream.avail_in = (uInt) In->Buf->BufUsed - 
+                                       (In->ReadWritePointer - In->Buf->buf);
+                       }
+                       else
+                       {
+                               stream->zstream.next_in = (Bytef *) In->Buf->buf;
+                               stream->zstream.avail_in = (uInt) In->Buf->BufUsed;
+                       }
+               }
+
+               stream->zstream.next_out = (unsigned char*)stream->OutBuf.buf + stream->OutBuf.BufUsed;
+               stream->zstream.avail_out = (uInt) stream->OutBuf.BufSize - stream->OutBuf.BufUsed;
+
+               err = inflate(&stream->zstream, Z_NO_FLUSH);
+
+               ///assert(ret != Z_STREAM_ERROR);  /* state not clobbered * /
+               switch (err) {
+               case Z_NEED_DICT:
+                       err = Z_DATA_ERROR;     /* and fall through */
+
+               case Z_DATA_ERROR:
+                       *Err = zError(err);
+               case Z_MEM_ERROR:
+                       (void)inflateEnd(&stream->zstream);
+                       return err;
+               }
+
+               stream->OutBuf.BufUsed += stream->zstream.total_out + org_outbuf_len;
+
+               if (Target) iSwapBuffers(Target->Buf, &stream->OutBuf);
+
+               if (stream->zstream.avail_in == 0)
+               {
+                       FlushStrBuf(In->Buf);
+                       In->ReadWritePointer = NULL;
+               }
+               else
+               {
+                       if (stream->zstream.avail_in < 64)
+                       {
+                               memmove(In->Buf->buf,
+                                       In->Buf->buf + In->Buf->BufUsed - stream->zstream.avail_in,
+                                       stream->zstream.avail_in);
+
+                               In->Buf->BufUsed = stream->zstream.avail_in;
+                               In->Buf->buf[In->Buf->BufUsed] = '\0';
+                       }
+                       else
+                       {
+                               
+                               In->ReadWritePointer = In->Buf->buf + 
+                                       (In->Buf->BufUsed - stream->zstream.avail_in);
+                       }
+               }
+       }
+               break;
+       case eEmtyCodec: {
+
+       }
+               break; /// TODO
+       }
+       return rc;
+}
+
 /**
  * @ingroup StrBuf_DeEnCoder
  * @brief decode a buffer from base 64 encoding; destroys original
@@ -2674,7 +3296,10 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
                        FlushStrBuf(*target);
                        StrBufAppendBuf(*target, source, 0);
                }
-               return (*target)->BufUsed;
+               if (*target != 0)
+                       return (*target)->BufUsed;
+               else
+                       return 0;
        }
        if (*target == NULL)
                *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
@@ -2688,7 +3313,6 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
                ch = (unsigned char) source->buf[i];
                if ((ch  <  32) || 
                    (ch  > 126) || 
-                   (ch ==  61) ||
                    (ch == '=') ||
                     (ch == '?') ||
                    (ch == '_') ||
@@ -2716,6 +3340,95 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
        return (*target)->BufUsed;;
 }
 
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief      Quoted-Printable encode a message; make it < 80 columns width.
+ * @param      source          Source string to be encoded.
+ * @returns     buffer with encoded message.
+ */
+StrBuf *StrBufRFC2047encodeMessage(const StrBuf *EncodeMe)
+{
+       StrBuf *OutBuf;
+       char *Optr, *OEptr;
+       const char *ptr, *eptr;
+       unsigned char ch;
+       int LinePos;
+
+       OutBuf = NewStrBufPlain(NULL, StrLength(EncodeMe) * 4);
+       Optr = OutBuf->buf;
+       OEptr = OutBuf->buf + OutBuf->BufSize;
+       ptr = EncodeMe->buf;
+       eptr = EncodeMe->buf + EncodeMe->BufUsed;
+       LinePos = 0;
+
+       while (ptr < eptr)
+       {
+               if (Optr + 4 >= OEptr)
+               {
+                       long Offset;
+                       Offset = Optr - OutBuf->buf;
+                       OutBuf->BufUsed = Optr - OutBuf->buf;
+                       IncreaseBuf(OutBuf, 1, 0);
+                       Optr = OutBuf->buf + Offset;
+                       OEptr = OutBuf->buf + OutBuf->BufSize;
+               }
+               if (*ptr == '\r')
+               {
+                       /* ignore carriage returns */
+                       ptr ++;
+               }
+               else if (*ptr == '\n') {
+                       /* hard line break */
+                       memcpy(Optr, HKEY("=0A"));
+                       Optr += 3;
+                       LinePos += 3;
+                       ptr ++;
+               }
+               else if (( (*ptr >= 32) && (*ptr <= 60) ) ||
+                        ( (*ptr >= 62) && (*ptr <= 126) ))
+               {
+                       *Optr = *ptr;
+                       Optr ++;
+                       ptr ++;
+                       LinePos ++;
+               }
+               else {
+                       ch = *ptr;
+                       *Optr = '=';
+                       Optr ++;
+                       *Optr = HexList[ch][0];
+                       Optr ++;
+                       *Optr = HexList[ch][1];
+                       Optr ++;
+                       LinePos += 3;
+                       ptr ++;
+               }
+
+               if (LinePos > 72) {
+                       /* soft line break */
+                       if (isspace(*(Optr - 1))) {
+                               ch = *(Optr - 1);
+                               Optr --;
+                               *Optr = '=';
+                               Optr ++;
+                               *Optr = HexList[ch][0];
+                               Optr ++;
+                               *Optr = HexList[ch][1];
+                               Optr ++;
+                               LinePos += 3;
+                       }
+                       *Optr = '=';
+                       Optr ++;
+                       *Optr = '\n';
+                       Optr ++;
+                       LinePos = 0;
+               }
+       }
+       *Optr = '\0';
+       OutBuf->BufUsed = Optr - OutBuf->buf;
+
+       return OutBuf;
+}
 
 
 static void AddRecipient(StrBuf *Target, 
@@ -2773,7 +3486,7 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
        while ((pch != NULL) && (pch < pche))
        {
                while (isspace(*pch)) pch++;
-               UserStart = UserEnd = EmailStart = EmailEnd = NULL;
+               UserEnd = EmailStart = EmailEnd = NULL;
                
                if ((*pch == '"') || (*pch == '\'')) {
                        UserStart = pch + 1;
@@ -2844,7 +3557,6 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
                                EmailStart ++;
                                if (UserStart >= UserEnd)
                                        UserStart = UserEnd = NULL;
-                               At = strchr(EmailStart, '@');
                        }
                        else { /* this is a local recipient... no domain, just a realname */
                                EmailStart = UserStart;
@@ -3023,6 +3735,9 @@ void StrBufConvert(StrBuf *ConvertBuf, StrBuf *TmpBuf, void *pic)
        size_t obuflen;                 /**< Length of output buffer */
 
 
+       if ((ConvertBuf == NULL) || (TmpBuf == NULL))
+               return;
+
        /* since we're converting to utf-8, one glyph may take up to 6 bytes */
        if (ConvertBuf->BufUsed * 6 >= TmpBuf->BufSize)
                IncreaseBuf(TmpBuf, 0, ConvertBuf->BufUsed * 6);
@@ -3058,7 +3773,7 @@ TRYAGAIN:
                TmpBuf->buf[TmpBuf->BufUsed] = '\0';
                
                /* little card game: wheres the red lady? */
-               SwapBuffers(ConvertBuf, TmpBuf);
+               iSwapBuffers(ConvertBuf, TmpBuf);
                FlushStrBuf(TmpBuf);
        }
 #endif
@@ -3205,9 +3920,12 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target,
 #endif
        const char *eptr;
        int passes = 0;
-       int i, len;
+       int i;
        int illegal_non_rfc2047_encoding = 0;
 
+
+       if (DecodeMe == NULL)
+               return;
        /* Sometimes, badly formed messages contain strings which were simply
         *  written out directly in some foreign character set instead of
         *  using RFC2047 encoding.  This is illegal but we will attempt to
@@ -3215,7 +3933,6 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target,
         *  charset to UTF-8 if we see any nonprintable characters.
         */
        
-       len = StrLength(DecodeMe);
        for (i=0; i<DecodeMe->BufUsed; ++i) {
                if ((DecodeMe->buf[i] < 32) || (DecodeMe->buf[i] > 126)) {
                        illegal_non_rfc2047_encoding = 1;
@@ -3239,8 +3956,7 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target,
        }
 
        /* pre evaluate the first pair */
-       nextend = end = NULL;
-       len = StrLength(DecodeMee);
+       end = NULL;
        start = strstr(DecodeMee->buf, "=?");
        eptr = DecodeMee->buf + DecodeMee->BufUsed;
        if (start != NULL) 
@@ -3257,7 +3973,6 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target,
                
                nFront = start - DecodeMee->buf;
                StrBufAppendBufPlain(Target, DecodeMee->buf, nFront, 0);
-               len -= nFront;
        }
        /*
         * Since spammers will go to all sorts of absurd lengths to get their
@@ -3427,11 +4142,11 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen)
                        n++;
                        aptr++;
                }
-               if (n > maxlen) {
+               if (n >= maxlen) {
                        *aptr = '\0';
                        Buf->BufUsed = aptr - Buf->buf;
                        return Buf->BufUsed;
-               }                       
+               }
        }
        return Buf->BufUsed;
 
@@ -3445,10 +4160,6 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen)
  *                               wrapping ZLib                                 *
  *******************************************************************************/
 
-#ifdef HAVE_ZLIB
-#define DEF_MEM_LEVEL 8 /*< memlevel??? */
-#define OS_CODE 0x03   /*< unix */
-
 /**
  * @ingroup StrBuf_DeEnCoder
  * @brief uses the same calling syntax as compress2(), but it
@@ -3459,14 +4170,13 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen)
  * @param sourceLen length of source to encode 
  * @param level compression level
  */
+#ifdef HAVE_ZLIB
 int ZEXPORT compress_gzip(Bytef * dest,
                          size_t * destLen,
                          const Bytef * source,
                          uLong sourceLen,     
                          int level)
 {
-       const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
-
        /* write gzip header */
        snprintf((char *) dest, *destLen, 
                 "%c%c%c%c%c%c%c%c%c%c",
@@ -3697,6 +4407,10 @@ eReadState StrBufChunkSipLine(StrBuf *LineBuf, IOBuffer *FB)
        const char *aptr, *ptr, *eptr;
        char *optr, *xptr;
 
+       if ((FB == NULL) || (LineBuf == NULL) || (LineBuf->buf == NULL))
+               return eReadFail;
+       
+
        if ((FB->Buf == NULL) || (FB->ReadWritePointer == StrBufNOTNULL)) {
                FB->ReadWritePointer = StrBufNOTNULL;
                return eReadFail;
@@ -3784,6 +4498,8 @@ eReadState StrBufCheckBuffer(IOBuffer *FB)
 
 long IOBufferStrLength(IOBuffer *FB)
 {
+       if ((FB == NULL) || (FB->Buf == NULL))
+               return 0;
        if (FB->ReadWritePointer == NULL)
                return StrLength(FB->Buf);
        
@@ -3791,143 +4507,6 @@ long IOBufferStrLength(IOBuffer *FB)
 }
 
 
-
-void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize)
-{
-       memset(FDB, 0, sizeof(FDIOBuffer));
-       FDB->ChunkSize = 
-               FDB->TotalSendSize = TotalSendSize;
-       FDB->IOB = IO;
-#ifndef LINUX_SENDFILE
-       FDB->ChunkBuffer = NewStrBuf();
-#else
-       pipe(FDB->SplicePipe);
-#endif
-       FDB->OtherFD = FD;
-}
-
-void FDIOBufferDelete(FDIOBuffer *FDB)
-{
-#ifndef LINUX_SENDFILE
-       FreeStrBuf(&FDB->ChunkBuffer);
-#else
-       close(FDB->SplicePipe[0]);
-       close(FDB->SplicePipe[1]);
-#endif
-       close(FDB->OtherFD);
-       memset(FDB, 0, sizeof(FDIOBuffer));     
-}
-
-int FileSendChunked(FDIOBuffer *FDB, const char **Err)
-{
-
-#ifdef LINUX_SENDFILE
-       ssize_t sent;
-       sent = sendfile(FDB->IOB->fd, FDB->OtherFD, &FDB->TotalSentAlready, FDB->ChunkSendRemain);
-       if (sent == -1)
-       {
-               *Err = strerror(errno);
-               return sent;
-       }
-       FDB->ChunkSendRemain -= sent;
-       return FDB->ChunkSendRemain;
-#else
-#endif
-       return 0;
-}
-
-int FileRecvChunked(FDIOBuffer *FDB, const char **Err)
-{
-
-#ifdef LINUX_SENDFILE
-       ssize_t sent, pipesize;
-
-       pipesize = splice(FDB->IOB->fd, NULL, 
-                         FDB->SplicePipe[1], NULL, 
-                         FDB->ChunkSendRemain, 
-                         SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
-       if (pipesize == -1)
-       {
-               *Err = strerror(errno);
-               return pipesize;
-       }
-       
-       sent = splice(FDB->SplicePipe[0], NULL, 
-                     FDB->OtherFD, &FDB->TotalSentAlready, 
-                     pipesize, SPLICE_F_MORE | SPLICE_F_MOVE);
-       if (sent == -1)
-       {
-               *Err = strerror(errno);
-               return sent;
-       }
-       FDB->ChunkSendRemain -= sent;
-       return sent;
-#else
-#endif
-       return 0;
-}
-
-eReadState WriteIOBAlreadyRead(FDIOBuffer *FDB, const char **Error)
-{
-       int IsNonBlock;
-       int fdflags;
-       long rlen;
-       long should_write;
-       int nSuccessLess = 0;
-       struct timeval tv;
-       fd_set rfds;
-
-       fdflags = fcntl(FDB->OtherFD, F_GETFL);
-       IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
-
-       while ((FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf < FDB->IOB->Buf->BufUsed) &&
-              (FDB->ChunkSendRemain > 0))
-       {
-               if (IsNonBlock){
-                       tv.tv_sec = 1; /* selectresolution; */
-                       tv.tv_usec = 0;
-                       
-                       FD_ZERO(&rfds);
-                       FD_SET(FDB->OtherFD, &rfds);
-                       if (select(FDB->OtherFD + 1, NULL, &rfds, NULL, &tv) == -1) {
-                               *Error = strerror(errno);
-                               return eReadFail;
-                       }
-               }
-               if (IsNonBlock && !  FD_ISSET(FDB->OtherFD, &rfds)) {
-                       nSuccessLess ++;
-                       continue;
-               }
-
-               should_write = FDB->IOB->Buf->BufUsed - 
-                       (FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf);
-               if (should_write > FDB->ChunkSendRemain)
-                       should_write = FDB->ChunkSendRemain;
-
-               rlen = write(FDB->OtherFD, 
-                            FDB->IOB->ReadWritePointer, 
-                            should_write);
-               if (rlen < 1) {
-                       *Error = strerror(errno);
-                                               
-                       return eReadFail;
-               }
-               FDB->TotalSentAlready += rlen;
-               FDB->IOB->ReadWritePointer += rlen;
-               FDB->ChunkSendRemain -= rlen;
-       }
-       if (FDB->IOB->ReadWritePointer >= FDB->IOB->Buf->buf + FDB->IOB->Buf->BufUsed)
-       {
-               FlushStrBuf(FDB->IOB->Buf);
-               FDB->IOB->ReadWritePointer = NULL;
-       }
-
-       if (FDB->ChunkSendRemain == 0)
-               return eReadSuccess;
-       else 
-               return eMustReadMore;
-}
-
 /*******************************************************************************
  *           File I/O; Prefer buffered read since its faster!                  *
  *******************************************************************************/
@@ -3946,6 +4525,11 @@ int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
 {
        int len, rlen, slen;
 
+       if ((buf == NULL) || (buf->buf == NULL)) {
+               *Error = strerror(EINVAL);
+               return -1;
+       }
+
        if (!append)
                FlushStrBuf(buf);
 
@@ -3975,6 +4559,7 @@ int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
        return len - slen;
 }
 
+
 /**
  * @ingroup StrBuf_BufferedIO
  * @brief Read a line from socket
@@ -4052,10 +4637,11 @@ int StrBufTCP_read_buffered_line(StrBuf *Line,
                        nSuccessLess = 0;
                        buf->BufUsed += rlen;
                        buf->buf[buf->BufUsed] = '\0';
-                       if (buf->BufUsed + 10 > buf->BufSize) {
-                               IncreaseBuf(buf, 1, -1);
-                       }
                        pch = strchr(buf->buf, '\n');
+                       if ((pch == NULL) &&
+                           (buf->BufUsed + 10 > buf->BufSize) &&
+                           (IncreaseBuf(buf, 1, -1) == -1))
+                               return -1;
                        continue;
                }
                
@@ -4245,6 +4831,10 @@ int StrBufTCP_read_buffered_line_fast(StrBuf *Line,
 
                        continue;
                }
+               else
+               {
+                       nSuccessLess++;
+               }
        }
        *Pos = NULL;
        if (pLF != NULL) {
@@ -4289,7 +4879,7 @@ int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **E
        struct timeval tv;
        fd_set rfds;
 
-       if ((Buf == NULL) || (*fd == -1))
+       if ((Buf == NULL) || (Buf->buf == NULL) || (*fd == -1))
        {
                *Error = ErrRBLF_BLOBPreConditionFailed;
                return -1;
@@ -4371,8 +4961,7 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
 {
        const char *pos;
        int fdflags;
-       int len = 0;
-       int rlen;
+       int rlen = 0;
        int nRead = 0;
        int nAlreadyRead = 0;
        int IsNonBlock;
@@ -4382,9 +4971,12 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
        int nSuccessLess = 0;
        int MaxTries;
 
-       if ((Blob == NULL) || (*fd == -1) || (IOBuf == NULL) || (Pos == NULL))
+       if ((Blob == NULL)  ||
+           (*fd == -1)     ||
+           (IOBuf == NULL) ||
+           (Pos == NULL))
        {
-               if (*Pos != NULL)
+               if (Pos != NULL)
                        *Pos = NULL;
                *Error = ErrRBB_BLOBFPreConditionFailed;
                return -1;
@@ -4398,8 +4990,8 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
        pos = *Pos;
 
        if (pos != NULL)
-               len = pos - IOBuf->buf;
-       rlen = IOBuf->BufUsed - len;
+               rlen = pos - IOBuf->buf;
+       rlen = IOBuf->BufUsed - rlen;
 
 
        if ((IOBuf->BufUsed > 0) && 
@@ -4433,8 +5025,6 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
                IncreaseBuf(IOBuf, 0, nBytes - nRead);
        ptr = IOBuf->buf;
 
-       len = Blob->BufUsed;
-
        fdflags = fcntl(*fd, F_GETFL);
        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
        if (IsNonBlock)
@@ -4531,7 +5121,11 @@ int StrBufSipLine(StrBuf *LineBuf, const StrBuf *Buf, const char **Ptr)
        const char *aptr, *ptr, *eptr;
        char *optr, *xptr;
 
-       if ((Buf == NULL) || (*Ptr == StrBufNOTNULL)) {
+       if ((Buf == NULL) ||
+           (*Ptr == StrBufNOTNULL) ||
+           (LineBuf == NULL)||
+           (LineBuf->buf == NULL))
+       {
                *Ptr = StrBufNOTNULL;
                return 0;
        }
@@ -4604,12 +5198,54 @@ void StrBufStripSlashes(StrBuf *Dir, int RemoveTrailingSlash)
                        b++; a++;
                }
        }
-       if ((RemoveTrailingSlash) && (*(b - 1) != '/')){
-               *b = '/';
-               b++;
+       if ((RemoveTrailingSlash) &&
+           (b > Dir->buf) && 
+           (*(b - 1) == '/')){
+               b--;
        }
        *b = '\0';
        Dir->BufUsed = b - Dir->buf;
 }
 
 
+/*
+ * Decode a quoted-printable encoded StrBuf buffer "in place"
+ * This is possible because the decoded will always be shorter than the encoded
+ * so we don't have to worry about the buffer being to small.
+ */
+void StrBufDecodeQP(StrBuf *Buf)
+{
+       if (!Buf) {                             // sanity check #1
+               return;
+       }
+
+       int source_len = StrLength(Buf);
+       if (source_len < 1) {                   // sanity check #2
+               return;
+       }
+
+       int spos = 0;                           // source position
+       int tpos = 0;                           // target position
+
+       while (spos < source_len) {
+               if (!strncmp(&Buf->buf[spos], "=\r\n", 3)) {
+                       spos += 3;
+               }
+               else if (!strncmp(&Buf->buf[spos], "=\n", 2)) {
+                       spos += 2;
+               }
+               else if (Buf->buf[spos] == '=') {
+                       ++spos;
+                       int ch;
+                       sscanf(&Buf->buf[spos], "%02x", &ch);
+                       Buf->buf[tpos++] = ch;
+                       spos +=2;
+               }
+               else {
+                       Buf->buf[tpos++] = Buf->buf[spos++];
+               }
+       }
+
+       Buf->buf[tpos] = 0;
+       Buf->BufUsed = tpos;
+}