Back to index

libcitadel  8.12
stringbuf.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1987-2011 by the citadel.org team
00003  *
00004  * This program is open source software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 3 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00017  */
00018 
00019 #define _GNU_SOURCE
00020 #include "sysdep.h"
00021 #include <ctype.h>
00022 #include <errno.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 #include <string.h>
00026 #include <stdio.h>
00027 #include <sys/select.h>
00028 #include <fcntl.h>
00029 #include <sys/types.h>
00030 #define SHOW_ME_VAPPEND_PRINTF
00031 #include <stdarg.h>
00032 
00033 #include "libcitadel.h"
00034 
00035 #ifdef HAVE_ICONV
00036 #include <iconv.h>
00037 #endif
00038 
00039 #ifdef HAVE_BACKTRACE
00040 #include <execinfo.h>
00041 #endif
00042 
00043 #ifdef LINUX_SENDFILE
00044 #include <sys/sendfile.h>
00045 #endif
00046 
00047 #ifdef HAVE_ZLIB
00048 #include <zlib.h>
00049 int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen,
00050                           const Bytef * source, uLong sourceLen, int level);
00051 #endif
00052 int BaseStrBufSize = 64;
00053 
00054 const char *StrBufNOTNULL = ((char*) NULL) - 1;
00055 
00056 const char HexList[256][3] = {
00057        "00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F",
00058        "10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F",
00059        "20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
00060        "30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F",
00061        "40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F",
00062        "50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
00063        "60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F",
00064        "70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F",
00065        "80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
00066        "90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F",
00067        "A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF",
00068        "B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
00069        "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",
00070        "D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF",
00071        "E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
00072        "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"};
00073 
00138 struct StrBuf {
00139        char *buf;         
00140        long BufSize;      
00141        long BufUsed;      
00142        int ConstBuf;      
00143 #ifdef SIZE_DEBUG
00144        long nIncreases;   
00145        char bt [SIZ];     
00146        char bt_lastinc [SIZ]; 
00147 #endif
00148 };
00149 
00150 
00151 static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE);
00152 static inline int Ctdl_IsUtf8SequenceStart(const char Char);
00153 
00154 #ifdef SIZE_DEBUG
00155 #ifdef HAVE_BACKTRACE
00156 static void StrBufBacktrace(StrBuf *Buf, int which)
00157 {
00158        int n;
00159        char *pstart, *pch;
00160        void *stack_frames[50];
00161        size_t size, i;
00162        char **strings;
00163 
00164        if (which)
00165               pstart = pch = Buf->bt;
00166        else
00167               pstart = pch = Buf->bt_lastinc;
00168        size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
00169        strings = backtrace_symbols(stack_frames, size);
00170        for (i = 0; i < size; i++) {
00171               if (strings != NULL)
00172                      n = snprintf(pch, SIZ - (pch - pstart), "%s\\n", strings[i]);
00173               else
00174                      n = snprintf(pch, SIZ - (pch - pstart), "%p\\n", stack_frames[i]);
00175               pch += n;
00176        }
00177        free(strings);
00178 
00179 
00180 }
00181 #endif
00182 
00183 void dbg_FreeStrBuf(StrBuf *FreeMe, char *FromWhere)
00184 {
00185        if (hFreeDbglog == -1){
00186               pid_t pid = getpid();
00187               char path [SIZ];
00188               snprintf(path, SIZ, "/tmp/libcitadel_strbuf_realloc.log.%d", pid);
00189               hFreeDbglog = open(path, O_APPEND|O_CREAT|O_WRONLY);
00190        }
00191        if ((*FreeMe)->nIncreases > 0)
00192        {
00193               char buf[SIZ * 3];
00194               long n;
00195               n = snprintf(buf, SIZ * 3, "%c+|%ld|%ld|%ld|%s|%s|\n",
00196                           FromWhere,
00197                           (*FreeMe)->nIncreases,
00198                           (*FreeMe)->BufUsed,
00199                           (*FreeMe)->BufSize,
00200                           (*FreeMe)->bt,
00201                           (*FreeMe)->bt_lastinc);
00202               n = write(hFreeDbglog, buf, n);
00203        }
00204        else
00205        {
00206               char buf[128];
00207               long n;
00208               n = snprintf(buf, 128, "%c_|0|%ld%ld|\n",
00209                           FromWhere,
00210                           (*FreeMe)->BufUsed,
00211                           (*FreeMe)->BufSize);
00212               n = write(hFreeDbglog, buf, n);
00213        }
00214 }
00215 
00216 void dbg_IncreaseBuf(StrBuf *IncMe)
00217 {
00218        Buf->nIncreases++;
00219 #ifdef HAVE_BACKTRACE
00220        StrBufBacktrace(Buf, 1);
00221 #endif
00222 }
00223 
00224 void dbg_Init(StrBuf *Buf)
00225 {
00226        Buf->nIncreases = 0;
00227        Buf->bt[0] = '\0';
00228        Buf->bt_lastinc[0] = '\0';
00229 #ifdef HAVE_BACKTRACE
00230        StrBufBacktrace(Buf, 0);
00231 #endif
00232 }
00233 
00234 #else
00235 /* void it... */
00236 #define dbg_FreeStrBuf(a, b)
00237 #define dbg_IncreaseBuf(a)
00238 #define dbg_Init(a)
00239 
00240 #endif
00241 
00249 static inline void SwapBuffers(StrBuf *A, StrBuf *B)
00250 {
00251        StrBuf C;
00252 
00253        memcpy(&C, A, sizeof(*A));
00254        memcpy(A, B, sizeof(*B));
00255        memcpy(B, &C, sizeof(C));
00256 
00257 }
00258 
00269 inline const char *ChrPtr(const StrBuf *Str)
00270 {
00271        if (Str == NULL)
00272               return "";
00273        return Str->buf;
00274 }
00275 
00282 inline int StrLength(const StrBuf *Str)
00283 {
00284        return (Str != NULL) ? Str->BufUsed : 0;
00285 }
00286 
00294 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
00295 {
00296        char *NewBuf;
00297        size_t NewSize = Buf->BufSize * 2;
00298 
00299        if (Buf->ConstBuf)
00300               return -1;
00301               
00302        if (DestSize > 0)
00303               while ((NewSize <= DestSize) && (NewSize != 0))
00304                      NewSize *= 2;
00305 
00306        if (NewSize == 0)
00307               return -1;
00308 
00309        NewBuf= (char*) malloc(NewSize);
00310        if (NewBuf == NULL)
00311               return -1;
00312 
00313        if (KeepOriginal && (Buf->BufUsed > 0))
00314        {
00315               memcpy(NewBuf, Buf->buf, Buf->BufUsed);
00316        }
00317        else
00318        {
00319               NewBuf[0] = '\0';
00320               Buf->BufUsed = 0;
00321        }
00322        free (Buf->buf);
00323        Buf->buf = NewBuf;
00324        Buf->BufSize = NewSize;
00325 
00326        dbg_IncreaseBuf(Buf);
00327 
00328        return Buf->BufSize;
00329 }
00330 
00338 void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize)
00339 {
00340        if ((Buf != NULL) && 
00341            (Buf->BufUsed == 0) &&
00342            (Buf->BufSize < ThreshHold)) {
00343               free(Buf->buf);
00344               Buf->buf = (char*) malloc(NewSize);
00345               Buf->BufUsed = 0;
00346               Buf->BufSize = NewSize;
00347        }
00348 }
00349 
00357 long StrBufShrinkToFit(StrBuf *Buf, int Force)
00358 {
00359        if (Buf == NULL)
00360               return -1;
00361        if (Force || 
00362            (Buf->BufUsed + (Buf->BufUsed / 3) > Buf->BufSize))
00363        {
00364               char *TmpBuf = (char*) malloc(Buf->BufUsed + 1);
00365               memcpy (TmpBuf, Buf->buf, Buf->BufUsed + 1);
00366               Buf->BufSize = Buf->BufUsed + 1;
00367               free(Buf->buf);
00368               Buf->buf = TmpBuf;
00369        }
00370        return Buf->BufUsed;
00371 }
00372 
00378 StrBuf* NewStrBuf(void)
00379 {
00380        StrBuf *NewBuf;
00381 
00382        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
00383        NewBuf->buf = (char*) malloc(BaseStrBufSize);
00384        NewBuf->buf[0] = '\0';
00385        NewBuf->BufSize = BaseStrBufSize;
00386        NewBuf->BufUsed = 0;
00387        NewBuf->ConstBuf = 0;
00388 
00389        dbg_Init (NewBuf);
00390 
00391        return NewBuf;
00392 }
00393 
00400 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
00401 {
00402        StrBuf *NewBuf;
00403        
00404        if (CopyMe == NULL)
00405               return NewStrBuf();
00406 
00407        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
00408        NewBuf->buf = (char*) malloc(CopyMe->BufSize);
00409        memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
00410        NewBuf->BufUsed = CopyMe->BufUsed;
00411        NewBuf->BufSize = CopyMe->BufSize;
00412        NewBuf->ConstBuf = 0;
00413 
00414        dbg_Init(NewBuf);
00415 
00416        return NewBuf;
00417 }
00418 
00428 void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, const char *NoMe, int KeepOriginal)
00429 {
00430        StrBuf *NewBuf;
00431        
00432        if (CreateRelpaceMe == NULL)
00433               return;
00434 
00435        if (NoMe != NULL)
00436        {
00437               if (*CreateRelpaceMe != NULL)
00438                      StrBufPlain(*CreateRelpaceMe, NoMe, KeepOriginal);
00439               else 
00440                      *CreateRelpaceMe = NewStrBufPlain(NoMe, KeepOriginal);
00441               return;
00442        }
00443 
00444        if (CopyFlushMe == NULL)
00445        {
00446               if (*CreateRelpaceMe != NULL)
00447                      FlushStrBuf(*CreateRelpaceMe);
00448               else 
00449                      *CreateRelpaceMe = NewStrBuf();
00450               return;
00451        }
00452 
00453        /* 
00454         * Randomly Chosen: bigger than 64 chars is cheaper to swap the buffers instead of copying.
00455         * else *CreateRelpaceMe may use more memory than needed in a longer term, CopyFlushMe might
00456         * be a big IO-Buffer...
00457         */
00458        if (KeepOriginal || (StrLength(CopyFlushMe) < 256))
00459        {
00460               if (*CreateRelpaceMe == NULL)
00461               {
00462                      *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
00463                      dbg_Init(NewBuf);
00464               }
00465               else 
00466               {
00467                      NewBuf = *CreateRelpaceMe;
00468                      FlushStrBuf(NewBuf);
00469               }
00470               StrBufAppendBuf(NewBuf, CopyFlushMe, 0);
00471        }
00472        else
00473        {
00474               if (*CreateRelpaceMe == NULL)
00475               {
00476                      *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
00477                      dbg_Init(NewBuf);
00478               }
00479               else 
00480                      NewBuf = *CreateRelpaceMe;
00481               SwapBuffers (NewBuf, CopyFlushMe);
00482        }
00483        if (!KeepOriginal)
00484               FlushStrBuf(CopyFlushMe);
00485        return;
00486 }
00487 
00497 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
00498 {
00499        StrBuf *NewBuf;
00500        size_t Siz = BaseStrBufSize;
00501        size_t CopySize;
00502 
00503        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
00504        if (nChars < 0)
00505               CopySize = strlen((ptr != NULL)?ptr:"");
00506        else
00507               CopySize = nChars;
00508 
00509        while ((Siz <= CopySize) && (Siz != 0))
00510               Siz *= 2;
00511 
00512        if (Siz == 0)
00513        {
00514               free(NewBuf);
00515               return NULL;
00516        }
00517 
00518        NewBuf->buf = (char*) malloc(Siz);
00519        if (NewBuf->buf == NULL)
00520        {
00521               free(NewBuf);
00522               return NULL;
00523        }
00524        NewBuf->BufSize = Siz;
00525        if (ptr != NULL) {
00526               memcpy(NewBuf->buf, ptr, CopySize);
00527               NewBuf->buf[CopySize] = '\0';
00528               NewBuf->BufUsed = CopySize;
00529        }
00530        else {
00531               NewBuf->buf[0] = '\0';
00532               NewBuf->BufUsed = 0;
00533        }
00534        NewBuf->ConstBuf = 0;
00535 
00536        dbg_Init(NewBuf);
00537 
00538        return NewBuf;
00539 }
00540 
00549 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
00550 {
00551        size_t Siz;
00552        size_t CopySize;
00553 
00554        if (Buf == NULL)
00555               return -1;
00556        if (ptr == NULL) {
00557               FlushStrBuf(Buf);
00558               return -1;
00559        }
00560 
00561        Siz = Buf->BufSize;
00562 
00563        if (nChars < 0)
00564               CopySize = strlen(ptr);
00565        else
00566               CopySize = nChars;
00567 
00568        while ((Siz <= CopySize) && (Siz != 0))
00569               Siz *= 2;
00570 
00571        if (Siz == 0) {
00572               FlushStrBuf(Buf);
00573               return -1;
00574        }
00575 
00576        if (Siz != Buf->BufSize)
00577               IncreaseBuf(Buf, 0, Siz);
00578        memcpy(Buf->buf, ptr, CopySize);
00579        Buf->buf[CopySize] = '\0';
00580        Buf->BufUsed = CopySize;
00581        Buf->ConstBuf = 0;
00582        return CopySize;
00583 }
00584 
00585 
00592 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
00593 {
00594        StrBuf *NewBuf;
00595 
00596        NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
00597        NewBuf->buf = (char*) StringConstant;
00598        NewBuf->BufSize = SizeOfStrConstant;
00599        NewBuf->BufUsed = SizeOfStrConstant;
00600        NewBuf->ConstBuf = 1;
00601 
00602        dbg_Init(NewBuf);
00603 
00604        return NewBuf;
00605 }
00606 
00607 
00613 int FlushStrBuf(StrBuf *buf)
00614 {
00615        if ((buf == NULL) || (buf->buf == NULL))
00616               return -1;
00617        if (buf->ConstBuf)
00618               return -1;       
00619        buf->buf[0] ='\0';
00620        buf->BufUsed = 0;
00621        return 0;
00622 }
00623 
00629 int FLUSHStrBuf(StrBuf *buf)
00630 {
00631        if (buf == NULL)
00632               return -1;
00633        if (buf->ConstBuf)
00634               return -1;
00635        if (buf->BufUsed > 0) {
00636               memset(buf->buf, 0, buf->BufUsed);
00637               buf->BufUsed = 0;
00638        }
00639        return 0;
00640 }
00641 
00642 #ifdef SIZE_DEBUG
00643 int hFreeDbglog = -1;
00644 #endif
00645 
00652 void FreeStrBuf (StrBuf **FreeMe)
00653 {
00654        if (*FreeMe == NULL)
00655               return;
00656 
00657        dbg_FreeStrBuf(FreeMe, 'F');
00658 
00659        if (!(*FreeMe)->ConstBuf) 
00660               free((*FreeMe)->buf);
00661        free(*FreeMe);
00662        *FreeMe = NULL;
00663 }
00664 
00674 char *SmashStrBuf (StrBuf **SmashMe)
00675 {
00676        char *Ret;
00677 
00678        if ((SmashMe == NULL) || (*SmashMe == NULL))
00679               return NULL;
00680        
00681        dbg_FreeStrBuf(SmashMe, 'S');
00682 
00683        Ret = (*SmashMe)->buf;
00684        free(*SmashMe);
00685        *SmashMe = NULL;
00686        return Ret;
00687 }
00688 
00695 void HFreeStrBuf (void *VFreeMe)
00696 {
00697        StrBuf *FreeMe = (StrBuf*)VFreeMe;
00698        if (FreeMe == NULL)
00699               return;
00700 
00701        dbg_FreeStrBuf(SmashMe, 'H');
00702 
00703        if (!FreeMe->ConstBuf) 
00704               free(FreeMe->buf);
00705        free(FreeMe);
00706 }
00707 
00708 
00709 /*******************************************************************************
00710  *                      Simple string transformations                          *
00711  *******************************************************************************/
00712 
00717 long StrTol(const StrBuf *Buf)
00718 {
00719        if (Buf == NULL)
00720               return 0;
00721        if(Buf->BufUsed > 0)
00722               return atol(Buf->buf);
00723        else
00724               return 0;
00725 }
00726 
00731 int StrToi(const StrBuf *Buf)
00732 {
00733        if (Buf == NULL)
00734               return 0;
00735        if (Buf->BufUsed > 0)
00736               return atoi(Buf->buf);
00737        else
00738               return 0;
00739 }
00740 
00747 int StrBufIsNumber(const StrBuf *Buf) {
00748        char * pEnd;
00749        if ((Buf == NULL) || (Buf->BufUsed == 0)) {
00750               return 0;
00751        }
00752        strtoll(Buf->buf, &pEnd, 10);
00753        if (pEnd == Buf->buf)
00754               return 0;
00755        if ((pEnd != NULL) && (pEnd == Buf->buf + Buf->BufUsed))
00756               return 1;
00757        if (Buf->buf == pEnd)
00758               return 0;
00759        return 0;
00760 } 
00761 
00771 long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
00772 {
00773        if (Buf == NULL)
00774               return -1;
00775        if (ptr != NULL)
00776               nThChar = ptr - Buf->buf;
00777        if ((nThChar < 0) || (nThChar > Buf->BufUsed))
00778               return -1;
00779        Buf->buf[nThChar] = PeekValue;
00780        return nThChar;
00781 }
00782 
00793 long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char PookValue)
00794 {
00795        if (Buf == NULL)
00796               return -1;
00797        if (ptr != NULL)
00798               nThChar = ptr - Buf->buf;
00799        if ((nThChar < 0) || (nThChar > Buf->BufUsed))
00800               return -1;
00801        if (nThChar + nChars > Buf->BufUsed)
00802               nChars =  Buf->BufUsed - nThChar;
00803 
00804        memset(Buf->buf + nThChar, PookValue, nChars);
00805        /* just to be shure... */
00806        Buf->buf[Buf->BufUsed] = 0;
00807        return nChars;
00808 }
00809 
00817 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, unsigned long Offset)
00818 {
00819        if ((AppendBuf == NULL) || (AppendBuf->buf == NULL) ||
00820            (Buf == NULL) || (Buf->buf == NULL))
00821               return;
00822 
00823        if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed + 1)
00824               IncreaseBuf(Buf, 
00825                          (Buf->BufUsed > 0), 
00826                          AppendBuf->BufUsed + Buf->BufUsed);
00827 
00828        memcpy(Buf->buf + Buf->BufUsed, 
00829               AppendBuf->buf + Offset, 
00830               AppendBuf->BufUsed - Offset);
00831        Buf->BufUsed += AppendBuf->BufUsed - Offset;
00832        Buf->buf[Buf->BufUsed] = '\0';
00833 }
00834 
00835 
00844 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, unsigned long Offset)
00845 {
00846        long aps;
00847        long BufSizeRequired;
00848 
00849        if ((AppendBuf == NULL) || (Buf == NULL))
00850               return;
00851 
00852        if (AppendSize < 0 )
00853               aps = strlen(AppendBuf + Offset);
00854        else
00855               aps = AppendSize - Offset;
00856 
00857        BufSizeRequired = Buf->BufUsed + aps + 1;
00858        if (Buf->BufSize <= BufSizeRequired)
00859               IncreaseBuf(Buf, (Buf->BufUsed > 0), BufSizeRequired);
00860 
00861        memcpy(Buf->buf + Buf->BufUsed, 
00862               AppendBuf + Offset, 
00863               aps);
00864        Buf->BufUsed += aps;
00865        Buf->buf[Buf->BufUsed] = '\0';
00866 }
00867 
00876 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
00877 {
00878        va_list apl;
00879        size_t BufSize;
00880        size_t nWritten;
00881        size_t Offset;
00882        size_t newused;
00883 
00884        if ((Buf == NULL)  || (format == NULL))
00885               return;
00886 
00887        BufSize = Buf->BufSize;
00888        nWritten = Buf->BufSize + 1;
00889        Offset = Buf->BufUsed;
00890        newused = Offset + nWritten;
00891        
00892        while (newused >= BufSize) {
00893               va_copy(apl, ap);
00894               nWritten = vsnprintf(Buf->buf + Offset, 
00895                                  Buf->BufSize - Offset, 
00896                                  format, apl);
00897               va_end(apl);
00898               newused = Offset + nWritten;
00899               if (newused >= Buf->BufSize) {
00900                      if (IncreaseBuf(Buf, 1, newused) == -1)
00901                             return; /* TODO: error handling? */
00902                      newused = Buf->BufSize + 1;
00903               }
00904               else {
00905                      Buf->BufUsed = Offset + nWritten;
00906                      BufSize = Buf->BufSize;
00907               }
00908 
00909        }
00910 }
00911 
00918 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
00919 {
00920        size_t BufSize;
00921        size_t nWritten;
00922        size_t Offset;
00923        size_t newused;
00924        va_list arg_ptr;
00925        
00926        if ((Buf == NULL)  || (format == NULL))
00927               return;
00928 
00929        BufSize = Buf->BufSize;
00930        nWritten = Buf->BufSize + 1;
00931        Offset = Buf->BufUsed;
00932        newused = Offset + nWritten;
00933 
00934        while (newused >= BufSize) {
00935               va_start(arg_ptr, format);
00936               nWritten = vsnprintf(Buf->buf + Buf->BufUsed, 
00937                                  Buf->BufSize - Buf->BufUsed, 
00938                                  format, arg_ptr);
00939               va_end(arg_ptr);
00940               newused = Buf->BufUsed + nWritten;
00941               if (newused >= Buf->BufSize) {
00942                      if (IncreaseBuf(Buf, 1, newused) == -1)
00943                             return; /* TODO: error handling? */
00944                      newused = Buf->BufSize + 1;
00945               }
00946               else {
00947                      Buf->BufUsed += nWritten;
00948                      BufSize = Buf->BufSize;
00949               }
00950 
00951        }
00952 }
00953 
00960 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
00961 {
00962        size_t nWritten;
00963        va_list arg_ptr;
00964        
00965        if ((Buf == NULL)  || (format == NULL))
00966               return;
00967 
00968        nWritten = Buf->BufSize + 1;
00969        while (nWritten >= Buf->BufSize) {
00970               va_start(arg_ptr, format);
00971               nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
00972               va_end(arg_ptr);
00973               if (nWritten >= Buf->BufSize) {
00974                      if (IncreaseBuf(Buf, 0, 0) == -1)
00975                             return; /* TODO: error handling? */
00976                      nWritten = Buf->BufSize + 1;
00977                      continue;
00978               }
00979               Buf->BufUsed = nWritten ;
00980        }
00981 }
00982 
00991 size_t CurlFillStrBuf_callback(void *ptr, size_t size, size_t nmemb, void *stream)
00992 {
00993 
00994        StrBuf *Target;
00995 
00996        Target = stream;
00997        if (ptr == NULL)
00998               return 0;
00999 
01000        StrBufAppendBufPlain(Target, ptr, size * nmemb, 0);
01001        return size * nmemb;
01002 }
01003 
01004 
01014 int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t nChars)
01015 {
01016        size_t NCharsRemain;
01017        if (Offset > Source->BufUsed)
01018        {
01019               if (dest != NULL)
01020                      FlushStrBuf(dest);
01021               return 0;
01022        }
01023        if (Offset + nChars < Source->BufUsed)
01024        {
01025               if (nChars >= dest->BufSize)
01026                      IncreaseBuf(dest, 0, nChars + 1);
01027               memcpy(dest->buf, Source->buf + Offset, nChars);
01028               dest->BufUsed = nChars;
01029               dest->buf[dest->BufUsed] = '\0';
01030               return nChars;
01031        }
01032        NCharsRemain = Source->BufUsed - Offset;
01033        if (NCharsRemain  >= dest->BufSize)
01034               IncreaseBuf(dest, 0, NCharsRemain + 1);
01035        memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
01036        dest->BufUsed = NCharsRemain;
01037        dest->buf[dest->BufUsed] = '\0';
01038        return NCharsRemain;
01039 }
01040 
01047 void StrBufCutLeft(StrBuf *Buf, int nChars)
01048 {
01049        if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
01050        if (nChars >= Buf->BufUsed) {
01051               FlushStrBuf(Buf);
01052               return;
01053        }
01054        memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
01055        Buf->BufUsed -= nChars;
01056        Buf->buf[Buf->BufUsed] = '\0';
01057 }
01058 
01065 void StrBufCutRight(StrBuf *Buf, int nChars)
01066 {
01067        if ((Buf == NULL) || (Buf->BufUsed == 0) || (Buf->buf == NULL))
01068               return;
01069 
01070        if (nChars >= Buf->BufUsed) {
01071               FlushStrBuf(Buf);
01072               return;
01073        }
01074        Buf->BufUsed -= nChars;
01075        Buf->buf[Buf->BufUsed] = '\0';
01076 }
01077 
01085 void StrBufCutAt(StrBuf *Buf, int AfternChars, const char *At)
01086 {
01087        if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
01088        if (At != NULL){
01089               AfternChars = At - Buf->buf;
01090        }
01091 
01092        if ((AfternChars < 0) || (AfternChars >= Buf->BufUsed))
01093               return;
01094        Buf->BufUsed = AfternChars;
01095        Buf->buf[Buf->BufUsed] = '\0';
01096 }
01097 
01098 
01104 void StrBufTrim(StrBuf *Buf)
01105 {
01106        int delta = 0;
01107        if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
01108 
01109        while ((Buf->BufUsed > 0) &&
01110               isspace(Buf->buf[Buf->BufUsed - 1]))
01111        {
01112               Buf->BufUsed --;
01113        }
01114        Buf->buf[Buf->BufUsed] = '\0';
01115 
01116        if (Buf->BufUsed == 0) return;
01117 
01118        while ((Buf->BufUsed > delta) && (isspace(Buf->buf[delta]))){
01119               delta ++;
01120        }
01121        if (delta > 0) StrBufCutLeft(Buf, delta);
01122 }
01128 void StrBufSpaceToBlank(StrBuf *Buf)
01129 {
01130        char *pche, *pch;
01131 
01132        if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
01133 
01134        pch = Buf->buf;
01135        pche = pch + Buf->BufUsed;
01136        while (pch < pche) 
01137        {
01138               if (isspace(*pch))
01139                      *pch = ' ';
01140               pch ++;
01141        }
01142 }
01143 
01144 void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
01145 {
01146        const char *pBuff;
01147        const char *pLeft;
01148        const char *pRight;
01149 
01150        if ((Buf == NULL) || (Buf->buf == NULL))
01151               return;
01152        pLeft = pBuff = Buf->buf;
01153        while (pBuff != NULL) {
01154               pLeft = pBuff;
01155               pBuff = strchr(pBuff, leftboundary);
01156               if (pBuff != NULL)
01157                      pBuff++;
01158        }
01159               
01160        if (pLeft != NULL)
01161               pBuff = pLeft;
01162        else
01163               pBuff = Buf->buf;
01164        pRight = strchr(pBuff, rightboundary);
01165        if (pRight != NULL)
01166               StrBufCutAt(Buf, 0, pRight);
01167        if (pLeft != NULL)
01168               StrBufCutLeft(Buf, pLeft - Buf->buf);
01169 }
01170 
01171 
01177 void StrBufUpCase(StrBuf *Buf) 
01178 {
01179        char *pch, *pche;
01180 
01181        if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
01182 
01183        pch = Buf->buf;
01184        pche = pch + Buf->BufUsed;
01185        while (pch < pche) {
01186               *pch = toupper(*pch);
01187               pch ++;
01188        }
01189 }
01190 
01191 
01197 void StrBufLowerCase(StrBuf *Buf) 
01198 {
01199        char *pch, *pche;
01200 
01201        if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
01202 
01203        pch = Buf->buf;
01204        pche = pch + Buf->BufUsed;
01205        while (pch < pche) {
01206               *pch = tolower(*pch);
01207               pch ++;
01208        }
01209 }
01210 
01211 
01212 /*******************************************************************************
01213  *           a tokenizer that kills, maims, and destroys                       *
01214  *******************************************************************************/
01215 
01226 int StrBufReplaceToken(StrBuf *Buf, long where, long HowLong, 
01227                      const char *Repl, long ReplLen)
01228 {
01229 
01230        if ((Buf == NULL) || 
01231            (where > Buf->BufUsed) ||
01232            (where + HowLong > Buf->BufUsed))
01233               return -1;
01234 
01235        if (where + ReplLen - HowLong > Buf->BufSize)
01236               if (IncreaseBuf(Buf, 1, Buf->BufUsed + ReplLen) < 0)
01237                      return -1;
01238 
01239        memmove(Buf->buf + where + ReplLen, 
01240               Buf->buf + where + HowLong,
01241               Buf->BufUsed - where - HowLong);
01242                                           
01243        memcpy(Buf->buf + where, 
01244               Repl, ReplLen);
01245 
01246        Buf->BufUsed += ReplLen - HowLong;
01247 
01248        return Buf->BufUsed;
01249 }
01250 
01258 int StrBufNum_tokens(const StrBuf *source, char tok)
01259 {
01260        char *pch, *pche;
01261        long NTokens;
01262        if ((source == NULL) || (source->BufUsed == 0))
01263               return 0;
01264        if ((source->BufUsed == 1) && (*source->buf == tok))
01265               return 2;
01266        NTokens = 1;
01267        pch = source->buf;
01268        pche = pch + source->BufUsed;
01269        while (pch < pche)
01270        {
01271               if (*pch == tok)
01272                      NTokens ++;
01273               pch ++;
01274        }
01275        return NTokens;
01276 }
01277 
01286 int StrBufRemove_token(StrBuf *Source, int parmnum, char separator)
01287 {
01288        int ReducedBy;
01289        char *d, *s, *end;          /* dest, source */
01290        int count = 0;
01291 
01292        /* Find desired @parameter */
01293        end = Source->buf + Source->BufUsed;
01294        d = Source->buf;
01295        while ((d <= end) && 
01296               (count < parmnum))
01297        {
01298               /* End of string, bail! */
01299               if (!*d) {
01300                      d = NULL;
01301                      break;
01302               }
01303               if (*d == separator) {
01304                      count++;
01305               }
01306               d++;
01307        }
01308        if ((d == NULL) || (d >= end))
01309               return 0;            /* @Parameter not found */
01310 
01311        /* Find next @parameter */
01312        s = d;
01313        while ((s <= end) && 
01314               (*s && *s != separator))
01315        {
01316               s++;
01317        }
01318        if (*s == separator)
01319               s++;
01320        ReducedBy = d - s;
01321 
01322        /* Hack and slash */
01323        if (s >= end) {
01324               return 0;
01325        }
01326        else if (*s) {
01327               memmove(d, s, Source->BufUsed - (s - Source->buf));
01328               Source->BufUsed += ReducedBy;
01329               Source->buf[Source->BufUsed] = '\0';
01330        }
01331        else if (d == Source->buf) {
01332               *d = 0;
01333               Source->BufUsed = 0;
01334        }
01335        else {
01336               *--d = '\0';
01337               Source->BufUsed += ReducedBy;
01338        }
01339        /*
01340        while (*s) {
01341               *d++ = *s++;
01342        }
01343        *d = 0;
01344        */
01345        return ReducedBy;
01346 }
01347 
01348 int StrBufExtract_tokenFromStr(StrBuf *dest, const char *Source, long SourceLen, int parmnum, char separator)
01349 {
01350        const StrBuf Temp = {
01351               (char*)Source,
01352               SourceLen,
01353               SourceLen,
01354               1
01355 #ifdef SIZE_DEBUG
01356               ,
01357               0,
01358               "",
01359               ""
01360 #endif
01361        };
01362 
01363        return StrBufExtract_token(dest, &Temp, parmnum, separator);
01364 }
01365 
01375 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
01376 {
01377        const char *s, *e;          //* source * /
01378        int len = 0;                //* running total length of extracted string * /
01379        int current_token = 0;             //* token currently being processed * /
01380         
01381        if (dest != NULL) {
01382               dest->buf[0] = '\0';
01383               dest->BufUsed = 0;
01384        }
01385        else
01386               return(-1);
01387 
01388        if ((Source == NULL) || (Source->BufUsed ==0)) {
01389               return(-1);
01390        }
01391        s = Source->buf;
01392        e = s + Source->BufUsed;
01393 
01394        //cit_backtrace();
01395        //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
01396 
01397        while ((s < e) && !IsEmptyStr(s)) {
01398               if (*s == separator) {
01399                      ++current_token;
01400               }
01401               if (len >= dest->BufSize) {
01402                      dest->BufUsed = len;
01403                      if (IncreaseBuf(dest, 1, -1) < 0) {
01404                             dest->BufUsed --;
01405                             break;
01406                      }
01407               }
01408               if ( (current_token == parmnum) && 
01409                    (*s != separator)) {
01410                      dest->buf[len] = *s;
01411                      ++len;
01412               }
01413               else if (current_token > parmnum) {
01414                      break;
01415               }
01416               ++s;
01417        }
01418        
01419        dest->buf[len] = '\0';
01420        dest->BufUsed = len;
01421               
01422        if (current_token < parmnum) {
01423               //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
01424               return(-1);
01425        }
01426        //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
01427        return(len);
01428 }
01429 
01430 
01431 
01432 
01433 
01442 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
01443 {
01444        StrBuf tmp;
01445        char buf[64];
01446        
01447        tmp.buf = buf;
01448        buf[0] = '\0';
01449        tmp.BufSize = 64;
01450        tmp.BufUsed = 0;
01451        tmp.ConstBuf = 1;
01452        if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
01453               return(atoi(buf));
01454        else
01455               return 0;
01456 }
01457 
01466 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
01467 {
01468        StrBuf tmp;
01469        char buf[64];
01470        
01471        tmp.buf = buf;
01472        buf[0] = '\0';
01473        tmp.BufSize = 64;
01474        tmp.BufUsed = 0;
01475        tmp.ConstBuf = 1;
01476        if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
01477               return(atoi(buf));
01478        else
01479               return 0;
01480 }
01481 
01482 
01491 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
01492 {
01493        StrBuf tmp;
01494        char buf[64];
01495        char *pnum;
01496        
01497        tmp.buf = buf;
01498        buf[0] = '\0';
01499        tmp.BufSize = 64;
01500        tmp.BufUsed = 0;
01501        tmp.ConstBuf = 1;
01502        if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0) {
01503               pnum = &buf[0];
01504               if (*pnum == '-')
01505                      pnum ++;
01506               return (unsigned long) atol(pnum);
01507        }
01508        else 
01509               return 0;
01510 }
01511 
01512 
01513 
01522 int StrBufHaveNextToken(const StrBuf *Source, const char **pStart)
01523 {
01524        if ((Source == NULL) || 
01525            (*pStart == StrBufNOTNULL) ||
01526            (Source->BufUsed == 0))
01527        {
01528               return 0;
01529        }
01530        if (*pStart == NULL)
01531        {
01532               return 1;
01533        }
01534        else if (*pStart > Source->buf + Source->BufUsed)
01535        {
01536               return 0;
01537        }
01538        else if (*pStart <= Source->buf)
01539        {
01540               return 0;
01541        }
01542 
01543        return 1;
01544 }
01545 
01555 int StrBufExtract_NextToken(StrBuf *dest, const StrBuf *Source, const char **pStart, char separator)
01556 {
01557        const char *s;          /* source */
01558        const char *EndBuffer;  /* end stop of source buffer */
01559        int current_token = 0;      /* token currently being processed */
01560        int len = 0;         /* running total length of extracted string */
01561 
01562        if ((Source          == NULL) || 
01563            (Source->BufUsed == 0)      ) 
01564        {
01565               *pStart = StrBufNOTNULL;
01566               if (dest != NULL)
01567                      FlushStrBuf(dest);
01568               return -1;
01569        }
01570         
01571        EndBuffer = Source->buf + Source->BufUsed;
01572 
01573        if (dest != NULL) 
01574        {
01575               dest->buf[0] = '\0';
01576               dest->BufUsed = 0;
01577        }
01578        else
01579        {
01580               *pStart = EndBuffer + 1;
01581               return -1;
01582        }
01583 
01584        if (*pStart == NULL)
01585        {
01586               *pStart = Source->buf; /* we're starting to examine this buffer. */
01587        }
01588        else if ((*pStart < Source->buf) || 
01589                (*pStart > EndBuffer  )   ) 
01590        {
01591               return -1; /* no more tokens to find. */
01592        }
01593 
01594        s = *pStart;
01595        /* start to find the next token */
01596        while ((s <= EndBuffer)      && 
01597               (current_token == 0) ) 
01598        {
01599               if (*s == separator) 
01600               {
01601                      /* we found the next token */
01602                      ++current_token;
01603               }
01604 
01605               if (len >= dest->BufSize) 
01606               {
01607                      /* our Dest-buffer isn't big enough, increase it. */
01608                      dest->BufUsed = len;
01609 
01610                      if (IncreaseBuf(dest, 1, -1) < 0) {
01611                             /* WHUT? no more mem? bail out. */
01612                             s = EndBuffer;
01613                             dest->BufUsed --;
01614                             break;
01615                      }
01616               }
01617 
01618               if ( (current_token == 0 ) &&   /* are we in our target token? */
01619                    (!IsEmptyStr(s)     ) &&
01620                    (separator     != *s)    ) /* don't copy the token itself */
01621               {
01622                      dest->buf[len] = *s;    /* Copy the payload */
01623                      ++len;                  /* remember the bigger size. */
01624               }
01625 
01626               ++s;
01627        }
01628 
01629        /* did we reach the end? */
01630        if ((s > EndBuffer)) {
01631               EndBuffer = StrBufNOTNULL;
01632               *pStart = EndBuffer;
01633        }
01634        else {
01635               *pStart = s;  /* remember the position for the next run */
01636        }
01637 
01638        /* sanitize our extracted token */
01639        dest->buf[len] = '\0';
01640        dest->BufUsed  = len;
01641 
01642        return (len);
01643 }
01644 
01645 
01655 int StrBufSkip_NTokenS(const StrBuf *Source, const char **pStart, char separator, int nTokens)
01656 {
01657        const char *s, *EndBuffer;  //* source * /
01658        int len = 0;                //* running total length of extracted string * /
01659        int current_token = 0;             //* token currently being processed * /
01660 
01661        if ((Source == NULL) || 
01662            (Source->BufUsed ==0)) {
01663               return(-1);
01664        }
01665        if (nTokens == 0)
01666               return Source->BufUsed;
01667 
01668        if (*pStart == NULL)
01669               *pStart = Source->buf;
01670 
01671        EndBuffer = Source->buf + Source->BufUsed;
01672 
01673        if ((*pStart < Source->buf) || 
01674            (*pStart >  EndBuffer)) {
01675               return (-1);
01676        }
01677 
01678 
01679        s = *pStart;
01680 
01681        //cit_backtrace();
01682        //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
01683 
01684        while ((s < EndBuffer) && !IsEmptyStr(s)) {
01685               if (*s == separator) {
01686                      ++current_token;
01687               }
01688               if (current_token >= nTokens) {
01689                      break;
01690               }
01691               ++s;
01692        }
01693        *pStart = s;
01694        (*pStart) ++;
01695 
01696        return(len);
01697 }
01698 
01707 int StrBufExtractNext_int(const StrBuf* Source, const char **pStart, char separator)
01708 {
01709        StrBuf tmp;
01710        char buf[64];
01711        
01712        tmp.buf = buf;
01713        buf[0] = '\0';
01714        tmp.BufSize = 64;
01715        tmp.BufUsed = 0;
01716        tmp.ConstBuf = 1;
01717        if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0)
01718               return(atoi(buf));
01719        else
01720               return 0;
01721 }
01722 
01731 long StrBufExtractNext_long(const StrBuf* Source, const char **pStart, char separator)
01732 {
01733        StrBuf tmp;
01734        char buf[64];
01735        
01736        tmp.buf = buf;
01737        buf[0] = '\0';
01738        tmp.BufSize = 64;
01739        tmp.BufUsed = 0;
01740        tmp.ConstBuf = 1;
01741        if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0)
01742               return(atoi(buf));
01743        else
01744               return 0;
01745 }
01746 
01747 
01756 unsigned long StrBufExtractNext_unsigned_long(const StrBuf* Source, const char **pStart, char separator)
01757 {
01758        StrBuf tmp;
01759        char buf[64];
01760        char *pnum;
01761        
01762        tmp.buf = buf;
01763        buf[0] = '\0';
01764        tmp.BufSize = 64;
01765        tmp.BufUsed = 0;
01766        tmp.ConstBuf = 1;
01767        if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0) {
01768               pnum = &buf[0];
01769               if (*pnum == '-')
01770                      pnum ++;
01771               return (unsigned long) atol(pnum);
01772        }
01773        else 
01774               return 0;
01775 }
01776 
01777 
01778 
01779 
01780 
01781 /*******************************************************************************
01782  *                             Escape Appending                                *
01783  *******************************************************************************/
01784 
01792 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
01793 {
01794        const char *pch, *pche;
01795        char *pt, *pte;
01796        int len;
01797        
01798        if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
01799               return;
01800        if (PlainIn != NULL) {
01801               len = strlen(PlainIn);
01802               pch = PlainIn;
01803               pche = pch + len;
01804        }
01805        else {
01806               pch = In->buf;
01807               pche = pch + In->BufUsed;
01808               len = In->BufUsed;
01809        }
01810 
01811        if (len == 0) 
01812               return;
01813 
01814        pt = OutBuf->buf + OutBuf->BufUsed;
01815        pte = OutBuf->buf + OutBuf->BufSize - 4; 
01817        while (pch < pche) {
01818               if (pt >= pte) {
01819                      IncreaseBuf(OutBuf, 1, -1);
01820                      pte = OutBuf->buf + OutBuf->BufSize - 4; 
01821                      pt = OutBuf->buf + OutBuf->BufUsed;
01822               }
01823 
01824               if((*pch >= 'a' && *pch <= 'z') ||
01825                  (*pch >= '@' && *pch <= 'Z') || /* @ A-Z */
01826                  (*pch >= '0' && *pch <= ':') || /* 0-9 : */
01827                  (*pch == '!') || (*pch == '_') || 
01828                  (*pch == ',') || (*pch == '.'))
01829               {
01830                      *(pt++) = *(pch++);
01831                      OutBuf->BufUsed++;
01832               }                    
01833               else {
01834                      *pt = '%';
01835                      *(pt + 1) = HexList[(unsigned char)*pch][0];
01836                      *(pt + 2) = HexList[(unsigned char)*pch][1];
01837                      pt += 3;
01838                      OutBuf->BufUsed += 3;
01839                      pch ++;
01840               }
01841        }
01842        *pt = '\0';
01843 }
01844 
01852 void StrBufUrlescUPAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
01853 {
01854        const char *pch, *pche;
01855        char *pt, *pte;
01856        int len;
01857        
01858        if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
01859               return;
01860        if (PlainIn != NULL) {
01861               len = strlen(PlainIn);
01862               pch = PlainIn;
01863               pche = pch + len;
01864        }
01865        else {
01866               pch = In->buf;
01867               pche = pch + In->BufUsed;
01868               len = In->BufUsed;
01869        }
01870 
01871        if (len == 0) 
01872               return;
01873 
01874        pt = OutBuf->buf + OutBuf->BufUsed;
01875        pte = OutBuf->buf + OutBuf->BufSize - 4; 
01877        while (pch < pche) {
01878               if (pt >= pte) {
01879                      IncreaseBuf(OutBuf, 1, -1);
01880                      pte = OutBuf->buf + OutBuf->BufSize - 4; 
01881                      pt = OutBuf->buf + OutBuf->BufUsed;
01882               }
01883 
01884               if((*pch >= 'a' && *pch <= 'z') ||
01885                  (*pch >= 'A' && *pch <= 'Z') || /* A-Z */
01886                  (*pch >= '0' && *pch <= ':') || /* 0-9 : */
01887                  (*pch == '!') || (*pch == '_') || 
01888                  (*pch == ',') || (*pch == '.'))
01889               {
01890                      *(pt++) = *(pch++);
01891                      OutBuf->BufUsed++;
01892               }                    
01893               else {
01894                      *pt = '%';
01895                      *(pt + 1) = HexList[(unsigned char)*pch][0];
01896                      *(pt + 2) = HexList[(unsigned char)*pch][1];
01897                      pt += 3;
01898                      OutBuf->BufUsed += 3;
01899                      pch ++;
01900               }
01901        }
01902        *pt = '\0';
01903 }
01904 
01913 void StrBufHexEscAppend(StrBuf *OutBuf, const StrBuf *In, const unsigned char *PlainIn, long PlainInLen)
01914 {
01915        const unsigned char *pch, *pche;
01916        char *pt, *pte;
01917        int len;
01918        
01919        if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
01920               return;
01921        if (PlainIn != NULL) {
01922               if (PlainInLen < 0)
01923                      len = strlen((const char*)PlainIn);
01924               else
01925                      len = PlainInLen;
01926               pch = PlainIn;
01927               pche = pch + len;
01928        }
01929        else {
01930               pch = (const unsigned char*)In->buf;
01931               pche = pch + In->BufUsed;
01932               len = In->BufUsed;
01933        }
01934 
01935        if (len == 0) 
01936               return;
01937 
01938        pt = OutBuf->buf + OutBuf->BufUsed;
01939        pte = OutBuf->buf + OutBuf->BufSize - 3; 
01941        while (pch < pche) {
01942               if (pt >= pte) {
01943                      IncreaseBuf(OutBuf, 1, -1);
01944                      pte = OutBuf->buf + OutBuf->BufSize - 3; 
01945                      pt = OutBuf->buf + OutBuf->BufUsed;
01946               }
01947 
01948               *pt = HexList[*pch][0];
01949               pt ++;
01950               *pt = HexList[*pch][1];
01951               pt ++; pch ++; OutBuf->BufUsed += 2;
01952        }
01953        *pt = '\0';
01954 }
01955 
01963 void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
01964 {
01965        StrBufHexEscAppend(OutBuf, In, (const unsigned char*) PlainIn, -1);
01966 }
01967 
01979 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
01980 {
01981        const char *aptr, *eiptr;
01982        char *bptr, *eptr;
01983        long len;
01984 
01985        if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
01986               return -1;
01987 
01988        if (PlainIn != NULL) {
01989               aptr = PlainIn;
01990               len = strlen(PlainIn);
01991               eiptr = aptr + len;
01992        }
01993        else {
01994               aptr = Source->buf;
01995               eiptr = aptr + Source->BufUsed;
01996               len = Source->BufUsed;
01997        }
01998 
01999        if (len == 0) 
02000               return -1;
02001 
02002        bptr = Target->buf + Target->BufUsed;
02003        eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in...  */
02004 
02005        while (aptr < eiptr){
02006               if(bptr >= eptr) {
02007                      IncreaseBuf(Target, 1, -1);
02008                      eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in...  */
02009                      bptr = Target->buf + Target->BufUsed;
02010               }
02011               if (*aptr == '<') {
02012                      memcpy(bptr, "&lt;", 4);
02013                      bptr += 4;
02014                      Target->BufUsed += 4;
02015               }
02016               else if (*aptr == '>') {
02017                      memcpy(bptr, "&gt;", 4);
02018                      bptr += 4;
02019                      Target->BufUsed += 4;
02020               }
02021               else if (*aptr == '&') {
02022                      memcpy(bptr, "&amp;", 5);
02023                      bptr += 5;
02024                      Target->BufUsed += 5;
02025               }
02026               else if (*aptr == '"') {
02027                      memcpy(bptr, "&quot;", 6);
02028                      bptr += 6;
02029                      Target->BufUsed += 6;
02030               }
02031               else if (*aptr == '\'') {
02032                      memcpy(bptr, "&#39;", 5);
02033                      bptr += 5;
02034                      Target->BufUsed += 5;
02035               }
02036               else if (*aptr == LB) {
02037                      *bptr = '<';
02038                      bptr ++;
02039                      Target->BufUsed ++;
02040               }
02041               else if (*aptr == RB) {
02042                      *bptr = '>';
02043                      bptr ++;
02044                      Target->BufUsed ++;
02045               }
02046               else if (*aptr == QU) {
02047                      *bptr ='"';
02048                      bptr ++;
02049                      Target->BufUsed ++;
02050               }
02051               else if ((*aptr == 32) && (nbsp == 1)) {
02052                      memcpy(bptr, "&nbsp;", 6);
02053                      bptr += 6;
02054                      Target->BufUsed += 6;
02055               }
02056               else if ((*aptr == '\n') && (nolinebreaks == 1)) {
02057                      *bptr='\0';   /* nothing */
02058               }
02059               else if ((*aptr == '\n') && (nolinebreaks == 2)) {
02060                      memcpy(bptr, "&lt;br/&gt;", 11);
02061                      bptr += 11;
02062                      Target->BufUsed += 11;
02063               }
02064 
02065 
02066               else if ((*aptr == '\r') && (nolinebreaks != 0)) {
02067                      *bptr='\0';   /* nothing */
02068               }
02069               else{
02070                      *bptr = *aptr;
02071                      bptr++;
02072                      Target->BufUsed ++;
02073               }
02074               aptr ++;
02075        }
02076        *bptr = '\0';
02077        if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
02078               return -1;
02079        return Target->BufUsed;
02080 }
02081 
02090 void StrMsgEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
02091 {
02092        const char *aptr, *eiptr;
02093        char *tptr, *eptr;
02094        long len;
02095 
02096        if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
02097               return ;
02098 
02099        if (PlainIn != NULL) {
02100               aptr = PlainIn;
02101               len = strlen(PlainIn);
02102               eiptr = aptr + len;
02103        }
02104        else {
02105               aptr = Source->buf;
02106               eiptr = aptr + Source->BufUsed;
02107               len = Source->BufUsed;
02108        }
02109 
02110        if (len == 0) 
02111               return;
02112 
02113        eptr = Target->buf + Target->BufSize - 8; 
02114        tptr = Target->buf + Target->BufUsed;
02115        
02116        while (aptr < eiptr){
02117               if(tptr >= eptr) {
02118                      IncreaseBuf(Target, 1, -1);
02119                      eptr = Target->buf + Target->BufSize - 8; 
02120                      tptr = Target->buf + Target->BufUsed;
02121               }
02122               
02123               if (*aptr == '\n') {
02124                      *tptr = ' ';
02125                      Target->BufUsed++;
02126               }
02127               else if (*aptr == '\r') {
02128                      *tptr = ' ';
02129                      Target->BufUsed++;
02130               }
02131               else if (*aptr == '\'') {
02132                      *(tptr++) = '&';
02133                      *(tptr++) = '#';
02134                      *(tptr++) = '3';
02135                      *(tptr++) = '9';
02136                      *tptr = ';';
02137                      Target->BufUsed += 5;
02138               } else {
02139                      *tptr = *aptr;
02140                      Target->BufUsed++;
02141               }
02142               tptr++; aptr++;
02143        }
02144        *tptr = '\0';
02145 }
02146 
02147 
02148 
02157 void StrIcalEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
02158 {
02159        const char *aptr, *eiptr;
02160        char *tptr, *eptr;
02161        long len;
02162 
02163        if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
02164               return ;
02165 
02166        if (PlainIn != NULL) {
02167               aptr = PlainIn;
02168               len = strlen(PlainIn);
02169               eiptr = aptr + len;
02170        }
02171        else {
02172               aptr = Source->buf;
02173               eiptr = aptr + Source->BufUsed;
02174               len = Source->BufUsed;
02175        }
02176 
02177        if (len == 0) 
02178               return;
02179 
02180        eptr = Target->buf + Target->BufSize - 8; 
02181        tptr = Target->buf + Target->BufUsed;
02182        
02183        while (aptr < eiptr){
02184               if(tptr + 3 >= eptr) {
02185                      IncreaseBuf(Target, 1, -1);
02186                      eptr = Target->buf + Target->BufSize - 8; 
02187                      tptr = Target->buf + Target->BufUsed;
02188               }
02189               
02190               if (*aptr == '\n') {
02191                      *tptr = '\\';
02192                      Target->BufUsed++;
02193                      tptr++;
02194                      *tptr = 'n';
02195                      Target->BufUsed++;
02196               }
02197               else if (*aptr == '\r') {
02198                      *tptr = '\\';
02199                      Target->BufUsed++;
02200                      tptr++;
02201                      *tptr = 'r';
02202                      Target->BufUsed++;
02203               }
02204               else if (*aptr == ',') {
02205                      *tptr = '\\';
02206                      Target->BufUsed++;
02207                      tptr++;
02208                      *tptr = ',';
02209                      Target->BufUsed++;
02210               } else {
02211                      *tptr = *aptr;
02212                      Target->BufUsed++;
02213               }
02214               tptr++; aptr++;
02215        }
02216        *tptr = '\0';
02217 }
02218 
02228 long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
02229 {
02230        const char *aptr, *eiptr;
02231        char *bptr, *eptr;
02232        long len;
02233        int IsUtf8Sequence;
02234 
02235        if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
02236               return -1;
02237 
02238        if (PlainIn != NULL) {
02239               aptr = PlainIn;
02240               len = strlen(PlainIn);
02241               eiptr = aptr + len;
02242        }
02243        else {
02244               aptr = Source->buf;
02245               eiptr = aptr + Source->BufUsed;
02246               len = Source->BufUsed;
02247        }
02248 
02249        if (len == 0) 
02250               return -1;
02251 
02252        bptr = Target->buf + Target->BufUsed;
02253        eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in...  */
02254 
02255        while (aptr < eiptr){
02256               if(bptr >= eptr) {
02257                      IncreaseBuf(Target, 1, -1);
02258                      eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in...  */
02259                      bptr = Target->buf + Target->BufUsed;
02260               }
02261               switch (*aptr) {
02262               case '\n':
02263                      memcpy(bptr, HKEY("\\n"));
02264                      bptr += 2;
02265                      Target->BufUsed += 2;                            
02266                      break;
02267               case '\r':
02268                      memcpy(bptr, HKEY("\\r"));
02269                      bptr += 2;
02270                      Target->BufUsed += 2;
02271                      break;
02272               case '"':
02273                      *bptr = '\\';
02274                      bptr ++;
02275                      *bptr = '"';
02276                      bptr ++;
02277                      Target->BufUsed += 2;
02278                      break;
02279               case '\\':
02280                      if ((*(aptr + 1) == 'u') &&
02281                          isxdigit(*(aptr + 2)) &&
02282                          isxdigit(*(aptr + 3)) &&
02283                          isxdigit(*(aptr + 4)) &&
02284                          isxdigit(*(aptr + 5)))
02285                      { /* oh, a unicode escaper. let it pass through. */
02286                             memcpy(bptr, aptr, 6);
02287                             aptr += 5;
02288                             bptr +=6;
02289                             Target->BufUsed += 6;
02290                      }
02291                      else 
02292                      {
02293                             *bptr = '\\';
02294                             bptr ++;
02295                             *bptr = '\\';
02296                             bptr ++;
02297                             Target->BufUsed += 2;
02298                      }
02299                      break;
02300               case '\b':
02301                      *bptr = '\\';
02302                      bptr ++;
02303                      *bptr = 'b';
02304                      bptr ++;
02305                      Target->BufUsed += 2;
02306                      break;
02307               case '\f':
02308                      *bptr = '\\';
02309                      bptr ++;
02310                      *bptr = 'f';
02311                      bptr ++;
02312                      Target->BufUsed += 2;
02313                      break;
02314               case '\t':
02315                      *bptr = '\\';
02316                      bptr ++;
02317                      *bptr = 't';
02318                      bptr ++;
02319                      Target->BufUsed += 2;
02320                      break;
02321               default:
02322                      IsUtf8Sequence =  Ctdl_GetUtf8SequenceLength(aptr, eiptr);
02323                      while (IsUtf8Sequence > 0){
02324                             *bptr = *aptr;
02325                             Target->BufUsed ++;
02326                             if (--IsUtf8Sequence)
02327                                    aptr++;
02328                             bptr++;
02329                      }
02330               }
02331               aptr ++;
02332        }
02333        *bptr = '\0';
02334        if ((bptr == eptr - 1 ) && !IsEmptyStr(aptr) )
02335               return -1;
02336        return Target->BufUsed;
02337 }
02338 
02350 long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
02351 {
02352        const char *aptr, *eiptr;
02353        char *bptr, *eptr;
02354        long len;
02355        int IsUtf8Sequence = 0;
02356 
02357        if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
02358               return -1;
02359 
02360        if (PlainIn != NULL) {
02361               aptr = PlainIn;
02362               len = strlen(PlainIn);
02363               eiptr = aptr + len;
02364        }
02365        else {
02366               aptr = Source->buf;
02367               eiptr = aptr + Source->BufUsed;
02368               len = Source->BufUsed;
02369        }
02370 
02371        if (len == 0) 
02372               return -1;
02373 
02374        bptr = Target->buf + Target->BufUsed;
02375        eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in...  */
02376 
02377        while (aptr < eiptr){
02378               if(bptr >= eptr) {
02379                      IncreaseBuf(Target, 1, -1);
02380                      eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in...  */
02381                      bptr = Target->buf + Target->BufUsed;
02382               }
02383               switch (*aptr) {
02384               case '<':
02385                      memcpy(bptr, HKEY("&lt;"));
02386                      bptr += 4;
02387                      Target->BufUsed += 4;
02388                      break;
02389               case '>':
02390                      memcpy(bptr, HKEY("&gt;"));
02391                      bptr += 4;
02392                      Target->BufUsed += 4;
02393                      break;
02394               case '&':
02395                      memcpy(bptr, HKEY("&amp;"));
02396                      bptr += 5;
02397                      Target->BufUsed += 5;
02398                      break;
02399               case LB:
02400                      *bptr = '<';
02401                      bptr ++;
02402                      Target->BufUsed ++;
02403                      break;
02404               case RB:
02405                      *bptr = '>';
02406                      bptr ++;
02407                      Target->BufUsed ++;
02408                      break;
02409               case '\n':
02410                      switch (nolinebreaks) {
02411                      case 1:
02412                             *bptr='\0';   /* nothing */
02413                             break;
02414                      case 2:
02415                             memcpy(bptr, HKEY("&lt;br/&gt;"));
02416                             bptr += 11;
02417                             Target->BufUsed += 11;
02418                             break;
02419                      default:
02420                             memcpy(bptr, HKEY("\\n"));
02421                             bptr += 2;
02422                             Target->BufUsed += 2;                            
02423                      }
02424                      break;
02425               case '\r':
02426                      switch (nolinebreaks) {
02427                      case 1:
02428                      case 2:
02429                             *bptr='\0';   /* nothing */
02430                             break;
02431                      default:
02432                             memcpy(bptr, HKEY("\\r"));
02433                             bptr += 2;
02434                             Target->BufUsed += 2;
02435                             break;
02436                      }
02437                      break;
02438               case '"':
02439               case QU:
02440                      *bptr = '\\';
02441                      bptr ++;
02442                      *bptr = '"';
02443                      bptr ++;
02444                      Target->BufUsed += 2;
02445                      break;
02446               case '\\':
02447                      if ((*(aptr + 1) == 'u') &&
02448                          isxdigit(*(aptr + 2)) &&
02449                          isxdigit(*(aptr + 3)) &&
02450                          isxdigit(*(aptr + 4)) &&
02451                          isxdigit(*(aptr + 5)))
02452                      { /* oh, a unicode escaper. let it pass through. */
02453                             memcpy(bptr, aptr, 6);
02454                             aptr += 5;
02455                             bptr +=6;
02456                             Target->BufUsed += 6;
02457                      }
02458                      else 
02459                      {
02460                             *bptr = '\\';
02461                             bptr ++;
02462                             *bptr = '\\';
02463                             bptr ++;
02464                             Target->BufUsed += 2;
02465                      }
02466                      break;
02467               case '\b':
02468                      *bptr = '\\';
02469                      bptr ++;
02470                      *bptr = 'b';
02471                      bptr ++;
02472                      Target->BufUsed += 2;
02473                      break;
02474               case '\f':
02475                      *bptr = '\\';
02476                      bptr ++;
02477                      *bptr = 'f';
02478                      bptr ++;
02479                      Target->BufUsed += 2;
02480                      break;
02481               case '\t':
02482                      *bptr = '\\';
02483                      bptr ++;
02484                      *bptr = 't';
02485                      bptr ++;
02486                      Target->BufUsed += 2;
02487                      break;
02488               case  32:
02489                      if (nbsp == 1) {
02490                             memcpy(bptr, HKEY("&nbsp;"));
02491                             bptr += 6;
02492                             Target->BufUsed += 6;
02493                             break;
02494                      }
02495               default:
02496                      IsUtf8Sequence =  Ctdl_GetUtf8SequenceLength(aptr, eiptr);
02497                      while (IsUtf8Sequence > 0){
02498                             *bptr = *aptr;
02499                             Target->BufUsed ++;
02500                             if (--IsUtf8Sequence)
02501                                    aptr++;
02502                             bptr++;
02503                      }
02504               }
02505               aptr ++;
02506        }
02507        *bptr = '\0';
02508        if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
02509               return -1;
02510        return Target->BufUsed;
02511 }
02512 
02519 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source) 
02520 {
02521        int a, b, len;
02522        char hex[3];
02523 
02524        if ((source == NULL) || (target == NULL) || (target->buf == NULL))
02525        {
02526               return;
02527        }
02528 
02529        if (target != NULL)
02530               FlushStrBuf(target);
02531 
02532        len = source->BufUsed;
02533        for (a = 0; a < len; ++a) {
02534               if (target->BufUsed >= target->BufSize)
02535                      IncreaseBuf(target, 1, -1);
02536 
02537               if (source->buf[a] == '=') {
02538                      hex[0] = source->buf[a + 1];
02539                      hex[1] = source->buf[a + 2];
02540                      hex[2] = 0;
02541                      b = 0;
02542                      sscanf(hex, "%02x", &b);
02543                      target->buf[target->BufUsed] = b;
02544                      target->buf[++target->BufUsed] = 0;
02545                      a += 2;
02546               }
02547               else {
02548                      target->buf[target->BufUsed] = source->buf[a];
02549                      target->buf[++target->BufUsed] = 0;
02550               }
02551        }
02552 }
02553 
02554 
02561 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source) 
02562 {
02563        int i, len;
02564 
02565        if (target != NULL)
02566               FlushStrBuf(target);
02567 
02568        if ((source == NULL) || (target == NULL) || (target->buf == NULL))
02569        {
02570               return;
02571        }
02572 
02573        len = source->BufUsed;
02574        for (i=0; i<len; ++i) {
02575               if (target->BufUsed + 4 >= target->BufSize)
02576                      IncreaseBuf(target, 1, -1);
02577               if ( (isalnum(source->buf[i])) || 
02578                    (source->buf[i]=='-') || 
02579                    (source->buf[i]=='_') ) {
02580                      target->buf[target->BufUsed++] = source->buf[i];
02581               }
02582               else {
02583                      sprintf(&target->buf[target->BufUsed], 
02584                             "=%02X", 
02585                             (0xFF &source->buf[i]));
02586                      target->BufUsed += 3;
02587               }
02588        }
02589        target->buf[target->BufUsed + 1] = '\0';
02590 }
02591 
02592 
02593 /*******************************************************************************
02594  *                      Quoted Printable de/encoding                           *
02595  *******************************************************************************/
02596 
02602 int StrBufDecodeBase64(StrBuf *Buf)
02603 {
02604        char *xferbuf;
02605        size_t siz;
02606        if (Buf == NULL) return -1;
02607 
02608        xferbuf = (char*) malloc(Buf->BufSize);
02609        *xferbuf = '\0';
02610        siz = CtdlDecodeBase64(xferbuf,
02611                             Buf->buf,
02612                             Buf->BufUsed);
02613        free(Buf->buf);
02614        Buf->buf = xferbuf;
02615        Buf->BufUsed = siz;
02616        return siz;
02617 }
02618 
02624 int StrBufDecodeHex(StrBuf *Buf)
02625 {
02626        unsigned int ch;
02627        char *pch, *pche, *pchi;
02628 
02629        if (Buf == NULL) return -1;
02630 
02631        pch = pchi = Buf->buf;
02632        pche = pch + Buf->BufUsed;
02633 
02634        while (pchi < pche){
02635               ch = decode_hex(pchi);
02636               *pch = ch;
02637               pch ++;
02638               pchi += 2;
02639        }
02640 
02641        *pch = '\0';
02642        Buf->BufUsed = pch - Buf->buf;
02643        return Buf->BufUsed;
02644 }
02645 
02652 int StrBufSanitizeAscii(StrBuf *Buf, const char Mute)
02653 {
02654        unsigned char *pch;
02655 
02656        if (Buf == NULL) return -1;
02657        pch = (unsigned char *)Buf->buf;
02658        while (pch < (unsigned char *)Buf->buf + Buf->BufUsed) {
02659               if ((*pch < 0x20) || (*pch > 0x7F))
02660                      *pch = Mute;
02661               pch ++;
02662        }
02663        return Buf->BufUsed;
02664 }
02665 
02666 
02673 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
02674 {
02675        int a, b;
02676        char hex[3];
02677        long len;
02678 
02679        if (Buf == NULL)
02680               return -1;
02681 
02682        while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
02683               Buf->buf[Buf->BufUsed - 1] = '\0';
02684               Buf->BufUsed --;
02685        }
02686 
02687        a = 0; 
02688        while (a < Buf->BufUsed) {
02689               if (Buf->buf[a] == '+')
02690                      Buf->buf[a] = ' ';
02691               else if (Buf->buf[a] == '%') {
02692                      /* don't let % chars through, rather truncate the input. */
02693                      if (a + 2 > Buf->BufUsed) {
02694                             Buf->buf[a] = '\0';
02695                             Buf->BufUsed = a;
02696                      }
02697                      else {               
02698                             hex[0] = Buf->buf[a + 1];
02699                             hex[1] = Buf->buf[a + 2];
02700                             hex[2] = 0;
02701                             b = 0;
02702                             sscanf(hex, "%02x", &b);
02703                             Buf->buf[a] = (char) b;
02704                             len = Buf->BufUsed - a - 2;
02705                             if (len > 0)
02706                                    memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
02707                      
02708                             Buf->BufUsed -=2;
02709                      }
02710               }
02711               a++;
02712        }
02713        return a;
02714 }
02715 
02716 
02727 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
02728 {
02729        const char headerStr[] = "=?UTF-8?Q?";
02730        int need_to_encode = 0;
02731        int i = 0;
02732        unsigned char ch;
02733 
02734        if ((source == NULL) || 
02735            (target == NULL))
02736            return -1;
02737 
02738        while ((i < source->BufUsed) &&
02739               (!IsEmptyStr (&source->buf[i])) &&
02740               (need_to_encode == 0)) {
02741               if (((unsigned char) source->buf[i] < 32) || 
02742                   ((unsigned char) source->buf[i] > 126)) {
02743                      need_to_encode = 1;
02744               }
02745               i++;
02746        }
02747 
02748        if (!need_to_encode) {
02749               if (*target == NULL) {
02750                      *target = NewStrBufPlain(source->buf, source->BufUsed);
02751               }
02752               else {
02753                      FlushStrBuf(*target);
02754                      StrBufAppendBuf(*target, source, 0);
02755               }
02756               if (*target != 0)
02757                      return (*target)->BufUsed;
02758               else
02759                      return 0;
02760        }
02761        if (*target == NULL)
02762               *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
02763        else if (sizeof(headerStr) + source->BufUsed >= (*target)->BufSize)
02764               IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
02765        memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
02766        (*target)->BufUsed = sizeof(headerStr) - 1;
02767        for (i=0; (i < source->BufUsed); ++i) {
02768               if ((*target)->BufUsed + 4 >= (*target)->BufSize)
02769                      IncreaseBuf(*target, 1, 0);
02770               ch = (unsigned char) source->buf[i];
02771               if ((ch  <  32) || 
02772                   (ch  > 126) || 
02773                   (ch ==  61) ||
02774                   (ch == '=') ||
02775                     (ch == '?') ||
02776                   (ch == '_') ||
02777                   (ch == '[') ||
02778                   (ch == ']')   )
02779               {
02780                      sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
02781                      (*target)->BufUsed += 3;
02782               }
02783               else {
02784                      if (ch == ' ')
02785                             (*target)->buf[(*target)->BufUsed] = '_';
02786                      else
02787                             (*target)->buf[(*target)->BufUsed] = ch;
02788                      (*target)->BufUsed++;
02789               }
02790        }
02791        
02792        if ((*target)->BufUsed + 4 >= (*target)->BufSize)
02793               IncreaseBuf(*target, 1, 0);
02794 
02795        (*target)->buf[(*target)->BufUsed++] = '?';
02796        (*target)->buf[(*target)->BufUsed++] = '=';
02797        (*target)->buf[(*target)->BufUsed] = '\0';
02798        return (*target)->BufUsed;;
02799 }
02800 
02801 
02802 
02803 static void AddRecipient(StrBuf *Target, 
02804                       StrBuf *UserName, 
02805                       StrBuf *EmailAddress, 
02806                       StrBuf *EncBuf)
02807 {
02808        int QuoteMe = 0;
02809 
02810        if (StrLength(Target) > 0) StrBufAppendBufPlain(Target, HKEY(", "), 0);
02811        if (strchr(ChrPtr(UserName), ',') != NULL) QuoteMe = 1;
02812 
02813        if (QuoteMe)  StrBufAppendBufPlain(Target, HKEY("\""), 0);
02814        StrBufRFC2047encode(&EncBuf, UserName);
02815        StrBufAppendBuf(Target, EncBuf, 0);
02816        if (QuoteMe)  StrBufAppendBufPlain(Target, HKEY("\" "), 0);
02817        else          StrBufAppendBufPlain(Target, HKEY(" "), 0);
02818 
02819        if (StrLength(EmailAddress) > 0){
02820               StrBufAppendBufPlain(Target, HKEY("<"), 0);
02821               StrBufAppendBuf(Target, EmailAddress, 0); /* TODO: what about IDN???? */
02822               StrBufAppendBufPlain(Target, HKEY(">"), 0);
02823        }
02824 }
02825 
02826 
02835 StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp, 
02836                                       StrBuf *UserName, 
02837                                       StrBuf *EmailAddress,
02838                                       StrBuf *EncBuf)
02839 {
02840        StrBuf *Target;
02841        const char *pch, *pche;
02842        const char *UserStart, *UserEnd, *EmailStart, *EmailEnd, *At;
02843 
02844        if ((Recp == NULL) || (StrLength(Recp) == 0))
02845               return NULL;
02846 
02847        pch = ChrPtr(Recp);
02848        pche = pch + StrLength(Recp);
02849 
02850        if (!CheckEncode(pch, -1, pche))
02851               return NewStrBufDup(Recp);
02852 
02853        Target = NewStrBufPlain(NULL, StrLength(Recp));
02854 
02855        while ((pch != NULL) && (pch < pche))
02856        {
02857               while (isspace(*pch)) pch++;
02858               UserEnd = EmailStart = EmailEnd = NULL;
02859               
02860               if ((*pch == '"') || (*pch == '\'')) {
02861                      UserStart = pch + 1;
02862                      
02863                      UserEnd = strchr(UserStart, *pch);
02864                      if (UserEnd == NULL) 
02865                             break; 
02866                      EmailStart = UserEnd + 1;
02867                      while (isspace(*EmailStart))
02868                             EmailStart++;
02869                      if (UserEnd == UserStart) {
02870                             UserStart = UserEnd = NULL;
02871                      }
02872                      
02873                      if (*EmailStart == '<') {
02874                             EmailStart++;
02875                             EmailEnd = strchr(EmailStart, '>');
02876                             if (EmailEnd == NULL)
02877                                    EmailEnd = strchr(EmailStart, ',');
02878                             
02879                      }
02880                      else {
02881                             EmailEnd = strchr(EmailStart, ',');
02882                      }
02883                      if (EmailEnd == NULL)
02884                             EmailEnd = pche;
02885                      pch = EmailEnd + 1;
02886               }
02887               else {
02888                      int gt = 0;
02889                      UserStart = pch;
02890                      EmailEnd = strchr(UserStart, ',');
02891                      if (EmailEnd == NULL) {
02892                             EmailEnd = strchr(pch, '>');
02893                             pch = NULL;
02894                             if (EmailEnd != NULL) {
02895                                    gt = 1;
02896                             }
02897                             else {
02898                                    EmailEnd = pche;
02899                             }
02900                      }
02901                      else {
02902 
02903                             pch = EmailEnd + 1;
02904                             while ((EmailEnd > UserStart) && !gt &&
02905                                    ((*EmailEnd == ',') ||
02906                                    (*EmailEnd == '>') ||
02907                                    (isspace(*EmailEnd))))
02908                             {
02909                                    if (*EmailEnd == '>')
02910                                           gt = 1;
02911                                    else 
02912                                           EmailEnd--;
02913                             }
02914                             if (EmailEnd == UserStart)
02915                                    break;
02916                      }
02917                      if (gt) {
02918                             EmailStart = strchr(UserStart, '<');
02919                             if ((EmailStart == NULL) || (EmailStart > EmailEnd))
02920                                    break;
02921                             UserEnd = EmailStart;
02922 
02923                             while ((UserEnd > UserStart) && 
02924                                    isspace (*(UserEnd - 1)))
02925                                    UserEnd --;
02926                             EmailStart ++;
02927                             if (UserStart >= UserEnd)
02928                                    UserStart = UserEnd = NULL;
02929                      }
02930                      else { /* this is a local recipient... no domain, just a realname */
02931                             EmailStart = UserStart;
02932                             At = strchr(EmailStart, '@');
02933                             if (At == NULL) {
02934                                    UserEnd = EmailEnd;
02935                                    EmailEnd = NULL;
02936                             }
02937                             else {
02938                                    EmailStart = UserStart;
02939                                    UserStart = NULL;
02940                             }
02941                      }
02942               }
02943 
02944               if ((UserStart != NULL) && (UserEnd != NULL))
02945                      StrBufPlain(UserName, UserStart, UserEnd - UserStart);
02946               else if ((UserStart != NULL) && (UserEnd == NULL))
02947                      StrBufPlain(UserName, UserStart, UserEnd - UserStart);
02948               else
02949                      FlushStrBuf(UserName);
02950 
02951               if ((EmailStart != NULL) && (EmailEnd != NULL))
02952                      StrBufPlain(EmailAddress, EmailStart, EmailEnd - EmailStart);
02953               else if ((EmailStart != NULL) && (EmailEnd == NULL))
02954                      StrBufPlain(EmailAddress, EmailStart, EmailEnd - pche);
02955               else 
02956                      FlushStrBuf(EmailAddress);
02957 
02958               AddRecipient(Target, UserName, EmailAddress, EncBuf);
02959 
02960               if (pch == NULL)
02961                      break;
02962               
02963               if ((pch != NULL) && (*pch == ','))
02964                      pch ++;
02965               if (pch != NULL) while (isspace(*pch))
02966                      pch ++;
02967        }
02968        return Target;
02969 }
02970 
02971 
02979 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
02980 {
02981        long i;
02982        if (buf == NULL)
02983               return;
02984        for (i=0; i<buf->BufUsed; i++)
02985               if (buf->buf[i] == search)
02986                      buf->buf[i] = replace;
02987 
02988 }
02989 
02995 void StrBufToUnixLF(StrBuf *buf)
02996 {
02997        char *pche, *pchS, *pchT;
02998        if (buf == NULL)
02999               return;
03000 
03001        pche = buf->buf + buf->BufUsed;
03002        pchS = pchT = buf->buf;
03003        while (pchS < pche)
03004        {
03005               if (*pchS == '\r')
03006               {
03007                      pchS ++;
03008                      if (*pchS != '\n') {
03009                             *pchT = '\n';
03010                             pchT++;
03011                      }
03012               }
03013               *pchT = *pchS;
03014               pchT++; pchS++;
03015        }
03016        *pchT = '\0';
03017        buf->BufUsed = pchT - buf->buf;
03018 }
03019 
03020 
03021 /*******************************************************************************
03022  *                 Iconv Wrapper; RFC822 de/encoding                           *
03023  *******************************************************************************/
03024 
03035 void  ctdl_iconv_open(const char *tocode, const char *fromcode, void *pic)
03036 {
03037 #ifdef HAVE_ICONV
03038        iconv_t ic = (iconv_t)(-1) ;
03039        ic = iconv_open(tocode, fromcode);
03040        if (ic == (iconv_t)(-1) ) {
03041               char alias_fromcode[64];
03042               if ( (strlen(fromcode) == 5) && (!strncasecmp(fromcode, "MS", 2)) ) {
03043                      safestrncpy(alias_fromcode, fromcode, sizeof alias_fromcode);
03044                      alias_fromcode[0] = 'C';
03045                      alias_fromcode[1] = 'P';
03046                      ic = iconv_open(tocode, alias_fromcode);
03047               }
03048        }
03049        *(iconv_t *)pic = ic;
03050 #endif
03051 }
03052 
03053 
03061 static inline const char *FindNextEnd (const StrBuf *Buf, const char *bptr)
03062 {
03063        const char * end;
03064        /* Find the next ?Q? */
03065        if (Buf->BufUsed - (bptr - Buf->buf)  < 6)
03066               return NULL;
03067 
03068        end = strchr(bptr + 2, '?');
03069 
03070        if (end == NULL)
03071               return NULL;
03072 
03073        if ((Buf->BufUsed - (end - Buf->buf) > 3) &&
03074            (((*(end + 1) == 'B') || (*(end + 1) == 'Q')) ||
03075             ((*(end + 1) == 'b') || (*(end + 1) == 'q'))) && 
03076            (*(end + 2) == '?')) {
03077               /* skip on to the end of the cluster, the next ?= */
03078               end = strstr(end + 3, "?=");
03079        }
03080        else
03081               /* sort of half valid encoding, try to find an end. */
03082               end = strstr(bptr, "?=");
03083        return end;
03084 }
03085 
03086 
03087 
03095 void StrBufConvert(StrBuf *ConvertBuf, StrBuf *TmpBuf, void *pic)
03096 {
03097 #ifdef HAVE_ICONV
03098        long trycount = 0;
03099        size_t siz;
03100        iconv_t ic;
03101        char *ibuf;                 
03102        char *obuf;                 
03103        size_t ibuflen;                    
03104        size_t obuflen;                    
03107        if ((ConvertBuf == NULL) || (TmpBuf == NULL))
03108               return;
03109 
03110        /* since we're converting to utf-8, one glyph may take up to 6 bytes */
03111        if (ConvertBuf->BufUsed * 6 >= TmpBuf->BufSize)
03112               IncreaseBuf(TmpBuf, 0, ConvertBuf->BufUsed * 6);
03113 TRYAGAIN:
03114        ic = *(iconv_t*)pic;
03115        ibuf = ConvertBuf->buf;
03116        ibuflen = ConvertBuf->BufUsed;
03117        obuf = TmpBuf->buf;
03118        obuflen = TmpBuf->BufSize;
03119        
03120        siz = iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
03121 
03122        if (siz < 0) {
03123               if (errno == E2BIG) {
03124                      trycount ++;                
03125                      IncreaseBuf(TmpBuf, 0, 0);
03126                      if (trycount < 5) 
03127                             goto TRYAGAIN;
03128 
03129               }
03130               else if (errno == EILSEQ){ 
03131                      /* hm, invalid utf8 sequence... what to do now? */
03132                      /* An invalid multibyte sequence has been encountered in the input */
03133               }
03134               else if (errno == EINVAL) {
03135                      /* An incomplete multibyte sequence has been encountered in the input. */
03136               }
03137 
03138               FlushStrBuf(TmpBuf);
03139        }
03140        else {
03141               TmpBuf->BufUsed = TmpBuf->BufSize - obuflen;
03142               TmpBuf->buf[TmpBuf->BufUsed] = '\0';
03143               
03144               /* little card game: wheres the red lady? */
03145               SwapBuffers(ConvertBuf, TmpBuf);
03146               FlushStrBuf(TmpBuf);
03147        }
03148 #endif
03149 }
03150 
03151 
03163 inline static void DecodeSegment(StrBuf *Target, 
03164                              const StrBuf *DecodeMe, 
03165                              const char *SegmentStart, 
03166                              const char *SegmentEnd, 
03167                              StrBuf *ConvertBuf,
03168                              StrBuf *ConvertBuf2, 
03169                              StrBuf *FoundCharset)
03170 {
03171        StrBuf StaticBuf;
03172        char charset[128];
03173        char encoding[16];
03174 #ifdef HAVE_ICONV
03175        iconv_t ic = (iconv_t)(-1);
03176 #else
03177        void *ic = NULL;
03178 #endif
03179        /* Now we handle foreign character sets properly encoded
03180         * in RFC2047 format.
03181         */
03182        StaticBuf.buf = (char*) SegmentStart; /*< it will just be read there... */
03183        StaticBuf.BufUsed = SegmentEnd - SegmentStart;
03184        StaticBuf.BufSize = DecodeMe->BufSize - (SegmentStart - DecodeMe->buf);
03185        extract_token(charset, SegmentStart, 1, '?', sizeof charset);
03186        if (FoundCharset != NULL) {
03187               FlushStrBuf(FoundCharset);
03188               StrBufAppendBufPlain(FoundCharset, charset, -1, 0);
03189        }
03190        extract_token(encoding, SegmentStart, 2, '?', sizeof encoding);
03191        StrBufExtract_token(ConvertBuf, &StaticBuf, 3, '?');
03192        
03193        *encoding = toupper(*encoding);
03194        if (*encoding == 'B') {     
03195               if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
03196                      IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
03197               ConvertBuf2->BufUsed = CtdlDecodeBase64(ConvertBuf2->buf, 
03198                                                  ConvertBuf->buf, 
03199                                                  ConvertBuf->BufUsed);
03200        }
03201        else if (*encoding == 'Q') {       
03202               long pos;
03203               
03204               pos = 0;
03205               while (pos < ConvertBuf->BufUsed)
03206               {
03207                      if (ConvertBuf->buf[pos] == '_') 
03208                             ConvertBuf->buf[pos] = ' ';
03209                      pos++;
03210               }
03211               
03212               if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
03213                      IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
03214 
03215               ConvertBuf2->BufUsed = CtdlDecodeQuotedPrintable(
03216                      ConvertBuf2->buf, 
03217                      ConvertBuf->buf,
03218                      ConvertBuf->BufUsed);
03219        }
03220        else {
03221               StrBufAppendBuf(ConvertBuf2, ConvertBuf, 0);
03222        }
03223 #ifdef HAVE_ICONV
03224        ctdl_iconv_open("UTF-8", charset, &ic);
03225        if (ic != (iconv_t)(-1) ) {        
03226 #endif
03227               StrBufConvert(ConvertBuf2, ConvertBuf, &ic);
03228               StrBufAppendBuf(Target, ConvertBuf2, 0);
03229 #ifdef HAVE_ICONV
03230               iconv_close(ic);
03231        }
03232        else {
03233               StrBufAppendBufPlain(Target, HKEY("(unreadable)"), 0);
03234        }
03235 #endif
03236 }
03237 
03248 void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf* DefaultCharset, StrBuf *FoundCharset)
03249 {
03250        StrBuf *ConvertBuf;
03251        StrBuf *ConvertBuf2;
03252        ConvertBuf = NewStrBufPlain(NULL, StrLength(DecodeMe));
03253        ConvertBuf2 = NewStrBufPlain(NULL, StrLength(DecodeMe));
03254        
03255        StrBuf_RFC822_2_Utf8(Target, 
03256                           DecodeMe, 
03257                           DefaultCharset, 
03258                           FoundCharset, 
03259                           ConvertBuf, 
03260                           ConvertBuf2);
03261        FreeStrBuf(&ConvertBuf);
03262        FreeStrBuf(&ConvertBuf2);
03263 }
03264 
03277 void StrBuf_RFC822_2_Utf8(StrBuf *Target, 
03278                        const StrBuf *DecodeMe, 
03279                        const StrBuf* DefaultCharset, 
03280                        StrBuf *FoundCharset, 
03281                        StrBuf *ConvertBuf, 
03282                        StrBuf *ConvertBuf2)
03283 {
03284        StrBuf *DecodedInvalidBuf = NULL;
03285        const StrBuf *DecodeMee = DecodeMe;
03286        const char *start, *end, *next, *nextend, *ptr = NULL;
03287 #ifdef HAVE_ICONV
03288        iconv_t ic = (iconv_t)(-1) ;
03289 #endif
03290        const char *eptr;
03291        int passes = 0;
03292        int i;
03293        int illegal_non_rfc2047_encoding = 0;
03294 
03295 
03296        if (DecodeMe == NULL)
03297               return;
03298        /* Sometimes, badly formed messages contain strings which were simply
03299         *  written out directly in some foreign character set instead of
03300         *  using RFC2047 encoding.  This is illegal but we will attempt to
03301         *  handle it anyway by converting from a user-specified default
03302         *  charset to UTF-8 if we see any nonprintable characters.
03303         */
03304        
03305        for (i=0; i<DecodeMe->BufUsed; ++i) {
03306               if ((DecodeMe->buf[i] < 32) || (DecodeMe->buf[i] > 126)) {
03307                      illegal_non_rfc2047_encoding = 1;
03308                      break;
03309               }
03310        }
03311 
03312        if ((illegal_non_rfc2047_encoding) &&
03313            (strcasecmp(ChrPtr(DefaultCharset), "UTF-8")) && 
03314            (strcasecmp(ChrPtr(DefaultCharset), "us-ascii")) )
03315        {
03316 #ifdef HAVE_ICONV
03317               ctdl_iconv_open("UTF-8", ChrPtr(DefaultCharset), &ic);
03318               if (ic != (iconv_t)(-1) ) {
03319                      DecodedInvalidBuf = NewStrBufDup(DecodeMe);
03320                      StrBufConvert(DecodedInvalidBuf, ConvertBuf, &ic);
03321                      DecodeMee = DecodedInvalidBuf;
03322                      iconv_close(ic);
03323               }
03324 #endif
03325        }
03326 
03327        /* pre evaluate the first pair */
03328        end = NULL;
03329        start = strstr(DecodeMee->buf, "=?");
03330        eptr = DecodeMee->buf + DecodeMee->BufUsed;
03331        if (start != NULL) 
03332               end = FindNextEnd (DecodeMee, start + 2);
03333        else {
03334               StrBufAppendBuf(Target, DecodeMee, 0);
03335               FreeStrBuf(&DecodedInvalidBuf);
03336               return;
03337        }
03338 
03339 
03340        if (start != DecodeMee->buf) {
03341               long nFront;
03342               
03343               nFront = start - DecodeMee->buf;
03344               StrBufAppendBufPlain(Target, DecodeMee->buf, nFront, 0);
03345        }
03346        /*
03347         * Since spammers will go to all sorts of absurd lengths to get their
03348         * messages through, there are LOTS of corrupt headers out there.
03349         * So, prevent a really badly formed RFC2047 header from throwing
03350         * this function into an infinite loop.
03351         */
03352        while ((start != NULL) && 
03353               (end != NULL) && 
03354               (start < eptr) && 
03355               (end < eptr) && 
03356               (passes < 20))
03357        {
03358               passes++;
03359               DecodeSegment(Target, 
03360                            DecodeMee, 
03361                            start, 
03362                            end, 
03363                            ConvertBuf,
03364                            ConvertBuf2,
03365                            FoundCharset);
03366               
03367               next = strstr(end, "=?");
03368               nextend = NULL;
03369               if ((next != NULL) && 
03370                   (next < eptr))
03371                      nextend = FindNextEnd(DecodeMee, next);
03372               if (nextend == NULL)
03373                      next = NULL;
03374 
03375               /* did we find two partitions */
03376               if ((next != NULL) && 
03377                   ((next - end) > 2))
03378               {
03379                      ptr = end + 2;
03380                      while ((ptr < next) && 
03381                             (isspace(*ptr) ||
03382                             (*ptr == '\r') ||
03383                             (*ptr == '\n') || 
03384                             (*ptr == '\t')))
03385                             ptr ++;
03386                      /* 
03387                       * did we find a gab just filled with blanks?
03388                       * if not, copy its stuff over.
03389                       */
03390                      if (ptr != next)
03391                      {
03392                             StrBufAppendBufPlain(Target, 
03393                                                end + 2, 
03394                                                next - end - 2,
03395                                                0);
03396                      }
03397               }
03398               /* our next-pair is our new first pair now. */
03399               ptr = end + 2;
03400               start = next;
03401               end = nextend;
03402        }
03403        end = ptr;
03404        nextend = DecodeMee->buf + DecodeMee->BufUsed;
03405        if ((end != NULL) && (end < nextend)) {
03406               ptr = end;
03407               while ( (ptr < nextend) &&
03408                      (isspace(*ptr) ||
03409                       (*ptr == '\r') ||
03410                       (*ptr == '\n') || 
03411                       (*ptr == '\t')))
03412                      ptr ++;
03413               if (ptr < nextend)
03414                      StrBufAppendBufPlain(Target, end, nextend - end, 0);
03415        }
03416        FreeStrBuf(&DecodedInvalidBuf);
03417 }
03418 
03419 /*******************************************************************************
03420  *                   Manipulating UTF-8 Strings                                *
03421  *******************************************************************************/
03422 
03429 static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE)
03430 {
03431        int n = 0;
03432         unsigned char test = (1<<7);
03433 
03434        if ((*CharS & 0xC0) != 0xC0) 
03435               return 1;
03436 
03437        while ((n < 8) && 
03438               ((test & ((unsigned char)*CharS)) != 0)) 
03439        {
03440               test = test >> 1;
03441               n ++;
03442        }
03443        if ((n > 6) || ((CharE - CharS) < n))
03444               n = 0;
03445        return n;
03446 }
03447 
03454 static inline int Ctdl_IsUtf8SequenceStart(const char Char)
03455 {
03457        return ((Char & 0xC0) == 0xC0);
03458 }
03459 
03466 long StrBuf_Utf8StrLen(StrBuf *Buf)
03467 {
03468        int n = 0;
03469        int m = 0;
03470        char *aptr, *eptr;
03471 
03472        if ((Buf == NULL) || (Buf->BufUsed == 0))
03473               return 0;
03474        aptr = Buf->buf;
03475        eptr = Buf->buf + Buf->BufUsed;
03476        while ((aptr < eptr) && (*aptr != '\0')) {
03477               if (Ctdl_IsUtf8SequenceStart(*aptr)){
03478                      m = Ctdl_GetUtf8SequenceLength(aptr, eptr);
03479                      while ((aptr < eptr) && (*aptr++ != '\0')&& (m-- > 0) );
03480                      n ++;
03481               }
03482               else {
03483                      n++;
03484                      aptr++;
03485               }
03486        }
03487        return n;
03488 }
03489 
03497 long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen)
03498 {
03499        char *aptr, *eptr;
03500        int n = 0, m = 0;
03501 
03502        aptr = Buf->buf;
03503        eptr = Buf->buf + Buf->BufUsed;
03504        while ((aptr < eptr) && (*aptr != '\0')) {
03505               if (Ctdl_IsUtf8SequenceStart(*aptr)){
03506                      m = Ctdl_GetUtf8SequenceLength(aptr, eptr);
03507                      while ((*aptr++ != '\0') && (m-- > 0));
03508                      n ++;
03509               }
03510               else {
03511                      n++;
03512                      aptr++;
03513               }
03514               if (n > maxlen) {
03515                      *aptr = '\0';
03516                      Buf->BufUsed = aptr - Buf->buf;
03517                      return Buf->BufUsed;
03518               }                    
03519        }
03520        return Buf->BufUsed;
03521 
03522 }
03523 
03524 
03525 
03526 
03527 
03528 /*******************************************************************************
03529  *                               wrapping ZLib                                 *
03530  *******************************************************************************/
03531 
03532 #ifdef HAVE_ZLIB
03533 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
03534 #define OS_CODE 0x03 /*< unix */
03535 
03546 int ZEXPORT compress_gzip(Bytef * dest,
03547                        size_t * destLen,
03548                        const Bytef * source,
03549                        uLong sourceLen,     
03550                        int level)
03551 {
03552        const int gz_magic[2] = { 0x1f, 0x8b };   /* gzip magic header */
03553 
03554        /* write gzip header */
03555        snprintf((char *) dest, *destLen, 
03556                "%c%c%c%c%c%c%c%c%c%c",
03557                gz_magic[0], gz_magic[1], Z_DEFLATED,
03558                0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
03559                OS_CODE);
03560 
03561        /* normal deflate */
03562        z_stream stream;
03563        int err;
03564        stream.next_in = (Bytef *) source;
03565        stream.avail_in = (uInt) sourceLen;
03566        stream.next_out = dest + 10L;      // after header
03567        stream.avail_out = (uInt) * destLen;
03568        if ((uLong) stream.avail_out != *destLen)
03569               return Z_BUF_ERROR;
03570 
03571        stream.zalloc = (alloc_func) 0;
03572        stream.zfree = (free_func) 0;
03573        stream.opaque = (voidpf) 0;
03574 
03575        err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
03576                         DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
03577        if (err != Z_OK)
03578               return err;
03579 
03580        err = deflate(&stream, Z_FINISH);
03581        if (err != Z_STREAM_END) {
03582               deflateEnd(&stream);
03583               return err == Z_OK ? Z_BUF_ERROR : err;
03584        }
03585        *destLen = stream.total_out + 10L;
03586 
03587        /* write CRC and Length */
03588        uLong crc = crc32(0L, source, sourceLen);
03589        int n;
03590        for (n = 0; n < 4; ++n, ++*destLen) {
03591               dest[*destLen] = (int) (crc & 0xff);
03592               crc >>= 8;
03593        }
03594        uLong len = stream.total_in;
03595        for (n = 0; n < 4; ++n, ++*destLen) {
03596               dest[*destLen] = (int) (len & 0xff);
03597               len >>= 8;
03598        }
03599        err = deflateEnd(&stream);
03600        return err;
03601 }
03602 #endif
03603 
03604 
03611 int CompressBuffer(StrBuf *Buf)
03612 {
03613 #ifdef HAVE_ZLIB
03614        char *compressed_data = NULL;
03615        size_t compressed_len, bufsize;
03616        int i = 0;
03617 
03618        bufsize = compressed_len = Buf->BufUsed +  (Buf->BufUsed / 100) + 100;
03619        compressed_data = malloc(compressed_len);
03620        
03621        if (compressed_data == NULL)
03622               return -1;
03623        /* Flush some space after the used payload so valgrind shuts up... */
03624         while ((i < 10) && (Buf->BufUsed + i < Buf->BufSize))
03625               Buf->buf[Buf->BufUsed + i++] = '\0';
03626        if (compress_gzip((Bytef *) compressed_data,
03627                        &compressed_len,
03628                        (Bytef *) Buf->buf,
03629                        (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
03630               if (!Buf->ConstBuf)
03631                      free(Buf->buf);
03632               Buf->buf = compressed_data;
03633               Buf->BufUsed = compressed_len;
03634               Buf->BufSize = bufsize;
03635               /* Flush some space after the used payload so valgrind shuts up... */
03636               i = 0;
03637               while ((i < 10) && (Buf->BufUsed + i < Buf->BufSize))
03638                      Buf->buf[Buf->BufUsed + i++] = '\0';
03639               return 1;
03640        } else {
03641               free(compressed_data);
03642        }
03643 #endif /* HAVE_ZLIB */
03644        return 0;
03645 }
03646 
03647 /*******************************************************************************
03648  *           File I/O; Callbacks to libevent                                   *
03649  *******************************************************************************/
03650 
03651 long StrBuf_read_one_chunk_callback (int fd, short event, IOBuffer *FB)
03652 {
03653        long bufremain = 0;
03654        int n;
03655        
03656        if ((FB == NULL) || (FB->Buf == NULL))
03657               return -1;
03658 
03659        /*
03660         * check whether the read pointer is somewhere in a range 
03661         * where a cut left is inexpensive
03662         */
03663 
03664        if (FB->ReadWritePointer != NULL)
03665        {
03666               long already_read;
03667               
03668               already_read = FB->ReadWritePointer - FB->Buf->buf;
03669               bufremain = FB->Buf->BufSize - FB->Buf->BufUsed - 1;
03670 
03671               if (already_read != 0) {
03672                      long unread;
03673                      
03674                      unread = FB->Buf->BufUsed - already_read;
03675 
03676                      /* else nothing to compact... */
03677                      if (unread == 0) {
03678                             FB->ReadWritePointer = FB->Buf->buf;
03679                             bufremain = FB->Buf->BufSize;                    
03680                      }
03681                      else if ((unread < 64) || 
03682                              (bufremain < already_read))
03683                      {
03684                             /* 
03685                              * if its just a tiny bit remaining, or we run out of space... 
03686                              * lets tidy up.
03687                              */
03688                             FB->Buf->BufUsed = unread;
03689                             if (unread < already_read)
03690                                    memcpy(FB->Buf->buf, FB->ReadWritePointer, unread);
03691                             else
03692                                    memmove(FB->Buf->buf, FB->ReadWritePointer, unread);
03693                             FB->ReadWritePointer = FB->Buf->buf;
03694                             bufremain = FB->Buf->BufSize - unread - 1;
03695                      }
03696                      else if (bufremain < (FB->Buf->BufSize / 10))
03697                      {
03698                             /* get a bigger buffer */ 
03699 
03700                             IncreaseBuf(FB->Buf, 0, FB->Buf->BufUsed + 1);
03701 
03702                             FB->ReadWritePointer = FB->Buf->buf + unread;
03703 
03704                             bufremain = FB->Buf->BufSize - unread - 1;
03705 /*TODO: special increase function that won't copy the already read! */
03706                      }
03707               }
03708               else if (bufremain < 10) {
03709                      IncreaseBuf(FB->Buf, 1, FB->Buf->BufUsed + 10);
03710                      
03711                      FB->ReadWritePointer = FB->Buf->buf;
03712                      
03713                      bufremain = FB->Buf->BufSize - FB->Buf->BufUsed - 1;
03714               }
03715               
03716        }
03717        else {
03718               FB->ReadWritePointer = FB->Buf->buf;
03719               bufremain = FB->Buf->BufSize - 1;
03720        }
03721 
03722        n = read(fd, FB->Buf->buf + FB->Buf->BufUsed, bufremain);
03723 
03724        if (n > 0) {
03725               FB->Buf->BufUsed += n;
03726               FB->Buf->buf[FB->Buf->BufUsed] = '\0';
03727        }
03728        return n;
03729 }
03730 
03731 int StrBuf_write_one_chunk_callback(int fd, short event, IOBuffer *FB)
03732 {
03733        long WriteRemain;
03734        int n;
03735 
03736        if ((FB == NULL) || (FB->Buf == NULL))
03737               return -1;
03738 
03739        if (FB->ReadWritePointer != NULL)
03740        {
03741               WriteRemain = FB->Buf->BufUsed - 
03742                      (FB->ReadWritePointer - 
03743                       FB->Buf->buf);
03744        }
03745        else {
03746               FB->ReadWritePointer = FB->Buf->buf;
03747               WriteRemain = FB->Buf->BufUsed;
03748        }
03749 
03750        n = write(fd, FB->ReadWritePointer, WriteRemain);
03751        if (n > 0) {
03752               FB->ReadWritePointer += n;
03753 
03754               if (FB->ReadWritePointer == 
03755                   FB->Buf->buf + FB->Buf->BufUsed)
03756               {
03757                      FlushStrBuf(FB->Buf);
03758                      FB->ReadWritePointer = NULL;
03759                      return 0;
03760               }
03761        // check whether we've got something to write
03762        // get the maximum chunk plus the pointer we can send
03763        // write whats there
03764        // if not all was sent, remember the send pointer for the next time
03765               return FB->ReadWritePointer - FB->Buf->buf + FB->Buf->BufUsed;
03766        }
03767        return n;
03768 }
03769 
03779 eReadState StrBufChunkSipLine(StrBuf *LineBuf, IOBuffer *FB)
03780 {
03781        const char *aptr, *ptr, *eptr;
03782        char *optr, *xptr;
03783 
03784        if ((FB == NULL) || (LineBuf == NULL) || (LineBuf->buf == NULL))
03785               return eReadFail;
03786        
03787 
03788        if ((FB->Buf == NULL) || (FB->ReadWritePointer == StrBufNOTNULL)) {
03789               FB->ReadWritePointer = StrBufNOTNULL;
03790               return eReadFail;
03791        }
03792 
03793        FlushStrBuf(LineBuf);
03794        if (FB->ReadWritePointer == NULL)
03795               ptr = aptr = FB->Buf->buf;
03796        else
03797               ptr = aptr = FB->ReadWritePointer;
03798 
03799        optr = LineBuf->buf;
03800        eptr = FB->Buf->buf + FB->Buf->BufUsed;
03801        xptr = LineBuf->buf + LineBuf->BufSize - 1;
03802 
03803        while ((ptr <= eptr) && 
03804               (*ptr != '\n') &&
03805               (*ptr != '\r') )
03806        {
03807               *optr = *ptr;
03808               optr++; ptr++;
03809               if (optr == xptr) {
03810                      LineBuf->BufUsed = optr - LineBuf->buf;
03811                      IncreaseBuf(LineBuf,  1, LineBuf->BufUsed + 1);
03812                      optr = LineBuf->buf + LineBuf->BufUsed;
03813                      xptr = LineBuf->buf + LineBuf->BufSize - 1;
03814               }
03815        }
03816 
03817        if (ptr >= eptr) {
03818               if (optr > LineBuf->buf)
03819                      optr --;
03820               if ((*(ptr - 1) != '\r') && (*(ptr - 1) != '\n')) {
03821                      LineBuf->BufUsed = optr - LineBuf->buf;
03822                      *optr = '\0';
03823                      if ((FB->ReadWritePointer != NULL) && 
03824                          (FB->ReadWritePointer != FB->Buf->buf))
03825                      {
03826                             /* Ok, the client application read all the data 
03827                                it was interested in so far. Since there is more to read, 
03828                                we now shrink the buffer, and move the rest over.
03829                             */
03830                             StrBufCutLeft(FB->Buf, 
03831                                          FB->ReadWritePointer - FB->Buf->buf);
03832                             FB->ReadWritePointer = FB->Buf->buf;
03833                      }
03834                      return eMustReadMore;
03835               }
03836        }
03837        LineBuf->BufUsed = optr - LineBuf->buf;
03838        *optr = '\0';       
03839        if ((ptr <= eptr) && (*ptr == '\r'))
03840               ptr ++;
03841        if ((ptr <= eptr) && (*ptr == '\n'))
03842               ptr ++;
03843        
03844        if (ptr < eptr) {
03845               FB->ReadWritePointer = ptr;
03846        }
03847        else {
03848               FlushStrBuf(FB->Buf);
03849               FB->ReadWritePointer = NULL;
03850        }
03851 
03852        return eReadSuccess;
03853 }
03854 
03860 eReadState StrBufCheckBuffer(IOBuffer *FB)
03861 {
03862        if (FB == NULL)
03863               return eReadFail;
03864        if (FB->Buf->BufUsed == 0)
03865               return eReadSuccess;
03866        if (FB->ReadWritePointer == NULL)
03867               return eBufferNotEmpty;
03868        if (FB->Buf->buf + FB->Buf->BufUsed > FB->ReadWritePointer)
03869               return eBufferNotEmpty;
03870        return eReadSuccess;
03871 }
03872 
03873 long IOBufferStrLength(IOBuffer *FB)
03874 {
03875        if ((FB == NULL) || (FB->Buf == NULL))
03876               return 0;
03877        if (FB->ReadWritePointer == NULL)
03878               return StrLength(FB->Buf);
03879        
03880        return StrLength(FB->Buf) - (FB->ReadWritePointer - FB->Buf->buf);
03881 }
03882 
03883 void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize)
03884 {
03885        memset(FDB, 0, sizeof(FDIOBuffer));
03886        FDB->ChunkSize = 
03887               FDB->TotalSendSize = TotalSendSize;
03888        FDB->IOB = IO;
03889 #ifndef LINUX_SPLICE
03890        FDB->ChunkBuffer = NewStrBufPlain(NULL, TotalSendSize + 1);
03891 #else
03892        pipe(FDB->SplicePipe);
03893 #endif
03894        FDB->OtherFD = FD;
03895 }
03896 
03897 void FDIOBufferDelete(FDIOBuffer *FDB)
03898 {
03899 #ifndef LINUX_SPLICE
03900        FreeStrBuf(&FDB->ChunkBuffer);
03901 #else
03902        close(FDB->SplicePipe[0]);
03903        close(FDB->SplicePipe[1]);
03904        
03905 #endif
03906        close(FDB->OtherFD);
03907        memset(FDB, 0, sizeof(FDIOBuffer));       
03908 }
03909 
03910 int FileSendChunked(FDIOBuffer *FDB, const char **Err)
03911 {
03912        ssize_t sent, pipesize;
03913 #ifdef LINUX_SPLICE
03914        if (FDB->PipeSize == 0)
03915        {
03916               pipesize = splice(FDB->OtherFD,
03917                               &FDB->TotalSentAlready, 
03918                               FDB->SplicePipe[1],
03919                               NULL, 
03920                               FDB->ChunkSendRemain, 
03921                               SPLICE_F_MOVE);
03922        
03923               if (pipesize == -1)
03924               {
03925                      *Err = strerror(errno);
03926                      return pipesize;
03927               }
03928               FDB->PipeSize = pipesize;
03929        }
03930        sent =  splice(FDB->SplicePipe[0],
03931                      NULL, 
03932                      FDB->IOB->fd,
03933                      NULL, 
03934                      FDB->PipeSize,
03935                      SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
03936        if (sent == -1)
03937        {
03938               *Err = strerror(errno);
03939               return sent;
03940        }
03941        FDB->PipeSize -= sent;
03942        FDB->ChunkSendRemain -= sent;
03943        return sent;
03944 #else
03945 
03946        char *pRead;
03947        long nRead = 0;
03948 
03949        pRead = FDB->ChunkBuffer->buf;
03950        while ((FDB->ChunkBuffer->BufUsed < FDB->TotalSendSize) && (nRead >= 0))
03951        {
03952               nRead = read(FDB->OtherFD, pRead, FDB->TotalSendSize - FDB->ChunkBuffer->BufUsed);
03953               if (nRead > 0) {
03954                      FDB->ChunkBuffer->BufUsed += nRead;
03955                      FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0';
03956               }
03957               else if (nRead == 0) {}
03958               else return nRead;
03959               
03960        }
03961 
03962        nRead = write(FDB->IOB->fd, FDB->ChunkBuffer->buf + FDB->TotalSentAlready, FDB->ChunkSendRemain);
03963 
03964        if (nRead >= 0) {
03965               FDB->TotalSentAlready += nRead;
03966               FDB->ChunkSendRemain -= nRead;
03967               return FDB->ChunkSendRemain;
03968        }
03969        else {
03970               return nRead;
03971        }
03972 #endif
03973 }
03974 
03975 int FileRecvChunked(FDIOBuffer *FDB, const char **Err)
03976 {
03977        ssize_t sent, pipesize;
03978 
03979 #ifdef LINUX_SPLICE
03980        if (FDB->PipeSize == 0)
03981        {
03982               pipesize = splice(FDB->IOB->fd,
03983                               NULL, 
03984                               FDB->SplicePipe[1],
03985                               NULL, 
03986                               FDB->ChunkSendRemain, 
03987                               SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
03988 
03989               if (pipesize == -1)
03990               {
03991                      *Err = strerror(errno);
03992                      return pipesize;
03993               }
03994               FDB->PipeSize = pipesize;
03995        }
03996        
03997        sent = splice(FDB->SplicePipe[0],
03998                     NULL, 
03999                     FDB->OtherFD,
04000                     &FDB->TotalSentAlready, 
04001                     FDB->PipeSize,
04002                     SPLICE_F_MORE | SPLICE_F_MOVE);
04003 
04004        if (sent == -1)
04005        {
04006               *Err = strerror(errno);
04007               return sent;
04008        }
04009        FDB->PipeSize -= sent;
04010        FDB->ChunkSendRemain -= sent;
04011        return sent;
04012 #else
04013        
04014        sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
04015        if (sent > 0) {
04016               int nWritten = 0;
04017               int rc; 
04018               
04019               FDB->ChunkBuffer->BufUsed = sent;
04020 
04021               while (nWritten < FDB->ChunkBuffer->BufUsed) {
04022                      rc =  write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
04023                      if (rc < 0) {
04024                             *Err = strerror(errno);
04025                             return rc;
04026                      }
04027                      nWritten += rc;
04028 
04029               }
04030               FDB->ChunkBuffer->BufUsed = 0;
04031               FDB->TotalSentAlready += sent;
04032               FDB->ChunkSendRemain -= sent;
04033               return FDB->ChunkSendRemain;
04034        }
04035        else if (sent < 0) {
04036               *Err = strerror(errno);
04037               return sent;
04038        }
04039 
04040 #endif
04041        return 0;
04042 }
04043 
04044 int FileMoveChunked(FDIOBuffer *FDB, const char **Err)
04045 {
04046        ssize_t sent, pipesize;
04047 
04048 #ifdef LINUX_SPLICE
04049        if (FDB->PipeSize == 0)
04050        {
04051               pipesize = splice(FDB->IOB->fd,
04052                               &FDB->TotalReadAlready, 
04053                               FDB->SplicePipe[1],
04054                               NULL, 
04055                               FDB->ChunkSendRemain, 
04056                               SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
04057 
04058               if (pipesize == -1)
04059               {
04060                      *Err = strerror(errno);
04061                      return pipesize;
04062               }
04063               FDB->PipeSize = pipesize;
04064        }
04065        
04066        sent = splice(FDB->SplicePipe[0],
04067                     NULL, 
04068                     FDB->OtherFD,
04069                     &FDB->TotalSentAlready, 
04070                     FDB->PipeSize,
04071                     SPLICE_F_MORE | SPLICE_F_MOVE);
04072 
04073        if (sent == -1)
04074        {
04075               *Err = strerror(errno);
04076               return sent;
04077        }
04078        FDB->PipeSize -= sent;
04079        FDB->ChunkSendRemain -= sent;
04080        return sent;
04081 #else
04082        
04083        sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
04084        if (sent > 0) {
04085               int nWritten = 0;
04086               int rc; 
04087               
04088               FDB->ChunkBuffer->BufUsed = sent;
04089 
04090               while (nWritten < FDB->ChunkBuffer->BufUsed) {
04091                      rc =  write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
04092                      if (rc < 0) {
04093                             *Err = strerror(errno);
04094                             return rc;
04095                      }
04096                      nWritten += rc;
04097 
04098               }
04099               FDB->ChunkBuffer->BufUsed = 0;
04100               FDB->TotalSentAlready += sent;
04101               FDB->ChunkSendRemain -= sent;
04102               return FDB->ChunkSendRemain;
04103        }
04104        else if (sent < 0) {
04105               *Err = strerror(errno);
04106               return sent;
04107        }
04108 
04109 #endif
04110        return 0;
04111 }
04112 
04113 eReadState WriteIOBAlreadyRead(FDIOBuffer *FDB, const char **Error)
04114 {
04115        int IsNonBlock;
04116        int fdflags;
04117        long rlen;
04118        long should_write;
04119        int nSuccessLess = 0;
04120        struct timeval tv;
04121        fd_set rfds;
04122 
04123        fdflags = fcntl(FDB->OtherFD, F_GETFL);
04124        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
04125 
04126        while ((FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf < FDB->IOB->Buf->BufUsed) &&
04127               (FDB->ChunkSendRemain > 0))
04128        {
04129               if (IsNonBlock){
04130                      tv.tv_sec = 1; /* selectresolution; */
04131                      tv.tv_usec = 0;
04132                      
04133                      FD_ZERO(&rfds);
04134                      FD_SET(FDB->OtherFD, &rfds);
04135                      if (select(FDB->OtherFD + 1, NULL, &rfds, NULL, &tv) == -1) {
04136                             *Error = strerror(errno);
04137                             return eReadFail;
04138                      }
04139               }
04140               if (IsNonBlock && !  FD_ISSET(FDB->OtherFD, &rfds)) {
04141                      nSuccessLess ++;
04142                      continue;
04143               }
04144 
04145               should_write = FDB->IOB->Buf->BufUsed - 
04146                      (FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf);
04147               if (should_write > FDB->ChunkSendRemain)
04148                      should_write = FDB->ChunkSendRemain;
04149 
04150               rlen = write(FDB->OtherFD, 
04151                           FDB->IOB->ReadWritePointer, 
04152                           should_write);
04153               if (rlen < 1) {
04154                      *Error = strerror(errno);
04155                                           
04156                      return eReadFail;
04157               }
04158               FDB->TotalSentAlready += rlen;
04159               FDB->IOB->ReadWritePointer += rlen;
04160               FDB->ChunkSendRemain -= rlen;
04161        }
04162        if (FDB->IOB->ReadWritePointer >= FDB->IOB->Buf->buf + FDB->IOB->Buf->BufUsed)
04163        {
04164               FlushStrBuf(FDB->IOB->Buf);
04165               FDB->IOB->ReadWritePointer = NULL;
04166        }
04167 
04168        if (FDB->ChunkSendRemain == 0)
04169               return eReadSuccess;
04170        else 
04171               return eMustReadMore;
04172 }
04173 
04174 /*******************************************************************************
04175  *           File I/O; Prefer buffered read since its faster!                  *
04176  *******************************************************************************/
04177 
04188 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
04189 {
04190        int len, rlen, slen;
04191 
04192        if ((buf == NULL) || (buf->buf == NULL)) {
04193               *Error = strerror(EINVAL);
04194               return -1;
04195        }
04196 
04197        if (!append)
04198               FlushStrBuf(buf);
04199 
04200        slen = len = buf->BufUsed;
04201        while (1) {
04202               rlen = read(*fd, &buf->buf[len], 1);
04203               if (rlen < 1) {
04204                      *Error = strerror(errno);
04205                      
04206                      close(*fd);
04207                      *fd = -1;
04208                      
04209                      return -1;
04210               }
04211               if (buf->buf[len] == '\n')
04212                      break;
04213               if (buf->buf[len] != '\r')
04214                      len ++;
04215               if (len + 2 >= buf->BufSize) {
04216                      buf->BufUsed = len;
04217                      buf->buf[len+1] = '\0';
04218                      IncreaseBuf(buf, 1, -1);
04219               }
04220        }
04221        buf->BufUsed = len;
04222        buf->buf[len] = '\0';
04223        return len - slen;
04224 }
04225 
04238 int StrBufTCP_read_buffered_line(StrBuf *Line, 
04239                              StrBuf *buf, 
04240                              int *fd, 
04241                              int timeout, 
04242                              int selectresolution, 
04243                              const char **Error)
04244 {
04245        int len, rlen;
04246        int nSuccessLess = 0;
04247        fd_set rfds;
04248        char *pch = NULL;
04249         int fdflags;
04250        int IsNonBlock;
04251        struct timeval tv;
04252 
04253        if (buf->BufUsed > 0) {
04254               pch = strchr(buf->buf, '\n');
04255               if (pch != NULL) {
04256                      rlen = 0;
04257                      len = pch - buf->buf;
04258                      if (len > 0 && (*(pch - 1) == '\r') )
04259                             rlen ++;
04260                      StrBufSub(Line, buf, 0, len - rlen);
04261                      StrBufCutLeft(buf, len + 1);
04262                      return len - rlen;
04263               }
04264        }
04265        
04266        if (buf->BufSize - buf->BufUsed < 10)
04267               IncreaseBuf(buf, 1, -1);
04268 
04269        fdflags = fcntl(*fd, F_GETFL);
04270        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
04271 
04272        while ((nSuccessLess < timeout) && (pch == NULL)) {
04273               if (IsNonBlock){
04274                      tv.tv_sec = selectresolution;
04275                      tv.tv_usec = 0;
04276                      
04277                      FD_ZERO(&rfds);
04278                      FD_SET(*fd, &rfds);
04279                      if (select(*fd + 1, NULL, &rfds, NULL, &tv) == -1) {
04280                             *Error = strerror(errno);
04281                             close (*fd);
04282                             *fd = -1;
04283                             return -1;
04284                      }
04285               }
04286               if (IsNonBlock && !  FD_ISSET(*fd, &rfds)) {
04287                      nSuccessLess ++;
04288                      continue;
04289               }
04290               rlen = read(*fd, 
04291                          &buf->buf[buf->BufUsed], 
04292                          buf->BufSize - buf->BufUsed - 1);
04293               if (rlen < 1) {
04294                      *Error = strerror(errno);
04295                      close(*fd);
04296                      *fd = -1;
04297                      return -1;
04298               }
04299               else if (rlen > 0) {
04300                      nSuccessLess = 0;
04301                      buf->BufUsed += rlen;
04302                      buf->buf[buf->BufUsed] = '\0';
04303                      if (buf->BufUsed + 10 > buf->BufSize) {
04304                             IncreaseBuf(buf, 1, -1);
04305                      }
04306                      pch = strchr(buf->buf, '\n');
04307                      continue;
04308               }
04309               
04310        }
04311        if (pch != NULL) {
04312               rlen = 0;
04313               len = pch - buf->buf;
04314               if (len > 0 && (*(pch - 1) == '\r') )
04315                      rlen ++;
04316               StrBufSub(Line, buf, 0, len - rlen);
04317               StrBufCutLeft(buf, len + 1);
04318               return len - rlen;
04319        }
04320        return -1;
04321 
04322 }
04323 
04324 static const char *ErrRBLF_PreConditionFailed="StrBufTCP_read_buffered_line_fast: Wrong arguments or invalid Filedescriptor";
04325 static const char *ErrRBLF_SelectFailed="StrBufTCP_read_buffered_line_fast: Select failed without reason";
04326 static const char *ErrRBLF_NotEnoughSentFromServer="StrBufTCP_read_buffered_line_fast: No complete line was sent from peer";
04340 int StrBufTCP_read_buffered_line_fast(StrBuf *Line, 
04341                                   StrBuf *IOBuf, 
04342                                   const char **Pos,
04343                                   int *fd, 
04344                                   int timeout, 
04345                                   int selectresolution, 
04346                                   const char **Error)
04347 {
04348        const char *pche = NULL;
04349        const char *pos = NULL;
04350        const char *pLF;
04351        int len, rlen, retlen;
04352        int nSuccessLess = 0;
04353        fd_set rfds;
04354        const char *pch = NULL;
04355         int fdflags;
04356        int IsNonBlock;
04357        struct timeval tv;
04358        
04359        retlen = 0;
04360        if ((Line == NULL) ||
04361            (Pos == NULL) ||
04362            (IOBuf == NULL) ||
04363            (*fd == -1))
04364        {
04365               if (Pos != NULL)
04366                      *Pos = NULL;
04367               *Error = ErrRBLF_PreConditionFailed;
04368               return -1;
04369        }
04370 
04371        pos = *Pos;
04372        if ((IOBuf->BufUsed > 0) && 
04373            (pos != NULL) && 
04374            (pos < IOBuf->buf + IOBuf->BufUsed)) 
04375        {
04376               char *pcht;
04377 
04378               pche = IOBuf->buf + IOBuf->BufUsed;
04379               pch = pos;
04380               pcht = Line->buf;
04381 
04382               while ((pch < pche) && (*pch != '\n'))
04383               {
04384                      if (Line->BufUsed + 10 > Line->BufSize)
04385                      {
04386                             long apos;
04387                             apos = pcht - Line->buf;
04388                             *pcht = '\0';
04389                             IncreaseBuf(Line, 1, -1);
04390                             pcht = Line->buf + apos;
04391                      }
04392                      *pcht++ = *pch++;
04393                      Line->BufUsed++;
04394                      retlen++;
04395               }
04396 
04397               len = pch - pos;
04398               if (len > 0 && (*(pch - 1) == '\r') )
04399               {
04400                      retlen--;
04401                      len --;
04402                      pcht --;
04403                      Line->BufUsed --;
04404               }
04405               *pcht = '\0';
04406 
04407               if ((pch >= pche) || (*pch == '\0'))
04408               {
04409                      FlushStrBuf(IOBuf);
04410                      *Pos = NULL;
04411                      pch = NULL;
04412                      pos = 0;
04413               }
04414 
04415               if ((pch != NULL) && 
04416                   (pch <= pche)) 
04417               {
04418                      if (pch + 1 >= pche) {
04419                             *Pos = NULL;
04420                             FlushStrBuf(IOBuf);
04421                      }
04422                      else
04423                             *Pos = pch + 1;
04424                      
04425                      return retlen;
04426               }
04427               else 
04428                      FlushStrBuf(IOBuf);
04429        }
04430 
04431        /* If we come here, Pos is Unset since we read everything into Line, and now go for more. */
04432        
04433        if (IOBuf->BufSize - IOBuf->BufUsed < 10)
04434               IncreaseBuf(IOBuf, 1, -1);
04435 
04436        fdflags = fcntl(*fd, F_GETFL);
04437        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
04438 
04439        pLF = NULL;
04440        while ((nSuccessLess < timeout) && 
04441               (pLF == NULL) &&
04442               (*fd != -1)) {
04443               if (IsNonBlock)
04444               {
04445                      tv.tv_sec = 1;
04446                      tv.tv_usec = 0;
04447               
04448                      FD_ZERO(&rfds);
04449                      FD_SET(*fd, &rfds);
04450                      if (select((*fd) + 1, &rfds, NULL, NULL, &tv) == -1) {
04451                             *Error = strerror(errno);
04452                             close (*fd);
04453                             *fd = -1;
04454                             if (*Error == NULL)
04455                                    *Error = ErrRBLF_SelectFailed;
04456                             return -1;
04457                      }
04458                      if (! FD_ISSET(*fd, &rfds) != 0) {
04459                             nSuccessLess ++;
04460                             continue;
04461                      }
04462               }
04463               rlen = read(*fd, 
04464                          &IOBuf->buf[IOBuf->BufUsed], 
04465                          IOBuf->BufSize - IOBuf->BufUsed - 1);
04466               if (rlen < 1) {
04467                      *Error = strerror(errno);
04468                      close(*fd);
04469                      *fd = -1;
04470                      return -1;
04471               }
04472               else if (rlen > 0) {
04473                      nSuccessLess = 0;
04474                      pLF = IOBuf->buf + IOBuf->BufUsed;
04475                      IOBuf->BufUsed += rlen;
04476                      IOBuf->buf[IOBuf->BufUsed] = '\0';
04477                      
04478                      pche = IOBuf->buf + IOBuf->BufUsed;
04479                      
04480                      while ((pLF < pche) && (*pLF != '\n'))
04481                             pLF ++;
04482                      if ((pLF >= pche) || (*pLF == '\0'))
04483                             pLF = NULL;
04484 
04485                      if (IOBuf->BufUsed + 10 > IOBuf->BufSize)
04486                      {
04487                             long apos = 0;
04488 
04489                             if (pLF != NULL) apos = pLF - IOBuf->buf;
04490                             IncreaseBuf(IOBuf, 1, -1);  
04491                             if (pLF != NULL) pLF = IOBuf->buf + apos;
04492                      }
04493 
04494                      continue;
04495               }
04496        }
04497        *Pos = NULL;
04498        if (pLF != NULL) {
04499               pos = IOBuf->buf;
04500               len = pLF - pos;
04501               if (len > 0 && (*(pLF - 1) == '\r') )
04502                      len --;
04503               StrBufAppendBufPlain(Line, ChrPtr(IOBuf), len, 0);
04504               if (pLF + 1 >= IOBuf->buf + IOBuf->BufUsed)
04505               {
04506                      FlushStrBuf(IOBuf);
04507               }
04508               else 
04509                      *Pos = pLF + 1;
04510               return retlen + len;
04511        }
04512        *Error = ErrRBLF_NotEnoughSentFromServer;
04513        return -1;
04514 
04515 }
04516 
04517 static const char *ErrRBLF_BLOBPreConditionFailed="StrBufReadBLOB: Wrong arguments or invalid Filedescriptor";
04529 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
04530 {
04531        int fdflags;
04532        int rlen;
04533        int nSuccessLess;
04534        int nRead = 0;
04535        char *ptr;
04536        int IsNonBlock;
04537        struct timeval tv;
04538        fd_set rfds;
04539 
04540        if ((Buf == NULL) || (Buf->buf == NULL) || (*fd == -1))
04541        {
04542               *Error = ErrRBLF_BLOBPreConditionFailed;
04543               return -1;
04544        }
04545        if (!append)
04546               FlushStrBuf(Buf);
04547        if (Buf->BufUsed + nBytes >= Buf->BufSize)
04548               IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
04549 
04550        ptr = Buf->buf + Buf->BufUsed;
04551 
04552        fdflags = fcntl(*fd, F_GETFL);
04553        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
04554        nSuccessLess = 0;
04555        while ((nRead < nBytes) && 
04556               (*fd != -1)) 
04557        {
04558               if (IsNonBlock)
04559               {
04560                      tv.tv_sec = 1;
04561                      tv.tv_usec = 0;
04562               
04563                      FD_ZERO(&rfds);
04564                      FD_SET(*fd, &rfds);
04565                      if (select(*fd + 1, &rfds, NULL, NULL, &tv) == -1) {
04566                             *Error = strerror(errno);
04567                             close (*fd);
04568                             *fd = -1;
04569                             if (*Error == NULL)
04570                                    *Error = ErrRBLF_SelectFailed;
04571                             return -1;
04572                      }
04573                      if (! FD_ISSET(*fd, &rfds) != 0) {
04574                             nSuccessLess ++;
04575                             continue;
04576                      }
04577               }
04578 
04579                 if ((rlen = read(*fd, 
04580                              ptr,
04581                              nBytes - nRead)) == -1) {
04582                      close(*fd);
04583                      *fd = -1;
04584                      *Error = strerror(errno);
04585                         return rlen;
04586                 }
04587               nRead += rlen;
04588               ptr += rlen;
04589               Buf->BufUsed += rlen;
04590        }
04591        Buf->buf[Buf->BufUsed] = '\0';
04592        return nRead;
04593 }
04594 
04595 const char *ErrRBB_BLOBFPreConditionFailed = "StrBufReadBLOBBuffered: to many selects; aborting.";
04596 const char *ErrRBB_too_many_selects        = "StrBufReadBLOBBuffered: to many selects; aborting.";
04611 int StrBufReadBLOBBuffered(StrBuf *Blob, 
04612                         StrBuf *IOBuf, 
04613                         const char **Pos,
04614                         int *fd, 
04615                         int append, 
04616                         long nBytes, 
04617                         int check, 
04618                         const char **Error)
04619 {
04620        const char *pos;
04621        int fdflags;
04622        int rlen = 0;
04623        int nRead = 0;
04624        int nAlreadyRead = 0;
04625        int IsNonBlock;
04626        char *ptr;
04627        fd_set rfds;
04628        struct timeval tv;
04629        int nSuccessLess = 0;
04630        int MaxTries;
04631 
04632        if ((Blob == NULL) || (*fd == -1) || (IOBuf == NULL) || (Pos == NULL))
04633        {
04634               if (*Pos != NULL)
04635                      *Pos = NULL;
04636               *Error = ErrRBB_BLOBFPreConditionFailed;
04637               return -1;
04638        }
04639 
04640        if (!append)
04641               FlushStrBuf(Blob);
04642        if (Blob->BufUsed + nBytes >= Blob->BufSize) 
04643               IncreaseBuf(Blob, append, Blob->BufUsed + nBytes);
04644        
04645        pos = *Pos;
04646 
04647        if (pos != NULL)
04648               rlen = pos - IOBuf->buf;
04649        rlen = IOBuf->BufUsed - rlen;
04650 
04651 
04652        if ((IOBuf->BufUsed > 0) && 
04653            (pos != NULL) && 
04654            (pos < IOBuf->buf + IOBuf->BufUsed)) 
04655        {
04656               if (rlen < nBytes) {
04657                      memcpy(Blob->buf + Blob->BufUsed, pos, rlen);
04658                      Blob->BufUsed += rlen;
04659                      Blob->buf[Blob->BufUsed] = '\0';
04660                      nAlreadyRead = nRead = rlen;
04661                      *Pos = NULL; 
04662               }
04663               if (rlen >= nBytes) {
04664                      memcpy(Blob->buf + Blob->BufUsed, pos, nBytes);
04665                      Blob->BufUsed += nBytes;
04666                      Blob->buf[Blob->BufUsed] = '\0';
04667                      if (rlen == nBytes) {
04668                             *Pos = NULL; 
04669                             FlushStrBuf(IOBuf);
04670                      }
04671                      else 
04672                             *Pos += nBytes;
04673                      return nBytes;
04674               }
04675        }
04676 
04677        FlushStrBuf(IOBuf);
04678        *Pos = NULL;
04679        if (IOBuf->BufSize < nBytes - nRead)
04680               IncreaseBuf(IOBuf, 0, nBytes - nRead);
04681        ptr = IOBuf->buf;
04682 
04683        fdflags = fcntl(*fd, F_GETFL);
04684        IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
04685        if (IsNonBlock)
04686               MaxTries =   1000;
04687        else
04688               MaxTries = 100000;
04689 
04690        nBytes -= nRead;
04691        nRead = 0;
04692        while ((nSuccessLess < MaxTries) && 
04693               (nRead < nBytes) &&
04694               (*fd != -1)) {
04695               if (IsNonBlock)
04696               {
04697                      tv.tv_sec = 1;
04698                      tv.tv_usec = 0;
04699               
04700                      FD_ZERO(&rfds);
04701                      FD_SET(*fd, &rfds);
04702                      if (select(*fd + 1, &rfds, NULL, NULL, &tv) == -1) {
04703                             *Error = strerror(errno);
04704                             close (*fd);
04705                             *fd = -1;
04706                             if (*Error == NULL)
04707                                    *Error = ErrRBLF_SelectFailed;
04708                             return -1;
04709                      }
04710                      if (! FD_ISSET(*fd, &rfds) != 0) {
04711                             nSuccessLess ++;
04712                             continue;
04713                      }
04714               }
04715               rlen = read(*fd, 
04716                          ptr,
04717                          IOBuf->BufSize - (ptr - IOBuf->buf));
04718               if (rlen == -1) {
04719                      close(*fd);
04720                      *fd = -1;
04721                      *Error = strerror(errno);
04722                      return rlen;
04723               }
04724               else if (rlen == 0){
04725                      if ((check == NNN_TERM) && 
04726                          (nRead > 5) &&
04727                          (strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0)) 
04728                      {
04729                             StrBufPlain(Blob, HKEY("\n000\n"));
04730                             StrBufCutRight(Blob, 5);
04731                             return Blob->BufUsed;
04732                      }
04733                      else if (!IsNonBlock) 
04734                             nSuccessLess ++;
04735                      else if (nSuccessLess > MaxTries) {
04736                             FlushStrBuf(IOBuf);
04737                             *Error = ErrRBB_too_many_selects;
04738                             return -1;
04739                      }
04740               }
04741               else if (rlen > 0) {
04742                      nSuccessLess = 0;
04743                      nRead += rlen;
04744                      ptr += rlen;
04745                      IOBuf->BufUsed += rlen;
04746               }
04747        }
04748        if (nSuccessLess >= MaxTries) {
04749               FlushStrBuf(IOBuf);
04750               *Error = ErrRBB_too_many_selects;
04751               return -1;
04752        }
04753 
04754        if (nRead > nBytes) {
04755               *Pos = IOBuf->buf + nBytes;
04756        }
04757        Blob->buf[Blob->BufUsed] = '\0';
04758        StrBufAppendBufPlain(Blob, IOBuf->buf, nBytes, 0);
04759        if (*Pos == NULL) {
04760               FlushStrBuf(IOBuf);
04761        }
04762        return nRead + nAlreadyRead;
04763 }
04764 
04774 int StrBufSipLine(StrBuf *LineBuf, const StrBuf *Buf, const char **Ptr)
04775 {
04776        const char *aptr, *ptr, *eptr;
04777        char *optr, *xptr;
04778 
04779        if ((Buf == NULL) ||
04780            (*Ptr == StrBufNOTNULL) ||
04781            (LineBuf == NULL)||
04782            (LineBuf->buf == NULL))
04783        {
04784               *Ptr = StrBufNOTNULL;
04785               return 0;
04786        }
04787 
04788        FlushStrBuf(LineBuf);
04789        if (*Ptr==NULL)
04790               ptr = aptr = Buf->buf;
04791        else
04792               ptr = aptr = *Ptr;
04793 
04794        optr = LineBuf->buf;
04795        eptr = Buf->buf + Buf->BufUsed;
04796        xptr = LineBuf->buf + LineBuf->BufSize - 1;
04797 
04798        while ((ptr <= eptr) && 
04799               (*ptr != '\n') &&
04800               (*ptr != '\r') )
04801        {
04802               *optr = *ptr;
04803               optr++; ptr++;
04804               if (optr == xptr) {
04805                      LineBuf->BufUsed = optr - LineBuf->buf;
04806                      IncreaseBuf(LineBuf,  1, LineBuf->BufUsed + 1);
04807                      optr = LineBuf->buf + LineBuf->BufUsed;
04808                      xptr = LineBuf->buf + LineBuf->BufSize - 1;
04809               }
04810        }
04811 
04812        if ((ptr >= eptr) && (optr > LineBuf->buf))
04813               optr --;
04814        LineBuf->BufUsed = optr - LineBuf->buf;
04815        *optr = '\0';       
04816        if ((ptr <= eptr) && (*ptr == '\r'))
04817               ptr ++;
04818        if ((ptr <= eptr) && (*ptr == '\n'))
04819               ptr ++;
04820        
04821        if (ptr < eptr) {
04822               *Ptr = ptr;
04823        }
04824        else {
04825               *Ptr = StrBufNOTNULL;
04826        }
04827 
04828        return Buf->BufUsed - (ptr - Buf->buf);
04829 }
04830 
04831 
04838 void StrBufStripSlashes(StrBuf *Dir, int RemoveTrailingSlash)
04839 {
04840        char *a, *b;
04841 
04842        a = b = Dir->buf;
04843 
04844        while (!IsEmptyStr(a)) {
04845               if (*a == '/') {
04846                      while (*a == '/')
04847                             a++;
04848                      *b = '/';
04849                      b++;
04850               }
04851               else {
04852                      *b = *a;
04853                      b++; a++;
04854               }
04855        }
04856        if ((RemoveTrailingSlash) &&
04857            (b > Dir->buf) && 
04858            (*(b - 1) == '/')){
04859               b--;
04860        }
04861        *b = '\0';
04862        Dir->BufUsed = b - Dir->buf;
04863 }
04864 
04865