fix QP encoding
[citadel.git] / libcitadel / lib / stringbuf.c
index 250b3109c4b57f97fdbceac74ac6cae2e576cc0a..cdb625cc99b86b03eaa6cafce09554529209f314 100644 (file)
@@ -215,6 +215,23 @@ void dbg_Init(StrBuf *Buf)
 
 #endif
 
+/**
+ * @ingroup StrBuf
+ * @brief swaps the contents of two StrBufs
+ * this is to be used to have cheap switched between a work-buffer and a target buffer 
+ * @param A First one
+ * @param B second one
+ */
+static inline void SwapBuffers(StrBuf *A, StrBuf *B)
+{
+       StrBuf C;
+
+       memcpy(&C, A, sizeof(*A));
+       memcpy(A, B, sizeof(*B));
+       memcpy(B, &C, sizeof(C));
+
+}
+
 /** 
  * @ingroup StrBuf_Cast
  * @brief Cast operator to Plain String 
@@ -259,9 +276,12 @@ static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
                return -1;
                
        if (DestSize > 0)
-               while (NewSize <= DestSize)
+               while ((NewSize <= DestSize) && (NewSize != 0))
                        NewSize *= 2;
 
+       if (NewSize == 0)
+               return -1;
+
        NewBuf= (char*) malloc(NewSize);
        if (NewBuf == NULL)
                return -1;
@@ -372,6 +392,75 @@ StrBuf* NewStrBufDup(const StrBuf *CopyMe)
        return NewBuf;
 }
 
+/** 
+ * @ingroup StrBuf_DeConstructors
+ * @brief Copy Constructor; CreateRelpaceMe will contain CopyFlushMe afterwards.
+ * @param NoMe if non-NULL, we will use that buffer as value; KeepOriginal will abused as len.
+ * @param CopyFlushMe Buffer to faxmilate if KeepOriginal, or to move into CreateRelpaceMe if !KeepOriginal.
+ * @param CreateRelpaceMe If NULL, will be created, else Flushed and filled CopyFlushMe 
+ * @param KeepOriginal should CopyFlushMe remain intact? or may we Steal its buffer?
+ * @returns the new stringbuffer
+ */
+void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, const char *NoMe, int KeepOriginal)
+{
+       StrBuf *NewBuf;
+       
+       if (CreateRelpaceMe == NULL)
+               return;
+
+       if (NoMe != NULL)
+       {
+               if (*CreateRelpaceMe != NULL)
+                       StrBufPlain(*CreateRelpaceMe, NoMe, KeepOriginal);
+               else 
+                       *CreateRelpaceMe = NewStrBufPlain(NoMe, KeepOriginal);
+               return;
+       }
+
+       if (CopyFlushMe == NULL)
+       {
+               if (*CreateRelpaceMe != NULL)
+                       FlushStrBuf(*CreateRelpaceMe);
+               else 
+                       *CreateRelpaceMe = NewStrBuf();
+               return;
+       }
+
+       /* 
+        * Randomly Chosen: bigger than 64 chars is cheaper to swap the buffers instead of copying.
+        * else *CreateRelpaceMe may use more memory than needed in a longer term, CopyFlushMe might
+        * be a big IO-Buffer...
+        */
+       if (KeepOriginal || (StrLength(CopyFlushMe) < 256))
+       {
+               if (*CreateRelpaceMe == NULL)
+               {
+                       *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
+                       dbg_Init(NewBuf);
+               }
+               else 
+               {
+                       NewBuf = *CreateRelpaceMe;
+                       FlushStrBuf(NewBuf);
+               }
+               StrBufAppendBuf(NewBuf, CopyFlushMe, 0);
+       }
+       else
+       {
+               if (*CreateRelpaceMe == NULL)
+               {
+                       *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
+                       dbg_Init(NewBuf);
+               }
+               else 
+                       NewBuf = *CreateRelpaceMe;
+               SwapBuffers (NewBuf, CopyFlushMe);
+       }
+       if (!KeepOriginal)
+               FlushStrBuf(CopyFlushMe);
+       return;
+}
+
 /**
  * @ingroup StrBuf_DeConstructors
  * @brief create a new Buffer using an existing c-string
@@ -393,10 +482,20 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars)
        else
                CopySize = nChars;
 
-       while (Siz <= CopySize)
+       while ((Siz <= CopySize) && (Siz != 0))
                Siz *= 2;
 
+       if (Siz == 0)
+       {
+               return NULL;
+       }
+
        NewBuf->buf = (char*) malloc(Siz);
+       if (NewBuf->buf == NULL)
+       {
+               free(NewBuf);
+               return NULL;
+       }
        NewBuf->BufSize = Siz;
        if (ptr != NULL) {
                memcpy(NewBuf->buf, ptr, CopySize);
@@ -409,9 +508,9 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars)
        }
        NewBuf->ConstBuf = 0;
 
-       dbg_Init(NewBuf)
+       dbg_Init(NewBuf);
 
-               return NewBuf;
+       return NewBuf;
 }
 
 /**
@@ -441,9 +540,14 @@ int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
        else
                CopySize = nChars;
 
-       while (Siz <= CopySize)
+       while ((Siz <= CopySize) && (Siz != 0))
                Siz *= 2;
 
+       if (Siz == 0) {
+               FlushStrBuf(Buf);
+               return -1;
+       }
+
        if (Siz != Buf->BufSize)
                IncreaseBuf(Buf, 0, Siz);
        memcpy(Buf->buf, ptr, CopySize);
@@ -767,7 +871,8 @@ void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
                va_end(apl);
                newused = Offset + nWritten;
                if (newused >= Buf->BufSize) {
-                       IncreaseBuf(Buf, 1, newused);
+                       if (IncreaseBuf(Buf, 1, newused) == -1)
+                               return; /* TODO: error handling? */
                        newused = Buf->BufSize + 1;
                }
                else {
@@ -808,7 +913,8 @@ void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
                va_end(arg_ptr);
                newused = Buf->BufUsed + nWritten;
                if (newused >= Buf->BufSize) {
-                       IncreaseBuf(Buf, 1, newused);
+                       if (IncreaseBuf(Buf, 1, newused) == -1)
+                               return; /* TODO: error handling? */
                        newused = Buf->BufSize + 1;
                }
                else {
@@ -839,7 +945,8 @@ void StrBufPrintf(StrBuf *Buf, const char *format, ...)
                nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
                va_end(arg_ptr);
                if (nWritten >= Buf->BufSize) {
-                       IncreaseBuf(Buf, 0, 0);
+                       if (IncreaseBuf(Buf, 0, 0) == -1)
+                               return; /* TODO: error handling? */
                        nWritten = Buf->BufSize + 1;
                        continue;
                }
@@ -985,6 +1092,26 @@ void StrBufTrim(StrBuf *Buf)
        }
        if (delta > 0) StrBufCutLeft(Buf, delta);
 }
+/**
+ * @ingroup StrBuf
+ * @brief changes all spaces in the string  (tab, linefeed...) to Blank (0x20)
+ * @param Buf the string to modify
+ */
+void StrBufSpaceToBlank(StrBuf *Buf)
+{
+       char *pche, *pch;
+
+       if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
+
+       pch = Buf->buf;
+       pche = pch + Buf->BufUsed;
+       while (pch < pche) 
+       {
+               if (isspace(*pch))
+                       *pch = ' ';
+               pch ++;
+       }
+}
 
 void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
 {
@@ -1222,7 +1349,7 @@ int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char se
        //cit_backtrace();
        //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
 
-       while ((s<e) && !IsEmptyStr(s)) {
+       while ((s < e) && !IsEmptyStr(s)) {
                if (*s == separator) {
                        ++current_token;
                }
@@ -1391,6 +1518,8 @@ int StrBufExtract_NextToken(StrBuf *dest, const StrBuf *Source, const char **pSt
            (Source->BufUsed == 0)      ) 
        {
                *pStart = StrBufNOTNULL;
+               if (dest != NULL)
+                       FlushStrBuf(dest);
                return -1;
        }
         
@@ -1507,7 +1636,7 @@ int StrBufSkip_NTokenS(const StrBuf *Source, const char **pStart, char separator
        //cit_backtrace();
        //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
 
-       while ((s<EndBuffer) && !IsEmptyStr(s)) {
+       while ((s < EndBuffer) && !IsEmptyStr(s)) {
                if (*s == separator) {
                        ++current_token;
                }
@@ -1674,22 +1803,26 @@ void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
  * @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?
  */
-void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
+void StrBufHexEscAppend(StrBuf *OutBuf, const StrBuf *In, const unsigned char *PlainIn, long PlainInLen)
 {
-       const char *pch, *pche;
+       const unsigned char *pch, *pche;
        char *pt, *pte;
        int len;
        
        if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
                return;
        if (PlainIn != NULL) {
-               len = strlen(PlainIn);
+               if (PlainInLen < 0)
+                       len = strlen((const char*)PlainIn);
+               else
+                       len = PlainInLen;
                pch = PlainIn;
                pche = pch + len;
        }
        else {
-               pch = In->buf;
+               pch = (const unsigned char*)In->buf;
                pche = pch + In->BufUsed;
                len = In->BufUsed;
        }
@@ -1707,14 +1840,26 @@ void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
                        pt = OutBuf->buf + OutBuf->BufUsed;
                }
 
-               *pt = HexList[(unsigned char)*pch][0];
+               *pt = HexList[*pch][0];
                pt ++;
-               *pt = HexList[(unsigned char)*pch][1];
+               *pt = HexList[*pch][1];
                pt ++; pch ++; OutBuf->BufUsed += 2;
        }
        *pt = '\0';
 }
 
+/** 
+ * @ingroup StrBuf_DeEnCoder
+ * @brief append a string in hex encoding to the buffer
+ * @param OutBuf the output buffer
+ * @param In Buffer to encode
+ * @param PlainIn way in from plain old c strings
+ */
+void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
+{
+       StrBufHexEscAppend(OutBuf, In, (const unsigned char*) PlainIn, -1);
+}
+
 /**
  * @ingroup StrBuf_DeEnCoder
  * @brief Append a string, escaping characters which have meaning in HTML.  
@@ -2259,6 +2404,7 @@ int StrBufDecodeBase64(StrBuf *Buf)
        if (Buf == NULL) return -1;
 
        xferbuf = (char*) malloc(Buf->BufSize);
+       *xferbuf = '\0';
        siz = CtdlDecodeBase64(xferbuf,
                               Buf->buf,
                               Buf->BufUsed);
@@ -2417,7 +2563,12 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
                if ((*target)->BufUsed + 4 >= (*target)->BufSize)
                        IncreaseBuf(*target, 1, 0);
                ch = (unsigned char) source->buf[i];
-               if ((ch < 32) || (ch > 126) || (ch == 61)) {
+               if ((ch  <  32) || 
+                   (ch  > 126) || 
+                   (ch ==  61) ||
+                   (ch == '[') ||
+                   (ch == ']')   )
+               {
                        sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
                        (*target)->BufUsed += 3;
                }
@@ -2476,15 +2627,12 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
                                           StrBuf *EncBuf)
 {
        StrBuf *Target;
-       int need_to_encode;
-
        const char *pch, *pche;
        const char *UserStart, *UserEnd, *EmailStart, *EmailEnd, *At;
 
        if ((Recp == NULL) || (StrLength(Recp) == 0))
                return NULL;
 
-       need_to_encode = 0;
        pch = ChrPtr(Recp);
        pche = pch + StrLength(Recp);
 
@@ -2495,8 +2643,6 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
 
        while ((pch != NULL) && (pch < pche))
        {
-               int ColonOk = 0;
-
                while (isspace(*pch)) pch++;
                UserStart = UserEnd = EmailStart = EmailEnd = NULL;
                
@@ -2526,7 +2672,6 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
                        if (EmailEnd == NULL)
                                EmailEnd = pche;
                        pch = EmailEnd + 1;
-                       ColonOk = 1;
                }
                else {
                        int gt = 0;
@@ -2537,7 +2682,6 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
                                pch = NULL;
                                if (EmailEnd != NULL) {
                                        gt = 1;
-                                       EmailEnd --;
                                }
                                else {
                                        EmailEnd = pche;
@@ -2546,14 +2690,15 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
                        else {
 
                                pch = EmailEnd + 1;
-                               while ((EmailEnd > UserStart) && 
+                               while ((EmailEnd > UserStart) && !gt &&
                                       ((*EmailEnd == ',') ||
                                        (*EmailEnd == '>') ||
                                        (isspace(*EmailEnd))))
                                {
                                        if (*EmailEnd == '>')
                                                gt = 1;
-                                       EmailEnd--;
+                                       else 
+                                               EmailEnd--;
                                }
                                if (EmailEnd == UserStart)
                                        break;
@@ -2562,7 +2707,11 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
                                EmailStart = strchr(UserStart, '<');
                                if ((EmailStart == NULL) || (EmailStart > EmailEnd))
                                        break;
-                               UserEnd = EmailStart - 1;
+                               UserEnd = EmailStart;
+
+                               while ((UserEnd > UserStart) && 
+                                      isspace (*(UserEnd - 1)))
+                                       UserEnd --;
                                EmailStart ++;
                                if (UserStart >= UserEnd)
                                        UserStart = UserEnd = NULL;
@@ -2630,7 +2779,7 @@ void StrBufReplaceChars(StrBuf *buf, char search, char replace)
 
 /**
  * @ingroup StrBuf
- * @brief removes all \r s from the string, or replaces them with \n if its not a combination of both.
+ * @brief removes all \\r s from the string, or replaces them with \n if its not a combination of both.
  * @param buf Buffer to modify
  */
 void StrBufToUnixLF(StrBuf *buf)
@@ -2712,7 +2861,8 @@ static inline const char *FindNextEnd (const StrBuf *Buf, const char *bptr)
                return NULL;
 
        if ((Buf->BufUsed - (end - Buf->buf) > 3) &&
-           ((*(end + 1) == 'B') || (*(end + 1) == 'Q')) && 
+           (((*(end + 1) == 'B') || (*(end + 1) == 'Q')) ||
+            ((*(end + 1) == 'b') || (*(end + 1) == 'q'))) && 
            (*(end + 2) == '?')) {
                /* skip on to the end of the cluster, the next ?= */
                end = strstr(end + 3, "?=");
@@ -2723,22 +2873,6 @@ static inline const char *FindNextEnd (const StrBuf *Buf, const char *bptr)
        return end;
 }
 
-/**
- * @ingroup StrBuf
- * @brief swaps the contents of two StrBufs
- * this is to be used to have cheap switched between a work-buffer and a target buffer 
- * @param A First one
- * @param B second one
- */
-static inline void SwapBuffers(StrBuf *A, StrBuf *B)
-{
-       StrBuf C;
-
-       memcpy(&C, A, sizeof(*A));
-       memcpy(A, B, sizeof(*B));
-       memcpy(B, &C, sizeof(C));
-
-}
 
 
 /**
@@ -2845,6 +2979,8 @@ inline static void DecodeSegment(StrBuf *Target,
        
        *encoding = toupper(*encoding);
        if (*encoding == 'B') { /**< base64 */
+               if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
+                       IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
                ConvertBuf2->BufUsed = CtdlDecodeBase64(ConvertBuf2->buf, 
                                                        ConvertBuf->buf, 
                                                        ConvertBuf->BufUsed);
@@ -2860,6 +2996,9 @@ inline static void DecodeSegment(StrBuf *Target,
                        pos++;
                }
                
+               if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
+                       IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
+
                ConvertBuf2->BufUsed = CtdlDecodeQuotedPrintable(
                        ConvertBuf2->buf, 
                        ConvertBuf->buf,
@@ -2885,7 +3024,7 @@ inline static void DecodeSegment(StrBuf *Target,
 
 /**
  * @ingroup StrBuf_DeEnCoder
- * @brief Handle subjects with RFC2047 encoding such as:
+ * @brief Handle subjects with RFC2047 encoding such as: [deprecated old syntax!]
  * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?=
  * @param Target where to put the decoded string to 
  * @param DecodeMe buffer with encoded string
@@ -2894,9 +3033,42 @@ inline static void DecodeSegment(StrBuf *Target,
  *        put it here for later use where no string might be known.
  */
 void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf* DefaultCharset, StrBuf *FoundCharset)
+{
+       StrBuf *ConvertBuf;
+       StrBuf *ConvertBuf2;
+       ConvertBuf = NewStrBufPlain(NULL, StrLength(DecodeMe));
+       ConvertBuf2 = NewStrBufPlain(NULL, StrLength(DecodeMe));
+       
+       StrBuf_RFC822_2_Utf8(Target, 
+                            DecodeMe, 
+                            DefaultCharset, 
+                            FoundCharset, 
+                            ConvertBuf, 
+                            ConvertBuf2);
+       FreeStrBuf(&ConvertBuf);
+       FreeStrBuf(&ConvertBuf2);
+}
+
+/**
+ * @ingroup StrBuf_DeEnCoder
+ * @brief Handle subjects with RFC2047 encoding such as:
+ * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?=
+ * @param Target where to put the decoded string to 
+ * @param DecodeMe buffer with encoded string
+ * @param DefaultCharset if we don't find one, which should we use?
+ * @param FoundCharset overrides DefaultCharset if non-empty; If we find a charset inside of the string, 
+ *        put it here for later use where no string might be known.
+ * @param ConvertBuf workbuffer. feed in, you shouldn't care about its content.
+ * @param ConvertBuf2 workbuffer. feed in, you shouldn't care about its content.
+ */
+void StrBuf_RFC822_2_Utf8(StrBuf *Target, 
+                         const StrBuf *DecodeMe, 
+                         const StrBuf* DefaultCharset, 
+                         StrBuf *FoundCharset, 
+                         StrBuf *ConvertBuf, 
+                         StrBuf *ConvertBuf2)
 {
        StrBuf *DecodedInvalidBuf = NULL;
-       StrBuf *ConvertBuf, *ConvertBuf2;
        const StrBuf *DecodeMee = DecodeMe;
        const char *start, *end, *next, *nextend, *ptr = NULL;
 #ifdef HAVE_ICONV
@@ -2922,7 +3094,6 @@ void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf*
                }
        }
 
-       ConvertBuf = NewStrBufPlain(NULL, StrLength(DecodeMe));
        if ((illegal_non_rfc2047_encoding) &&
            (strcasecmp(ChrPtr(DefaultCharset), "UTF-8")) && 
            (strcasecmp(ChrPtr(DefaultCharset), "us-ascii")) )
@@ -2944,15 +3115,13 @@ void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf*
        start = strstr(DecodeMee->buf, "=?");
        eptr = DecodeMee->buf + DecodeMee->BufUsed;
        if (start != NULL) 
-               end = FindNextEnd (DecodeMee, start);
+               end = FindNextEnd (DecodeMee, start + 2);
        else {
                StrBufAppendBuf(Target, DecodeMee, 0);
-               FreeStrBuf(&ConvertBuf);
                FreeStrBuf(&DecodedInvalidBuf);
                return;
        }
 
-       ConvertBuf2 = NewStrBufPlain(NULL, StrLength(DecodeMee));
 
        if (start != DecodeMee->buf) {
                long nFront;
@@ -3031,8 +3200,6 @@ void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf*
                if (ptr < nextend)
                        StrBufAppendBufPlain(Target, end, nextend - end, 0);
        }
-       FreeStrBuf(&ConvertBuf);
-       FreeStrBuf(&ConvertBuf2);
        FreeStrBuf(&DecodedInvalidBuf);
 }
 
@@ -3259,7 +3426,216 @@ int CompressBuffer(StrBuf *Buf)
        return 0;
 }
 
+/*******************************************************************************
+ *           File I/O; Callbacks to libevent                                   *
+ *******************************************************************************/
+
+long StrBuf_read_one_chunk_callback (int fd, short event, IOBuffer *FB)
+{
+       long bufremain = 0;
+       int n;
+       
+       if ((FB == NULL) || (FB->Buf == NULL))
+               return -1;
+
+       /*
+        * check whether the read pointer is somewhere in a range 
+        * where a cut left is inexpensive
+        */
+
+       if (FB->ReadWritePointer != NULL)
+       {
+               long already_read;
+               
+               already_read = FB->ReadWritePointer - FB->Buf->buf;
+               bufremain = FB->Buf->BufSize - FB->Buf->BufUsed - 1;
+
+               if (already_read != 0) {
+                       long unread;
+                       
+                       unread = FB->Buf->BufUsed - already_read;
+
+                       /* else nothing to compact... */
+                       if (unread == 0) {
+                               FB->ReadWritePointer = FB->Buf->buf;
+                               bufremain = FB->Buf->BufSize;                   
+                       }
+                       else if ((unread < 64) || 
+                                (bufremain < already_read))
+                       {
+                               /* 
+                                * if its just a tiny bit remaining, or we run out of space... 
+                                * lets tidy up.
+                                */
+                               FB->Buf->BufUsed = unread;
+                               if (unread < already_read)
+                                       memcpy(FB->Buf->buf, FB->ReadWritePointer, unread);
+                               else
+                                       memmove(FB->Buf->buf, FB->ReadWritePointer, unread);
+                               FB->ReadWritePointer = FB->Buf->buf;
+                               bufremain = FB->Buf->BufSize - unread - 1;
+                       }
+                       else if (bufremain < (FB->Buf->BufSize / 10))
+                       {
+                               /* get a bigger buffer */ 
+
+                               IncreaseBuf(FB->Buf, 0, FB->Buf->BufUsed + 1);
+
+                               FB->ReadWritePointer = FB->Buf->buf + unread;
+
+                               bufremain = FB->Buf->BufSize - unread - 1;
+/*TODO: special increase function that won't copy the already read! */
+                       }
+               }
+               else if (bufremain < 10) {
+                       IncreaseBuf(FB->Buf, 1, FB->Buf->BufUsed + 10);
+                       
+                       FB->ReadWritePointer = FB->Buf->buf;
+                       
+                       bufremain = FB->Buf->BufSize - FB->Buf->BufUsed - 1;
+               }
+               
+       }
+       else {
+               FB->ReadWritePointer = FB->Buf->buf;
+               bufremain = FB->Buf->BufSize - 1;
+       }
+
+       n = read(fd, FB->Buf->buf + FB->Buf->BufUsed, bufremain);
+
+       if (n > 0) {
+               FB->Buf->BufUsed += n;
+               FB->Buf->buf[FB->Buf->BufUsed] = '\0';
+       }
+       return n;
+}
+
+int StrBuf_write_one_chunk_callback(int fd, short event, IOBuffer *FB)
+{
+       long WriteRemain;
+       int n;
+
+       if ((FB == NULL) || (FB->Buf == NULL))
+               return -1;
+
+       if (FB->ReadWritePointer != NULL)
+       {
+               WriteRemain = FB->Buf->BufUsed - 
+                       (FB->ReadWritePointer - 
+                        FB->Buf->buf);
+       }
+       else {
+               FB->ReadWritePointer = FB->Buf->buf;
+               WriteRemain = FB->Buf->BufUsed;
+       }
+
+       n = write(fd, FB->ReadWritePointer, WriteRemain);
+       if (n > 0) {
+               FB->ReadWritePointer += n;
+
+               if (FB->ReadWritePointer == 
+                   FB->Buf->buf + FB->Buf->BufUsed)
+               {
+                       FlushStrBuf(FB->Buf);
+                       FB->ReadWritePointer = NULL;
+                       return 0;
+               }
+       // check whether we've got something to write
+       // get the maximum chunk plus the pointer we can send
+       // write whats there
+       // if not all was sent, remember the send pointer for the next time
+               return FB->ReadWritePointer - FB->Buf->buf + FB->Buf->BufUsed;
+       }
+       return n;
+}
+
+/**
+ * @ingroup StrBuf_IO
+ * @brief extract a "next line" from Buf; Ptr to persist across several iterations
+ * @param LineBuf your line will be copied here.
+ * @param FB BLOB with lines of text...
+ * @param Ptr moved arround to keep the next-line across several iterations
+ *        has to be &NULL on start; will be &NotNULL on end of buffer
+ * @returns size of copied buffer
+ */
+eReadState StrBufChunkSipLine(StrBuf *LineBuf, IOBuffer *FB)
+{
+       const char *aptr, *ptr, *eptr;
+       char *optr, *xptr;
+
+       if ((FB->Buf == NULL) || (FB->ReadWritePointer == StrBufNOTNULL)) {
+               FB->ReadWritePointer = StrBufNOTNULL;
+               return eReadFail;
+       }
+
+       FlushStrBuf(LineBuf);
+       if (FB->ReadWritePointer == NULL)
+               ptr = aptr = FB->Buf->buf;
+       else
+               ptr = aptr = FB->ReadWritePointer;
+
+       optr = LineBuf->buf;
+       eptr = FB->Buf->buf + FB->Buf->BufUsed;
+       xptr = LineBuf->buf + LineBuf->BufSize - 1;
+
+       while ((ptr <= eptr) && 
+              (*ptr != '\n') &&
+              (*ptr != '\r') )
+       {
+               *optr = *ptr;
+               optr++; ptr++;
+               if (optr == xptr) {
+                       LineBuf->BufUsed = optr - LineBuf->buf;
+                       IncreaseBuf(LineBuf,  1, LineBuf->BufUsed + 1);
+                       optr = LineBuf->buf + LineBuf->BufUsed;
+                       xptr = LineBuf->buf + LineBuf->BufSize - 1;
+               }
+       }
+
+       if (ptr >= eptr) {
+               if (optr > LineBuf->buf)
+                       optr --;
+               if ((*(ptr - 1) != '\r') && (*(ptr - 1) != '\n')) {
+                       LineBuf->BufUsed = optr - LineBuf->buf;
+                       *optr = '\0';       
+                       return eMustReadMore;
+               }
+       }
+       LineBuf->BufUsed = optr - LineBuf->buf;
+       *optr = '\0';       
+       if ((ptr <= eptr) && (*ptr == '\r'))
+               ptr ++;
+       if ((ptr <= eptr) && (*ptr == '\n'))
+               ptr ++;
+       
+       if (ptr < eptr) {
+               FB->ReadWritePointer = ptr;
+       }
+       else {
+               FlushStrBuf(FB->Buf);
+               FB->ReadWritePointer = NULL;
+       }
+
+       return eReadSuccess;
+}
 
+/**
+ * @ingroup StrBuf_CHUNKED_IO
+ * @brief check whether the chunk-buffer has more data waiting or not.
+ * @param FB Chunk-Buffer to inspect
+ */
+eReadState StrBufCheckBuffer(IOBuffer *FB)
+{
+       if (FB == NULL)
+               return eReadFail;
+       if (FB->Buf->BufUsed == 0)
+               return eReadSuccess;
+       if (FB->ReadWritePointer == NULL)
+               return eBufferNotEmpty;
+       if (FB->Buf->buf + FB->Buf->BufUsed > FB->ReadWritePointer)
+               return eBufferNotEmpty;
+       return eReadSuccess;
+}
 
 /*******************************************************************************
  *           File I/O; Prefer buffered read since its faster!                  *
@@ -3614,7 +3990,7 @@ static const char *ErrRBLF_BLOBPreConditionFailed="StrBufReadBLOB: Wrong argumen
 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
 {
        int fdflags;
-       int len, rlen, slen;
+       int rlen;
        int nSuccessLess;
        int nRead = 0;
        char *ptr;
@@ -3634,8 +4010,6 @@ int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **E
 
        ptr = Buf->buf + Buf->BufUsed;
 
-       slen = len = Buf->BufUsed;
-
        fdflags = fcntl(*fd, F_GETFL);
        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
        nSuccessLess = 0;
@@ -3704,17 +4078,15 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
                           int check, 
                           const char **Error)
 {
-       const char *pche;
        const char *pos;
        int fdflags;
        int len = 0;
-       int rlen, slen;
+       int rlen;
        int nRead = 0;
        int nAlreadyRead = 0;
        int IsNonBlock;
        char *ptr;
        fd_set rfds;
-       const char *pch;
        struct timeval tv;
        int nSuccessLess = 0;
        int MaxTries;
@@ -3743,9 +4115,6 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
            (pos != NULL) && 
            (pos < IOBuf->buf + IOBuf->BufUsed)) 
        {
-               pche = IOBuf->buf + IOBuf->BufUsed;
-               pch = pos;
-
                if (rlen < nBytes) {
                        memcpy(Blob->buf + Blob->BufUsed, pos, rlen);
                        Blob->BufUsed += rlen;
@@ -3773,7 +4142,7 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
                IncreaseBuf(IOBuf, 0, nBytes - nRead);
        ptr = IOBuf->buf;
 
-       slen = len = Blob->BufUsed;
+       len = Blob->BufUsed;
 
        fdflags = fcntl(*fd, F_GETFL);
        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
@@ -3864,9 +4233,9 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
  * @param Buf BLOB with lines of text...
  * @param Ptr moved arround to keep the next-line across several iterations
  *        has to be &NULL on start; will be &NotNULL on end of buffer
- * @returns size of copied buffer
+ * @returns size of remaining buffer
  */
-int StrBufSipLine(StrBuf *LineBuf, StrBuf *Buf, const char **Ptr)
+int StrBufSipLine(StrBuf *LineBuf, const StrBuf *Buf, const char **Ptr)
 {
        const char *aptr, *ptr, *eptr;
        char *optr, *xptr;