1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/stream.c,v 1.6 2011/05/16 16:21:59 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_STREAM_C_
22 
23 #include "tgifdefs.h"
24 
25 #include "dialog.e"
26 #include "drawing.e"
27 #include "file.e"
28 #include "http.e"
29 #include "import.e"
30 #include "menu.e"
31 #include "move.e"
32 #include "msg.e"
33 #include "navigate.e"
34 #include "obj.e"
35 #include "remote.e"
36 #include "setup.e"
37 #include "stream.e"
38 #include "strtbl.e"
39 #include "util.e"
40 
41 static int gnMultipartReplace=FALSE;
42 static int gnPossibleMultipartReplace=TRUE;
43 
44 static int gnJustLF=0;
45 static int gnHeaderLen=0;
46 static int gnStartIndex=0;
47 static int gnBoundaryLen=0;
48 
49 static char *gpszBoundary=NULL;
50 
51 static struct ObjRec *gpVideoObj=NULL;
52 
53 static char **gaszFilterForContentType=NULL;
54 static int gnMaxStreamFilters=0;
55 
56 static
CleanUpFilter()57 void CleanUpFilter()
58 {
59    if (gaszFilterForContentType != NULL) {
60       int i=0;
61 
62       for (i=0; i < (gnMaxStreamFilters<<1); i++) {
63          UtilFree(gaszFilterForContentType[i]);
64          UtilFree(gaszFilterForContentType[++i]);
65       }
66       free(gaszFilterForContentType);
67    }
68    gaszFilterForContentType = NULL;
69    gnMaxStreamFilters = 0;
70 }
71 
72 static
InitFilter()73 void InitFilter()
74 {
75    char *c_ptr=NULL;
76    int max_filters=0;
77 
78    if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"MaxStreamFilters")) != NULL) {
79       max_filters = atoi(c_ptr);
80       if (max_filters <= 0) {
81          sprintf(gszMsgBox, TgLoadString(STID_BAD_XDEF_MUST_BE_GT_0),
82                TOOL_NAME, "MaxStreamFilters", c_ptr);
83          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
84       }
85    }
86    gnMaxStreamFilters = 0;
87    if (max_filters > 0) {
88       int i=0;
89 
90       gaszFilterForContentType =
91             (char**)malloc(((max_filters<<1)+1)*sizeof(char*));
92       if (gaszFilterForContentType == NULL) FailAllocMessage();
93       memset(gaszFilterForContentType, 0, ((max_filters<<1)+1)*sizeof(char*));
94       for (i=0; i < max_filters; i++) {
95          char buf[80];
96 
97          sprintf(buf, "StreamFilter%1d", i);
98          if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,buf)) == NULL) {
99             sprintf(gszMsgBox, TgLoadString(STID_CANT_FIND_XDEF), TOOL_NAME,
100                   buf);
101             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
102             max_filters = i;
103             break;
104          } else {
105             char *psz=strchr(c_ptr, ':');
106             int index=(i<<1);
107 
108             if (psz == NULL) {
109                sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF), TOOL_NAME,
110                      buf, c_ptr);
111                MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
112                max_filters = i;
113                break;
114             }
115             *psz++ = '\0';
116             gaszFilterForContentType[index] = UtilStrDup(c_ptr);
117             gaszFilterForContentType[index+1] = UtilStrDup(psz);
118             if (gaszFilterForContentType[index] == NULL ||
119                   gaszFilterForContentType[index+1] == NULL) {
120                FailAllocMessage();
121             }
122             UtilTrimBlanks(gaszFilterForContentType[index]);
123             UtilTrimBlanks(gaszFilterForContentType[index+1]);
124          }
125       }
126       if (max_filters == 0) {
127          free(gaszFilterForContentType);
128          gaszFilterForContentType = NULL;
129       }
130    }
131    gnMaxStreamFilters = max_filters;
132 }
133 
CleanUpMime()134 void CleanUpMime()
135 {
136    gnMultipartReplace = FALSE;
137    gnPossibleMultipartReplace = TRUE;
138    gnJustLF = gnHeaderLen = gnStartIndex = gnBoundaryLen = 0;
139    UtilFree(gpszBoundary);
140    gpszBoundary = NULL;
141    if (gpVideoObj != NULL) {
142       UnlinkObj(gpVideoObj);
143       FreeObj(gpVideoObj);
144    }
145    gpVideoObj = NULL;
146    CleanUpFilter();
147 }
148 
InitMime()149 void InitMime()
150 {
151    gnMultipartReplace = FALSE;
152    gnPossibleMultipartReplace = TRUE;
153    gnJustLF = gnHeaderLen = gnStartIndex = gnBoundaryLen = 0;
154    gpszBoundary = NULL;
155    gpVideoObj = NULL;
156    InitFilter();
157 }
158 
ResetMultipartReplace(redraw)159 void ResetMultipartReplace(redraw)
160    int redraw;
161 {
162    gnMultipartReplace = FALSE;
163    gnPossibleMultipartReplace = TRUE;
164    gnJustLF = gnHeaderLen = gnStartIndex = gnBoundaryLen = 0;
165    UtilFree(gpszBoundary);
166    gpszBoundary = NULL;
167    if (gpVideoObj != NULL) {
168       UnlinkObj(gpVideoObj);
169       FreeObj(gpVideoObj);
170       if (redraw) {
171          ClearAndRedrawDrawWindow();
172       }
173    }
174    gpVideoObj = NULL;
175 }
176 
IsJustLF(buf)177 int IsJustLF(buf)
178    char *buf;
179 {
180    char *first_lf=strchr(buf, '\n');
181 
182    if (first_lf == NULL) return TRUE;
183    if (first_lf == buf) return TRUE;
184    --first_lf;
185    return (*first_lf != '\r');
186 }
187 
GetHeaderLine(psz_start,just_lf)188 char *GetHeaderLine(psz_start, just_lf)
189    char *psz_start;
190    int just_lf;
191 {
192    if (just_lf) {
193       return strchr(psz_start, '\n');
194    } else {
195       return strstr(psz_start, "\r\n");
196    }
197 }
198 
199 static char *gppszValidMultipartReplace[] = {
200     "multipart/x-mixed-replace",  /* only knows about JPEG movie */
201     NULL
202 };
203 
204 static
ValidMultipartReplace(buf,pn_multipart)205 int ValidMultipartReplace(buf, pn_multipart)
206    char *buf;
207    int *pn_multipart;
208 {
209    char *psz=NULL, *psz_copy=UtilStrDup(buf);
210    char **ppsz=NULL;
211 
212    *pn_multipart = FALSE;
213 
214    if (psz_copy == NULL) FailAllocMessage();
215    UtilTrimBlanks(psz_copy);
216    psz = strchr(psz_copy, '/');
217    if (psz != NULL) {
218       *psz = '\0';
219       if (UtilStrICmp(psz_copy, "multipart") == 0) {
220          *pn_multipart = TRUE;
221       }
222       *psz = '/';
223    } else {
224       UtilFree(psz_copy);
225       return FALSE;
226    }
227    for (ppsz=gppszValidMultipartReplace; *ppsz != NULL; ppsz++) {
228       if (UtilStrICmp(*ppsz, psz_copy) == 0) {
229          UtilFree(psz_copy);
230          return TRUE;
231       }
232    }
233    UtilFree(psz_copy);
234    return FALSE;
235 }
236 
237 static char *gppszValidImageContentType[] = {
238     "image/jpeg", "JPEG-dither", /* JPEG movie or Motion JPEG */
239     "image/jpg", "JPEG-dither", /* JPEG movie or Motion JPEG */
240     "image/png", "PNG-dither", /* Netscape Server Push */
241     NULL
242 };
243 
244 static
ValidImageContentType(buf,ppsz_filter)245 int ValidImageContentType(buf, ppsz_filter)
246    char *buf, **ppsz_filter;
247 {
248    char *psz_copy=UtilStrDup(buf);
249    char **ppsz=NULL;
250 
251    if (psz_copy == NULL) FailAllocMessage();
252    UtilTrimBlanks(psz_copy);
253    ppsz = (gaszFilterForContentType==NULL ? gppszValidImageContentType:
254          gaszFilterForContentType);
255    for ( ; *ppsz != NULL; ppsz++) {
256       if (UtilStrICmp(*ppsz, psz_copy) == 0) {
257          if (ppsz_filter != NULL) *ppsz_filter = ppsz[1];
258          UtilFree(psz_copy);
259          return TRUE;
260       }
261       ppsz++;
262    }
263    if (UtilStrICmp(psz_copy, "text/html") == 0) {
264       if (ppsz_filter != NULL) *ppsz_filter = NULL;
265       UtilFree(psz_copy);
266       return TRUE;
267    }
268    UtilFree(psz_copy);
269    return FALSE;
270 }
271 
272 static
UpdateBoundary(buf)273 void UpdateBoundary(buf)
274    char *buf;
275 {
276    UtilFree(gpszBoundary);
277    gpszBoundary = (char*)malloc(strlen(buf)+3);
278    if (gpszBoundary == NULL) FailAllocMessage();
279    sprintf(gpszBoundary, "--%s", buf);
280    UtilTrimBlanks(gpszBoundary);
281    if (*gpszBoundary == '"') {
282       int len=strlen(gpszBoundary);
283 
284       if (len > 2 && gpszBoundary[len-1] == '"') {
285          char *psz=gpszBoundary, *psz1=(&gpszBoundary[1]);
286 
287          gpszBoundary[--len] = '\0';
288          while (*psz1 != '\0') {
289             *psz++ = *psz1++;
290          }
291          *psz = '\0';
292       }
293    }
294    gnBoundaryLen = strlen(gpszBoundary);
295 }
296 
297 static
FindBoundary(buf)298 int FindBoundary(buf)
299    char *buf;
300 {
301    char *semi_colon=NULL;
302    int found=FALSE;
303 
304    while (*buf == ' ' || *buf == '\t') buf++;
305    semi_colon = strchr(buf, ';');
306    while (!found) {
307       char *equal_ptr=NULL;
308 
309       if (semi_colon != NULL) *semi_colon = '\0';
310       equal_ptr = strchr(buf, '=');
311       if (equal_ptr != NULL) {
312          *equal_ptr = '\0';
313          if (UtilStrICmp(buf, "boundary") == 0) {
314             UpdateBoundary(&equal_ptr[1]);
315             found = TRUE;
316          }
317          *equal_ptr = '=';
318       }
319       if (semi_colon == NULL) break;
320       *semi_colon++ = ';';
321       buf = semi_colon;
322       while (*buf == ' ' || *buf == '\t') buf++;
323       semi_colon = strchr(buf, ';');
324    }
325    return found;
326 }
327 
328 static
GetContentLength(buf)329 int GetContentLength(buf)
330    char *buf;
331 {
332    char *c_ptr=NULL, *psz=NULL, *line_ptr=buf;
333    int content_len=(-1), just_lf=IsJustLF(buf);
334    int good_content_type=FALSE, last_line_is_content_type=FALSE;
335    int inc=(just_lf?1:2);
336 
337    for (c_ptr=GetHeaderLine(line_ptr, just_lf); c_ptr != NULL;
338          c_ptr=GetHeaderLine(line_ptr, just_lf)) {
339       char *colon_ptr=NULL;
340 
341       if (c_ptr == line_ptr) {
342          /* reach the end of header, now decide if the header is good */
343          gnJustLF = just_lf;
344          gnHeaderLen = gnStartIndex = ((&c_ptr[inc]) - buf);
345          if (good_content_type && gpszBoundary != NULL) {
346             gnMultipartReplace = TRUE;
347             if ((debugHttp % 100) == 99 && cmdLineDumpURL &&
348                   cmdLineDumpURLWithHeader) {
349                fprintf(stdout, "%s", buf);
350             }
351          } else {
352             ResetMultipartReplace(FALSE);
353             gnPossibleMultipartReplace = FALSE;
354          }
355          return (content_len==(-1) ? 0 : content_len);
356       }
357       *c_ptr = '\0';
358       if (*line_ptr == ' ' || *line_ptr == '\t') {
359          if (last_line_is_content_type && good_content_type) {
360             for (psz=line_ptr; *psz == ' ' || *psz == '\t'; psz++) ;
361             FindBoundary(psz);
362          }
363       } else {
364          last_line_is_content_type = FALSE;
365          colon_ptr = strchr(line_ptr, ':');
366          if (colon_ptr != NULL) {
367             *colon_ptr = '\0';
368             if (UtilStrICmp(line_ptr, "Content-Length") == 0) {
369                char length_str[MAXSTRING];
370                int len=0;
371 
372                UtilStrCpyN(length_str, MAXSTRING-1, &colon_ptr[1]);
373                UtilTrimBlanks(length_str);
374                if (sscanf(length_str, "%d", &len) == 1) {
375                   content_len = len;
376                }
377             } else if (UtilStrICmp(line_ptr, "Content-Type") == 0) {
378                int multipart=FALSE;
379 
380                last_line_is_content_type = TRUE;
381                psz = strchr(&colon_ptr[1], ';');
382                if (psz != NULL) *psz = '\0';
383                good_content_type = ValidMultipartReplace(&colon_ptr[1],
384                      &multipart);
385                if (!good_content_type && multipart) {
386 #ifdef _TGIF_DBG /* debug, do not translate */
387                   fprintf(stderr, "%s Content-Type: %s\n",
388                         "Does not know how to handle", &colon_ptr[1]);
389 #endif /* _TGIF_DBG */
390                }
391                if (psz != NULL) {
392                   *psz++ = ';';
393                   if (good_content_type) {
394                      FindBoundary(psz);
395                   }
396                }
397             }
398             *colon_ptr = ':';
399          }
400       }
401       *c_ptr = (just_lf ? '\n' : '\r');
402       line_ptr = (&c_ptr[inc]);
403    }
404    return (-1);
405 }
406 
407 static
ScanHeader(buf)408 void ScanHeader(buf)
409    char *buf;
410 {
411    if (GetContentLength(buf) > 0) {
412       /* the header contains Content-Length, no good! */
413       ResetMultipartReplace(FALSE);
414       gnPossibleMultipartReplace = FALSE;
415    }
416 }
417 
418 typedef struct tagImageContentInfo {
419    char sz_content_type[MAXSTRING];
420    char *psz_filter;
421    int content_len;
422    int header_len;
423 } ImageContentInfo;
424 
425 /*
426  * The data in the buffer is expected to have the following structure:
427  *
428  *     HTTP/1.0 200
429  *     Content-Type: multipart/x-mixed-replace: boundary=BOUNDARYPATTERN
430  *
431  *     --BOUNDARYPATTERN
432  *     Content-Type: image/jpeg
433  *
434  *     ~~~~..JFIF.....H.H..~~..Photoshop 3.0.8BIM.~....
435  *     3~O~~~~~~.~~~~?~G~~~~~~~~,~~~a~ \~~~
436  *
437  *     --BOUNDARYPATTERN
438  *     Content-Type: image/jpeg
439  *
440  *     ~~~~..JFIF..........~~.C...........#!.$.M2.**.^C
441  *     ..................................~~
442  *
443  * Notices that the first 3 bytes in a JPEG file is ff d8 ff and
444  * the last 2 bytes are ff d9.  This is how the code can figure
445  * out the end of the JPEG file without Content-Length.
446  */
447 
448 static
GetContent(buf,buf_len,start_index,pici)449 int GetContent(buf, buf_len, start_index, pici)
450    char *buf;
451    int buf_len, start_index;
452    ImageContentInfo *pici;
453 {
454    char *c_ptr=NULL, *line_ptr=(&buf[start_index]);
455    int content_len=(-1), just_lf=IsJustLF(line_ptr);
456    int found_boundary=FALSE, inc=(just_lf?1:2), first_line=TRUE;
457    int faked_found_boundary=FALSE, seen_none_blank_line=FALSE;
458 
459    memset(pici, 0, sizeof(ImageContentInfo));
460    for (c_ptr=GetHeaderLine(line_ptr, just_lf); c_ptr != NULL;
461          c_ptr=GetHeaderLine(line_ptr, just_lf)) {
462       char *colon_ptr=NULL;
463 
464       if (!found_boundary) {
465          *c_ptr = '\0';
466          if (*line_ptr == ' ' || *line_ptr == '\t') {
467             /* ignore */
468          } else if (first_line && *line_ptr == '\0') {
469             /*
470              * it may not have the boundary line, just pretend that the
471              *       boundary line is found
472              */
473             found_boundary = TRUE;
474             faked_found_boundary = TRUE;
475          } else {
476             if (strcmp(line_ptr, gpszBoundary) == 0) {
477                found_boundary = TRUE;
478             } else if (strncmp(gpszBoundary, "----", 4) == 0 &&
479                   strcmp(line_ptr, &gpszBoundary[2]) == 0) {
480                found_boundary = TRUE;
481                UpdateBoundary(&line_ptr[2]);
482             }
483             seen_none_blank_line = TRUE;
484          }
485          first_line = FALSE;
486          *c_ptr = (just_lf ? '\n' : '\r');
487          line_ptr = (&c_ptr[inc]);
488          continue;
489       }
490       if (c_ptr == line_ptr && seen_none_blank_line) {
491          /* reach the end of header, now decide if the header is good */
492 
493          pici->header_len = ((&c_ptr[inc])-(&buf[start_index]));
494          pici->content_len = (content_len==(-1) ? 0 : content_len);
495          if (pici->content_len == 0) {
496             /*
497              * no content length information, see if it's really a JPEG file,
498              *       and if it is, just look for the EOI
499              */
500             if (start_index+pici->header_len+3 <= buf_len) {
501                char *psz=(&buf[start_index+pici->header_len]);
502 
503                if (psz[0] == ((char)0xff) && psz[1] == ((char)0xd8) &&
504                      psz[2] == ((char)0xff)) {
505                   int index=0;
506 
507                   /* now look for EOI, which is 0xffd9 */
508                   for (index=start_index+pici->header_len; index < buf_len-1;
509                         index++, psz++) {
510                      if (*psz == ((char)0xff) && psz[1] == ((char)0xd9)) {
511                         /* got EOI, now we know the content length */
512                         pici->content_len = content_len =
513                               index+2-(start_index+pici->header_len);
514                         break;
515                      }
516                   }
517                } else if (psz[0] == ((char)0x89) && psz[1] == 'P' &&
518                      psz[2] == 'N' && psz[3] == 'G') {
519                   /*
520                    * Well, Content-Length better be there!
521                    */
522                } else {
523                   /* this stream should be abandoned */
524                }
525             }
526          }
527          if (start_index+pici->header_len+pici->content_len >= buf_len) {
528             /* image is not in the buffer yet */
529             return (-1);
530          }
531          return (content_len==(-1) ? 0 : content_len);
532       }
533       *c_ptr = '\0';
534       if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == '\0') {
535          /* ignore */
536       } else {
537          seen_none_blank_line = TRUE;
538 
539          colon_ptr = strchr(line_ptr, ':');
540          if (colon_ptr != NULL) {
541             *colon_ptr = '\0';
542             if (UtilStrICmp(line_ptr, "Content-Length") == 0) {
543                char length_str[MAXSTRING];
544                int len;
545 
546                UtilStrCpyN(length_str, MAXSTRING-1, &colon_ptr[1]);
547                UtilTrimBlanks(length_str);
548                if (sscanf(length_str, "%d", &len) == 1) {
549                   content_len = len;
550                }
551             } else if (UtilStrICmp(line_ptr, "Content-Type") == 0) {
552                char *psz=strchr(&colon_ptr[1], ';');
553 
554                if (psz != NULL) *psz = '\0';
555                UtilStrCpyN(pici->sz_content_type,
556                      sizeof(pici->sz_content_type),
557                      &colon_ptr[1]);
558                UtilTrimBlanks(pici->sz_content_type);
559                if (!ValidImageContentType(&colon_ptr[1], &pici->psz_filter)) {
560                   fprintf(stderr,
561                         TgLoadCachedString(CSTID_DONT_KNOW_HOW_HANDLE_FRAME_CT),
562                         &colon_ptr[1]);
563                   fprintf(stderr, "\n");
564                } else if (pici->psz_filter == NULL) {
565                   /* content-type is text/html, pretend it's okay */
566                }
567                if (psz != NULL) *psz++ = ';';
568             }
569             *colon_ptr = ':';
570          } else if (faked_found_boundary) {
571             if (strcmp(line_ptr, gpszBoundary) == 0) {
572                faked_found_boundary = FALSE;
573             }
574          }
575       }
576       *c_ptr = (just_lf ? '\n' : '\r');
577       line_ptr = (&c_ptr[inc]);
578    }
579    return (-1);
580 }
581 
582 static
ScanBody(buf,pn_buf_len)583 void ScanBody(buf, pn_buf_len)
584    char *buf;
585    int *pn_buf_len;
586 {
587    ImageContentInfo ici;
588 
589    memset(&ici, 0, sizeof(ImageContentInfo));
590    while (GetContent(buf, *pn_buf_len, gnStartIndex, &ici) > 0) {
591       if (*ici.sz_content_type != '\0' && ici.psz_filter != NULL) {
592          char *tmp_fname=WriteRemoteFileIntoTemp(
593                &buf[gnStartIndex+ici.header_len], ici.content_len, NULL);
594 
595          if (tmp_fname != NULL) {
596             int left_over=0;
597             int saved_enable_failed_import_msgbox=GetEnableFailedImportMsgBox();
598             char *dest=NULL, *src=NULL;
599 
600             if (gpVideoObj != NULL) {
601                UnlinkObj(gpVideoObj);
602                FreeObj(gpVideoObj);
603             }
604             gpVideoObj = NULL;
605             if (strcmp(ici.sz_content_type, "image/png") == 0) {
606                SetEnableFailedImportMsgBox(FALSE);
607             }
608             if (ImportSpecifiedFileType(tmp_fname, ici.psz_filter)) {
609                gpVideoObj = topObj;
610                MoveObj(gpVideoObj, drawOrigX-gpVideoObj->obbox.ltx,
611                      drawOrigY-gpVideoObj->obbox.lty);
612                DrawObj(drawWindow, gpVideoObj);
613             }
614             SetEnableFailedImportMsgBox(saved_enable_failed_import_msgbox);
615             unlink(tmp_fname);
616             free(tmp_fname);
617             /* now we need to shrink the buffer */
618             left_over = *pn_buf_len -
619                   gnStartIndex - ici.header_len - ici.content_len;
620             dest = (&buf[gnStartIndex]);
621             src = (&buf[gnStartIndex+ici.header_len+ici.content_len]);
622             if (left_over >= 5 && UtilStrNCaseCmp(src, "HTTP/", 5) == 0) {
623                dest = buf;
624                memcpy(dest, src, left_over*sizeof(char));
625                *pn_buf_len = left_over;
626                ResetMultipartReplace(FALSE);
627                ScanHeader(buf);
628                if (!gnMultipartReplace) {
629                   return;
630                }
631             } else {
632                memcpy(dest, src, left_over*sizeof(char));
633                *pn_buf_len = gnStartIndex + left_over;
634             }
635          }
636       }
637    }
638 }
639 
HandleMultipartReplace(buf,pn_buf_len)640 void HandleMultipartReplace(buf, pn_buf_len)
641    char *buf;
642    int *pn_buf_len;
643 {
644    if (!gnPossibleMultipartReplace) return;
645 
646    if (gnMultipartReplace) {
647       ScanBody(buf, pn_buf_len);
648    } else {
649       ScanHeader(buf);
650       if (gnMultipartReplace) {
651          ScanBody(buf, pn_buf_len);
652       }
653    }
654 }
655 
FakeUserAgent(buf)656 void FakeUserAgent(buf)
657    char *buf;
658 {
659    char prev_agent[MAXSTRING<<1], spec[MAXSTRING<<1];
660 
661    if (buf != NULL && strcmp(buf, "-1") != 0) {
662       int len=0;
663 
664       UtilStrCpyN(spec, sizeof(spec), buf);
665       UtilTrimBlanks(spec);
666       len = strlen(spec);
667       if (len > 0 && spec[len-1] == ')') spec[len-1] = '\0';
668    } else {
669       *prev_agent = '\0';
670       GetUserAgent(prev_agent, sizeof(prev_agent));
671       if (*prev_agent == '\0') {
672          sprintf(gszMsgBox, TgLoadString(STID_ENTER_USERAGENT_FOR_HTTP));
673       } else {
674          sprintf(gszMsgBox, TgLoadString(STID_ENTER_USERAGENT_FOR_HTTP_CUR),
675                prev_agent);
676       }
677       *spec = '\0';
678       if (Dialog(gszMsgBox, TgLoadString(STID_PRESS_ENTER_FOR_DEF_USERAGENT),
679             spec) == INVALID) {
680          return;
681       }
682    }
683    UtilTrimBlanks(spec);
684    SetUserAgent(spec);
685    *prev_agent = '\0';
686    GetUserAgent(prev_agent, sizeof(prev_agent));
687    if (*prev_agent == '\0') {
688       sprintf(gszMsgBox, TgLoadString(STID_WILL_USE_DEF_USERAGENT_HTTP));
689    } else {
690       sprintf(gszMsgBox, TgLoadString(STID_WILL_USE_NAMED_USERAGENT_HTTP),
691             prev_agent);
692    }
693    Msg(gszMsgBox);
694 }
695 
FakeReferer(buf)696 void FakeReferer(buf)
697    char *buf;
698 {
699    char spec[MAXSTRING<<1];
700 
701    *spec = '\0';
702    if (buf != NULL && strcmp(buf, "-1") != 0) {
703       int len=0;
704 
705       UtilStrCpyN(spec, sizeof(spec), buf);
706       UtilTrimBlanks(spec);
707       len = strlen(spec);
708       if (len > 0 && spec[len-1] == ')') spec[len-1] = '\0';
709    } else {
710       if (gpszFakedReferer == NULL) {
711          sprintf(gszMsgBox, TgLoadString(STID_ENTER_REFERRER_FOR_HTTP));
712       } else {
713          sprintf(gszMsgBox, TgLoadString(STID_ENTER_REFERRER_FOR_HTTP_CUR),
714                gpszFakedReferer);
715       }
716       *spec = '\0';
717       if (Dialog(gszMsgBox, TgLoadString(STID_PRESS_ENTER_FOR_NO_REFERRER),
718             spec) == INVALID) {
719          return;
720       }
721    }
722    if (*spec != '\0') {
723       if (!navigatingBackAndForth) BeforeNavigate();
724       ClearFileInfo(FALSE);
725       RedrawTitleWindow();
726    }
727    UtilTrimBlanks(spec);
728    HttpFakeReferer(spec);
729    if (gpszFakedReferer == NULL) {
730       sprintf(gszMsgBox, TgLoadString(STID_WILL_NOT_USE_REFERRER_HTTP));
731    } else {
732       sprintf(gszMsgBox, TgLoadString(STID_WILL_USE_NAMED_REFERRER_HTTP),
733             gpszFakedReferer);
734    }
735    Msg(gszMsgBox);
736 }
737 
ToggleKeepAlive()738 void ToggleKeepAlive()
739 {
740    gnHttpKeepAlive = (!gnHttpKeepAlive);
741    sprintf(gszMsgBox, TgLoadString(gnHttpKeepAlive ?
742          STID_WILL_USE_KEEP_ALIVE_HTTP : STID_NOT_WILL_USE_KEEP_ALIVE_HTTP));
743    Msg(gszMsgBox);
744 }
745 
746