]> code.citadel.org Git - citadel.git/blob - libcitadel/lib/stringbuf.c
* move the pointer forward while selecting.
[citadel.git] / libcitadel / lib / stringbuf.c
1 #include <ctype.h>
2 #include <errno.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <sys/select.h>
8 #include <fcntl.h>
9 #define SHOW_ME_VAPPEND_PRINTF
10 #include <stdarg.h>
11 #include "libcitadel.h"
12
13
14 struct StrBuf {
15         char *buf;
16         long BufSize;
17         long BufUsed;
18         int ConstBuf;
19 };
20
21
22 inline const char *ChrPtr(const StrBuf *Str)
23 {
24         if (Str == NULL)
25                 return "";
26         return Str->buf;
27 }
28
29 inline int StrLength(const StrBuf *Str)
30 {
31         return (Str != NULL) ? Str->BufUsed : 0;
32 }
33
34 StrBuf* NewStrBuf(void)
35 {
36         StrBuf *NewBuf;
37
38         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
39         NewBuf->buf = (char*) malloc(SIZ);
40         NewBuf->buf[0] = '\0';
41         NewBuf->BufSize = SIZ;
42         NewBuf->BufUsed = 0;
43         NewBuf->ConstBuf = 0;
44         return NewBuf;
45 }
46
47 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
48 {
49         StrBuf *NewBuf;
50         
51         if (CopyMe == NULL)
52                 return NewStrBuf();
53
54         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
55         NewBuf->buf = (char*) malloc(CopyMe->BufSize);
56         memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
57         NewBuf->BufUsed = CopyMe->BufUsed;
58         NewBuf->BufSize = CopyMe->BufSize;
59         NewBuf->ConstBuf = 0;
60         return NewBuf;
61 }
62
63 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
64 {
65         StrBuf *NewBuf;
66         size_t Siz = SIZ;
67         size_t CopySize;
68
69         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
70         if (nChars < 0)
71                 CopySize = strlen((ptr != NULL)?ptr:"");
72         else
73                 CopySize = nChars;
74
75         while (Siz <= CopySize)
76                 Siz *= 2;
77
78         NewBuf->buf = (char*) malloc(Siz);
79         NewBuf->BufSize = Siz;
80         if (ptr != NULL) {
81                 memcpy(NewBuf->buf, ptr, CopySize);
82                 NewBuf->buf[CopySize] = '\0';
83                 NewBuf->BufUsed = CopySize;
84         }
85         else {
86                 NewBuf->buf[0] = '\0';
87                 NewBuf->BufUsed = 0;
88         }
89         NewBuf->ConstBuf = 0;
90         return NewBuf;
91 }
92
93
94 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
95 {
96         StrBuf *NewBuf;
97
98         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
99         NewBuf->buf = (char*) StringConstant;
100         NewBuf->BufSize = SizeOfStrConstant;
101         NewBuf->BufUsed = SizeOfStrConstant;
102         NewBuf->ConstBuf = 1;
103         return NewBuf;
104 }
105
106
107 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
108 {
109         char *NewBuf;
110         size_t NewSize = Buf->BufSize * 2;
111
112         if (Buf->ConstBuf)
113                 return -1;
114                 
115         if (DestSize > 0)
116                 while (NewSize < DestSize)
117                         NewSize *= 2;
118
119         NewBuf= (char*) malloc(NewSize);
120         if (KeepOriginal && (Buf->BufUsed > 0))
121         {
122                 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
123         }
124         else
125         {
126                 NewBuf[0] = '\0';
127                 Buf->BufUsed = 0;
128         }
129         free (Buf->buf);
130         Buf->buf = NewBuf;
131         Buf->BufSize *= 2;
132         return Buf->BufSize;
133 }
134
135 int FlushStrBuf(StrBuf *buf)
136 {
137         if (buf->ConstBuf)
138                 return -1;       
139         buf->buf[0] ='\0';
140         buf->BufUsed = 0;
141         return 0;
142 }
143
144 void FreeStrBuf (StrBuf **FreeMe)
145 {
146         if (*FreeMe == NULL)
147                 return;
148         if (!(*FreeMe)->ConstBuf) 
149                 free((*FreeMe)->buf);
150         free(*FreeMe);
151         *FreeMe = NULL;
152 }
153
154 void HFreeStrBuf (void *VFreeMe)
155 {
156         StrBuf *FreeMe = (StrBuf*)VFreeMe;
157         if (FreeMe == NULL)
158                 return;
159         if (!FreeMe->ConstBuf) 
160                 free(FreeMe->buf);
161         free(FreeMe);
162 }
163
164 long StrTol(const StrBuf *Buf)
165 {
166         if(Buf->BufUsed > 0)
167                 return atol(Buf->buf);
168         else
169                 return 0;
170 }
171
172 int StrToi(const StrBuf *Buf)
173 {
174         if(Buf->BufUsed > 0)
175                 return atoi(Buf->buf);
176         else
177                 return 0;
178 }
179
180 long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
181 {
182         if (Buf == NULL)
183                 return -1;
184         if (ptr != NULL)
185                 nThChar = ptr - Buf->buf;
186         if ((nThChar < 0) || (nThChar > Buf->BufUsed))
187                 return -1;
188         Buf->buf[nThChar] = PeekValue;
189         return nThChar;
190 }
191
192
193 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
194 {
195         size_t Siz = Buf->BufSize;
196         size_t CopySize;
197
198         if (nChars < 0)
199                 CopySize = strlen(ptr);
200         else
201                 CopySize = nChars;
202
203         while (Siz <= CopySize)
204                 Siz *= 2;
205
206         if (Siz != Buf->BufSize)
207                 IncreaseBuf(Buf, 0, Siz);
208         memcpy(Buf->buf, ptr, CopySize);
209         Buf->buf[CopySize] = '\0';
210         Buf->BufUsed = CopySize;
211         Buf->ConstBuf = 0;
212         return CopySize;
213 }
214
215 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, size_t Offset)
216 {
217         if ((AppendBuf == NULL) || (Buf == NULL))
218                 return;
219
220         if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed)
221                 IncreaseBuf(Buf, 
222                             (Buf->BufUsed > 0), 
223                             AppendBuf->BufUsed + Buf->BufUsed);
224
225         memcpy(Buf->buf + Buf->BufUsed, 
226                AppendBuf->buf + Offset, 
227                AppendBuf->BufUsed - Offset);
228         Buf->BufUsed += AppendBuf->BufUsed - Offset;
229         Buf->buf[Buf->BufUsed] = '\0';
230 }
231
232
233 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, size_t Offset)
234 {
235         long aps;
236
237         if ((AppendBuf == NULL) || (Buf == NULL))
238                 return;
239
240         if (AppendSize < 0 )
241                 aps = strlen(AppendBuf + Offset);
242         else
243                 aps = AppendSize - Offset;
244
245         if (Buf->BufSize < Buf->BufUsed + aps)
246                 IncreaseBuf(Buf, (Buf->BufUsed > 0), Buf->BufUsed + aps);
247
248         memcpy(Buf->buf + Buf->BufUsed, 
249                AppendBuf + Offset, 
250                aps);
251         Buf->BufUsed += aps;
252         Buf->buf[Buf->BufUsed] = '\0';
253 }
254
255
256 /** 
257  * \brief Escape a string for feeding out as a URL.
258  * \param outbuf the output buffer
259  * \param oblen the size of outbuf to sanitize
260  * \param strbuf the input buffer
261  */
262 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
263 {
264         const char *pch, *pche;
265         char *pt, *pte;
266         int b, c, len;
267         const char ec[] = " +#&;`'|*?-~<>^()[]{}/$\"\\";
268         int eclen = sizeof(ec) -1;
269
270         if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
271                 return;
272         if (PlainIn != NULL) {
273                 len = strlen(PlainIn);
274                 pch = PlainIn;
275                 pche = pch + len;
276         }
277         else {
278                 pch = In->buf;
279                 pche = pch + In->BufUsed;
280                 len = In->BufUsed;
281         }
282
283         if (len == 0) 
284                 return;
285
286         pt = OutBuf->buf + OutBuf->BufUsed;
287         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
288
289         while (pch < pche) {
290                 if (pt >= pte) {
291                         IncreaseBuf(OutBuf, 1, -1);
292                         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
293                         pt = OutBuf->buf + OutBuf->BufUsed;
294                 }
295                 
296                 c = 0;
297                 for (b = 0; b < eclen; ++b) {
298                         if (*pch == ec[b]) {
299                                 c = 1;
300                                 b += eclen;
301                         }
302                 }
303                 if (c == 1) {
304                         sprintf(pt,"%%%02X", *pch);
305                         pt += 3;
306                         OutBuf->BufUsed += 3;
307                         pch ++;
308                 }
309                 else {
310                         *(pt++) = *(pch++);
311                         OutBuf->BufUsed++;
312                 }
313         }
314         *pt = '\0';
315 }
316
317 /*
318  * Copy a string, escaping characters which have meaning in HTML.  
319  *
320  * target               target buffer
321  * strbuf               source buffer
322  * nbsp                 If nonzero, spaces are converted to non-breaking spaces.
323  * nolinebreaks         if set, linebreaks are removed from the string.
324  */
325 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
326 {
327         const char *aptr, *eiptr;
328         char *bptr, *eptr;
329         long len;
330
331         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
332                 return -1;
333
334         if (PlainIn != NULL) {
335                 aptr = PlainIn;
336                 len = strlen(PlainIn);
337                 eiptr = aptr + len;
338         }
339         else {
340                 aptr = Source->buf;
341                 eiptr = aptr + Source->BufUsed;
342                 len = Source->BufUsed;
343         }
344
345         if (len == 0) 
346                 return -1;
347
348         bptr = Target->buf + Target->BufUsed;
349         eptr = Target->buf + Target->BufSize - 6; /* our biggest unit to put in...  */
350
351         while (aptr < eiptr){
352                 if(bptr >= eptr) {
353                         IncreaseBuf(Target, 1, -1);
354                         eptr = Target->buf + Target->BufSize - 6; 
355                         bptr = Target->buf + Target->BufUsed;
356                 }
357                 if (*aptr == '<') {
358                         memcpy(bptr, "&lt;", 4);
359                         bptr += 4;
360                         Target->BufUsed += 4;
361                 }
362                 else if (*aptr == '>') {
363                         memcpy(bptr, "&gt;", 4);
364                         bptr += 4;
365                         Target->BufUsed += 4;
366                 }
367                 else if (*aptr == '&') {
368                         memcpy(bptr, "&amp;", 5);
369                         bptr += 5;
370                         Target->BufUsed += 5;
371                 }
372                 else if (*aptr == '\"') {
373                         memcpy(bptr, "&quot;", 6);
374                         bptr += 6;
375                         Target->BufUsed += 6;
376                 }
377                 else if (*aptr == '\'') {
378                         memcpy(bptr, "&#39;", 5);
379                         bptr += 5;
380                         Target->BufUsed += 5;
381                 }
382                 else if (*aptr == LB) {
383                         *bptr = '<';
384                         bptr ++;
385                         Target->BufUsed ++;
386                 }
387                 else if (*aptr == RB) {
388                         *bptr = '>';
389                         bptr ++;
390                         Target->BufUsed ++;
391                 }
392                 else if (*aptr == QU) {
393                         *bptr ='"';
394                         bptr ++;
395                         Target->BufUsed ++;
396                 }
397                 else if ((*aptr == 32) && (nbsp == 1)) {
398                         memcpy(bptr, "&nbsp;", 6);
399                         bptr += 6;
400                         Target->BufUsed += 6;
401                 }
402                 else if ((*aptr == '\n') && (nolinebreaks)) {
403                         *bptr='\0';     /* nothing */
404                 }
405                 else if ((*aptr == '\r') && (nolinebreaks)) {
406                         *bptr='\0';     /* nothing */
407                 }
408                 else{
409                         *bptr = *aptr;
410                         bptr++;
411                         Target->BufUsed ++;
412                 }
413                 aptr ++;
414         }
415         *bptr = '\0';
416         if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
417                 return -1;
418         return Target->BufUsed;
419 }
420
421 void StrMsgEscAppend(StrBuf *Target, StrBuf *Source, const char *PlainIn)
422 {
423         const char *aptr, *eiptr;
424         char *tptr, *eptr;
425         long len;
426
427         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
428                 return ;
429
430         if (PlainIn != NULL) {
431                 aptr = PlainIn;
432                 len = strlen(PlainIn);
433                 eiptr = aptr + len;
434         }
435         else {
436                 aptr = Source->buf;
437                 eiptr = aptr + Source->BufUsed;
438                 len = Source->BufUsed;
439         }
440
441         if (len == 0) 
442                 return;
443
444         eptr = Target->buf + Target->BufSize - 6; 
445         tptr = Target->buf + Target->BufUsed;
446         
447         while (aptr < eiptr){
448                 if(tptr >= eptr) {
449                         IncreaseBuf(Target, 1, -1);
450                         eptr = Target->buf + Target->BufSize - 6; 
451                         tptr = Target->buf + Target->BufUsed;
452                 }
453                
454                 if (*aptr == '\n') {
455                         *tptr = ' ';
456                         Target->BufUsed++;
457                 }
458                 else if (*aptr == '\r') {
459                         *tptr = ' ';
460                         Target->BufUsed++;
461                 }
462                 else if (*aptr == '\'') {
463                         *(tptr++) = '&';
464                         *(tptr++) = '#';
465                         *(tptr++) = '3';
466                         *(tptr++) = '9';
467                         *tptr = ';';
468                         Target->BufUsed += 5;
469                 } else {
470                         *tptr = *aptr;
471                         Target->BufUsed++;
472                 }
473                 tptr++; aptr++;
474         }
475         *tptr = '\0';
476 }
477
478
479 inline int StrBufNum_tokens(const StrBuf *source, char tok)
480 {
481         return num_tokens(source->buf, tok);
482 }
483
484
485 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
486 {
487         size_t NCharsRemain;
488         if (Offset > Source->BufUsed)
489         {
490                 FlushStrBuf(dest);
491                 return 0;
492         }
493         if (Offset + nChars < Source->BufUsed)
494         {
495                 if (nChars > dest->BufSize)
496                         IncreaseBuf(dest, 0, nChars + 1);
497                 memcpy(dest->buf, Source->buf + Offset, nChars);
498                 dest->BufUsed = nChars;
499                 dest->buf[dest->BufUsed] = '\0';
500                 return nChars;
501         }
502         NCharsRemain = Source->BufUsed - Offset;
503         if (NCharsRemain > dest->BufSize)
504                 IncreaseBuf(dest, 0, NCharsRemain + 1);
505         memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
506         dest->BufUsed = NCharsRemain;
507         dest->buf[dest->BufUsed] = '\0';
508         return NCharsRemain;
509 }
510
511
512 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
513 {
514         va_list apl;
515         size_t BufSize = Buf->BufSize;
516         size_t nWritten = Buf->BufSize + 1;
517         size_t Offset = Buf->BufUsed;
518         size_t newused = Offset + nWritten;
519         
520         while (newused >= BufSize) {
521                 va_copy(apl, ap);
522                 nWritten = vsnprintf(Buf->buf + Offset, 
523                                      Buf->BufSize - Offset, 
524                                      format, apl);
525                 va_end(apl);
526                 newused = Offset + nWritten;
527                 if (newused >= Buf->BufSize) {
528                         IncreaseBuf(Buf, 1, newused);
529                 }
530                 else {
531                         Buf->BufUsed = Offset + nWritten;
532                         BufSize = Buf->BufSize;
533                 }
534
535         }
536 }
537
538 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
539 {
540         size_t BufSize = Buf->BufSize;
541         size_t nWritten = Buf->BufSize + 1;
542         size_t Offset = Buf->BufUsed;
543         size_t newused = Offset + nWritten;
544         va_list arg_ptr;
545         
546         while (newused >= BufSize) {
547                 va_start(arg_ptr, format);
548                 nWritten = vsnprintf(Buf->buf + Buf->BufUsed, 
549                                      Buf->BufSize - Buf->BufUsed, 
550                                      format, arg_ptr);
551                 va_end(arg_ptr);
552                 newused = Buf->BufUsed + nWritten;
553                 if (newused >= Buf->BufSize) {
554                         IncreaseBuf(Buf, 1, newused);
555                 }
556                 else {
557                         Buf->BufUsed += nWritten;
558                         BufSize = Buf->BufSize;
559                 }
560
561         }
562 }
563
564 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
565 {
566         size_t nWritten = Buf->BufSize + 1;
567         va_list arg_ptr;
568         
569         while (nWritten >= Buf->BufSize) {
570                 va_start(arg_ptr, format);
571                 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
572                 va_end(arg_ptr);
573                 Buf->BufUsed = nWritten ;
574                 if (nWritten >= Buf->BufSize)
575                         IncreaseBuf(Buf, 0, 0);
576         }
577 }
578
579
580 /**
581  * \brief a string tokenizer
582  * \param dest Destination StringBuffer
583  * \param Source StringBuffer to read into
584  * \param separator tokenizer param
585  * \returns -1 if not found, else length of token.
586  */
587 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
588 {
589         const char *s, *e;              //* source * /
590         int len = 0;                    //* running total length of extracted string * /
591         int current_token = 0;          //* token currently being processed * /
592
593         if ((Source == NULL) || (Source->BufUsed ==0)) {
594                 return(-1);
595         }
596         s = Source->buf;
597         e = s + Source->BufUsed;
598         if (dest == NULL) {
599                 return(-1);
600         }
601
602         //cit_backtrace();
603         //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
604         dest->buf[0] = '\0';
605         dest->BufUsed = 0;
606
607         while ((s<e) && !IsEmptyStr(s)) {
608                 if (*s == separator) {
609                         ++current_token;
610                 }
611                 if (len >= dest->BufSize)
612                         if (!IncreaseBuf(dest, 1, -1))
613                                 break;
614                 if ( (current_token == parmnum) && 
615                      (*s != separator)) {
616                         dest->buf[len] = *s;
617                         ++len;
618                 }
619                 else if (current_token > parmnum) {
620                         break;
621                 }
622                 ++s;
623         }
624         
625         dest->buf[len] = '\0';
626         dest->BufUsed = len;
627                 
628         if (current_token < parmnum) {
629                 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
630                 return(-1);
631         }
632         //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
633         return(len);
634 }
635
636
637 /*
638  * extract_int()  -  extract an int parm w/o supplying a buffer
639  */
640 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
641 {
642         StrBuf tmp;
643         char buf[64];
644         
645         tmp.buf = buf;
646         buf[0] = '\0';
647         tmp.BufSize = 64;
648         tmp.BufUsed = 0;
649         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
650                 return(atoi(buf));
651         else
652                 return 0;
653 }
654
655 /*
656  * extract_long()  -  extract an long parm w/o supplying a buffer
657  */
658 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
659 {
660         StrBuf tmp;
661         char buf[64];
662         
663         tmp.buf = buf;
664         buf[0] = '\0';
665         tmp.BufSize = 64;
666         tmp.BufUsed = 0;
667         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
668                 return(atoi(buf));
669         else
670                 return 0;
671 }
672
673
674 /*
675  * extract_unsigned_long() - extract an unsigned long parm
676  */
677 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
678 {
679         StrBuf tmp;
680         char buf[64];
681         
682         tmp.buf = buf;
683         buf[0] = '\0';
684         tmp.BufSize = 64;
685         tmp.BufUsed = 0;
686         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
687                 return(atoi(buf));
688         else 
689                 return 0;
690 }
691
692
693
694 /**
695  * \brief Input binary data from socket
696  * \param buf the buffer to get the input to
697  * \param bytes the maximal number of bytes to read
698  */
699 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
700 {
701         int len, rlen, slen;
702
703         if (!append)
704                 FlushStrBuf(buf);
705
706         slen = len = buf->BufUsed;
707         while (1) {
708                 rlen = read(*fd, &buf->buf[len], 1);
709                 if (rlen < 1) {
710                         *Error = strerror(errno);
711                         
712                         close(*fd);
713                         *fd = -1;
714                         
715                         return -1;
716                 }
717                 if (buf->buf[len] == '\n')
718                         break;
719                 if (buf->buf[len] != '\r')
720                         len ++;
721                 if (!(len < buf->BufSize)) {
722                         buf->BufUsed = len;
723                         buf->buf[len+1] = '\0';
724                         IncreaseBuf(buf, 1, -1);
725                 }
726         }
727         buf->BufUsed = len;
728         buf->buf[len] = '\0';
729         return len - slen;
730 }
731
732 /**
733  * \brief Input binary data from socket
734  * \param buf the buffer to get the input to
735  * \param bytes the maximal number of bytes to read
736  */
737 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
738 {
739         fd_set wset;
740         int fdflags;
741         int len, rlen, slen;
742         int nRead = 0;
743         char *ptr;
744
745         if ((Buf == NULL) || (*fd == -1))
746                 return -1;
747         if (!append)
748                 FlushStrBuf(Buf);
749         if (Buf->BufUsed + nBytes > Buf->BufSize)
750                 IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
751
752         ptr = Buf->buf + Buf->BufUsed;
753
754         slen = len = Buf->BufUsed;
755
756         fdflags = fcntl(*fd, F_GETFL);
757
758         while (nRead < nBytes) {
759                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
760                         FD_ZERO(&wset);
761                         FD_SET(*fd, &wset);
762                         if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
763                                 *Error = strerror(errno);
764                                 return -1;
765                         }
766                 }
767
768                 if ((rlen = read(*fd, 
769                                  ptr,
770                                  nBytes - nRead)) == -1) {
771                         close(*fd);
772                         *fd = -1;
773                         *Error = strerror(errno);
774                         return rlen;
775                 }
776                 nRead += rlen;
777                 ptr += rlen;
778                 Buf->BufUsed += rlen;
779         }
780         Buf->buf[Buf->BufUsed] = '\0';
781         return nRead;
782 }
783
784 void StrBufCutLeft(StrBuf *Buf, int nChars)
785 {
786         if (nChars >= Buf->BufUsed) {
787                 FlushStrBuf(Buf);
788                 return;
789         }
790         memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
791         Buf->BufUsed -= nChars;
792         Buf->buf[Buf->BufUsed] = '\0';
793 }
794
795 void StrBufCutRight(StrBuf *Buf, int nChars)
796 {
797         if (nChars >= Buf->BufUsed) {
798                 FlushStrBuf(Buf);
799                 return;
800         }
801         Buf->BufUsed -= nChars;
802         Buf->buf[Buf->BufUsed] = '\0';
803 }
804
805
806 /*
807  * string conversion function
808  */
809 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source) 
810 {
811         int a, b, len;
812         char hex[3];
813
814         if (target != NULL)
815                 FlushStrBuf(target);
816
817         if (source == NULL ||target == NULL)
818         {
819                 return;
820         }
821
822         len = source->BufUsed;
823         for (a = 0; a < len; ++a) {
824                 if (target->BufUsed >= target->BufSize)
825                         IncreaseBuf(target, 1, -1);
826
827                 if (source->buf[a] == '=') {
828                         hex[0] = source->buf[a + 1];
829                         hex[1] = source->buf[a + 2];
830                         hex[2] = 0;
831                         b = 0;
832                         sscanf(hex, "%02x", &b);
833                         target->buf[target->BufUsed] = b;
834                         target->buf[++target->BufUsed] = 0;
835                         a += 2;
836                 }
837                 else {
838                         target->buf[target->BufUsed] = source->buf[a];
839                         target->buf[++target->BufUsed] = 0;
840                 }
841         }
842 }
843
844
845 /*
846  * string conversion function
847  */
848 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source) 
849 {
850         int i, len;
851
852         if (target != NULL)
853                 FlushStrBuf(target);
854
855         if (source == NULL ||target == NULL)
856         {
857                 return;
858         }
859
860         len = source->BufUsed;
861         for (i=0; i<len; ++i) {
862                 if (target->BufUsed + 4 >= target->BufSize)
863                         IncreaseBuf(target, 1, -1);
864                 if ( (isalnum(source->buf[i])) || 
865                      (source->buf[i]=='-') || 
866                      (source->buf[i]=='_') ) {
867                         target->buf[target->BufUsed++] = source->buf[i];
868                 }
869                 else {
870                         sprintf(&target->buf[target->BufUsed], 
871                                 "=%02X", 
872                                 (0xFF &source->buf[i]));
873                         target->BufUsed += 3;
874                 }
875         }
876         target->buf[target->BufUsed + 1] = '\0';
877 }
878
879 /*
880  * \brief uses the same calling syntax as compress2(), but it
881  * creates a stream compatible with HTTP "Content-encoding: gzip"
882  */
883 #ifdef HAVE_ZLIB
884 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
885 #define OS_CODE 0x03    /*< unix */
886 int ZEXPORT compress_gzip(Bytef * dest,         /*< compressed buffer*/
887                           size_t * destLen,     /*< length of the compresed data */
888                           const Bytef * source, /*< source to encode */
889                           uLong sourceLen,      /*< length of source to encode */
890                           int level)            /*< compression level */
891 {
892         const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
893
894         /* write gzip header */
895         snprintf((char *) dest, *destLen, 
896                  "%c%c%c%c%c%c%c%c%c%c",
897                  gz_magic[0], gz_magic[1], Z_DEFLATED,
898                  0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
899                  OS_CODE);
900
901         /* normal deflate */
902         z_stream stream;
903         int err;
904         stream.next_in = (Bytef *) source;
905         stream.avail_in = (uInt) sourceLen;
906         stream.next_out = dest + 10L;   // after header
907         stream.avail_out = (uInt) * destLen;
908         if ((uLong) stream.avail_out != *destLen)
909                 return Z_BUF_ERROR;
910
911         stream.zalloc = (alloc_func) 0;
912         stream.zfree = (free_func) 0;
913         stream.opaque = (voidpf) 0;
914
915         err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
916                            DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
917         if (err != Z_OK)
918                 return err;
919
920         err = deflate(&stream, Z_FINISH);
921         if (err != Z_STREAM_END) {
922                 deflateEnd(&stream);
923                 return err == Z_OK ? Z_BUF_ERROR : err;
924         }
925         *destLen = stream.total_out + 10L;
926
927         /* write CRC and Length */
928         uLong crc = crc32(0L, source, sourceLen);
929         int n;
930         for (n = 0; n < 4; ++n, ++*destLen) {
931                 dest[*destLen] = (int) (crc & 0xff);
932                 crc >>= 8;
933         }
934         uLong len = stream.total_in;
935         for (n = 0; n < 4; ++n, ++*destLen) {
936                 dest[*destLen] = (int) (len & 0xff);
937                 len >>= 8;
938         }
939         err = deflateEnd(&stream);
940         return err;
941 }
942 #endif
943
944
945 /**
946  * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
947  */
948 int CompressBuffer(StrBuf *Buf)
949 {
950 #ifdef HAVE_ZLIB
951         char *compressed_data = NULL;
952         size_t compressed_len, bufsize;
953         
954         bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
955         compressed_data = malloc(compressed_len);
956         
957         if (compress_gzip((Bytef *) compressed_data,
958                           &compressed_len,
959                           (Bytef *) Buf->buf,
960                           (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
961                 if (!ConstBuf)
962                         free(Buf->buf);
963                 Buf->buf = compressed_data;
964                 Buf->BufUsed = compressed_len;
965                 Buf->BufSize = bufsize;
966                 return 1;
967         } else {
968                 free(compressed_data);
969         }
970 #endif  /* HAVE_ZLIB */
971         return 0;
972 }
973
974 int StrBufDecodeBase64(StrBuf *Buf)
975 {
976         char *xferbuf;
977         size_t siz;
978         if (Buf == NULL) return -1;
979
980         xferbuf = (char*) malloc(Buf->BufSize);
981         siz = CtdlDecodeBase64(xferbuf,
982                                Buf->buf,
983                                Buf->BufUsed);
984         free(Buf->buf);
985         Buf->buf = xferbuf;
986         Buf->BufUsed = siz;
987         return siz;
988 }
989
990
991 /*   
992  * remove escaped strings from i.e. the url string (like %20 for blanks)
993  */
994 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
995 {
996         int a, b;
997         char hex[3];
998         long len;
999
1000         while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
1001                 Buf->buf[Buf->BufUsed - 1] = '\0';
1002                 Buf->BufUsed --;
1003         }
1004
1005         a = 0; 
1006         while (a < Buf->BufUsed) {
1007                 if (Buf->buf[a] == '+')
1008                         Buf->buf[a] = ' ';
1009                 else if (Buf->buf[a] == '%') {
1010                         /* don't let % chars through, rather truncate the input. */
1011                         if (a + 2 > Buf->BufUsed) {
1012                                 Buf->buf[a] = '\0';
1013                                 Buf->BufUsed = a;
1014                         }
1015                         else {                  
1016                                 hex[0] = Buf->buf[a + 1];
1017                                 hex[1] = Buf->buf[a + 2];
1018                                 hex[2] = 0;
1019                                 b = 0;
1020                                 sscanf(hex, "%02x", &b);
1021                                 Buf->buf[a] = (char) b;
1022                                 len = Buf->BufUsed - a - 2;
1023                                 if (len > 0)
1024                                         memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
1025                         
1026                                 Buf->BufUsed -=2;
1027                         }
1028                 }
1029                 a++;
1030         }
1031         return a;
1032 }
1033
1034
1035 /**
1036  * \brief       RFC2047-encode a header field if necessary.
1037  *              If no non-ASCII characters are found, the string
1038  *              will be copied verbatim without encoding.
1039  *
1040  * \param       target          Target buffer.
1041  * \param       source          Source string to be encoded.
1042  * \returns     encoded length; -1 if non success.
1043  */
1044 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
1045 {
1046         const char headerStr[] = "=?UTF-8?Q?";
1047         int need_to_encode = 0;
1048         int i = 0;
1049         unsigned char ch;
1050
1051         if ((source == NULL) || 
1052             (target == NULL))
1053             return -1;
1054
1055         while ((i < source->BufUsed) &&
1056                (!IsEmptyStr (&source->buf[i])) &&
1057                (need_to_encode == 0)) {
1058                 if (((unsigned char) source->buf[i] < 32) || 
1059                     ((unsigned char) source->buf[i] > 126)) {
1060                         need_to_encode = 1;
1061                 }
1062                 i++;
1063         }
1064
1065         if (!need_to_encode) {
1066                 if (*target == NULL) {
1067                         *target = NewStrBufPlain(source->buf, source->BufUsed);
1068                 }
1069                 else {
1070                         FlushStrBuf(*target);
1071                         StrBufAppendBuf(*target, source, 0);
1072                 }
1073                 return (*target)->BufUsed;
1074         }
1075         if (*target == NULL)
1076                 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
1077         else if (sizeof(headerStr) + source->BufUsed > (*target)->BufSize)
1078                 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
1079         memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
1080         (*target)->BufUsed = sizeof(headerStr) - 1;
1081         for (i=0; (i < source->BufUsed); ++i) {
1082                 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1083                         IncreaseBuf(*target, 1, 0);
1084                 ch = (unsigned char) source->buf[i];
1085                 if ((ch < 32) || (ch > 126) || (ch == 61)) {
1086                         sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
1087                         (*target)->BufUsed += 3;
1088                 }
1089                 else {
1090                         (*target)->buf[(*target)->BufUsed] = ch;
1091                         (*target)->BufUsed++;
1092                 }
1093         }
1094         
1095         if ((*target)->BufUsed + 4 > (*target)->BufSize)
1096                 IncreaseBuf(*target, 1, 0);
1097
1098         (*target)->buf[(*target)->BufUsed++] = '?';
1099         (*target)->buf[(*target)->BufUsed++] = '=';
1100         (*target)->buf[(*target)->BufUsed] = '\0';
1101         return (*target)->BufUsed;;
1102 }
1103
1104 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
1105 {
1106         long i;
1107         if (buf == NULL)
1108                 return;
1109         for (i=0; i<buf->BufUsed; i++)
1110                 if (buf->buf[i] == search)
1111                         buf->buf[i] = replace;
1112
1113 }