X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=libcitadel%2Flib%2Fstringbuf.c;h=88cea7d704681a9490a25264a2b7aa40883c4d84;hb=90a90f347bea035bbed1b3d13e40b7a23765af11;hp=fe4913fa4487a48fb166485ed04bfe2d5b396eae;hpb=c8efd51f573bb8665d842c8785f63d784d1d1a90;p=citadel.git diff --git a/libcitadel/lib/stringbuf.c b/libcitadel/lib/stringbuf.c index fe4913fa4..88cea7d70 100644 --- a/libcitadel/lib/stringbuf.c +++ b/libcitadel/lib/stringbuf.c @@ -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 @@ -286,14 +303,16 @@ static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize) /** * @ingroup StrBuf_DeConstructors - * @brief shrink an _EMPTY_ buffer if its Buffer superseeds threshhold to NewSize. Buffercontent is thoroughly ignored and flushed. + * @brief shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed. * @param Buf Buffer to shrink (has to be empty) * @param ThreshHold if the buffer is bigger then this, its readjusted * @param NewSize if we Shrink it, how big are we going to be afterwards? */ void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize) { - if ((Buf != NULL) && (Buf->BufUsed > ThreshHold)) { + if ((Buf != NULL) && + (Buf->BufUsed == 0) && + (Buf->BufSize < ThreshHold)) { free(Buf->buf); Buf->buf = (char*) malloc(NewSize); Buf->BufUsed = 0; @@ -370,6 +389,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 @@ -395,6 +483,11 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars) Siz *= 2; NewBuf->buf = (char*) malloc(Siz); + if (NewBuf->buf == NULL) + { + free(NewBuf); + return NULL; + } NewBuf->BufSize = Siz; if (ptr != NULL) { memcpy(NewBuf->buf, ptr, CopySize); @@ -407,9 +500,9 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars) } NewBuf->ConstBuf = 0; - dbg_Init(NewBuf) + dbg_Init(NewBuf); - return NewBuf; + return NewBuf; } /** @@ -422,9 +515,18 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars) */ int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars) { - size_t Siz = Buf->BufSize; + size_t Siz; size_t CopySize; + if (Buf == NULL) + return -1; + if (ptr == NULL) { + FlushStrBuf(Buf); + return -1; + } + + Siz = Buf->BufSize; + if (nChars < 0) CopySize = strlen(ptr); else @@ -618,6 +720,7 @@ int StrBufIsNumber(const StrBuf *Buf) { return 0; return 0; } + /** * @ingroup StrBuf_Filler * @brief modifies a Single char of the Buf @@ -639,6 +742,33 @@ long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue) return nThChar; } +/** + * @ingroup StrBuf_Filler + * @brief modifies a range of chars of the Buf + * You can point to it via char* or a zero-based integer + * @param Buf The buffer to manipulate + * @param ptr char* to zero; use NULL if unused + * @param nThChar zero based pointer into the string; use -1 if unused + * @param nChars how many chars are to be flushed? + * @param PookValue The Character to place into that area + */ +long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char PookValue) +{ + if (Buf == NULL) + return -1; + if (ptr != NULL) + nThChar = ptr - Buf->buf; + if ((nThChar < 0) || (nThChar > Buf->BufUsed)) + return -1; + if (nThChar + nChars > Buf->BufUsed) + nChars = Buf->BufUsed - nThChar; + + memset(Buf->buf + nThChar, PookValue, nChars); + /* just to be shure... */ + Buf->buf[Buf->BufUsed] = 0; + return nChars; +} + /** * @ingroup StrBuf_Filler * @brief Append a StringBuffer to the buffer @@ -844,7 +974,8 @@ int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t n size_t NCharsRemain; if (Offset > Source->BufUsed) { - FlushStrBuf(dest); + if (dest != NULL) + FlushStrBuf(dest); return 0; } if (Offset + nChars < Source->BufUsed) @@ -931,18 +1062,69 @@ void StrBufTrim(StrBuf *Buf) int delta = 0; if ((Buf == NULL) || (Buf->BufUsed == 0)) return; + while ((Buf->BufUsed > 0) && + isspace(Buf->buf[Buf->BufUsed - 1])) + { + Buf->BufUsed --; + } + Buf->buf[Buf->BufUsed] = '\0'; + + if (Buf->BufUsed == 0) return; + while ((Buf->BufUsed > delta) && (isspace(Buf->buf[delta]))){ delta ++; } 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->BufUsed == 0) return; - while (isspace(Buf->buf[Buf->BufUsed - 1])){ - Buf->BufUsed --; + if ((Buf == NULL) || (Buf->BufUsed == 0)) return; + + pch = Buf->buf; + pche = pch + Buf->BufUsed; + while (pch < pche) + { + if (isspace(*pch)) + *pch = ' '; + pch ++; } - Buf->buf[Buf->BufUsed] = '\0'; } +void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary) +{ + const char *pBuff; + const char *pLeft; + const char *pRight; + + if (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) + StrBufCutAt(Buf, 0, pRight); + if (pLeft != NULL) + StrBufCutLeft(Buf, pLeft - Buf->buf); +} + + /** * @ingroup StrBuf_Filler * @brief uppercase the contents of a buffer @@ -987,6 +1169,41 @@ void StrBufLowerCase(StrBuf *Buf) * a tokenizer that kills, maims, and destroys * *******************************************************************************/ +/** + * @ingroup StrBuf_Tokenizer + * @brief Replace a token at a given place with a given length by another token with given length + * @param Buf String where to work on + * @param where where inside of the Buf is the search-token + * @param HowLong How long is the token to be replaced + * @param Repl Token to insert at 'where' + * @param ReplLen Length of repl + * @returns -1 if fail else length of resulting Buf + */ +int StrBufReplaceToken(StrBuf *Buf, long where, long HowLong, + const char *Repl, long ReplLen) +{ + + if ((Buf == NULL) || + (where > Buf->BufUsed) || + (where + HowLong > Buf->BufUsed)) + return -1; + + if (where + ReplLen - HowLong > Buf->BufSize) + if (IncreaseBuf(Buf, 1, Buf->BufUsed + ReplLen) < 0) + return -1; + + memmove(Buf->buf + where + ReplLen, + Buf->buf + where + HowLong, + Buf->BufUsed - where - HowLong); + + memcpy(Buf->buf + where, + Repl, ReplLen); + + Buf->BufUsed += ReplLen - HowLong; + + return Buf->BufUsed; +} + /** * @ingroup StrBuf_Tokenizer * @brief Counts the numbmer of tokens in a buffer @@ -1545,8 +1762,7 @@ void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn) (*pch >= '@' && *pch <= 'Z') || /* @ A-Z */ (*pch >= '0' && *pch <= ':') || /* 0-9 : */ (*pch == '!') || (*pch == '_') || - (*pch == ',') || (*pch == '.') || - (*pch == ',')) + (*pch == ',') || (*pch == '.')) { *(pt++) = *(pch++); OutBuf->BufUsed++; @@ -2154,6 +2370,7 @@ int StrBufDecodeBase64(StrBuf *Buf) if (Buf == NULL) return -1; xferbuf = (char*) malloc(Buf->BufSize); + *xferbuf = '\0'; siz = CtdlDecodeBase64(xferbuf, Buf->buf, Buf->BufUsed); @@ -2331,6 +2548,184 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source) return (*target)->BufUsed;; } + + +static void AddRecipient(StrBuf *Target, + StrBuf *UserName, + StrBuf *EmailAddress, + StrBuf *EncBuf) +{ + int QuoteMe = 0; + + if (StrLength(Target) > 0) StrBufAppendBufPlain(Target, HKEY(", "), 0); + if (strchr(ChrPtr(UserName), ',') != NULL) QuoteMe = 1; + + if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\""), 0); + StrBufRFC2047encode(&EncBuf, UserName); + StrBufAppendBuf(Target, EncBuf, 0); + if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\" "), 0); + else StrBufAppendBufPlain(Target, HKEY(" "), 0); + + if (StrLength(EmailAddress) > 0){ + StrBufAppendBufPlain(Target, HKEY("<"), 0); + StrBufAppendBuf(Target, EmailAddress, 0); /* TODO: what about IDN???? */ + StrBufAppendBufPlain(Target, HKEY(">"), 0); + } +} + + +/** + * \brief QP encode parts of an email TO/CC/BCC vector, and strip/filter invalid parts + * \param Recp Source list of email recipients + * \param UserName Temporary buffer for internal use; Please provide valid buffer. + * \param EmailAddress Temporary buffer for internal use; Please provide valid buffer. + * \param EncBuf Temporary buffer for internal use; Please provide valid buffer. + * \returns encoded & sanitized buffer with the contents of Recp; Caller owns this memory. + */ +StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp, + StrBuf *UserName, + StrBuf *EmailAddress, + 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); + + if (!CheckEncode(pch, -1, pche)) + return NewStrBufDup(Recp); + + Target = NewStrBufPlain(NULL, StrLength(Recp)); + + while ((pch != NULL) && (pch < pche)) + { + int ColonOk = 0; + + while (isspace(*pch)) pch++; + UserStart = UserEnd = EmailStart = EmailEnd = NULL; + + if ((*pch == '"') || (*pch == '\'')) { + UserStart = pch + 1; + + UserEnd = strchr(UserStart, *pch); + if (UserEnd == NULL) + break; ///TODO: Userfeedback?? + EmailStart = UserEnd + 1; + while (isspace(*EmailStart)) + EmailStart++; + if (UserEnd == UserStart) { + UserStart = UserEnd = NULL; + } + + if (*EmailStart == '<') { + EmailStart++; + EmailEnd = strchr(EmailStart, '>'); + if (EmailEnd == NULL) + EmailEnd = strchr(EmailStart, ','); + + } + else { + EmailEnd = strchr(EmailStart, ','); + } + if (EmailEnd == NULL) + EmailEnd = pche; + pch = EmailEnd + 1; + ColonOk = 1; + } + else { + int gt = 0; + UserStart = pch; + EmailEnd = strchr(UserStart, ','); + if (EmailEnd == NULL) { + EmailEnd = strchr(pch, '>'); + pch = NULL; + if (EmailEnd != NULL) { + gt = 1; + } + else { + EmailEnd = pche; + } + } + else { + + pch = EmailEnd + 1; + while ((EmailEnd > UserStart) && !gt && + ((*EmailEnd == ',') || + (*EmailEnd == '>') || + (isspace(*EmailEnd)))) + { + if (*EmailEnd == '>') + gt = 1; + else + EmailEnd--; + } + if (EmailEnd == UserStart) + break; + } + if (gt) { + EmailStart = strchr(UserStart, '<'); + if ((EmailStart == NULL) || (EmailStart > EmailEnd)) + break; + UserEnd = EmailStart; + + while ((UserEnd > UserStart) && + isspace (*(UserEnd - 1))) + UserEnd --; + EmailStart ++; + if (UserStart >= UserEnd) + UserStart = UserEnd = NULL; + At = strchr(EmailStart, '@'); + } + else { /* this is a local recipient... no domain, just a realname */ + EmailStart = UserStart; + At = strchr(EmailStart, '@'); + if (At == NULL) { + UserEnd = EmailEnd; + EmailEnd = NULL; + } + else { + EmailStart = UserStart; + UserStart = NULL; + } + } + } + + if ((UserStart != NULL) && (UserEnd != NULL)) + StrBufPlain(UserName, UserStart, UserEnd - UserStart); + else if ((UserStart != NULL) && (UserEnd == NULL)) + StrBufPlain(UserName, UserStart, UserEnd - UserStart); + else + FlushStrBuf(UserName); + + if ((EmailStart != NULL) && (EmailEnd != NULL)) + StrBufPlain(EmailAddress, EmailStart, EmailEnd - EmailStart); + else if ((EmailStart != NULL) && (EmailEnd == NULL)) + StrBufPlain(EmailAddress, EmailStart, EmailEnd - pche); + else + FlushStrBuf(EmailAddress); + + AddRecipient(Target, UserName, EmailAddress, EncBuf); + + if (pch == NULL) + break; + + if ((pch != NULL) && (*pch == ',')) + pch ++; + if (pch != NULL) while (isspace(*pch)) + pch ++; + } + return Target; +} + + /** * @ingroup StrBuf * @brief replaces all occurances of 'search' by 'replace' @@ -2444,22 +2839,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)); - -} /** @@ -2566,6 +2945,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); @@ -2581,6 +2962,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, @@ -2606,7 +2990,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 @@ -2615,9 +2999,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 @@ -2643,7 +3060,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")) ) @@ -2668,12 +3084,10 @@ void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf* end = FindNextEnd (DecodeMee, start); else { StrBufAppendBuf(Target, DecodeMee, 0); - FreeStrBuf(&ConvertBuf); FreeStrBuf(&DecodedInvalidBuf); return; } - ConvertBuf2 = NewStrBufPlain(NULL, StrLength(DecodeMee)); if (start != DecodeMee->buf) { long nFront; @@ -2752,8 +3166,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); } @@ -3290,7 +3702,7 @@ int StrBufTCP_read_buffered_line_fast(StrBuf *Line, if (IOBuf->BufUsed + 10 > IOBuf->BufSize) { - long apos; + long apos = 0; if (pLF != NULL) apos = pLF - IOBuf->buf; IncreaseBuf(IOBuf, 1, -1); @@ -3401,7 +3813,7 @@ int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **E } const char *ErrRBB_BLOBFPreConditionFailed = "StrBufReadBLOBBuffered: to many selects; aborting."; -const char *ErrRBB_too_many_selects = "StrBufReadBLOBBuffered: to many selects; aborting."; +const char *ErrRBB_too_many_selects = "StrBufReadBLOBBuffered: to many selects; aborting."; /** * @ingroup StrBuf_BufferedIO * @brief Input binary data from socket @@ -3427,8 +3839,6 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, { const char *pche; const char *pos; - int nSelects = 0; - int SelRes; int fdflags; int len = 0; int rlen, slen; @@ -3439,7 +3849,8 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, fd_set rfds; const char *pch; struct timeval tv; - int nSuccessLess; + int nSuccessLess = 0; + int MaxTries; if ((Blob == NULL) || (*fd == -1) || (IOBuf == NULL) || (Pos == NULL)) { @@ -3499,11 +3910,15 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, fdflags = fcntl(*fd, F_GETFL); IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK; + if (IsNonBlock) + MaxTries = 1000; + else + MaxTries = 100000; - SelRes = 1; nBytes -= nRead; nRead = 0; - while ((nRead < nBytes) && + while ((nSuccessLess < MaxTries) && + (nRead < nBytes) && (*fd != -1)) { if (IsNonBlock) { @@ -3525,10 +3940,9 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, continue; } } - nSuccessLess = 0; rlen = read(*fd, ptr, - nBytes - nRead); + IOBuf->BufSize - (ptr - IOBuf->buf)); if (rlen == -1) { close(*fd); *fd = -1; @@ -3536,7 +3950,6 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, return rlen; } else if (rlen == 0){ - nSuccessLess ++; if ((check == NNN_TERM) && (nRead > 5) && (strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0)) @@ -3545,18 +3958,27 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, StrBufCutRight(Blob, 5); return Blob->BufUsed; } - if (nSelects > 10) { + else if (!IsNonBlock) + nSuccessLess ++; + else if (nSuccessLess > MaxTries) { FlushStrBuf(IOBuf); *Error = ErrRBB_too_many_selects; return -1; } } else if (rlen > 0) { + nSuccessLess = 0; nRead += rlen; ptr += rlen; IOBuf->BufUsed += rlen; } } + if (nSuccessLess >= MaxTries) { + FlushStrBuf(IOBuf); + *Error = ErrRBB_too_many_selects; + return -1; + } + if (nRead > nBytes) { *Pos = IOBuf->buf + nBytes; }