~ubuntu-branches/ubuntu/trusty/hyperestraier/trusty-proposed

« back to all changes in this revision

Viewing changes to estproxy.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2006-11-14 05:28:32 UTC
  • mfrom: (2.1.4 feisty)
  • Revision ID: james.westby@ubuntu.com-20061114052832-0lzqzcefn8mt4yqe
Tags: 1.4.9-1.1
* Non-maintainer upload.
* High-urgency upload for RC bugfix.
* Set HOME=$(CURDIR)/junkhome when building, otherwise the package build
  will incorrectly look for headers there -- and fail when the directory
  exists and is unreadable, as happens sometimes on sudo-using
  autobuilders!

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*************************************************************************************************
 
2
 * A proxy with highlighting
 
3
 *                                                      Copyright (C) 2004-2006 Mikio Hirabayashi
 
4
 * This file is part of Hyper Estraier.
 
5
 * Hyper Estraier is free software; you can redistribute it and/or modify it under the terms of
 
6
 * the GNU Lesser General Public License as published by the Free Software Foundation; either
 
7
 * version 2.1 of the License or any later version.  Hyper Estraier is distributed in the hope
 
8
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
10
 * License for more details.
 
11
 * You should have received a copy of the GNU Lesser General Public License along with Hyper
 
12
 * Estraier; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 
13
 * Boston, MA 02111-1307 USA.
 
14
 *************************************************************************************************/
 
15
 
 
16
 
 
17
#if defined(MYFCGI)
 
18
#include <fcgi_stdio.h>
 
19
#endif
 
20
#include "estraier.h"
 
21
#include "estmtdb.h"
 
22
#include "estnode.h"
 
23
#include "myconf.h"
 
24
 
 
25
#define AGENTNAME      "EstProxy"        /* name of the user agent */
 
26
#define CONFSUFFIX     ".conf"           /* suffix of the configuration file */
 
27
#define NUMBUFSIZ      32                /* size of a buffer for a number */
 
28
#define URIBUFSIZ      8192              /* size of a buffer for an URI */
 
29
#define OUTBUFSIZ      262144            /* size of the output buffer */
 
30
#define SOCKBUFSIZ     8192              /* size of the socket buffer */
 
31
#define MINIBNUM       31                /* bucket number of map for trivial use */
 
32
 
 
33
#define DRAFTCMD       "[DRAFT]"         /* built-in command for document draft */
 
34
#define TEXTCMD        "[TEXT]"          /* built-in command for plain text */
 
35
#define HTMLCMD        "[HTML]"          /* built-in command for HTML */
 
36
#define MIMECMD        "[MIME]"          /* built-in command for MIME */
 
37
 
 
38
 
 
39
/* global variables for configurations */
 
40
const char *g_conffile = NULL;           /* path of the configuration file */
 
41
const CBLIST *g_replexprs = NULL;        /* list of URL replacement expressions */
 
42
const CBLIST *g_rxlist = NULL;           /* list of regular expressions for URL allowing */
 
43
int g_passaddr = FALSE;                  /* whether to pass the IP address of clients */
 
44
int g_limitsize = 0;                     /* limit size of data to receive */
 
45
CBMAP *g_urlrules = NULL;                /* rules of URLs */
 
46
CBMAP *g_mtrules = NULL;                 /* rules of media types */
 
47
int g_language = 0;                      /* preferred language */
 
48
int g_shownavi = 0;                      /* whether to show navigation bar */
 
49
 
 
50
 
 
51
/* global variables for parameters */
 
52
const char *p_url = NULL;                /* target URL */
 
53
const CBLIST *p_words = NULL;            /* words to be highlighted */
 
54
int p_once = FALSE;                      /* whether to use direct link */
 
55
 
 
56
 
 
57
/* other global variables */
 
58
char g_outbuf[OUTBUFSIZ];                /* output buffer */
 
59
const char *g_remoteaddr = NULL;         /* IP address of the client */
 
60
const char *g_scriptname = NULL;         /* name of the script */
 
61
const char *g_hostname = NULL;           /* name of the host */
 
62
const char *g_scriptpath = NULL;         /* path of the script */
 
63
const char *g_agentname = NULL;          /* name of the user agent */
 
64
 
 
65
 
 
66
/* color definitions */
 
67
const char *g_wordcolors[] = {           /* highlighted colors */
 
68
  "#ffff77",
 
69
  "#ffaaaa",
 
70
  "#bbbbff",
 
71
  "#aaffaa",
 
72
  "#88ffff",
 
73
  "#ff99ff"
 
74
};
 
75
 
 
76
 
 
77
/* function prototypes */
 
78
int main(int argc, char **argv);
 
79
static int realmain(int argc, char **argv);
 
80
static void showerror(const char *msg);
 
81
static const char *skiplabel(const char *str);
 
82
static CBMAP *getparameters(void);
 
83
static void xmlprintf(const char *format, ...);
 
84
static char *replaceurl(const char *uri);
 
85
static void sendform(void);
 
86
static char *urltopath(const char *url);
 
87
static int getlocalconnection(const char *url, int *codep, CBMAP *heads);
 
88
static void senddirlist(const char *path);
 
89
static char *readall(int fd, int *sp);
 
90
static void passlocalrawdata(int fd);
 
91
static void sendlocaldata(void);
 
92
static int gethttpconnection(const char *url, int *codep, CBMAP *heads);
 
93
static char *recvall(int sock, int *sp);
 
94
static void passhttprawdata(int sock);
 
95
static void modifylocation(CBMAP *heads, const char *name);
 
96
static void sendhttpdata(void);
 
97
static void sendnavibar(void);
 
98
static void sendsnippet(const char *str);
 
99
static const char *langstr(void);
 
100
static void sendpagefromdraft(const char *buf, int size, const char *penc);
 
101
static void sendpagefromtext(const char *buf, int size, const char *penc);
 
102
static void sendpagefromhtml(const char *buf, int size, const char *penc);
 
103
static char *htmlenc(const char *str);
 
104
static char *htmlrawtext(const char *html);
 
105
static void sendpagefrommime(const char *buf, int size, const char *penc);
 
106
static void sendmimepart(const char *body, int bsiz, CBMAP *attrs, const char *penc);
 
107
static char *mimestr(const char *mime);
 
108
static void sendpagewithxcmd(const char *buf, int size, const char *penc, const char *cmd);
 
109
 
 
110
 
 
111
/* main routine */
 
112
int main(int argc, char **argv){
 
113
#if defined(MYFCGI)
 
114
  static int cnt = 0;
 
115
  est_proc_env_reset();
 
116
  est_init_net_env();
 
117
  while(FCGI_Accept() >= 0){
 
118
    if(++cnt >= 256){
 
119
      cbggcsweep();
 
120
      cnt = 0;
 
121
    }
 
122
    realmain(argc, argv);
 
123
  }
 
124
  est_free_net_env();
 
125
  return 0;
 
126
#else
 
127
  est_proc_env_reset();
 
128
  est_init_net_env();
 
129
  realmain(argc, argv);
 
130
  est_free_net_env();
 
131
  return 0;
 
132
#endif
 
133
}
 
134
 
 
135
 
 
136
/* real main routine */
 
137
static int realmain(int argc, char **argv){
 
138
  CBLIST *lines, *rplist, *rxlist, *wlist, *list;
 
139
  CBMAP *params, *urlmap, *mtmap;
 
140
  const char *rp, *pv;
 
141
  char *tmp, *wp, numbuf[NUMBUFSIZ];
 
142
  int i, len, allow;
 
143
  setvbuf(stdout, g_outbuf, _IOFBF, OUTBUFSIZ);
 
144
  if((rp = getenv("REMOTE_ADDR")) != NULL){
 
145
    g_remoteaddr = rp;
 
146
  } else {
 
147
    g_remoteaddr = "0.0.0.0";
 
148
  }
 
149
  g_scriptname = argv[0];
 
150
  if((rp = getenv("SCRIPT_NAME")) != NULL) g_scriptname = rp;
 
151
  g_hostname = est_get_host_name();
 
152
  if((rp = getenv("HTTP_HOST")) != NULL) g_hostname = rp;
 
153
  g_scriptpath = g_scriptname;
 
154
  g_agentname = AGENTNAME;
 
155
  if((rp = getenv("HTTP_USER_AGENT")) != NULL) g_agentname = rp;
 
156
  if((rp = strrchr(g_scriptname, '/')) != NULL) g_scriptname = rp + 1;
 
157
  tmp = cbmalloc(strlen(g_scriptname) + strlen(CONFSUFFIX) + 1);
 
158
  sprintf(tmp, "%s", g_scriptname);
 
159
  cbglobalgc(tmp, free);
 
160
  if(!(wp = strrchr(tmp, '.'))) wp = tmp + strlen(tmp);
 
161
  sprintf(wp, "%s", CONFSUFFIX);
 
162
  g_conffile = tmp;
 
163
  if(!(lines = cbreadlines(g_conffile))) showerror("the configuration file is missing.");
 
164
  cbglobalgc(lines, (void (*)(void *))cblistclose);
 
165
  rplist = cblistopen();
 
166
  cbglobalgc(rplist, (void (*)(void *))cblistclose);
 
167
  rxlist = cblistopen();
 
168
  cbglobalgc(rxlist, (void (*)(void *))cblistclose);
 
169
  urlmap = cbmapopenex(MINIBNUM);
 
170
  cbglobalgc(urlmap, (void (*)(void *))cbmapclose);
 
171
  mtmap = cbmapopenex(MINIBNUM);
 
172
  cbglobalgc(mtmap, (void (*)(void *))cbmapclose);
 
173
  for(i = 0; i < cblistnum(lines); i++){
 
174
    rp = cblistval(lines, i, NULL);
 
175
    if(cbstrfwimatch(rp, "replace:")){
 
176
      rp = skiplabel(rp);
 
177
      if(*rp != '\0') cblistpush(rplist, rp, -1);
 
178
    } else if(cbstrfwimatch(rp, "allowrx:")){
 
179
      rp = skiplabel(rp);
 
180
      if(*rp != '\0'){
 
181
        tmp = cbsprintf("a*I:%s", rp);
 
182
        cblistpushbuf(rxlist, tmp, strlen(tmp));
 
183
      }
 
184
    } else if(cbstrfwimatch(rp, "denyrx:")){
 
185
      rp = skiplabel(rp);
 
186
      if(*rp != '\0'){
 
187
        tmp = cbsprintf("d*I:%s", rp);
 
188
        cblistpushbuf(rxlist, tmp, strlen(tmp));
 
189
      }
 
190
    } else if(cbstrfwimatch(rp, "passaddr:")){
 
191
      g_passaddr = atoi(skiplabel(rp)) > 0;
 
192
    } else if(cbstrfwimatch(rp, "limitsize:")){
 
193
      g_limitsize = atoi(skiplabel(rp)) * 1024 * 1024;
 
194
    } else if(cbstrfwimatch(rp, "urlrule:")){
 
195
      rp = skiplabel(rp);
 
196
      if((pv = strstr(rp, "{{!}}")) != NULL) cbmapput(urlmap, rp, pv - rp, pv + 5, -1, TRUE);
 
197
    } else if(cbstrfwimatch(rp, "typerule:")){
 
198
      rp = skiplabel(rp);
 
199
      if((pv = strstr(rp, "{{!}}")) != NULL) cbmapput(mtmap, rp, pv - rp, pv + 5, -1, TRUE);
 
200
    } else if(cbstrfwimatch(rp, "language:")){
 
201
      g_language = atoi(skiplabel(rp));
 
202
    } else if(cbstrfwimatch(rp, "shownavi:")){
 
203
      g_shownavi = atoi(skiplabel(rp)) > 0;
 
204
    }
 
205
  }
 
206
  g_replexprs = rplist;
 
207
  g_rxlist = rxlist;
 
208
  g_urlrules = urlmap;
 
209
  g_mtrules = mtmap;
 
210
  params = getparameters();
 
211
  cbglobalgc(params, (void (*)(void *))cbmapclose);
 
212
  wlist = cblistopen();
 
213
  cbglobalgc(wlist, (void (*)(void *))cblistclose);
 
214
  if(!(p_url = cbmapget(params, "url", -1, NULL))) p_url = "";
 
215
  for(i = 0; i < 256; i++){
 
216
    len = sprintf(numbuf, "word%d", i);
 
217
    if((rp = cbmapget(params, numbuf, len, NULL)) != NULL && *rp != '\0')
 
218
      cblistpush(wlist, rp, -1);
 
219
  }
 
220
  if((rp = cbmapget(params, "words", -1, NULL)) != NULL){
 
221
    tmp = est_regex_replace(rp, "(\xe3\x80\x80)+", " ");
 
222
    list = cbsplit(tmp, -1, ", \t\n\r");
 
223
    for(i = 0; i < cblistnum(list); i++){
 
224
      rp = cblistval(list, i, NULL);
 
225
      if(*rp != '\0') cblistpush(wlist, rp, -1);
 
226
    }
 
227
    cblistclose(list);
 
228
    free(tmp);
 
229
  }
 
230
  if((rp = cbmapget(params, "once", -1, NULL)) != NULL) p_once = atoi(rp) > 0;
 
231
  p_words = wlist;
 
232
  if(*p_url == '\0'){
 
233
    sendform();
 
234
  } else {
 
235
    allow = FALSE;
 
236
    tmp = replaceurl(p_url);
 
237
    for(i = 0; i < cblistnum(rxlist); i++){
 
238
      rp = cblistval(rxlist, i, NULL);
 
239
      switch(*rp){
 
240
      case 'a':
 
241
        rp++;
 
242
        if(est_regex_match_str(rp, tmp)) allow = TRUE;
 
243
        break;
 
244
      case 'd':
 
245
        rp++;
 
246
        if(est_regex_match_str(rp, tmp)) allow = FALSE;
 
247
        break;
 
248
      default:
 
249
        break;
 
250
      }
 
251
    }
 
252
    if(allow && cbstrfwimatch(tmp, "file://")){
 
253
      sendlocaldata();
 
254
    } else if(allow && cbstrfwimatch(tmp, "http://")){
 
255
      sendhttpdata();
 
256
    } else {
 
257
      printf("Status: 400 Forbidden\r\n");
 
258
      printf("Content-Type: text/plain; charset=UTF-8\r\n");
 
259
      printf("\r\n");
 
260
      printf("Error: the requested URL is not allowed\n");
 
261
    }
 
262
    free(tmp);
 
263
  }
 
264
  return 0;
 
265
}
 
266
 
 
267
 
 
268
/* show the error page and exit */
 
269
static void showerror(const char *msg){
 
270
  printf("Status: 500 Internal Server Error\r\n");
 
271
  printf("Content-Type: text/plain; charset=UTF-8\r\n");
 
272
  printf("\r\n");
 
273
  printf("Error: %s\n", msg);
 
274
  exit(1);
 
275
}
 
276
 
 
277
 
 
278
/* skip the label of a line */
 
279
static const char *skiplabel(const char *str){
 
280
  if(!(str = strchr(str, ':'))) return "";
 
281
  str++;
 
282
  while(*str != '\0' && (*str == ' ' || *str == '\t')){
 
283
    str++;
 
284
  }
 
285
  return str;
 
286
}
 
287
 
 
288
 
 
289
/* get CGI parameters */
 
290
static CBMAP *getparameters(void){
 
291
  int maxlen = 1024 * 1024 * 32;
 
292
  CBMAP *map, *attrs;
 
293
  CBLIST *pairs, *parts;
 
294
  const char *rp, *body;
 
295
  char *buf, *key, *val, *dkey, *dval, *wp, *bound, *fbuf, *aname;
 
296
  int i, len, c, blen, flen;
 
297
  map = cbmapopenex(37);
 
298
  buf = NULL;
 
299
  len = 0;
 
300
  if((rp = getenv("REQUEST_METHOD")) != NULL && !strcmp(rp, "POST") &&
 
301
     (rp = getenv("CONTENT_LENGTH")) != NULL && (len = atoi(rp)) > 0){
 
302
    if(len > maxlen) len = maxlen;
 
303
    buf = cbmalloc(len + 1);
 
304
    for(i = 0; i < len && (c = getchar()) != EOF; i++){
 
305
      buf[i] = c;
 
306
    }
 
307
    buf[i] = '\0';
 
308
    if(i != len){
 
309
      free(buf);
 
310
      buf = NULL;
 
311
    }
 
312
  } else if((rp = getenv("QUERY_STRING")) != NULL){
 
313
    buf = cbmemdup(rp, -1);
 
314
    len = strlen(buf);
 
315
  }
 
316
  if(buf && len > 0){
 
317
    if((rp = getenv("CONTENT_TYPE")) != NULL && cbstrfwmatch(rp, "multipart/form-data") &&
 
318
       (rp = strstr(rp, "boundary=")) != NULL){
 
319
      rp += 9;
 
320
      bound = cbmemdup(rp, -1);
 
321
      if((wp = strchr(bound, ';')) != NULL) *wp = '\0';
 
322
      parts = cbmimeparts(buf, len, bound);
 
323
      for(i = 0; i < cblistnum(parts); i++){
 
324
        body = cblistval(parts, i, &blen);
 
325
        attrs = cbmapopen();
 
326
        fbuf = cbmimebreak(body, blen, attrs, &flen);
 
327
        if((rp = cbmapget(attrs, "NAME", -1, NULL)) != NULL){
 
328
          cbmapput(map, rp, -1, fbuf, flen, FALSE);
 
329
          aname = cbsprintf("%s-filename", rp);
 
330
          if((rp = cbmapget(attrs, "FILENAME", -1, NULL)) != NULL)
 
331
            cbmapput(map, aname, -1, rp, -1, FALSE);
 
332
          free(aname);
 
333
        }
 
334
        free(fbuf);
 
335
        cbmapclose(attrs);
 
336
      }
 
337
      cblistclose(parts);
 
338
      free(bound);
 
339
    } else {
 
340
      pairs = cbsplit(buf, -1, "&");
 
341
      for(i = 0; i < cblistnum(pairs); i++){
 
342
        key = cbmemdup(cblistval(pairs, i, NULL), -1);
 
343
        if((val = strchr(key, '=')) != NULL){
 
344
          *(val++) = '\0';
 
345
          dkey = cburldecode(key, NULL);
 
346
          dval = cburldecode(val, NULL);
 
347
          cbmapput(map, dkey, -1, dval, -1, FALSE);
 
348
          free(dval);
 
349
          free(dkey);
 
350
        }
 
351
        free(key);
 
352
      }
 
353
      cblistclose(pairs);
 
354
    }
 
355
  }
 
356
  free(buf);
 
357
  return map;
 
358
}
 
359
 
 
360
 
 
361
/* output escaped string */
 
362
static void xmlprintf(const char *format, ...){
 
363
  va_list ap;
 
364
  const char *rp;
 
365
  char *tmp, cbuf[32], *ebuf;
 
366
  unsigned char c;
 
367
  int cblen, cnt, mlen;
 
368
  va_start(ap, format);
 
369
  while(*format != '\0'){
 
370
    if(*format == '%'){
 
371
      cbuf[0] = '%';
 
372
      cblen = 1;
 
373
      format++;
 
374
      while(strchr("0123456789 .+-", *format) && *format != '\0' && cblen < sizeof(cbuf) - 1){
 
375
        cbuf[cblen++] = *format;
 
376
        format++;
 
377
      }
 
378
      cbuf[cblen++] = *format;
 
379
      cbuf[cblen] = '\0';
 
380
      switch(*format){
 
381
      case 's':
 
382
        tmp = va_arg(ap, char *);
 
383
        if(!tmp) tmp = "(null)";
 
384
        printf(cbuf, tmp);
 
385
        break;
 
386
      case 'd':
 
387
        printf(cbuf, va_arg(ap, int));
 
388
        break;
 
389
      case 'o': case 'u': case 'x': case 'X': case 'c':
 
390
        printf(cbuf, va_arg(ap, unsigned int));
 
391
        break;
 
392
      case 'e': case 'E': case 'f': case 'g': case 'G':
 
393
        printf(cbuf, va_arg(ap, double));
 
394
        break;
 
395
      case '@':
 
396
        tmp = va_arg(ap, char *);
 
397
        if(!tmp) tmp = "(null)";
 
398
        ebuf = NULL;
 
399
        if(cblen > 2){
 
400
          mlen = atoi(cbuf + 1) * 10;
 
401
          cnt = 0;
 
402
          rp = tmp;
 
403
          while(*rp != '\0'){
 
404
            if((*rp & 0x80) == 0x00){
 
405
              cnt += 10;
 
406
            } else if((*rp & 0xe0) == 0xc0){
 
407
              cnt += 15;
 
408
            } else if((*rp & 0xf0) == 0xe0 || (*rp & 0xf8) == 0xf0){
 
409
              cnt += 20;
 
410
            }
 
411
            if(cnt > mlen){
 
412
              ebuf = cbmemdup(tmp, rp - tmp);
 
413
              tmp = ebuf;
 
414
              break;
 
415
            }
 
416
            rp++;
 
417
          }
 
418
        }
 
419
        while(*tmp){
 
420
          switch(*tmp){
 
421
          case '&': printf("&amp;"); break;
 
422
          case '<': printf("&lt;"); break;
 
423
          case '>': printf("&gt;"); break;
 
424
          case '"': printf("&quot;"); break;
 
425
          default:
 
426
            if(!((*tmp >= 0 && *tmp <= 0x8) || (*tmp >= 0x0e && *tmp <= 0x1f))) putchar(*tmp);
 
427
            break;
 
428
            }
 
429
          tmp++;
 
430
        }
 
431
        if(ebuf){
 
432
          free(ebuf);
 
433
          printf("...");
 
434
        }
 
435
        break;
 
436
      case '?':
 
437
        tmp = va_arg(ap, char *);
 
438
        if(!tmp) tmp = "(null)";
 
439
        while(*tmp){
 
440
          c = *(unsigned char *)tmp;
 
441
          if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
 
442
             (c >= '0' && c <= '9') || (c != '\0' && strchr("_-.", c))){
 
443
            putchar(c);
 
444
          } else {
 
445
            printf("%%%02X", c);
 
446
          }
 
447
          tmp++;
 
448
        }
 
449
        break;
 
450
      case '%':
 
451
        putchar('%');
 
452
        break;
 
453
      }
 
454
    } else {
 
455
      putchar(*format);
 
456
    }
 
457
    format++;
 
458
  }
 
459
  va_end(ap);
 
460
}
 
461
 
 
462
 
 
463
/* make a URI to be shown */
 
464
static char *replaceurl(const char *uri){
 
465
  char *turi, *bef, *aft, *pv, *nuri;
 
466
  int i;
 
467
  turi = cbmemdup(uri, -1);
 
468
  for(i = 0; i < cblistnum(g_replexprs); i++){
 
469
    bef = cbmemdup(cblistval(g_replexprs, i, NULL), -1);
 
470
    if((pv = strstr(bef, "{{!}}")) != NULL){
 
471
      *pv = '\0';
 
472
      aft = pv + 5;
 
473
    } else {
 
474
      aft = "";
 
475
    }
 
476
    nuri = est_regex_replace(turi, bef, aft);
 
477
    free(turi);
 
478
    turi = nuri;
 
479
    free(bef);
 
480
  }
 
481
  return turi;
 
482
}
 
483
 
 
484
 
 
485
/* show the input form */
 
486
static void sendform(void){
 
487
  printf("Content-Type: text/html; charset=UTF-8\r\n");
 
488
  printf("\r\n");
 
489
  xmlprintf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
490
  xmlprintf("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\""
 
491
         " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
 
492
  xmlprintf("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n");
 
493
  xmlprintf("<head>\n");
 
494
  xmlprintf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n");
 
495
  xmlprintf("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n");
 
496
  xmlprintf("<meta name=\"robots\" content=\"NOFOLLOW\" />\n");
 
497
  xmlprintf("<link rel=\"contents\" href=\"./\" />\n");
 
498
  xmlprintf("<title>%@/%@</title>\n", AGENTNAME, est_version);
 
499
  xmlprintf("<style type=\"text/css\">html {\n");
 
500
  xmlprintf("  margin: 0em 0em; padding: 0em 0em;\n");
 
501
  xmlprintf("  background: #ffffff none;\n");
 
502
  xmlprintf("}\n");
 
503
  xmlprintf("body {\n");
 
504
  xmlprintf("  margin: 2em 2em; padding: 0em 0em;\n");
 
505
  xmlprintf("  color: #111111;\n");
 
506
  xmlprintf("}\n");
 
507
  xmlprintf("div.form_frame {\n");
 
508
  xmlprintf("  margin: 0em 0em; padding: 0.5em 0.5em;\n");
 
509
  xmlprintf("  background: #eeeeff none; border: solid 1pt #bbbbcc;\n");
 
510
  xmlprintf("}\n");
 
511
  xmlprintf("div.form_basic, div.form_extension {\n");
 
512
  xmlprintf("  margin: 0.5em 0.5em; padding: 0em 0em;\n");
 
513
  xmlprintf("  color: #111111;\n");
 
514
  xmlprintf("}\n");
 
515
  xmlprintf("label {\n");
 
516
  xmlprintf("  margin-left: 0.8em;\n");
 
517
  xmlprintf("  color: #333333;\n");
 
518
  xmlprintf("}\n");
 
519
  xmlprintf("</style>\n");
 
520
  xmlprintf("</head>\n");
 
521
  xmlprintf("<body>\n");
 
522
  xmlprintf("<h1>%@/%@</h1>\n", AGENTNAME, est_version);
 
523
  xmlprintf("<div class=\"form_frame\">\n");
 
524
  xmlprintf("<form action=\"%@\" method=\"get\" id=\"form_self\">\n", g_scriptname);
 
525
  xmlprintf("<div class=\"form_basic\">\n");
 
526
  xmlprintf("<label for=\"url\" class=\"label\">URL:</label>\n");
 
527
  xmlprintf("<input type=\"text\" name=\"url\" value=\"\""
 
528
            " size=\"64\" id=\"url\" class=\"url\" tabindex=\"1\" accesskey=\"0\" />\n");
 
529
  xmlprintf("<input type=\"submit\" value=\"Go\""
 
530
            " id=\"search\" class=\"submit\" tabindex=\"2\" accesskey=\"1\" />\n");
 
531
  xmlprintf("</div>\n");
 
532
  xmlprintf("<div class=\"form_extension\">\n");
 
533
  xmlprintf("<label for=\"words\" class=\"label\">highlighted words:</label>\n");
 
534
  xmlprintf("<input type=\"text\" name=\"words\" value=\"\""
 
535
            " size=\"48\" id=\"words\" class=\"text\" tabindex=\"3\" accesskey=\"2\" />\n");
 
536
  xmlprintf("<label for=\"once\" class=\"label\">once:</label>\n");
 
537
  xmlprintf("<input type=\"checkbox\" name=\"once\" value=\"1\" id=\"once\""
 
538
            " class=\"checkbox\" tabindex=\"4\" accesskey=\"3\" />\n");
 
539
  xmlprintf("</div>\n");
 
540
  xmlprintf("</form>\n");
 
541
  xmlprintf("</div>\n");
 
542
  xmlprintf("</body>\n");
 
543
  xmlprintf("</html>\n");
 
544
}
 
545
 
 
546
 
 
547
/* get the local path of a URL */
 
548
static char *urltopath(const char *url){
 
549
  static char pbuf[URIBUFSIZ];
 
550
  const char *pv, *elem;
 
551
  char *wp, *dbuf;
 
552
  CBLIST *list;
 
553
  int i;
 
554
  if(!cbstrfwimatch(url, "file://")) return NULL;
 
555
  pv = url + 7;
 
556
  if(!(url = strchr(pv, '/'))) return NULL;
 
557
  wp = pbuf;
 
558
  if(ESTPATHCHR == '\\'){
 
559
    if(url[0] == '/' && ((url[1] >= 'A' && url[1] <= 'Z') || (url[1] >= 'a' && url[1] <= 'z')) &&
 
560
       url[2] == '|' && url[3] == '/'){
 
561
      wp += sprintf(wp, "%c:", url[1]);
 
562
      url += 3;
 
563
    } else if(url > pv){
 
564
      wp += sprintf(wp, "\\\\");
 
565
      memcpy(wp, pv, url - pv);
 
566
      wp += url - pv;
 
567
    }
 
568
  }
 
569
  list = cbsplit(url, -1, "/");
 
570
  for(i = 0; i < cblistnum(list); i++){
 
571
    elem = cblistval(list, i, NULL);
 
572
    if(elem[0] == '\0') continue;
 
573
    dbuf = cburldecode(elem, NULL);
 
574
    wp += sprintf(wp, "%c%s", ESTPATHCHR, dbuf);
 
575
    free(dbuf);
 
576
  }
 
577
  *wp = '\0';
 
578
  cblistclose(list);
 
579
  return cbmemdup(pbuf, -1);
 
580
}
 
581
 
 
582
 
 
583
/* get the connection of a URL */
 
584
static int getlocalconnection(const char *url, int *codep, CBMAP *heads){
 
585
  const char *ext, *pv;
 
586
  char *path;
 
587
  int fd;
 
588
  struct stat sbuf;
 
589
  cbmapput(heads, "ERROR", -1, "", -1, TRUE);
 
590
  cbmapput(heads, "", -1, "", -1, TRUE);
 
591
  if(!(path = urltopath(url))){
 
592
    *codep = 400;
 
593
    cbmapput(heads, "ERROR", -1, "invalid URL", -1, TRUE);
 
594
    return -1;
 
595
  }
 
596
  if(stat(path, &sbuf) == -1){
 
597
    if(errno == EACCES){
 
598
      *codep = 403;
 
599
      cbmapput(heads, "ERROR", -1, "forbidden", -1, TRUE);
 
600
    } else {
 
601
      *codep = 404;
 
602
      cbmapput(heads, "ERROR", -1, "file not found", -1, TRUE);
 
603
    }
 
604
  }
 
605
  if(S_ISDIR(sbuf.st_mode)){
 
606
    *codep = 0;
 
607
    cbmapput(heads, "ERROR", -1, path, -1, TRUE);
 
608
    free(path);
 
609
    return -1;
 
610
  }
 
611
  if((fd = open(path, O_RDONLY, 0)) == -1){
 
612
    if(errno == EACCES){
 
613
      *codep = 403;
 
614
      cbmapput(heads, "ERROR", -1, "forbidden", -1, TRUE);
 
615
    } else {
 
616
      *codep = 404;
 
617
      cbmapput(heads, "ERROR", -1, "file not found", -1, TRUE);
 
618
    }
 
619
    free(path);
 
620
    return -1;
 
621
  }
 
622
  *codep = 200;
 
623
  ext = NULL;
 
624
  if(!(pv = strrchr(url, ESTPATHCHR))) pv = url;
 
625
  if((pv = strrchr(pv, ESTEXTCHR)) != NULL) ext = pv;
 
626
  cbmapput(heads, "content-type", -1, est_ext_type(ext ? ext : ""), -1, TRUE);
 
627
  free(path);
 
628
  return fd;
 
629
}
 
630
 
 
631
 
 
632
/* send a list of files in a directory */
 
633
static void senddirlist(const char *path){
 
634
  CBLIST *list;
 
635
  const char *elem;
 
636
  char *burl, *eurl, *nurl;
 
637
  int i;
 
638
  printf("Content-Type: text/html\n");
 
639
  printf("\r\n");
 
640
  xmlprintf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
641
  xmlprintf("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\""
 
642
         " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
 
643
  xmlprintf("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%@\" lang=\"%p\">\n",
 
644
            g_language, g_language);
 
645
  xmlprintf("<head>\n");
 
646
  xmlprintf("<meta http-equiv=\"Content-Type\" content=\"text/html\" />\n");
 
647
  xmlprintf("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n");
 
648
  xmlprintf("<meta name=\"robots\" content=\"NOFOLLOW\" />\n");
 
649
  xmlprintf("<link rel=\"contents\" href=\"./\" />\n");
 
650
  xmlprintf("<title>%@/%@</title>\n", AGENTNAME, est_version);
 
651
  xmlprintf("<style type=\"text/css\">html {\n");
 
652
  xmlprintf("  margin: 0em 0em; padding: 0em 0em;\n");
 
653
  xmlprintf("  background: #ffffff none;\n");
 
654
  xmlprintf("}\n");
 
655
  xmlprintf("body {\n");
 
656
  xmlprintf("  margin: 2em 2em; padding: 0em 0em;\n");
 
657
  xmlprintf("  color: #111111;\n");
 
658
  xmlprintf("}\n");
 
659
  xmlprintf("</style>\n");
 
660
  xmlprintf("</head>\n");
 
661
  xmlprintf("<body>\n");
 
662
  xmlprintf("<h1>%@</h1>\n", path);
 
663
  if((list = cbdirlist(path)) != NULL){
 
664
    burl = cbsprintf("%s/", p_url);
 
665
    cblistsort(list);
 
666
    for(i = 0; i < cblistnum(list); i++){
 
667
      elem = cblistval(list, i, NULL);
 
668
      eurl = cburlencode(elem, -1);
 
669
      nurl = cburlresolve(burl, elem);
 
670
      if(p_once){
 
671
        xmlprintf("<li><a href=\"%@\">%@</a></li>", nurl, elem);
 
672
      } else {
 
673
        xmlprintf("<li><a href=\"%s?url=%?\">%@</a></li>", g_scriptname, nurl, elem);
 
674
      }
 
675
      free(nurl);
 
676
      free(eurl);
 
677
    }
 
678
    cblistclose(list);
 
679
    free(burl);
 
680
  } else {
 
681
    xmlprintf("<p>The directory could not be opened.</p>\n");
 
682
  }
 
683
  xmlprintf("</body>\n");
 
684
  xmlprintf("</html>\n");
 
685
}
 
686
 
 
687
 
 
688
/* read all data of a local connection */
 
689
static char *readall(int fd, int *sp){
 
690
  CBDATUM *datum;
 
691
  char iobuf[SOCKBUFSIZ];
 
692
  int size;
 
693
  datum = cbdatumopen(NULL, -1);
 
694
  while(cbdatumsize(datum) < g_limitsize && (size = read(fd, iobuf, SOCKBUFSIZ)) > 0){
 
695
    cbdatumcat(datum, iobuf, size);
 
696
  }
 
697
  return cbdatumtomalloc(datum, sp);
 
698
}
 
699
 
 
700
 
 
701
/* pass through raw data of a connection */
 
702
static void passlocalrawdata(int fd){
 
703
  char iobuf[SOCKBUFSIZ];
 
704
  int size;
 
705
  while((size = read(fd, iobuf, SOCKBUFSIZ)) > 0){
 
706
    fwrite(iobuf, 1, size, stdout);
 
707
  }
 
708
}
 
709
 
 
710
 
 
711
/* send the data of local file */
 
712
static void sendlocaldata(void){
 
713
  CBMAP *heads;
 
714
  const char *kbuf, *vbuf, *cmd;
 
715
  char *url, *type, *enc, *pv, *rbuf;
 
716
  int fd, code, ksiz, rsiz;
 
717
  url = replaceurl(p_url);
 
718
  heads = cbmapopenex(MINIBNUM);
 
719
  if((fd = getlocalconnection(url, &code, heads)) == -1){
 
720
    if(code == 0){
 
721
      senddirlist(cbmapget(heads, "ERROR", -1, NULL));
 
722
    } else {
 
723
      showerror(cbmapget(heads, "ERROR", -1, NULL));
 
724
    }
 
725
    cbmapclose(heads);
 
726
    free(url);
 
727
    return;
 
728
  }
 
729
  cbmapiterinit(g_urlrules);
 
730
  while((kbuf = cbmapiternext(g_urlrules, &ksiz)) != NULL){
 
731
    if(est_regex_match_str(kbuf, p_url)){
 
732
      cbmapput(heads, "content-type", -1, cbmapget(g_urlrules, kbuf, ksiz, NULL), -1, TRUE);
 
733
      break;
 
734
    }
 
735
  }
 
736
  if(!(vbuf = cbmapget(heads, "content-type", -1, NULL))) vbuf = "text/plain";
 
737
  type = cbmemdup(vbuf, -1);
 
738
  if((pv = strchr(type, ';')) != NULL) *pv = '\0';
 
739
  cbstrtolower(type);
 
740
  enc = NULL;
 
741
  if((pv = strstr(vbuf, "charset=")) != NULL || (pv = strstr(vbuf, "CHARSET=")) != NULL){
 
742
    pv = strchr(pv, '=') + 1;
 
743
    if(*pv == '"') pv++;
 
744
    enc = cbmemdup(pv, -1);
 
745
    if((pv = strchr(enc, '"')) != NULL) *pv = '\0';
 
746
  }
 
747
  cmd = "";
 
748
  cbmapiterinit(g_mtrules);
 
749
  while((kbuf = cbmapiternext(g_mtrules, &ksiz)) != NULL){
 
750
    if(est_regex_match_str(kbuf, type)){
 
751
      cmd = cbmapget(g_mtrules, kbuf, ksiz, NULL);
 
752
      break;
 
753
    }
 
754
  }
 
755
  printf("Status: %d\r\n", code);
 
756
  cbmapout(heads, "", -1);
 
757
  cbmapout(heads, "ERROR", -1);
 
758
  if(*cmd != '\0'){
 
759
    cbmapput(heads, "content-type", -1, "text/html; charset=UTF-8", -1, TRUE);
 
760
    cbmapout(heads, "content-length", -1);
 
761
    cbmapout(heads, "content-encoding", -1);
 
762
    cbmapout(heads, "connection", -1);
 
763
    cbmapout(heads, "set-cookie", -1);
 
764
    cbmapout(heads, "set-cookie2", -1);
 
765
    cbmapout(heads, "etag", -1);
 
766
    cbmapout(heads, "transfer-encoding", -1);
 
767
  }
 
768
  modifylocation(heads, "location");
 
769
  modifylocation(heads, "content-location");
 
770
  cbmapiterinit(heads);
 
771
  while((kbuf = cbmapiternext(heads, &ksiz)) != NULL){
 
772
    printf("%s: %s\r\n", kbuf, cbmapget(heads, kbuf, ksiz, NULL));
 
773
  }
 
774
  printf("\r\n");
 
775
  if(!strcmp(cmd, DRAFTCMD)){
 
776
    rbuf = readall(fd, &rsiz);
 
777
    sendpagefromdraft(rbuf, rsiz, enc);
 
778
    free(rbuf);
 
779
  } else if(!strcmp(cmd, TEXTCMD)){
 
780
    rbuf = readall(fd, &rsiz);
 
781
    sendpagefromtext(rbuf, rsiz, enc);
 
782
    free(rbuf);
 
783
  } else if(!strcmp(cmd, HTMLCMD)){
 
784
    rbuf = readall(fd, &rsiz);
 
785
    sendpagefromhtml(rbuf, rsiz, enc);
 
786
    free(rbuf);
 
787
  } else if(!strcmp(cmd, MIMECMD)){
 
788
    rbuf = readall(fd, &rsiz);
 
789
    sendpagefrommime(rbuf, rsiz, enc);
 
790
    free(rbuf);
 
791
  } else if(*cmd != '\0'){
 
792
    rbuf = readall(fd, &rsiz);
 
793
    sendpagewithxcmd(rbuf, rsiz, enc, cmd);
 
794
    free(rbuf);
 
795
  } else {
 
796
    passlocalrawdata(fd);
 
797
  }
 
798
  free(enc);
 
799
  free(type);
 
800
  close(fd);
 
801
  cbmapclose(heads);
 
802
  free(url);
 
803
}
 
804
 
 
805
 
 
806
/* get the HTTP connection of a URL */
 
807
static int gethttpconnection(const char *url, int *codep, CBMAP *heads){
 
808
  CBMAP *elems;
 
809
  const char *scheme, *host, *pstr, *auth, *path, *query, *rp;
 
810
  char *addr, iobuf[SOCKBUFSIZ], *wp, *tmp, name[SOCKBUFSIZ], *pv;
 
811
  int pnum, sock, size, nsiz;
 
812
  cbmapput(heads, "ERROR", -1, "", -1, TRUE);
 
813
  cbmapput(heads, "", -1, "", -1, TRUE);
 
814
  elems = cburlbreak(url);
 
815
  scheme = cbmapget(elems, "scheme", -1, NULL);
 
816
  host = cbmapget(elems, "host", -1, NULL);
 
817
  pnum = (pstr = cbmapget(elems, "port", -1, NULL)) ? atoi(pstr) : 80;
 
818
  auth = cbmapget(elems, "authority", -1, NULL);
 
819
  path = cbmapget(elems, "path", -1, NULL);
 
820
  query = cbmapget(elems, "query", -1, NULL);
 
821
  if(!scheme || cbstricmp(scheme, "http") || !host || pnum < 1){
 
822
    cbmapput(heads, "ERROR", -1, "invalid URL", -1, TRUE);
 
823
    cbmapclose(elems);
 
824
    return -1;
 
825
  }
 
826
  if(!auth) auth = "";
 
827
  if(!path) path = "/";
 
828
  if(!query) query = "";
 
829
  if(!(addr = est_get_host_addr(host))){
 
830
    cbmapput(heads, "ERROR", -1, "unknown host", -1, TRUE);
 
831
    cbmapclose(elems);
 
832
    return -1;
 
833
  }
 
834
  if((sock = est_get_client_sock(addr, pnum)) == -1){
 
835
    cbmapput(heads, "ERROR", -1, "connection failed", -1, TRUE);
 
836
    cbmapclose(elems);
 
837
    return -1;
 
838
  }
 
839
  wp = iobuf;
 
840
  wp += sprintf(wp, "GET %s%s%s HTTP/1.0\r\n", path, query[0] != '\0' ? "?" : "", query);
 
841
  wp += sprintf(wp, "Host: %s:%d\r\n", host, pnum);
 
842
  wp += sprintf(wp, "Connection: close\r\n");
 
843
  if(auth[0] != '\0'){
 
844
    tmp = cbbaseencode(auth, -1);
 
845
    wp += sprintf(wp, "Authorization: Basic %s\r\n", tmp);
 
846
    free(tmp);
 
847
  }
 
848
  wp += sprintf(wp, "User-Agent: %s\r\n", g_agentname);
 
849
  if(g_passaddr) wp += sprintf(wp, "X-Forwarded-For: %s\r\n", g_remoteaddr);
 
850
  switch(g_language){
 
851
  case ESTLANGEN:
 
852
    wp += sprintf(wp, "Accept-Language: en,ja\r\n");
 
853
    break;
 
854
  case ESTLANGJA:
 
855
    wp += sprintf(wp, "Accept-Language: ja,en\r\n");
 
856
    break;
 
857
  case ESTLANGZH:
 
858
    wp += sprintf(wp, "Accept-Language: zh,en\r\n");
 
859
    break;
 
860
  case ESTLANGKO:
 
861
    wp += sprintf(wp, "Accept-Language: ko,en\r\n");
 
862
    break;
 
863
  }
 
864
  wp += sprintf(wp, "\r\n");
 
865
  est_sock_send_all(sock, iobuf, wp - iobuf);
 
866
  if((size = est_sock_recv_line(sock, iobuf, SOCKBUFSIZ - 1)) < 1 ||
 
867
     !cbstrfwmatch(iobuf, "HTTP/") || !(rp = strchr(iobuf, ' '))){
 
868
    cbmapput(heads, "ERROR", -1, "no data received", -1, TRUE);
 
869
    est_sock_down(sock);
 
870
    cbmapclose(elems);
 
871
    return -1;
 
872
  }
 
873
  *codep = atoi(rp);
 
874
  cbmapput(heads, "", 0, iobuf, size, TRUE);
 
875
  name[0] = '\0';
 
876
  nsiz = 0;
 
877
  while((size = est_sock_recv_line(sock, iobuf, SOCKBUFSIZ - 1)) > 0){
 
878
    if(iobuf[0] == ' ' || iobuf[0] == '\t'){
 
879
      if(name[0] != '\0'){
 
880
        iobuf[0] = ' ';
 
881
        cbmapputcat(heads, name, nsiz, iobuf, size);
 
882
      }
 
883
    } else if((rp = strchr(iobuf, ':')) > iobuf){
 
884
      nsiz = rp - iobuf;
 
885
      memcpy(name, iobuf, nsiz);
 
886
      name[nsiz] = '\0';
 
887
      for(pv = name; *pv != '\0'; pv++){
 
888
        if(*pv >= 'A'&& *pv <= 'Z') *pv = *pv + ('a' - 'A');
 
889
      }
 
890
      rp++;
 
891
      if(*rp == ' ' || *rp == '\t') rp++;
 
892
      if(cbmapget(heads, name, nsiz, NULL)){
 
893
        cbmapputcat(heads, name, nsiz, ", ", 2);
 
894
        cbmapputcat(heads, name, nsiz, pv, -1);
 
895
      } else {
 
896
        cbmapput(heads, name, nsiz, rp, -1, TRUE);
 
897
      }
 
898
    }
 
899
  }
 
900
  cbmapclose(elems);
 
901
  return sock;
 
902
}
 
903
 
 
904
 
 
905
/* receive all data of a networdk connection */
 
906
static char *recvall(int sock, int *sp){
 
907
  CBDATUM *datum;
 
908
  char iobuf[SOCKBUFSIZ];
 
909
  int size;
 
910
  datum = cbdatumopen(NULL, -1);
 
911
  while(cbdatumsize(datum) < g_limitsize && (size = recv(sock, iobuf, SOCKBUFSIZ, 0)) > 0){
 
912
    cbdatumcat(datum, iobuf, size);
 
913
  }
 
914
  return cbdatumtomalloc(datum, sp);
 
915
}
 
916
 
 
917
 
 
918
/* pass through raw data of a connection */
 
919
static void passhttprawdata(int sock){
 
920
  char iobuf[SOCKBUFSIZ];
 
921
  int size;
 
922
  while((size = recv(sock, iobuf, SOCKBUFSIZ, 0)) > 0){
 
923
    fwrite(iobuf, 1, size, stdout);
 
924
  }
 
925
}
 
926
 
 
927
 
 
928
/* modify a header of location */
 
929
static void modifylocation(CBMAP *heads, const char *name){
 
930
  CBDATUM *datum;
 
931
  const char *url;
 
932
  char *nurl;
 
933
  int i;
 
934
  if(!(url = cbmapget(heads, name, -1, NULL))) return;
 
935
  nurl = cburlresolve(p_url, url);
 
936
  datum = cbdatumopen(NULL, -1);
 
937
  est_datum_printf(datum, "http://%s%s?url=%?&once=%d", g_hostname, g_scriptpath, nurl, p_once);
 
938
  for(i = 0; i < cblistnum(p_words); i++){
 
939
    est_datum_printf(datum, "&word%d=%?", i + 1, cblistval(p_words, i, NULL));
 
940
  }
 
941
  cbmapput(heads, name, -1, cbdatumptr(datum), cbdatumsize(datum), TRUE);
 
942
  cbdatumclose(datum);
 
943
  free(nurl);
 
944
}
 
945
 
 
946
 
 
947
/* send the data of HTTP connection */
 
948
static void sendhttpdata(void){
 
949
  CBMAP *heads;
 
950
  const char *kbuf, *vbuf, *cmd;
 
951
  char *url, *type, *enc, *pv, *rbuf;
 
952
  int sock, code, ksiz, rsiz;
 
953
  url = replaceurl(p_url);
 
954
  heads = cbmapopenex(MINIBNUM);
 
955
  if((sock = gethttpconnection(url, &code, heads)) == -1){
 
956
    showerror(cbmapget(heads, "ERROR", -1, NULL));
 
957
    cbmapclose(heads);
 
958
    free(url);
 
959
    return;
 
960
  }
 
961
  cbmapiterinit(g_urlrules);
 
962
  while((kbuf = cbmapiternext(g_urlrules, &ksiz)) != NULL){
 
963
    if(est_regex_match_str(kbuf, p_url)){
 
964
      cbmapput(heads, "content-type", -1, cbmapget(g_urlrules, kbuf, ksiz, NULL), -1, TRUE);
 
965
      break;
 
966
    }
 
967
  }
 
968
  if(!(vbuf = cbmapget(heads, "content-type", -1, NULL))) vbuf = "text/plain";
 
969
  type = cbmemdup(vbuf, -1);
 
970
  if((pv = strchr(type, ';')) != NULL) *pv = '\0';
 
971
  cbstrtolower(type);
 
972
  enc = NULL;
 
973
  if((pv = strstr(vbuf, "charset=")) != NULL || (pv = strstr(vbuf, "CHARSET=")) != NULL){
 
974
    pv = strchr(pv, '=') + 1;
 
975
    if(*pv == '"') pv++;
 
976
    enc = cbmemdup(pv, -1);
 
977
    if((pv = strchr(enc, '"')) != NULL) *pv = '\0';
 
978
  }
 
979
  cmd = "";
 
980
  cbmapiterinit(g_mtrules);
 
981
  while((kbuf = cbmapiternext(g_mtrules, &ksiz)) != NULL){
 
982
    if(est_regex_match_str(kbuf, type)){
 
983
      cmd = cbmapget(g_mtrules, kbuf, ksiz, NULL);
 
984
      break;
 
985
    }
 
986
  }
 
987
  printf("Status: %d\r\n", code);
 
988
  cbmapout(heads, "", -1);
 
989
  cbmapout(heads, "ERROR", -1);
 
990
  if(*cmd != '\0'){
 
991
    cbmapput(heads, "content-type", -1, "text/html; charset=UTF-8", -1, TRUE);
 
992
    cbmapout(heads, "content-length", -1);
 
993
    cbmapout(heads, "content-encoding", -1);
 
994
    cbmapout(heads, "connection", -1);
 
995
    cbmapout(heads, "set-cookie", -1);
 
996
    cbmapout(heads, "set-cookie2", -1);
 
997
    cbmapout(heads, "etag", -1);
 
998
    cbmapout(heads, "transfer-encoding", -1);
 
999
  }
 
1000
  modifylocation(heads, "location");
 
1001
  modifylocation(heads, "content-location");
 
1002
  cbmapiterinit(heads);
 
1003
  while((kbuf = cbmapiternext(heads, &ksiz)) != NULL){
 
1004
    printf("%s: %s\r\n", kbuf, cbmapget(heads, kbuf, ksiz, NULL));
 
1005
  }
 
1006
  printf("\r\n");
 
1007
  if(!strcmp(cmd, DRAFTCMD)){
 
1008
    rbuf = recvall(sock, &rsiz);
 
1009
    sendpagefromdraft(rbuf, rsiz, enc);
 
1010
    free(rbuf);
 
1011
  } else if(!strcmp(cmd, TEXTCMD)){
 
1012
    rbuf = recvall(sock, &rsiz);
 
1013
    sendpagefromtext(rbuf, rsiz, enc);
 
1014
    free(rbuf);
 
1015
  } else if(!strcmp(cmd, HTMLCMD)){
 
1016
    rbuf = recvall(sock, &rsiz);
 
1017
    sendpagefromhtml(rbuf, rsiz, enc);
 
1018
    free(rbuf);
 
1019
  } else if(!strcmp(cmd, MIMECMD)){
 
1020
    rbuf = recvall(sock, &rsiz);
 
1021
    sendpagefrommime(rbuf, rsiz, enc);
 
1022
    free(rbuf);
 
1023
  } else if(*cmd != '\0'){
 
1024
    rbuf = recvall(sock, &rsiz);
 
1025
    sendpagewithxcmd(rbuf, rsiz, enc, cmd);
 
1026
    free(rbuf);
 
1027
  } else {
 
1028
    passhttprawdata(sock);
 
1029
  }
 
1030
  free(enc);
 
1031
  free(type);
 
1032
  est_sock_down(sock);
 
1033
  cbmapclose(heads);
 
1034
  free(url);
 
1035
}
 
1036
 
 
1037
 
 
1038
/* send the navigation bar */
 
1039
static void sendnavibar(void){
 
1040
  static int first = TRUE;
 
1041
  const char *defstyle = "text-align: left; text-indent: 0em;"
 
1042
    " margin: 0.2em 0.2em; padding 0em; 0em;"
 
1043
    " color: #111111; background: transparent none; border: none;"
 
1044
    " font-size: small; font-weight: normal;";
 
1045
  int i;
 
1046
  if(!first) return;
 
1047
  first = FALSE;
 
1048
  xmlprintf("<div id=\"estproxy_navi\" class=\"estproxy_navi\""
 
1049
            " style=\"display: block; margin: 0.2em 0.2em 0.5em 0.2em; padding: 0.5em 1.0em;"
 
1050
            " background: #eeeeff; border: outset 1pt #bbbbcc;\">\n");
 
1051
  xmlprintf("<p class=\"estproxy_note\" style=\"%@ font-style: italic; float: left;\">"
 
1052
            "This page have been mediated by Hyper Estraier %@.</p>\n", defstyle, est_version);
 
1053
  xmlprintf("<form action=\"%@\" method=\"get\" id=\"estproxy_form\" style=\"%@\">\n",
 
1054
            g_scriptname, defstyle);
 
1055
  xmlprintf("<div class=\"estproxy_reloadnavi\" style=\"%@ text-align: right;\">\n", defstyle);
 
1056
  xmlprintf("<label for=\"estproxy_words\" class=\"estproxy_label\">"
 
1057
            "highlighted words:</label>\n");
 
1058
  xmlprintf("<input type=\"text\" name=\"words\" value=\"");
 
1059
  for(i = 0; i < cblistnum(p_words); i++){
 
1060
    if(i > 0) xmlprintf(" ");
 
1061
    xmlprintf("%@", cblistval(p_words, i, NULL));
 
1062
  }
 
1063
  xmlprintf("\" size=\"24\" id=\"estproxy_words\" tabindex=\"1\" accesskey=\"0\" />\n");
 
1064
  xmlprintf("<input type=\"submit\" value=\"Reload\""
 
1065
            " id=\"estproxy_submit\" tabindex=\"2\" accesskey=\"1\" />\n");
 
1066
  xmlprintf("<input type=\"hidden\" name=\"url\" value=\"%@\" id=\"estproxy_url\" />\n",
 
1067
            p_url);
 
1068
  xmlprintf("<input type=\"hidden\" name=\"once\" value=\"%d\" id=\"estproxy_once\" />\n",
 
1069
            p_once);
 
1070
  xmlprintf("</div>\n");
 
1071
  xmlprintf("</form>\n");
 
1072
  if(cblistnum(p_words) > 0){
 
1073
    xmlprintf("<div class=\"estproxy_jumpnavi\""
 
1074
              " style=\"%@ margin: 0.2em 0.8em; clear: both; float: left;\">\n", defstyle);
 
1075
    xmlprintf("<span class=\"estproxy_label\">jump to:</span>\n");
 
1076
    for(i = 0; i < cblistnum(p_words); i++){
 
1077
      xmlprintf("<a href=\"#estproxy_word%d\" style=\"padding: 0em 0.3em; color: #111111;"
 
1078
                " background: %@ none; text-decoration: none; -moz-border-radius:0.2em;\">"
 
1079
                "%@</a>\n", i + 1, g_wordcolors[i%(sizeof(g_wordcolors)/sizeof(char *))],
 
1080
                cblistval(p_words, i, NULL));
 
1081
    }
 
1082
    xmlprintf("</div>\n");
 
1083
  }
 
1084
  xmlprintf("<div class=\"estproxy_jumpsrc\" style=\"%@ clear: right; text-align: right;\">\n",
 
1085
            defstyle);
 
1086
  xmlprintf("<span class=\"estproxy_label\">original page:</span>\n");
 
1087
  xmlprintf("<a href=\"%@\" style=\"color: #0011ee; text-decoration: none;\""
 
1088
            " class=\"estproxy_srclink\">%64@</a>\n", p_url, p_url);
 
1089
  xmlprintf("</div>\n");
 
1090
  xmlprintf("</div>\n");
 
1091
}
 
1092
 
 
1093
 
 
1094
/* send a snippet string */
 
1095
static void sendsnippet(const char *str){
 
1096
  static CBMAP *colors = NULL;
 
1097
  static CBMAP *ids = NULL;
 
1098
  CBLIST *chunks, *lines;
 
1099
  const char *line, *color, *id;
 
1100
  char numbuf[NUMBUFSIZ], *snippet, *word, *pv;
 
1101
  int i, j, len, tail;
 
1102
  if(!colors){
 
1103
    colors = cbmapopenex(MINIBNUM);
 
1104
    cbglobalgc(colors, (void (*)(void *))cbmapclose);
 
1105
    ids = cbmapopenex(MINIBNUM);
 
1106
    cbglobalgc(ids, (void (*)(void *))cbmapclose);
 
1107
    for(i = 0; i < cblistnum(p_words); i++){
 
1108
      cbmapput(colors, cblistval(p_words, i, NULL), -1,
 
1109
               g_wordcolors[i%(sizeof(g_wordcolors)/sizeof(char *))], -1, FALSE);
 
1110
      len = sprintf(numbuf, "estproxy_word%d", i + 1);
 
1111
      cbmapput(ids, cblistval(p_words, i, NULL), -1, numbuf, len, FALSE);
 
1112
    }
 
1113
  }
 
1114
  if(cblistnum(p_words) < 1){
 
1115
    xmlprintf("%@", str);
 
1116
    return;
 
1117
  }
 
1118
  tail = cbstrbwmatch(str, "\n");
 
1119
  chunks = cbsplit(str, -1, "\n");
 
1120
  for(i = 0; i < cblistnum(chunks); i++){
 
1121
    snippet = est_str_make_snippet(cblistval(chunks, i, NULL), p_words, INT_MAX, INT_MAX, 0);
 
1122
    lines = cbsplit(snippet, -1, "\n");
 
1123
    for(j = 0; j < cblistnum(lines); j++){
 
1124
      line = cblistval(lines, j, NULL);
 
1125
      if((pv = strchr(line, '\t')) != NULL){
 
1126
        word = cbmemdup(line, pv - line);
 
1127
        pv++;
 
1128
        len = strlen(pv);
 
1129
        if(!(color = cbmapget(colors, pv, len, NULL))) color = "#cccccc";
 
1130
        if((id = cbmapget(ids, pv, len, NULL)) != NULL){
 
1131
          xmlprintf("<strong style=\"color:#000000;background-color:%@;"
 
1132
                    "-moz-border-radius:0.2em;\" id=\"%@\">%@</strong>",
 
1133
                    color, id, word);
 
1134
          cbmapout(ids, pv, len);
 
1135
        } else {
 
1136
          xmlprintf("<strong style=\"color:#000000;background-color:%@;"
 
1137
                    "-moz-border-radius: 0.2em;\">%@</strong>",
 
1138
                    color, word);
 
1139
        }
 
1140
        free(word);
 
1141
      } else {
 
1142
        xmlprintf("%@", line);
 
1143
      }
 
1144
    }
 
1145
    free(snippet);
 
1146
    if(i < cblistnum(chunks) - 1) xmlprintf("\n");
 
1147
  }
 
1148
  cblistclose(chunks);
 
1149
  if(tail) xmlprintf("\n");
 
1150
}
 
1151
 
 
1152
 
 
1153
/* get the language string */
 
1154
static const char *langstr(void){
 
1155
  switch(g_language){
 
1156
  case ESTLANGEN: return "en";
 
1157
  case ESTLANGJA: return "ja";
 
1158
  case ESTLANGZH: return "zh";
 
1159
  case ESTLANGKO: return "ko";
 
1160
  default: break;
 
1161
  }
 
1162
  return "en";
 
1163
}
 
1164
 
 
1165
 
 
1166
/* send the result made from document draft */
 
1167
static void sendpagefromdraft(const char *buf, int size, const char *penc){
 
1168
  ESTDOC *doc;
 
1169
  CBMAP *kwords;
 
1170
  const CBLIST *texts;
 
1171
  CBLIST *names;
 
1172
  const char *lang, *title, *rp;
 
1173
  int i;
 
1174
  doc = est_doc_new_from_draft(buf);
 
1175
  if(!(lang = est_doc_attr(doc, ESTDATTRLANG))) lang = langstr();
 
1176
  if(!(title = est_doc_attr(doc, ESTDATTRTITLE))){
 
1177
    if((title = est_doc_attr(doc, ESTDATTRURI)) != NULL){
 
1178
      if((rp = strrchr(title, '/')) != NULL && rp[1] != '\0') title = rp + 1;
 
1179
    } else {
 
1180
      title = "(no title)";
 
1181
    }
 
1182
  }
 
1183
  xmlprintf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
1184
  xmlprintf("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\""
 
1185
            " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
 
1186
  xmlprintf("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%@\" lang=\"%@\">\n",
 
1187
            lang, lang);
 
1188
  xmlprintf("<head>\n");
 
1189
  xmlprintf("<meta http-equiv=\"Content-Language\" content=\"%@\" />\n", lang);
 
1190
  xmlprintf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n");
 
1191
  xmlprintf("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n");
 
1192
  xmlprintf("<link rel=\"contents\" href=\"%@\" />\n", g_scriptname);
 
1193
  xmlprintf("<title>%@</title>\n", title);
 
1194
  xmlprintf("<style type=\"text/css\">html {\n");
 
1195
  xmlprintf("  margin: 0em 0em; padding: 0em 0em;\n");
 
1196
  xmlprintf("  background: #ffffff none;\n");
 
1197
  xmlprintf("}\n");
 
1198
  xmlprintf("body {\n");
 
1199
  xmlprintf("  margin: 1em 1em; padding: 0em 0em;\n");
 
1200
  xmlprintf("  color: #111111;\n");
 
1201
  xmlprintf("}\n");
 
1202
  xmlprintf("div.attrlist {\n");
 
1203
  xmlprintf("  margin: 0.2em 0.2em; padding: 0.2em 0.5em;\n");
 
1204
  xmlprintf("  background: #eeeeee none;\n");
 
1205
  xmlprintf("  -moz-border-radius: 0.4em;\n");
 
1206
  xmlprintf("}\n");
 
1207
  xmlprintf("span.attrname {\n");
 
1208
  xmlprintf("  font-weight: bold;\n");
 
1209
  xmlprintf("}\n");
 
1210
  xmlprintf("p {\n");
 
1211
  xmlprintf("  margin: 0.5em 1em; text-indent: 0.8em;\n");
 
1212
  xmlprintf("}\n");
 
1213
  xmlprintf("p.keywords {\n");
 
1214
  xmlprintf("  margin: 0.5em 1.5em;\n");
 
1215
  xmlprintf("  font-style: italic; color: #333333;\n");
 
1216
  xmlprintf("}\n");
 
1217
  xmlprintf("p.hiddentext {\n");
 
1218
  xmlprintf("  margin: 0.5em 2em;\n");
 
1219
  xmlprintf("  font-size: smaller; font-style: italic; color: #555555;\n");
 
1220
  xmlprintf("}\n");
 
1221
  xmlprintf("</style>\n");
 
1222
  xmlprintf("</head>\n");
 
1223
  xmlprintf("<body>\n");
 
1224
  if(g_shownavi) sendnavibar();
 
1225
  xmlprintf("<h1>%@</h1>\n", title);
 
1226
  xmlprintf("<div class=\"attrlist\">\n");
 
1227
  names = est_doc_attr_names(doc);
 
1228
  for(i = 0; i < cblistnum(names); i++){
 
1229
    rp = cblistval(names, i, NULL);
 
1230
    xmlprintf("<div><span id=\"attrname%d\" class=\"attrname\">%@</span>:"
 
1231
              " <span id=\"attrvalue%d\" class=\"attrvalue\">%@</span></div>\n",
 
1232
              i + 1, rp, i + 1, est_doc_attr(doc, rp));
 
1233
  }
 
1234
  cblistclose(names);
 
1235
  xmlprintf("</div>\n");
 
1236
  if((kwords = est_doc_keywords(doc)) != NULL && cbmaprnum(kwords) > 0){
 
1237
    xmlprintf("<hr />\n");
 
1238
    xmlprintf("<p class=\"keywords\">");
 
1239
    cbmapiterinit(kwords);
 
1240
    for(i = 1; (rp = cbmapiternext(kwords, NULL)) != NULL; i++){
 
1241
      if(i > 1) xmlprintf(", ");
 
1242
      xmlprintf("<span id=\"keyword%d\" class=\"keyword\">%@</span>"
 
1243
                " (<span id=\"keyscore%d\" class=\"keyscore\">%@</span>)",
 
1244
                i, rp, i, cbmapget(kwords, rp, -1, NULL));
 
1245
    }
 
1246
    xmlprintf("</p>\n");
 
1247
  }
 
1248
  xmlprintf("<hr />\n");
 
1249
  texts = est_doc_texts(doc);
 
1250
  for(i = 0; i < cblistnum(texts); i++){
 
1251
    rp = cblistval(texts, i, NULL);
 
1252
    xmlprintf("<p class=\"text\">");
 
1253
    sendsnippet(rp);
 
1254
    xmlprintf("</p>\n");
 
1255
  }
 
1256
  rp = est_doc_hidden_texts(doc);
 
1257
  if(*rp != '\0'){
 
1258
    xmlprintf("<hr />\n");
 
1259
    xmlprintf("<p class=\"hiddentext\">");
 
1260
    sendsnippet(rp);
 
1261
    xmlprintf("</p>\n");
 
1262
  }
 
1263
  xmlprintf("<hr />\n");
 
1264
  xmlprintf("</body>\n");
 
1265
  xmlprintf("</html>\n");
 
1266
  est_doc_delete(doc);
 
1267
}
 
1268
 
 
1269
 
 
1270
/* send the result made from plain text */
 
1271
static void sendpagefromtext(const char *buf, int size, const char *penc){
 
1272
  const char *lang, *enc, *text;
 
1273
  char *title, *nbuf;
 
1274
  lang = langstr();
 
1275
  title = est_regex_replace(p_url, ".*/([^/]*)/?$", "\\1");
 
1276
  enc = penc ? penc : est_enc_name(buf, size, g_language);
 
1277
  if(!strcmp(enc, "UTF-8")){
 
1278
    nbuf = NULL;
 
1279
    text = buf;
 
1280
  } else {
 
1281
    text = buf;
 
1282
    nbuf = est_iconv(buf, size, enc, "UTF-8", NULL, NULL);
 
1283
      if(nbuf) text = nbuf;
 
1284
  }
 
1285
  xmlprintf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
1286
  xmlprintf("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\""
 
1287
            " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
 
1288
  xmlprintf("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%@\" lang=\"%@\">\n",
 
1289
            lang, lang);
 
1290
  xmlprintf("<head>\n");
 
1291
  xmlprintf("<meta http-equiv=\"Content-Language\" content=\"%@\" />\n", lang);
 
1292
  xmlprintf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n");
 
1293
  xmlprintf("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n");
 
1294
  xmlprintf("<link rel=\"contents\" href=\"%@\" />\n", g_scriptname);
 
1295
  xmlprintf("<title>%@</title>\n", title);
 
1296
  xmlprintf("<style type=\"text/css\">html {\n");
 
1297
  xmlprintf("  margin: 0em 0em; padding: 0em 0em;\n");
 
1298
  xmlprintf("  background: #ffffff none;\n");
 
1299
  xmlprintf("}\n");
 
1300
  xmlprintf("body {\n");
 
1301
  xmlprintf("  margin: 1em 0.8em; padding: 0em 0em;\n");
 
1302
  xmlprintf("  color: #111111;\n");
 
1303
  xmlprintf("}\n");
 
1304
  xmlprintf("pre {\n");
 
1305
  xmlprintf("  white-space: pre-wrap;\n");
 
1306
  xmlprintf("  white-space: -moz-pre-wrap; word-wrap: break-word;\n");
 
1307
  xmlprintf("}\n");
 
1308
  xmlprintf("</style>\n");
 
1309
  xmlprintf("</head>\n");
 
1310
  xmlprintf("<body>\n");
 
1311
  if(g_shownavi) sendnavibar();
 
1312
  xmlprintf("<pre>");
 
1313
  sendsnippet(text);
 
1314
  xmlprintf("</pre>\n");
 
1315
  xmlprintf("</body>\n");
 
1316
  xmlprintf("</html>\n");
 
1317
  free(nbuf);
 
1318
  free(title);
 
1319
}
 
1320
 
 
1321
 
 
1322
/* send the result made from HTML */
 
1323
static void sendpagefromhtml(const char *buf, int size, const char *penc){
 
1324
  CBMAP *attrs;
 
1325
  CBLIST *elems;
 
1326
  const char *enc, *html, *elem, *name, *kbuf, *vbuf;
 
1327
  char *nbuf, *nenc, *raw, *nurl;
 
1328
  int i, esiz, ksiz, asis;
 
1329
  enc = est_enc_name(buf, size, g_language);
 
1330
  html = NULL;
 
1331
  nbuf = NULL;
 
1332
  if(!strcmp(enc, "UTF-16") || !strcmp(enc, "UTF-16BE") || !strcmp(enc, "UTF-16LE")){
 
1333
    nbuf = est_iconv(buf, size, enc, "UTF-8", NULL, NULL);
 
1334
  } else if(!strcmp(enc, "US-ASCII")){
 
1335
    nbuf = NULL;
 
1336
  } else {
 
1337
    if((nenc = penc ? cbmemdup(penc, -1) : htmlenc(buf)) != NULL){
 
1338
      if(cbstricmp(nenc, "UTF-8")){
 
1339
        nbuf = est_iconv(buf, size, nenc, "UTF-8", NULL, NULL);
 
1340
        if(!nbuf) nbuf = est_iconv(buf, size, enc, "UTF-8", NULL, NULL);
 
1341
      }
 
1342
      free(nenc);
 
1343
    } else {
 
1344
      nbuf = est_iconv(buf, size, enc, "UTF-8", NULL, NULL);
 
1345
    }
 
1346
  }
 
1347
  if(nbuf) html = nbuf;
 
1348
  if(!html) html = buf;
 
1349
  asis = FALSE;
 
1350
  elems = cbxmlbreak(html, FALSE);
 
1351
  for(i = 0; i < CB_LISTNUM(elems); i++){
 
1352
    elem = CB_LISTVAL2(elems, i, esiz);
 
1353
    if(elem[0] == '<'){
 
1354
      if(elem[1] == '?' || elem[1] == '!' || elem[1] == '/'){
 
1355
        xmlprintf("%s", elem);
 
1356
        asis = FALSE;
 
1357
      } else {
 
1358
        attrs = cbxmlattrs(elem);
 
1359
        name = cbmapget(attrs, "", -1, NULL);
 
1360
        if(!cbstricmp(name, "title") || !cbstricmp(name, "script") || !cbstricmp(name, "style"))
 
1361
          asis = TRUE;
 
1362
        if(!cbstricmp(name, "meta")){
 
1363
          vbuf = cbmapget(attrs, "name", -1, NULL);
 
1364
          if(!vbuf) vbuf = cbmapget(attrs, "Name", -1, NULL);
 
1365
          if(!vbuf) vbuf = cbmapget(attrs, "NAME", -1, NULL);
 
1366
          if(!vbuf) vbuf = cbmapget(attrs, "http-equiv", -1, NULL);
 
1367
          if(!vbuf) vbuf = cbmapget(attrs, "Http-equiv", -1, NULL);
 
1368
          if(!vbuf) vbuf = cbmapget(attrs, "Http-Equiv", -1, NULL);
 
1369
          if(!vbuf) vbuf = cbmapget(attrs, "HTTP-EQUIV", -1, NULL);
 
1370
          if(vbuf && !cbstricmp(vbuf, "content-type")){
 
1371
            xmlprintf("<meta http-equiv=\"Content-Type\""
 
1372
                      " content=\"text/html; charset=UTF-8\" />");
 
1373
          } else {
 
1374
            xmlprintf("%s", elem);
 
1375
          }
 
1376
        } else {
 
1377
          xmlprintf("<%s", name);
 
1378
          cbmapiterinit(attrs);
 
1379
          while((kbuf = cbmapiternext(attrs, &ksiz)) != NULL){
 
1380
            if(ksiz < 1) continue;
 
1381
            vbuf = cbmapget(attrs, kbuf, ksiz, NULL);
 
1382
            if(!cbstricmp(kbuf, "src") || !cbstricmp(kbuf, "href") || !cbstricmp(kbuf, "data")){
 
1383
              nurl = cburlresolve(p_url, vbuf);
 
1384
              if(p_once){
 
1385
                xmlprintf(" %@=\"%@\"", kbuf, nurl);
 
1386
              } else {
 
1387
                xmlprintf(" %@=\"%s?url=%?\"", kbuf, g_scriptname, nurl);
 
1388
              }
 
1389
              free(nurl);
 
1390
            } else if(!cbstricmp(kbuf, "action")){
 
1391
              nurl = cburlresolve(p_url, vbuf);
 
1392
              xmlprintf(" %@=\"%@\"", kbuf, nurl);
 
1393
              free(nurl);
 
1394
            } else if(strchr(vbuf, '&')){
 
1395
              raw = htmlrawtext(vbuf);
 
1396
              xmlprintf(" %@=\"%@\"", kbuf, raw);
 
1397
              free(raw);
 
1398
            } else {
 
1399
              xmlprintf(" %@=\"%@\"", kbuf, vbuf);
 
1400
            }
 
1401
          }
 
1402
          if(cbstrbwmatch(elem, "/>")){
 
1403
            xmlprintf(" />");
 
1404
          } else {
 
1405
            xmlprintf(">");
 
1406
          }
 
1407
        }
 
1408
        if(!cbstricmp(name, "body") && g_shownavi){
 
1409
          xmlprintf("\n");
 
1410
          sendnavibar();
 
1411
        }
 
1412
        cbmapclose(attrs);
 
1413
      }
 
1414
    } else if(asis){
 
1415
      xmlprintf("%s", elem);
 
1416
    } else {
 
1417
      if(strchr(elem, '&')){
 
1418
        raw = htmlrawtext(elem);
 
1419
        sendsnippet(raw);
 
1420
        free(raw);
 
1421
      } else {
 
1422
        sendsnippet(elem);
 
1423
      }
 
1424
    }
 
1425
  }
 
1426
  cblistclose(elems);
 
1427
  free(nbuf);
 
1428
}
 
1429
 
 
1430
 
 
1431
/* get the encoding of an HTML string */
 
1432
static char *htmlenc(const char *str){
 
1433
  CBLIST *elems;
 
1434
  CBMAP *attrs;
 
1435
  const char *elem, *equiv, *content;
 
1436
  char *enc, *pv;
 
1437
  int i;
 
1438
  elems = cbxmlbreak(str, TRUE);
 
1439
  for(i = 0; i < CB_LISTNUM(elems); i++){
 
1440
    elem = CB_LISTVAL(elems, i);
 
1441
    if(elem[0] != '<' || !cbstrfwimatch(elem, "<meta")) continue;
 
1442
    enc = NULL;
 
1443
    attrs = cbxmlattrs(elem);
 
1444
    equiv = cbmapget(attrs, "http-equiv", -1, NULL);
 
1445
    if(!equiv) equiv = cbmapget(attrs, "HTTP-EQUIV", -1, NULL);
 
1446
    if(!equiv) equiv = cbmapget(attrs, "Http-Equiv", -1, NULL);
 
1447
    if(!equiv) equiv = cbmapget(attrs, "Http-equiv", -1, NULL);
 
1448
    if(equiv && !cbstricmp(equiv, "Content-Type")){
 
1449
      content = cbmapget(attrs, "content", -1, NULL);
 
1450
      if(!content) content = cbmapget(attrs, "Content", -1, NULL);
 
1451
      if(!content) content = cbmapget(attrs, "CONTENT", -1, NULL);
 
1452
      if(content && ((pv = strstr(content, "charset")) != NULL ||
 
1453
                     (pv = strstr(content, "Charset")) != NULL ||
 
1454
                     (pv = strstr(content, "CHARSET")) != NULL)){
 
1455
        enc = cbmemdup(pv + 8, -1);
 
1456
        if((pv = strchr(enc, ';')) != NULL || (pv = strchr(enc, '\r')) != NULL ||
 
1457
           (pv = strchr(enc, '\n')) != NULL || (pv = strchr(enc, ' ')) != NULL) *pv = '\0';
 
1458
      }
 
1459
    }
 
1460
    cbmapclose(attrs);
 
1461
    if(enc){
 
1462
      CB_LISTCLOSE(elems);
 
1463
      return enc;
 
1464
    }
 
1465
  }
 
1466
  CB_LISTCLOSE(elems);
 
1467
  return NULL;
 
1468
}
 
1469
 
 
1470
 
 
1471
/* unescape entity references of HTML */
 
1472
static char *htmlrawtext(const char *html){
 
1473
  static const char *pairs[] = {
 
1474
    "&amp;", "&", "&lt;", "<", "&gt;", ">", "&quot;", "\"", "&apos;", "'",
 
1475
    "&nbsp;", "\xc2\xa0", "&iexcl;", "\xc2\xa1", "&cent;", "\xc2\xa2",
 
1476
    "&pound;", "\xc2\xa3", "&curren;", "\xc2\xa4", "&yen;", "\xc2\xa5",
 
1477
    "&brvbar;", "\xc2\xa6", "&sect;", "\xc2\xa7", "&uml;", "\xc2\xa8",
 
1478
    "&copy;", "\xc2\xa9", "&ordf;", "\xc2\xaa", "&laquo;", "\xc2\xab",
 
1479
    "&not;", "\xc2\xac", "&shy;", "\xc2\xad", "&reg;", "\xc2\xae",
 
1480
    "&macr;", "\xc2\xaf", "&deg;", "\xc2\xb0", "&plusmn;", "\xc2\xb1",
 
1481
    "&sup2;", "\xc2\xb2", "&sup3;", "\xc2\xb3", "&acute;", "\xc2\xb4",
 
1482
    "&micro;", "\xc2\xb5", "&para;", "\xc2\xb6", "&middot;", "\xc2\xb7",
 
1483
    "&cedil;", "\xc2\xb8", "&sup1;", "\xc2\xb9", "&ordm;", "\xc2\xba",
 
1484
    "&raquo;", "\xc2\xbb", "&frac14;", "\xc2\xbc", "&frac12;", "\xc2\xbd",
 
1485
    "&frac34;", "\xc2\xbe", "&iquest;", "\xc2\xbf", "&Agrave;", "\xc3\x80",
 
1486
    "&Aacute;", "\xc3\x81", "&Acirc;", "\xc3\x82", "&Atilde;", "\xc3\x83",
 
1487
    "&Auml;", "\xc3\x84", "&Aring;", "\xc3\x85", "&AElig;", "\xc3\x86",
 
1488
    "&Ccedil;", "\xc3\x87", "&Egrave;", "\xc3\x88", "&Eacute;", "\xc3\x89",
 
1489
    "&Ecirc;", "\xc3\x8a", "&Euml;", "\xc3\x8b", "&Igrave;", "\xc3\x8c",
 
1490
    "&Iacute;", "\xc3\x8d", "&Icirc;", "\xc3\x8e", "&Iuml;", "\xc3\x8f",
 
1491
    "&ETH;", "\xc3\x90", "&Ntilde;", "\xc3\x91", "&Ograve;", "\xc3\x92",
 
1492
    "&Oacute;", "\xc3\x93", "&Ocirc;", "\xc3\x94", "&Otilde;", "\xc3\x95",
 
1493
    "&Ouml;", "\xc3\x96", "&times;", "\xc3\x97", "&Oslash;", "\xc3\x98",
 
1494
    "&Ugrave;", "\xc3\x99", "&Uacute;", "\xc3\x9a", "&Ucirc;", "\xc3\x9b",
 
1495
    "&Uuml;", "\xc3\x9c", "&Yacute;", "\xc3\x9d", "&THORN;", "\xc3\x9e",
 
1496
    "&szlig;", "\xc3\x9f", "&agrave;", "\xc3\xa0", "&aacute;", "\xc3\xa1",
 
1497
    "&acirc;", "\xc3\xa2", "&atilde;", "\xc3\xa3", "&auml;", "\xc3\xa4",
 
1498
    "&aring;", "\xc3\xa5", "&aelig;", "\xc3\xa6", "&ccedil;", "\xc3\xa7",
 
1499
    "&egrave;", "\xc3\xa8", "&eacute;", "\xc3\xa9", "&ecirc;", "\xc3\xaa",
 
1500
    "&euml;", "\xc3\xab", "&igrave;", "\xc3\xac", "&iacute;", "\xc3\xad",
 
1501
    "&icirc;", "\xc3\xae", "&iuml;", "\xc3\xaf", "&eth;", "\xc3\xb0",
 
1502
    "&ntilde;", "\xc3\xb1", "&ograve;", "\xc3\xb2", "&oacute;", "\xc3\xb3",
 
1503
    "&ocirc;", "\xc3\xb4", "&otilde;", "\xc3\xb5", "&ouml;", "\xc3\xb6",
 
1504
    "&divide;", "\xc3\xb7", "&oslash;", "\xc3\xb8", "&ugrave;", "\xc3\xb9",
 
1505
    "&uacute;", "\xc3\xba", "&ucirc;", "\xc3\xbb", "&uuml;", "\xc3\xbc",
 
1506
    "&yacute;", "\xc3\xbd", "&thorn;", "\xc3\xbe", "&yuml;", "\xc3\xbf",
 
1507
    "&fnof;", "\xc6\x92", "&Alpha;", "\xce\x91", "&Beta;", "\xce\x92",
 
1508
    "&Gamma;", "\xce\x93", "&Delta;", "\xce\x94", "&Epsilon;", "\xce\x95",
 
1509
    "&Zeta;", "\xce\x96", "&Eta;", "\xce\x97", "&Theta;", "\xce\x98",
 
1510
    "&Iota;", "\xce\x99", "&Kappa;", "\xce\x9a", "&Lambda;", "\xce\x9b",
 
1511
    "&Mu;", "\xce\x9c", "&Nu;", "\xce\x9d", "&Xi;", "\xce\x9e",
 
1512
    "&Omicron;", "\xce\x9f", "&Pi;", "\xce\xa0", "&Rho;", "\xce\xa1",
 
1513
    "&Sigma;", "\xce\xa3", "&Tau;", "\xce\xa4", "&Upsilon;", "\xce\xa5",
 
1514
    "&Phi;", "\xce\xa6", "&Chi;", "\xce\xa7", "&Psi;", "\xce\xa8",
 
1515
    "&Omega;", "\xce\xa9", "&alpha;", "\xce\xb1", "&beta;", "\xce\xb2",
 
1516
    "&gamma;", "\xce\xb3", "&delta;", "\xce\xb4", "&epsilon;", "\xce\xb5",
 
1517
    "&zeta;", "\xce\xb6", "&eta;", "\xce\xb7", "&theta;", "\xce\xb8",
 
1518
    "&iota;", "\xce\xb9", "&kappa;", "\xce\xba", "&lambda;", "\xce\xbb",
 
1519
    "&mu;", "\xce\xbc", "&nu;", "\xce\xbd", "&xi;", "\xce\xbe",
 
1520
    "&omicron;", "\xce\xbf", "&pi;", "\xcf\x80", "&rho;", "\xcf\x81",
 
1521
    "&sigmaf;", "\xcf\x82", "&sigma;", "\xcf\x83", "&tau;", "\xcf\x84",
 
1522
    "&upsilon;", "\xcf\x85", "&phi;", "\xcf\x86", "&chi;", "\xcf\x87",
 
1523
    "&psi;", "\xcf\x88", "&omega;", "\xcf\x89", "&thetasym;", "\xcf\x91",
 
1524
    "&upsih;", "\xcf\x92", "&piv;", "\xcf\x96", "&bull;", "\xe2\x80\xa2",
 
1525
    "&hellip;", "\xe2\x80\xa6", "&prime;", "\xe2\x80\xb2", "&Prime;", "\xe2\x80\xb3",
 
1526
    "&oline;", "\xe2\x80\xbe", "&frasl;", "\xe2\x81\x84", "&weierp;", "\xe2\x84\x98",
 
1527
    "&image;", "\xe2\x84\x91", "&real;", "\xe2\x84\x9c", "&trade;", "\xe2\x84\xa2",
 
1528
    "&alefsym;", "\xe2\x84\xb5", "&larr;", "\xe2\x86\x90", "&uarr;", "\xe2\x86\x91",
 
1529
    "&rarr;", "\xe2\x86\x92", "&darr;", "\xe2\x86\x93", "&harr;", "\xe2\x86\x94",
 
1530
    "&crarr;", "\xe2\x86\xb5", "&lArr;", "\xe2\x87\x90", "&uArr;", "\xe2\x87\x91",
 
1531
    "&rArr;", "\xe2\x87\x92", "&dArr;", "\xe2\x87\x93", "&hArr;", "\xe2\x87\x94",
 
1532
    "&forall;", "\xe2\x88\x80", "&part;", "\xe2\x88\x82", "&exist;", "\xe2\x88\x83",
 
1533
    "&empty;", "\xe2\x88\x85", "&nabla;", "\xe2\x88\x87", "&isin;", "\xe2\x88\x88",
 
1534
    "&notin;", "\xe2\x88\x89", "&ni;", "\xe2\x88\x8b", "&prod;", "\xe2\x88\x8f",
 
1535
    "&sum;", "\xe2\x88\x91", "&minus;", "\xe2\x88\x92", "&lowast;", "\xe2\x88\x97",
 
1536
    "&radic;", "\xe2\x88\x9a", "&prop;", "\xe2\x88\x9d", "&infin;", "\xe2\x88\x9e",
 
1537
    "&ang;", "\xe2\x88\xa0", "&and;", "\xe2\x88\xa7", "&or;", "\xe2\x88\xa8",
 
1538
    "&cap;", "\xe2\x88\xa9", "&cup;", "\xe2\x88\xaa", "&int;", "\xe2\x88\xab",
 
1539
    "&there4;", "\xe2\x88\xb4", "&sim;", "\xe2\x88\xbc", "&cong;", "\xe2\x89\x85",
 
1540
    "&asymp;", "\xe2\x89\x88", "&ne;", "\xe2\x89\xa0", "&equiv;", "\xe2\x89\xa1",
 
1541
    "&le;", "\xe2\x89\xa4", "&ge;", "\xe2\x89\xa5", "&sub;", "\xe2\x8a\x82",
 
1542
    "&sup;", "\xe2\x8a\x83", "&nsub;", "\xe2\x8a\x84", "&sube;", "\xe2\x8a\x86",
 
1543
    "&supe;", "\xe2\x8a\x87", "&oplus;", "\xe2\x8a\x95", "&otimes;", "\xe2\x8a\x97",
 
1544
    "&perp;", "\xe2\x8a\xa5", "&sdot;", "\xe2\x8b\x85", "&lceil;", "\xe2\x8c\x88",
 
1545
    "&rceil;", "\xe2\x8c\x89", "&lfloor;", "\xe2\x8c\x8a", "&rfloor;", "\xe2\x8c\x8b",
 
1546
    "&lang;", "\xe2\x8c\xa9", "&rang;", "\xe2\x8c\xaa", "&loz;", "\xe2\x97\x8a",
 
1547
    "&spades;", "\xe2\x99\xa0", "&clubs;", "\xe2\x99\xa3", "&hearts;", "\xe2\x99\xa5",
 
1548
    "&diams;", "\xe2\x99\xa6", "&OElig;", "\xc5\x92", "&oelig;", "\xc5\x93",
 
1549
    "&Scaron;", "\xc5\xa0", "&scaron;", "\xc5\xa1", "&Yuml;", "\xc5\xb8",
 
1550
    "&circ;", "\xcb\x86", "&tilde;", "\xcb\x9c", "&ensp;", "\xe2\x80\x82",
 
1551
    "&emsp;", "\xe2\x80\x83", "&thinsp;", "\xe2\x80\x89", "&zwnj;", "\xe2\x80\x8c",
 
1552
    "&zwj;", "\xe2\x80\x8d", "&lrm;", "\xe2\x80\x8e", "&rlm;", "\xe2\x80\x8f",
 
1553
    "&ndash;", "\xe2\x80\x93", "&mdash;", "\xe2\x80\x94", "&lsquo;", "\xe2\x80\x98",
 
1554
    "&rsquo;", "\xe2\x80\x99", "&sbquo;", "\xe2\x80\x9a", "&ldquo;", "\xe2\x80\x9c",
 
1555
    "&rdquo;", "\xe2\x80\x9d", "&bdquo;", "\xe2\x80\x9e", "&dagger;", "\xe2\x80\xa0",
 
1556
    "&Dagger;", "\xe2\x80\xa1", "&permil;", "\xe2\x80\xb0", "&lsaquo;", "\xe2\x80\xb9",
 
1557
    "&rsaquo;", "\xe2\x80\xba", "&euro;", "\xe2\x82\xac",
 
1558
    NULL
 
1559
  };
 
1560
  char *raw, *wp, buf[2], *tmp;
 
1561
  int i, j, hit, num, tsiz;
 
1562
  CB_MALLOC(raw, strlen(html) * 3 + 1);
 
1563
  wp = raw;
 
1564
  while(*html != '\0'){
 
1565
    if(*html == '&'){
 
1566
      if(*(html + 1) == '#'){
 
1567
        if(*(html + 2) == 'x' || *(html + 2) == 'X'){
 
1568
          num = strtol(html + 3, NULL, 16);
 
1569
        } else {
 
1570
          num = atoi(html + 2);
 
1571
        }
 
1572
        buf[0] = num / 256;
 
1573
        buf[1] = num % 256;
 
1574
        if((tmp = est_uconv_out(buf, 2, &tsiz)) != NULL){
 
1575
          for(j = 0; j < tsiz; j++){
 
1576
            *wp = ((unsigned char *)tmp)[j];
 
1577
            wp++;
 
1578
          }
 
1579
          free(tmp);
 
1580
        }
 
1581
        while(*html != ';' && *html != ' ' && *html != '\n' && *html != '\0'){
 
1582
          html++;
 
1583
        }
 
1584
        if(*html == ';') html++;
 
1585
      } else {
 
1586
        hit = FALSE;
 
1587
        for(i = 0; pairs[i] != NULL; i += 2){
 
1588
          if(cbstrfwmatch(html, pairs[i])){
 
1589
            wp += sprintf(wp, "%s", pairs[i+1]);
 
1590
            html += strlen(pairs[i]);
 
1591
            hit = TRUE;
 
1592
            break;
 
1593
          }
 
1594
        }
 
1595
        if(!hit){
 
1596
          *wp = *html;
 
1597
          wp++;
 
1598
          html++;
 
1599
        }
 
1600
      }
 
1601
    } else {
 
1602
      *wp = *html;
 
1603
      wp++;
 
1604
      html++;
 
1605
    }
 
1606
  }
 
1607
  *wp = '\0';
 
1608
  return raw;
 
1609
}
 
1610
 
 
1611
 
 
1612
/* send the result made from MIME */
 
1613
static void sendpagefrommime(const char *buf, int size, const char *penc){
 
1614
  CBMAP *attrs, *pattrs;
 
1615
  CBLIST *parts;
 
1616
  const char *val, *lang, *bound, *part;
 
1617
  char *body, *title, *raw, *pbody;
 
1618
  int i, bsiz, psiz, pbsiz;
 
1619
  lang = langstr();
 
1620
  attrs = cbmapopenex(MINIBNUM);
 
1621
  body = cbmimebreak(buf, size, attrs, &bsiz);
 
1622
  if((val = cbmapget(attrs, "subject", -1, NULL)) != NULL){
 
1623
    title = mimestr(val);
 
1624
  } else {
 
1625
    title = cbmemdup("(no title)", -1);
 
1626
  }
 
1627
  xmlprintf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
1628
  xmlprintf("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\""
 
1629
            " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
 
1630
  xmlprintf("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%@\" lang=\"%@\">\n",
 
1631
            lang, lang);
 
1632
  xmlprintf("<head>\n");
 
1633
  xmlprintf("<meta http-equiv=\"Content-Language\" content=\"%@\" />\n", lang);
 
1634
  xmlprintf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n");
 
1635
  xmlprintf("<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n");
 
1636
  xmlprintf("<link rel=\"contents\" href=\"%@\" />\n", g_scriptname);
 
1637
  xmlprintf("<title>%@</title>\n", title);
 
1638
  xmlprintf("<style type=\"text/css\">html {\n");
 
1639
  xmlprintf("  margin: 0em 0em; padding: 0em 0em;\n");
 
1640
  xmlprintf("  background: #ffffff none;\n");
 
1641
  xmlprintf("}\n");
 
1642
  xmlprintf("body {\n");
 
1643
  xmlprintf("  margin: 1em 1em; padding: 0em 0em;\n");
 
1644
  xmlprintf("  color: #111111;\n");
 
1645
  xmlprintf("}\n");
 
1646
  xmlprintf("div.attrlist {\n");
 
1647
  xmlprintf("  margin: 0.2em 0.2em; padding: 0.2em 0.5em;\n");
 
1648
  xmlprintf("  background: #eeeeee none;\n");
 
1649
  xmlprintf("  -moz-border-radius: 0.4em;\n");
 
1650
  xmlprintf("}\n");
 
1651
  xmlprintf("span.attrname {\n");
 
1652
  xmlprintf("  font-weight: bold;\n");
 
1653
  xmlprintf("}\n");
 
1654
  xmlprintf("pre {\n");
 
1655
  xmlprintf("  margin: 1em 1em; white-space: pre-wrap;\n");
 
1656
  xmlprintf("  white-space: -moz-pre-wrap; word-wrap: break-word;\n");
 
1657
  xmlprintf("}\n");
 
1658
  xmlprintf("div.note {\n");
 
1659
  xmlprintf("  color: #888888; font-size: small;\n");
 
1660
  xmlprintf("}\n");
 
1661
  xmlprintf("</style>\n");
 
1662
  xmlprintf("</head>\n");
 
1663
  xmlprintf("<body>\n");
 
1664
  if(g_shownavi) sendnavibar();
 
1665
  xmlprintf("<h1>%@</h1>\n", title);
 
1666
  xmlprintf("<div class=\"attrlist\">\n");
 
1667
  if((val = cbmapget(attrs, "from", -1, NULL)) != NULL){
 
1668
    raw = mimestr(val);
 
1669
    xmlprintf("<div><span class=\"attrname\">From</span>:"
 
1670
              " <span id=\"from\" class=\"attrvalue\">%@</span></div>\n", raw);
 
1671
    free(raw);
 
1672
  }
 
1673
  if((val = cbmapget(attrs, "to", -1, NULL)) != NULL){
 
1674
    raw = mimestr(val);
 
1675
    xmlprintf("<div><span class=\"attrname\">To</span>:"
 
1676
              " <span id=\"to\" class=\"attrvalue\">%@</span></div>\n", raw);
 
1677
    free(raw);
 
1678
  }
 
1679
  if((val = cbmapget(attrs, "cc", -1, NULL)) != NULL){
 
1680
    raw = mimestr(val);
 
1681
    xmlprintf("<div><span class=\"attrname\">Cc</span>:"
 
1682
              " <span id=\"cc\" class=\"attrvalue\">%@</span></div>\n", raw);
 
1683
    free(raw);
 
1684
  }
 
1685
  if((val = cbmapget(attrs, "subject", -1, NULL)) != NULL){
 
1686
    raw = mimestr(val);
 
1687
    xmlprintf("<div><span class=\"attrname\">Subject</span>:"
 
1688
              " <span id=\"subject\" class=\"attrvalue\">%@</span></div>\n", raw);
 
1689
    free(raw);
 
1690
  }
 
1691
  if((val = cbmapget(attrs, "date", -1, NULL)) != NULL){
 
1692
    raw = mimestr(val);
 
1693
    xmlprintf("<div><span class=\"attrname\">Date</span>:"
 
1694
              " <span id=\"date\" class=\"attrvalue\">%@</span></div>\n", raw);
 
1695
    free(raw);
 
1696
  }
 
1697
  if((val = cbmapget(attrs, "x-mailer", -1, NULL)) != NULL){
 
1698
    raw = mimestr(val);
 
1699
    xmlprintf("<div><span class=\"attrname\">X-Mailer</span>:"
 
1700
              " <span id=\"xmailer\" class=\"attrvalue\">%@</span></div>\n", raw);
 
1701
    free(raw);
 
1702
  }
 
1703
  xmlprintf("</div>\n");
 
1704
  if((val = cbmapget(attrs, "TYPE", -1, NULL)) != NULL && cbstrfwimatch(val, "multipart/")){
 
1705
    if((bound = cbmapget(attrs, "BOUNDARY", -1, NULL)) != NULL){
 
1706
      parts = cbmimeparts(body, bsiz, bound);
 
1707
      for(i = 0; i < CB_LISTNUM(parts) && i < 8; i++){
 
1708
        part = cblistval(parts, i, &psiz);
 
1709
        pattrs = cbmapopenex(MINIBNUM);
 
1710
        pbody = cbmimebreak(part, psiz, pattrs, &pbsiz);
 
1711
        sendmimepart(pbody, pbsiz, pattrs, NULL);
 
1712
        free(pbody);
 
1713
        cbmapclose(pattrs);
 
1714
      }
 
1715
      cblistclose(parts);
 
1716
    }
 
1717
  } else {
 
1718
    sendmimepart(body, bsiz, attrs, penc);
 
1719
  }
 
1720
  xmlprintf("<hr />\n");
 
1721
  xmlprintf("</body>\n");
 
1722
  xmlprintf("</html>\n");
 
1723
  free(title);
 
1724
  free(body);
 
1725
  cbmapclose(attrs);
 
1726
}
 
1727
 
 
1728
 
 
1729
/* send a part of MIME */
 
1730
static void sendmimepart(const char *body, int bsiz, CBMAP *attrs, const char *penc){
 
1731
  const char *val;
 
1732
  char *tbuf, *ebuf, *cbuf;
 
1733
  int tsiz, esiz, csiz;
 
1734
  tbuf = NULL;
 
1735
  ebuf = NULL;
 
1736
  cbuf = NULL;
 
1737
  val = cbmapget(attrs, "content-transfer-encoding", -1, NULL);
 
1738
  if(val && cbstrfwimatch(val, "base64")){
 
1739
    tbuf = cbbasedecode(body, &tsiz);
 
1740
    body = tbuf;
 
1741
    bsiz = tsiz;
 
1742
  } else if(val && cbstrfwimatch(val, "quoted-printable")){
 
1743
    tbuf = cbquotedecode(body, &tsiz);
 
1744
    body = tbuf;
 
1745
    bsiz = tsiz;
 
1746
  }
 
1747
  val = cbmapget(attrs, "content-encoding", -1, NULL);
 
1748
  if(val && (cbstrfwimatch(val, "x-gzip") || cbstrfwimatch(val, "gzip")) &&
 
1749
     (ebuf = cbgzdecode(body, bsiz, &esiz)) != NULL){
 
1750
    body = ebuf;
 
1751
    bsiz = esiz;
 
1752
  } else if(val && (cbstrfwimatch(val, "x-deflate") || cbstrfwimatch(val, "deflate")) &&
 
1753
            (ebuf = cbinflate(body, bsiz, &esiz)) != NULL){
 
1754
    body = ebuf;
 
1755
    bsiz = esiz;
 
1756
  }
 
1757
  if(penc && (cbuf = est_iconv(body, bsiz, penc, "UTF-8", &csiz, NULL)) != NULL){
 
1758
    body = cbuf;
 
1759
    bsiz = csiz;
 
1760
  } else if((val = cbmapget(attrs, "CHARSET", -1, NULL)) != NULL &&
 
1761
            (cbuf = est_iconv(body, bsiz, val, "UTF-8", &csiz, NULL)) != NULL){
 
1762
    body = cbuf;
 
1763
    bsiz = csiz;
 
1764
  }
 
1765
  xmlprintf("<hr />\n");
 
1766
  if(!(val = cbmapget(attrs, "TYPE", -1, NULL))) val = "text/plain";
 
1767
  if(cbstrfwimatch(val, "text/")){
 
1768
    if(!cbstrfwimatch(val, "text/plain")) xmlprintf("<div class=\"note\">(%@)</div>\n", val);
 
1769
    xmlprintf("<pre>");
 
1770
    sendsnippet(body);
 
1771
    xmlprintf("</pre>\n");
 
1772
  } else {
 
1773
    xmlprintf("<div class=\"note\">(%@; not shown)</div>\n", val);
 
1774
  }
 
1775
  free(cbuf);
 
1776
  free(ebuf);
 
1777
  free(tbuf);
 
1778
}
 
1779
 
 
1780
 
 
1781
/* convert MIME encoded string into plain string */
 
1782
static char *mimestr(const char *mime){
 
1783
  char enc[64], *ebuf, *rbuf;
 
1784
  ebuf = cbmimedecode(mime, enc);
 
1785
  rbuf = est_iconv(ebuf, -1, enc, "UTF-8", NULL, NULL);
 
1786
  free(ebuf);
 
1787
  return rbuf ? rbuf : cbmemdup(mime, -1);
 
1788
}
 
1789
 
 
1790
 
 
1791
/* send the result made with an outer command */
 
1792
static void sendpagewithxcmd(const char *buf, int size, const char *penc, const char *cmd){
 
1793
  const char *tmpdir, *pv, *ext, *fmt;
 
1794
  char iname[URIBUFSIZ], oname[URIBUFSIZ], cbuf[URIBUFSIZ], *rbuf;
 
1795
  int rnd, pid, rsiz;
 
1796
  struct stat sbuf;
 
1797
  if(ESTPATHCHR == '/' && stat("/tmp", &sbuf) == 0){
 
1798
    tmpdir = "/tmp";
 
1799
  } else if(ESTPATHCHR == '\\' &&
 
1800
            ((pv = getenv("TMP")) != NULL || (pv = getenv("TEMP")) != NULL) &&
 
1801
            stat(pv, &sbuf) == 0){
 
1802
    tmpdir = pv;
 
1803
  } else {
 
1804
    tmpdir = ESTCDIRSTR;
 
1805
  }
 
1806
  ext = NULL;
 
1807
  if(!(pv = strrchr(p_url, ESTPATHCHR))) pv = p_url;
 
1808
  if((pv = strrchr(pv, ESTEXTCHR)) != NULL) ext = pv;
 
1809
  if(!ext || strlen(ext) >= 32 || strchr(ext, '"') || strchr(ext, '\\')) ext = "";
 
1810
  rnd = dpouterhash(p_url, -1) & 0xffff;
 
1811
  pid = (int)getpid() & 0xffff;
 
1812
  sprintf(iname, "%s%cxcmd-in-%04X%04X%s", tmpdir, ESTPATHCHR, pid, rnd, ext);
 
1813
  sprintf(oname, "%s%cxcmd-out-%04X%04X%cest", tmpdir, ESTPATHCHR, pid, rnd, ESTEXTCHR);
 
1814
  fmt = DRAFTCMD;
 
1815
  if(cbstrfwmatch(cmd, "T@")){
 
1816
    fmt = TEXTCMD;
 
1817
    cmd += 2;
 
1818
  } else if(cbstrfwmatch(cmd, "H@")){
 
1819
    fmt = HTMLCMD;
 
1820
    cmd += 2;
 
1821
  } else if(cbstrfwmatch(cmd, "M@")){
 
1822
    fmt = MIMECMD;
 
1823
    cmd += 2;
 
1824
  }
 
1825
  cbwritefile(iname, buf, size);
 
1826
  sprintf(cbuf, "%s \"%s\" \"%s\"", cmd, iname, oname);
 
1827
  system(cbuf);
 
1828
  if((rbuf = cbreadfile(oname, &rsiz)) != NULL){
 
1829
    if(fmt == DRAFTCMD){
 
1830
      sendpagefromdraft(rbuf, rsiz, NULL);
 
1831
    } else if(fmt == TEXTCMD){
 
1832
      sendpagefromtext(rbuf, rsiz, NULL);
 
1833
    } else if(fmt == HTMLCMD){
 
1834
      sendpagefromhtml(rbuf, rsiz, NULL);
 
1835
    } else if(fmt == MIMECMD){
 
1836
      sendpagefrommime(rbuf, rsiz, NULL);
 
1837
    }
 
1838
    free(rbuf);
 
1839
  }
 
1840
  unlink(oname);
 
1841
  unlink(iname);
 
1842
}
 
1843
 
 
1844
 
 
1845
 
 
1846
/* END OF FILE */