Add FileMoveChunked(); which can read and write with offsets.
[citadel.git] / libcitadel / lib / stringbuf.c
index 4f381dd4813d0766bc4d9adeff105bc809568459..3e81aac65efa992a96496250c6668201e848e391 100644 (file)
@@ -511,6 +511,7 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars)
 
        if (Siz == 0)
        {
+               free(NewBuf);
                return NULL;
        }
 
@@ -611,7 +612,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;       
@@ -815,7 +816,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)
@@ -1062,7 +1064,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;
@@ -1143,7 +1147,7 @@ void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
        const char *pLeft;
        const char *pRight;
 
-       if (Buf == NULL)
+       if ((Buf == NULL) || (Buf->buf == NULL))
                return;
        pLeft = pBuff = Buf->buf;
        while (pBuff != NULL) {
@@ -1341,6 +1345,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
@@ -2500,14 +2521,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)
@@ -2544,7 +2565,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;
        }
@@ -2732,7 +2753,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);
@@ -2831,7 +2855,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;
@@ -2902,7 +2926,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;
@@ -3081,6 +3104,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);
@@ -3263,9 +3289,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
@@ -3273,7 +3302,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;
@@ -3297,8 +3325,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) 
@@ -3315,7 +3342,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
@@ -3755,6 +3781,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;
@@ -3842,6 +3872,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);
        
@@ -3854,7 +3886,7 @@ void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize)
        FDB->ChunkSize = 
                FDB->TotalSendSize = TotalSendSize;
        FDB->IOB = IO;
-#ifndef LINUX_SENDFILE
+#ifndef LINUX_SPLICE
        FDB->ChunkBuffer = NewStrBufPlain(NULL, TotalSendSize + 1);
 #else
        pipe(FDB->SplicePipe);
@@ -3864,7 +3896,7 @@ void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize)
 
 void FDIOBufferDelete(FDIOBuffer *FDB)
 {
-#ifndef LINUX_SENDFILE
+#ifndef LINUX_SPLICE
        FreeStrBuf(&FDB->ChunkBuffer);
 #else
        close(FDB->SplicePipe[0]);
@@ -3877,21 +3909,43 @@ void FDIOBufferDelete(FDIOBuffer *FDB)
 
 int FileSendChunked(FDIOBuffer *FDB, const char **Err)
 {
-       char *pRead;
-       long nRead = 0;
+       ssize_t sent, pipesize;
+#ifdef LINUX_SPLICE
+       if (FDB->PipeSize == 0)
+       {
+               pipesize = splice(FDB->OtherFD,
+                                 &FDB->TotalSentAlready, 
+                                 FDB->SplicePipe[1],
+                                 NULL, 
+                                 FDB->ChunkSendRemain, 
+                                 SPLICE_F_MOVE);
        
-#ifdef LINUX_SENDFILE
-       ssize_t sent;
-       sent = sendfile(FDB->IOB->fd, FDB->OtherFD, &FDB->TotalSentAlready, FDB->ChunkSendRemain);
+               if (pipesize == -1)
+               {
+                       *Err = strerror(errno);
+                       return pipesize;
+               }
+               FDB->PipeSize = pipesize;
+       }
+       sent =  splice(FDB->SplicePipe[0],
+                      NULL, 
+                      FDB->IOB->fd,
+                      NULL, 
+                      FDB->PipeSize,
+                      SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
        if (sent == -1)
        {
                *Err = strerror(errno);
                return sent;
        }
+       FDB->PipeSize -= sent;
        FDB->ChunkSendRemain -= sent;
-       FDB->TotalSentAlready += sent;
-       return FDB->ChunkSendRemain;
+       return sent;
 #else
+
+       char *pRead;
+       long nRead = 0;
+
        pRead = FDB->ChunkBuffer->buf;
        while ((FDB->ChunkBuffer->BufUsed < FDB->TotalSendSize) && (nRead >= 0))
        {
@@ -3922,26 +3976,106 @@ int FileRecvChunked(FDIOBuffer *FDB, const char **Err)
 {
        ssize_t sent, pipesize;
 
-#ifdef LINUX_SENDFILE
+#ifdef LINUX_SPLICE
+       if (FDB->PipeSize == 0)
+       {
+               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;
+               }
+               FDB->PipeSize = pipesize;
+       }
+       
+       sent = splice(FDB->SplicePipe[0],
+                     NULL, 
+                     FDB->OtherFD,
+                     &FDB->TotalSentAlready, 
+                     FDB->PipeSize,
+                     SPLICE_F_MORE | SPLICE_F_MOVE);
 
-       pipesize = splice(FDB->IOB->fd, NULL, 
-                         FDB->SplicePipe[1], NULL, 
-                         FDB->ChunkSendRemain, 
-                         SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
-       if (pipesize == -1)
+       if (sent == -1)
        {
                *Err = strerror(errno);
-               return pipesize;
+               return sent;
        }
+       FDB->PipeSize -= sent;
+       FDB->ChunkSendRemain -= sent;
+       return sent;
+#else
        
-       sent = splice(FDB->SplicePipe[0], NULL, 
-                     FDB->OtherFD, &FDB->TotalSentAlready, 
-                     pipesize, SPLICE_F_MORE | SPLICE_F_MOVE);
+       sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
+       if (sent > 0) {
+               int nWritten = 0;
+               int rc; 
+               
+               FDB->ChunkBuffer->BufUsed = sent;
+
+               while (nWritten < FDB->ChunkBuffer->BufUsed) {
+                       rc =  write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
+                       if (rc < 0) {
+                               *Err = strerror(errno);
+                               return rc;
+                       }
+                       nWritten += rc;
+
+               }
+               FDB->ChunkBuffer->BufUsed = 0;
+               FDB->TotalSentAlready += sent;
+               FDB->ChunkSendRemain -= sent;
+               return FDB->ChunkSendRemain;
+       }
+       else if (sent < 0) {
+               *Err = strerror(errno);
+               return sent;
+       }
+
+#endif
+       return 0;
+}
+
+int FileMoveChunked(FDIOBuffer *FDB, const char **Err)
+{
+       ssize_t sent, pipesize;
+
+#ifdef LINUX_SPLICE
+       if (FDB->PipeSize == 0)
+       {
+               pipesize = splice(FDB->IOB->fd,
+                                 &FDB->TotalReadAlready, 
+                                 FDB->SplicePipe[1],
+                                 NULL, 
+                                 FDB->ChunkSendRemain, 
+                                 SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
+
+               if (pipesize == -1)
+               {
+                       *Err = strerror(errno);
+                       return pipesize;
+               }
+               FDB->PipeSize = pipesize;
+       }
+       
+       sent = splice(FDB->SplicePipe[0],
+                     NULL, 
+                     FDB->OtherFD,
+                     &FDB->TotalSentAlready, 
+                     FDB->PipeSize,
+                     SPLICE_F_MORE | SPLICE_F_MOVE);
+
        if (sent == -1)
        {
                *Err = strerror(errno);
                return sent;
        }
+       FDB->PipeSize -= sent;
        FDB->ChunkSendRemain -= sent;
        return sent;
 #else
@@ -4055,6 +4189,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);
 
@@ -4398,7 +4537,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;
@@ -4480,8 +4619,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;
@@ -4507,8 +4645,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) && 
@@ -4542,8 +4680,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)
@@ -4640,7 +4776,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;
        }