X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=libcitadel%2Flib%2Fstringbuf.c;h=08e904b315fc36f896823e6a9f0b174abf556a72;hb=aa1bc013ff54eb118855365945aae4218d099003;hp=18d9870b5067660242fd5e17e32913402244bfb5;hpb=2da33e9a303d108d625aecdb627a96b5b14dd2cd;p=citadel.git diff --git a/libcitadel/lib/stringbuf.c b/libcitadel/lib/stringbuf.c index 18d9870b5..08e904b31 100644 --- a/libcitadel/lib/stringbuf.c +++ b/libcitadel/lib/stringbuf.c @@ -1,3 +1,21 @@ +/* + * Copyright (c) 1987-2011 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #include "sysdep.h" #include #include @@ -10,6 +28,9 @@ #include #define SHOW_ME_VAPPEND_PRINTF #include +#ifndef LINUX_SENDFILE +#include +#endif #include "libcitadel.h" #ifdef HAVE_ICONV @@ -20,6 +41,10 @@ #include #endif +#ifdef LINUX_SENDFILE +#include +#endif + #ifdef HAVE_ZLIB #include int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen, @@ -2125,6 +2150,7 @@ long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn) const char *aptr, *eiptr; char *bptr, *eptr; long len; + int IsUtf8Sequence; if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) ) return -1; @@ -2144,31 +2170,83 @@ long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn) return -1; bptr = Target->buf + Target->BufUsed; - eptr = Target->buf + Target->BufSize - 3; /* our biggest unit to put in... */ + eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in... */ while (aptr < eiptr){ if(bptr >= eptr) { IncreaseBuf(Target, 1, -1); - eptr = Target->buf + Target->BufSize - 3; + eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in... */ bptr = Target->buf + Target->BufUsed; } - if (*aptr == '"') { + switch (*aptr) { + case '\n': + memcpy(bptr, HKEY("\\n")); + bptr += 2; + Target->BufUsed += 2; + break; + case '\r': + memcpy(bptr, HKEY("\\r")); + bptr += 2; + Target->BufUsed += 2; + break; + case '"': *bptr = '\\'; bptr ++; *bptr = '"'; bptr ++; Target->BufUsed += 2; - } else if (*aptr == '\\') { + break; + case '\\': + if ((*(aptr + 1) == 'u') && + isxdigit(*(aptr + 2)) && + isxdigit(*(aptr + 3)) && + isxdigit(*(aptr + 4)) && + isxdigit(*(aptr + 5))) + { /* oh, a unicode escaper. let it pass through. */ + memcpy(bptr, aptr, 6); + aptr += 5; + bptr +=6; + Target->BufUsed += 6; + } + else + { + *bptr = '\\'; + bptr ++; + *bptr = '\\'; + bptr ++; + Target->BufUsed += 2; + } + break; + case '\b': + *bptr = '\\'; + bptr ++; + *bptr = 'b'; + bptr ++; + Target->BufUsed += 2; + break; + case '\f': *bptr = '\\'; bptr ++; + *bptr = 'f'; + bptr ++; + Target->BufUsed += 2; + break; + case '\t': *bptr = '\\'; bptr ++; + *bptr = 't'; + bptr ++; Target->BufUsed += 2; - } - else{ - *bptr = *aptr; - bptr++; - Target->BufUsed ++; + break; + default: + IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr); + while (IsUtf8Sequence > 0){ + *bptr = *aptr; + Target->BufUsed ++; + if (--IsUtf8Sequence) + aptr++; + bptr++; + } } aptr ++; } @@ -2248,12 +2326,6 @@ long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *Plai bptr ++; Target->BufUsed ++; break; - case 32: -//) && (nbsp == 1)) { - memcpy(bptr, HKEY(" ")); - bptr += 6; - Target->BufUsed += 6; - break; case '\n': switch (nolinebreaks) { case 1: @@ -2333,6 +2405,13 @@ long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *Plai bptr ++; Target->BufUsed += 2; break; + case 32: + if (nbsp == 1) { + memcpy(bptr, HKEY(" ")); + bptr += 6; + Target->BufUsed += 6; + break; + } default: IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr); while (IsUtf8Sequence > 0){ @@ -2610,6 +2689,8 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source) (ch > 126) || (ch == 61) || (ch == '=') || + (ch == '?') || + (ch == '_') || (ch == '[') || (ch == ']') ) { @@ -2617,7 +2698,10 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source) (*target)->BufUsed += 3; } else { - (*target)->buf[(*target)->BufUsed] = ch; + if (ch == ' ') + (*target)->buf[(*target)->BufUsed] = '_'; + else + (*target)->buf[(*target)->BufUsed] = ch; (*target)->BufUsed++; } } @@ -3259,14 +3343,16 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target, */ static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE) { - int n = 1; - char test = (1<<7); + int n = 0; + unsigned char test = (1<<7); - if ((*CharS & 0xC0) == 0) + if ((*CharS & 0xC0) != 0xC0) return 1; - while ((n < 8) && ((test & *CharS) != 0)) { - test = test << 1; + while ((n < 8) && + ((test & ((unsigned char)*CharS)) != 0)) + { + test = test >> 1; n ++; } if ((n > 6) || ((CharE - CharS) < n)) @@ -3283,7 +3369,7 @@ static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *Char static inline int Ctdl_IsUtf8SequenceStart(const char Char) { /** 11??.???? indicates an UTF8 Sequence. */ - return ((Char & 0xC0) != 0); + return ((Char & 0xC0) == 0xC0); } /** @@ -3644,7 +3730,18 @@ eReadState StrBufChunkSipLine(StrBuf *LineBuf, IOBuffer *FB) optr --; if ((*(ptr - 1) != '\r') && (*(ptr - 1) != '\n')) { LineBuf->BufUsed = optr - LineBuf->buf; - *optr = '\0'; + *optr = '\0'; + if ((FB->ReadWritePointer != NULL) && + (FB->ReadWritePointer != FB->Buf->buf)) + { + /* Ok, the client application read all the data + it was interested in so far. Since there is more to read, + we now shrink the buffer, and move the rest over. + */ + StrBufCutLeft(FB->Buf, + FB->ReadWritePointer - FB->Buf->buf); + FB->ReadWritePointer = FB->Buf->buf; + } return eMustReadMore; } } @@ -3684,6 +3781,125 @@ eReadState StrBufCheckBuffer(IOBuffer *FB) return eReadSuccess; } +long IOBufferStrLength(IOBuffer *FB) +{ + if (FB->ReadWritePointer == NULL) + return StrLength(FB->Buf); + + return StrLength(FB->Buf) - (FB->ReadWritePointer - FB->Buf->buf); +} + + + +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(); +#endif + FDB->OtherFD = FD; +} + +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; + sent = sendfile(FDB->OtherFD, FDB->IOB->fd, &FDB->TotalSentAlready, FDB->ChunkSendRemain); + if (sent == -1) + { + *Err = strerror(errno); + return sent; + } + FDB->ChunkSendRemain -= sent; + return FDB->ChunkSendRemain; +#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! * *******************************************************************************/