]> code.citadel.org Git - citadel.git/blob - libcitadel/lib/stringbuf.c
* provide a strbuf version of the webcit escapers
[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)
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         pt = OutBuf->buf + OutBuf->BufUsed;
284         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
285
286         while (pch < pche) {
287                 if (pt >= pte) {
288                         IncreaseBuf(OutBuf, 1, -1);
289                         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
290                 }
291                 
292                 c = 0;
293                 for (b = 0; b < eclen; ++b) {
294                         if (*pch == ec[b]) {
295                                 c = 1;
296                                 b += eclen;
297                         }
298                 }
299                 if (c == 1) {
300                         snprintf(pt, pt - pte, "%%%02x", *pch);
301                         pt += 3;
302                         OutBuf->BufUsed += 3;
303                 }
304                 else {
305                         *(pt++) = *(pch++);
306                         OutBuf->BufUsed++;
307                 }
308         }
309         *pt = '\0';
310 }
311
312 /*
313  * Copy a string, escaping characters which have meaning in HTML.  
314  *
315  * target               target buffer
316  * strbuf               source buffer
317  * nbsp                 If nonzero, spaces are converted to non-breaking spaces.
318  * nolinebreaks         if set, linebreaks are removed from the string.
319  */
320 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
321 {
322         const char *aptr, *eiptr;
323         char *bptr, *eptr;
324         long len;
325
326         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
327                 return -1;
328
329         if (PlainIn != NULL) {
330                 aptr = PlainIn;
331                 len = strlen(PlainIn);
332                 eiptr = aptr + len;
333         }
334         else {
335                 aptr = Source->buf;
336                 eiptr = aptr + Source->BufUsed;
337                 len = Source->BufUsed;
338         }
339
340         bptr = Target->buf + Target->BufUsed;
341         eptr = Target->buf + Target->BufSize - 6; /* our biggest unit to put in...  */
342
343         while (aptr < eiptr){
344                 if(bptr >= eptr) {
345                         IncreaseBuf(Target, 1, -1);
346                         eptr = Target->buf + Target->BufSize - 6; 
347                 }
348                 if (*aptr == '<') {
349                         memcpy(bptr, "&lt;", 4);
350                         bptr += 4;
351                         Target->BufUsed += 4;
352                 }
353                 else if (*aptr == '>') {
354                         memcpy(bptr, "&gt;", 4);
355                         bptr += 4;
356                         Target->BufUsed += 4;
357                 }
358                 else if (*aptr == '&') {
359                         memcpy(bptr, "&amp;", 5);
360                         bptr += 5;
361                         Target->BufUsed += 5;
362                 }
363                 else if (*aptr == '\"') {
364                         memcpy(bptr, "&quot;", 6);
365                         bptr += 6;
366                         Target->BufUsed += 6;
367                 }
368                 else if (*aptr == '\'') {
369                         memcpy(bptr, "&#39;", 5);
370                         bptr += 5;
371                         Target->BufUsed += 5;
372                 }
373                 else if (*aptr == LB) {
374                         *bptr = '<';
375                         bptr ++;
376                         Target->BufUsed ++;
377                 }
378                 else if (*aptr == RB) {
379                         *bptr = '>';
380                         bptr ++;
381                         Target->BufUsed ++;
382                 }
383                 else if (*aptr == QU) {
384                         *bptr ='"';
385                         bptr ++;
386                         Target->BufUsed ++;
387                 }
388                 else if ((*aptr == 32) && (nbsp == 1)) {
389                         memcpy(bptr, "&nbsp;", 6);
390                         bptr += 6;
391                         Target->BufUsed += 6;
392                 }
393                 else if ((*aptr == '\n') && (nolinebreaks)) {
394                         *bptr='\0';     /* nothing */
395                 }
396                 else if ((*aptr == '\r') && (nolinebreaks)) {
397                         *bptr='\0';     /* nothing */
398                 }
399                 else{
400                         *bptr = *aptr;
401                         bptr++;
402                         Target->BufUsed ++;
403                 }
404                 aptr ++;
405         }
406         *bptr = '\0';
407         if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
408                 return -1;
409         return Target->BufUsed;
410 }
411
412 inline int StrBufNum_tokens(const StrBuf *source, char tok)
413 {
414         return num_tokens(source->buf, tok);
415 }
416
417
418 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
419 {
420         size_t NCharsRemain;
421         if (Offset > Source->BufUsed)
422         {
423                 FlushStrBuf(dest);
424                 return 0;
425         }
426         if (Offset + nChars < Source->BufUsed)
427         {
428                 if (nChars > dest->BufSize)
429                         IncreaseBuf(dest, 0, nChars + 1);
430                 memcpy(dest->buf, Source->buf + Offset, nChars);
431                 dest->BufUsed = nChars;
432                 dest->buf[dest->BufUsed] = '\0';
433                 return nChars;
434         }
435         NCharsRemain = Source->BufUsed - Offset;
436         if (NCharsRemain > dest->BufSize)
437                 IncreaseBuf(dest, 0, NCharsRemain + 1);
438         memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
439         dest->BufUsed = NCharsRemain;
440         dest->buf[dest->BufUsed] = '\0';
441         return NCharsRemain;
442 }
443
444
445 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
446 {
447         size_t nWritten = Buf->BufSize + 1;
448         size_t Offset = Buf->BufUsed;
449         size_t newused = Offset + nWritten;
450         
451         while (newused >= Buf->BufSize) {
452                 nWritten = vsnprintf(Buf->buf + Offset, 
453                                      Buf->BufSize - Offset, 
454                                      format, ap);
455                 newused = Offset + nWritten;
456                 if (newused >= Buf->BufSize)
457                         IncreaseBuf(Buf, 1, 0);
458                 else
459                         Buf->BufUsed = Offset + nWritten ;
460
461         }
462 }
463
464 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
465 {
466         size_t nWritten = Buf->BufSize + 1;
467         size_t Offset = Buf->BufUsed;
468         size_t newused = Offset + nWritten;
469         va_list arg_ptr;
470         
471         while (newused >= Buf->BufSize) {
472                 va_start(arg_ptr, format);
473                 nWritten = vsnprintf(Buf->buf + Offset, 
474                                      Buf->BufSize - Offset, 
475                                      format, arg_ptr);
476                 va_end(arg_ptr);
477                 newused = Offset + nWritten;
478                 if (newused >= Buf->BufSize)
479                         IncreaseBuf(Buf, 1, 0);
480                 else
481                         Buf->BufUsed = Offset + nWritten ;
482
483         }
484 }
485
486 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
487 {
488         size_t nWritten = Buf->BufSize + 1;
489         va_list arg_ptr;
490         
491         while (nWritten >= Buf->BufSize) {
492                 va_start(arg_ptr, format);
493                 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
494                 va_end(arg_ptr);
495                 Buf->BufUsed = nWritten ;
496                 if (nWritten >= Buf->BufSize)
497                         IncreaseBuf(Buf, 0, 0);
498         }
499 }
500
501
502 /**
503  * \brief a string tokenizer
504  * \param dest Destination StringBuffer
505  * \param Source StringBuffer to read into
506  * \param separator tokenizer param
507  * \returns -1 if not found, else length of token.
508  */
509 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
510 {
511         const char *s, *e;              //* source * /
512         int len = 0;                    //* running total length of extracted string * /
513         int current_token = 0;          //* token currently being processed * /
514
515         if ((Source == NULL) || (Source->BufUsed ==0)) {
516                 return(-1);
517         }
518         s = Source->buf;
519         e = s + Source->BufUsed;
520         if (dest == NULL) {
521                 return(-1);
522         }
523
524         //cit_backtrace();
525         //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
526         dest->buf[0] = '\0';
527         dest->BufUsed = 0;
528
529         while ((s<e) && !IsEmptyStr(s)) {
530                 if (*s == separator) {
531                         ++current_token;
532                 }
533                 if (len >= dest->BufSize)
534                         if (!IncreaseBuf(dest, 1, -1))
535                                 break;
536                 if ( (current_token == parmnum) && 
537                      (*s != separator)) {
538                         dest->buf[len] = *s;
539                         ++len;
540                 }
541                 else if (current_token > parmnum) {
542                         break;
543                 }
544                 ++s;
545         }
546         
547         dest->buf[len] = '\0';
548         dest->BufUsed = len;
549                 
550         if (current_token < parmnum) {
551                 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
552                 return(-1);
553         }
554         //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
555         return(len);
556 }
557
558
559 /*
560  * extract_int()  -  extract an int parm w/o supplying a buffer
561  */
562 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
563 {
564         StrBuf tmp;
565         char buf[64];
566         
567         tmp.buf = buf;
568         buf[0] = '\0';
569         tmp.BufSize = 64;
570         tmp.BufUsed = 0;
571         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
572                 return(atoi(buf));
573         else
574                 return 0;
575 }
576
577 /*
578  * extract_long()  -  extract an long parm w/o supplying a buffer
579  */
580 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
581 {
582         StrBuf tmp;
583         char buf[64];
584         
585         tmp.buf = buf;
586         buf[0] = '\0';
587         tmp.BufSize = 64;
588         tmp.BufUsed = 0;
589         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
590                 return(atoi(buf));
591         else
592                 return 0;
593 }
594
595
596 /*
597  * extract_unsigned_long() - extract an unsigned long parm
598  */
599 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
600 {
601         StrBuf tmp;
602         char buf[64];
603         
604         tmp.buf = buf;
605         buf[0] = '\0';
606         tmp.BufSize = 64;
607         tmp.BufUsed = 0;
608         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
609                 return(atoi(buf));
610         else 
611                 return 0;
612 }
613
614
615
616 /**
617  * \brief Input binary data from socket
618  * \param buf the buffer to get the input to
619  * \param bytes the maximal number of bytes to read
620  */
621 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
622 {
623         int len, rlen, slen;
624
625         if (!append)
626                 FlushStrBuf(buf);
627
628         slen = len = buf->BufUsed;
629         while (1) {
630                 rlen = read(*fd, &buf->buf[len], 1);
631                 if (rlen < 1) {
632                         *Error = strerror(errno);
633                         
634                         close(*fd);
635                         *fd = -1;
636                         
637                         return -1;
638                 }
639                 if (buf->buf[len] == '\n')
640                         break;
641                 if (buf->buf[len] != '\r')
642                         len ++;
643                 if (!(len < buf->BufSize)) {
644                         buf->BufUsed = len;
645                         buf->buf[len+1] = '\0';
646                         IncreaseBuf(buf, 1, -1);
647                 }
648         }
649         buf->BufUsed = len;
650         buf->buf[len] = '\0';
651         return len - slen;
652 }
653
654 /**
655  * \brief Input binary data from socket
656  * \param buf the buffer to get the input to
657  * \param bytes the maximal number of bytes to read
658  */
659 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
660 {
661         fd_set wset;
662         int fdflags;
663         int len, rlen, slen;
664         int nRead = 0;
665         char *ptr;
666
667         if ((Buf == NULL) || (*fd == -1))
668                 return -1;
669         if (!append)
670                 FlushStrBuf(Buf);
671         if (Buf->BufUsed + nBytes > Buf->BufSize)
672                 IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
673
674         ptr = Buf->buf + Buf->BufUsed;
675
676         slen = len = Buf->BufUsed;
677
678         fdflags = fcntl(*fd, F_GETFL);
679
680         while (nRead < nBytes) {
681                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
682                         FD_ZERO(&wset);
683                         FD_SET(*fd, &wset);
684                         if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
685                                 *Error = strerror(errno);
686                                 return -1;
687                         }
688                 }
689
690                 if ((rlen = read(*fd, 
691                                  ptr,
692                                  nBytes - nRead)) == -1) {
693                         close(*fd);
694                         *fd = -1;
695                         *Error = strerror(errno);
696                         return rlen;
697                 }
698                 nRead += rlen;
699                 Buf->BufUsed += rlen;
700         }
701         Buf->buf[Buf->BufUsed] = '\0';
702         return nRead;
703 }
704
705 void StrBufCutLeft(StrBuf *Buf, int nChars)
706 {
707         if (nChars >= Buf->BufUsed) {
708                 FlushStrBuf(Buf);
709                 return;
710         }
711         memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
712         Buf->BufUsed -= nChars;
713         Buf->buf[Buf->BufUsed] = '\0';
714 }
715
716 void StrBufCutRight(StrBuf *Buf, int nChars)
717 {
718         if (nChars >= Buf->BufUsed) {
719                 FlushStrBuf(Buf);
720                 return;
721         }
722         Buf->BufUsed -= nChars;
723         Buf->buf[Buf->BufUsed] = '\0';
724 }
725
726
727 /*
728  * string conversion function
729  */
730 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source) 
731 {
732         int a, b, len;
733         char hex[3];
734
735         if (target != NULL)
736                 FlushStrBuf(target);
737
738         if (source == NULL ||target == NULL)
739         {
740                 return;
741         }
742
743         len = source->BufUsed;
744         for (a = 0; a < len; ++a) {
745                 if (target->BufUsed >= target->BufSize)
746                         IncreaseBuf(target, 1, -1);
747
748                 if (source->buf[a] == '=') {
749                         hex[0] = source->buf[a + 1];
750                         hex[1] = source->buf[a + 2];
751                         hex[2] = 0;
752                         b = 0;
753                         sscanf(hex, "%02x", &b);
754                         target->buf[target->BufUsed] = b;
755                         target->buf[++target->BufUsed] = 0;
756                         a += 2;
757                 }
758                 else {
759                         target->buf[target->BufUsed] = source->buf[a];
760                         target->buf[++target->BufUsed] = 0;
761                 }
762         }
763 }
764
765
766 /*
767  * string conversion function
768  */
769 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source) 
770 {
771         int i, len;
772
773         if (target != NULL)
774                 FlushStrBuf(target);
775
776         if (source == NULL ||target == NULL)
777         {
778                 return;
779         }
780
781         len = source->BufUsed;
782         for (i=0; i<len; ++i) {
783                 if (target->BufUsed + 4 >= target->BufSize)
784                         IncreaseBuf(target, 1, -1);
785                 if ( (isalnum(source->buf[i])) || 
786                      (source->buf[i]=='-') || 
787                      (source->buf[i]=='_') ) {
788                         target->buf[target->BufUsed++] = source->buf[i];
789                 }
790                 else {
791                         sprintf(&target->buf[target->BufUsed], 
792                                 "=%02X", 
793                                 (0xFF &source->buf[i]));
794                         target->BufUsed += 3;
795                 }
796         }
797         target->buf[target->BufUsed + 1] = '\0';
798 }
799
800 /*
801  * \brief uses the same calling syntax as compress2(), but it
802  * creates a stream compatible with HTTP "Content-encoding: gzip"
803  */
804 #ifdef HAVE_ZLIB
805 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
806 #define OS_CODE 0x03    /*< unix */
807 int ZEXPORT compress_gzip(Bytef * dest,         /*< compressed buffer*/
808                           size_t * destLen,     /*< length of the compresed data */
809                           const Bytef * source, /*< source to encode */
810                           uLong sourceLen,      /*< length of source to encode */
811                           int level)            /*< compression level */
812 {
813         const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
814
815         /* write gzip header */
816         snprintf((char *) dest, *destLen, 
817                  "%c%c%c%c%c%c%c%c%c%c",
818                  gz_magic[0], gz_magic[1], Z_DEFLATED,
819                  0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
820                  OS_CODE);
821
822         /* normal deflate */
823         z_stream stream;
824         int err;
825         stream.next_in = (Bytef *) source;
826         stream.avail_in = (uInt) sourceLen;
827         stream.next_out = dest + 10L;   // after header
828         stream.avail_out = (uInt) * destLen;
829         if ((uLong) stream.avail_out != *destLen)
830                 return Z_BUF_ERROR;
831
832         stream.zalloc = (alloc_func) 0;
833         stream.zfree = (free_func) 0;
834         stream.opaque = (voidpf) 0;
835
836         err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
837                            DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
838         if (err != Z_OK)
839                 return err;
840
841         err = deflate(&stream, Z_FINISH);
842         if (err != Z_STREAM_END) {
843                 deflateEnd(&stream);
844                 return err == Z_OK ? Z_BUF_ERROR : err;
845         }
846         *destLen = stream.total_out + 10L;
847
848         /* write CRC and Length */
849         uLong crc = crc32(0L, source, sourceLen);
850         int n;
851         for (n = 0; n < 4; ++n, ++*destLen) {
852                 dest[*destLen] = (int) (crc & 0xff);
853                 crc >>= 8;
854         }
855         uLong len = stream.total_in;
856         for (n = 0; n < 4; ++n, ++*destLen) {
857                 dest[*destLen] = (int) (len & 0xff);
858                 len >>= 8;
859         }
860         err = deflateEnd(&stream);
861         return err;
862 }
863 #endif
864
865
866 /**
867  * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
868  */
869 int CompressBuffer(StrBuf *Buf)
870 {
871 #ifdef HAVE_ZLIB
872         char *compressed_data = NULL;
873         size_t compressed_len, bufsize;
874         
875         bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
876         compressed_data = malloc(compressed_len);
877         
878         if (compress_gzip((Bytef *) compressed_data,
879                           &compressed_len,
880                           (Bytef *) Buf->buf,
881                           (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
882                 if (!ConstBuf)
883                         free(Buf->buf);
884                 Buf->buf = compressed_data;
885                 Buf->BufUsed = compressed_len;
886                 Buf->BufSize = bufsize;
887                 return 1;
888         } else {
889                 free(compressed_data);
890         }
891 #endif  /* HAVE_ZLIB */
892         return 0;
893 }
894
895 int StrBufDecodeBase64(StrBuf *Buf)
896 {
897         char *xferbuf;
898         size_t siz;
899         if (Buf == NULL) return -1;
900
901         xferbuf = (char*) malloc(Buf->BufSize);
902         siz = CtdlDecodeBase64(xferbuf,
903                                Buf->buf,
904                                Buf->BufUsed);
905         free(Buf->buf);
906         Buf->buf = xferbuf;
907         Buf->BufUsed = siz;
908         return siz;
909 }
910
911
912 /*   
913  * remove escaped strings from i.e. the url string (like %20 for blanks)
914  */
915 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
916 {
917         int a, b;
918         char hex[3];
919         long len;
920
921         while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
922                 Buf->buf[Buf->BufUsed - 1] = '\0';
923                 Buf->BufUsed --;
924         }
925
926         a = 0; 
927         while (a < Buf->BufUsed) {
928                 if (Buf->buf[a] == '+')
929                         Buf->buf[a] = ' ';
930                 else if (Buf->buf[a] == '%') {
931                         /* don't let % chars through, rather truncate the input. */
932                         if (a + 2 > Buf->BufUsed) {
933                                 Buf->buf[a] = '\0';
934                                 Buf->BufUsed = a;
935                         }
936                         else {                  
937                                 hex[0] = Buf->buf[a + 1];
938                                 hex[1] = Buf->buf[a + 2];
939                                 hex[2] = 0;
940                                 b = 0;
941                                 sscanf(hex, "%02x", &b);
942                                 Buf->buf[a] = (char) b;
943                                 len = Buf->BufUsed - a - 2;
944                                 if (len > 0)
945                                         memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
946                         
947                                 Buf->BufUsed -=2;
948                         }
949                 }
950                 a++;
951         }
952         return a;
953 }
954
955
956 /**
957  * \brief       RFC2047-encode a header field if necessary.
958  *              If no non-ASCII characters are found, the string
959  *              will be copied verbatim without encoding.
960  *
961  * \param       target          Target buffer.
962  * \param       source          Source string to be encoded.
963  * \returns     encoded length; -1 if non success.
964  */
965 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
966 {
967         const char headerStr[] = "=?UTF-8?Q?";
968         int need_to_encode = 0;
969         int i = 0;
970         unsigned char ch;
971
972         if ((source == NULL) || 
973             (target == NULL))
974             return -1;
975
976         while ((i < source->BufUsed) &&
977                (!IsEmptyStr (&source->buf[i])) &&
978                (need_to_encode == 0)) {
979                 if (((unsigned char) source->buf[i] < 32) || 
980                     ((unsigned char) source->buf[i] > 126)) {
981                         need_to_encode = 1;
982                 }
983                 i++;
984         }
985
986         if (!need_to_encode) {
987                 if (*target == NULL) {
988                         *target = NewStrBufPlain(source->buf, source->BufUsed);
989                 }
990                 else {
991                         FlushStrBuf(*target);
992                         StrBufAppendBuf(*target, source, 0);
993                 }
994                 return (*target)->BufUsed;
995         }
996         if (*target == NULL)
997                 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
998         else if (sizeof(headerStr) + source->BufUsed > (*target)->BufSize)
999                 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
1000         memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
1001         (*target)->BufUsed = sizeof(headerStr) - 1;
1002         for (i=0; (i < source->BufUsed); ++i) {
1003                 if ((*target)->BufUsed + 4 > (*target)->BufSize)
1004                         IncreaseBuf(*target, 1, 0);
1005                 ch = (unsigned char) source->buf[i];
1006                 if ((ch < 32) || (ch > 126) || (ch == 61)) {
1007                         sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
1008                         (*target)->BufUsed += 3;
1009                 }
1010                 else {
1011                         (*target)->buf[(*target)->BufUsed] = ch;
1012                         (*target)->BufUsed++;
1013                 }
1014         }
1015         
1016         if ((*target)->BufUsed + 4 > (*target)->BufSize)
1017                 IncreaseBuf(*target, 1, 0);
1018
1019         (*target)->buf[(*target)->BufUsed++] = '?';
1020         (*target)->buf[(*target)->BufUsed++] = '=';
1021         (*target)->buf[(*target)->BufUsed] = '\0';
1022         return (*target)->BufUsed;;
1023 }
1024
1025 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
1026 {
1027         long i;
1028         if (buf == NULL)
1029                 return;
1030         for (i=0; i<buf->BufUsed; i++)
1031                 if (buf->buf[i] == search)
1032                         buf->buf[i] = replace;
1033
1034 }