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
*************************************************************************************************/
18
#include <fcgi_stdio.h>
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 */
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 */
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 */
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 */
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 */
66
/* color definitions */
67
const char *g_wordcolors[] = { /* highlighted colors */
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);
112
int main(int argc, char **argv){
115
est_proc_env_reset();
117
while(FCGI_Accept() >= 0){
122
realmain(argc, argv);
127
est_proc_env_reset();
129
realmain(argc, argv);
136
/* real main routine */
137
static int realmain(int argc, char **argv){
138
CBLIST *lines, *rplist, *rxlist, *wlist, *list;
139
CBMAP *params, *urlmap, *mtmap;
141
char *tmp, *wp, numbuf[NUMBUFSIZ];
143
setvbuf(stdout, g_outbuf, _IOFBF, OUTBUFSIZ);
144
if((rp = getenv("REMOTE_ADDR")) != NULL){
147
g_remoteaddr = "0.0.0.0";
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);
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:")){
177
if(*rp != '\0') cblistpush(rplist, rp, -1);
178
} else if(cbstrfwimatch(rp, "allowrx:")){
181
tmp = cbsprintf("a*I:%s", rp);
182
cblistpushbuf(rxlist, tmp, strlen(tmp));
184
} else if(cbstrfwimatch(rp, "denyrx:")){
187
tmp = cbsprintf("d*I:%s", rp);
188
cblistpushbuf(rxlist, tmp, strlen(tmp));
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:")){
196
if((pv = strstr(rp, "{{!}}")) != NULL) cbmapput(urlmap, rp, pv - rp, pv + 5, -1, TRUE);
197
} else if(cbstrfwimatch(rp, "typerule:")){
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;
206
g_replexprs = rplist;
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);
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);
230
if((rp = cbmapget(params, "once", -1, NULL)) != NULL) p_once = atoi(rp) > 0;
236
tmp = replaceurl(p_url);
237
for(i = 0; i < cblistnum(rxlist); i++){
238
rp = cblistval(rxlist, i, NULL);
242
if(est_regex_match_str(rp, tmp)) allow = TRUE;
246
if(est_regex_match_str(rp, tmp)) allow = FALSE;
252
if(allow && cbstrfwimatch(tmp, "file://")){
254
} else if(allow && cbstrfwimatch(tmp, "http://")){
257
printf("Status: 400 Forbidden\r\n");
258
printf("Content-Type: text/plain; charset=UTF-8\r\n");
260
printf("Error: the requested URL is not allowed\n");
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");
273
printf("Error: %s\n", msg);
278
/* skip the label of a line */
279
static const char *skiplabel(const char *str){
280
if(!(str = strchr(str, ':'))) return "";
282
while(*str != '\0' && (*str == ' ' || *str == '\t')){
289
/* get CGI parameters */
290
static CBMAP *getparameters(void){
291
int maxlen = 1024 * 1024 * 32;
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);
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++){
312
} else if((rp = getenv("QUERY_STRING")) != NULL){
313
buf = cbmemdup(rp, -1);
317
if((rp = getenv("CONTENT_TYPE")) != NULL && cbstrfwmatch(rp, "multipart/form-data") &&
318
(rp = strstr(rp, "boundary=")) != NULL){
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);
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);
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){
345
dkey = cburldecode(key, NULL);
346
dval = cburldecode(val, NULL);
347
cbmapput(map, dkey, -1, dval, -1, FALSE);
361
/* output escaped string */
362
static void xmlprintf(const char *format, ...){
365
char *tmp, cbuf[32], *ebuf;
367
int cblen, cnt, mlen;
368
va_start(ap, format);
369
while(*format != '\0'){
374
while(strchr("0123456789 .+-", *format) && *format != '\0' && cblen < sizeof(cbuf) - 1){
375
cbuf[cblen++] = *format;
378
cbuf[cblen++] = *format;
382
tmp = va_arg(ap, char *);
383
if(!tmp) tmp = "(null)";
387
printf(cbuf, va_arg(ap, int));
389
case 'o': case 'u': case 'x': case 'X': case 'c':
390
printf(cbuf, va_arg(ap, unsigned int));
392
case 'e': case 'E': case 'f': case 'g': case 'G':
393
printf(cbuf, va_arg(ap, double));
396
tmp = va_arg(ap, char *);
397
if(!tmp) tmp = "(null)";
400
mlen = atoi(cbuf + 1) * 10;
404
if((*rp & 0x80) == 0x00){
406
} else if((*rp & 0xe0) == 0xc0){
408
} else if((*rp & 0xf0) == 0xe0 || (*rp & 0xf8) == 0xf0){
412
ebuf = cbmemdup(tmp, rp - tmp);
421
case '&': printf("&"); break;
422
case '<': printf("<"); break;
423
case '>': printf(">"); break;
424
case '"': printf("""); break;
426
if(!((*tmp >= 0 && *tmp <= 0x8) || (*tmp >= 0x0e && *tmp <= 0x1f))) putchar(*tmp);
437
tmp = va_arg(ap, char *);
438
if(!tmp) tmp = "(null)";
440
c = *(unsigned char *)tmp;
441
if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
442
(c >= '0' && c <= '9') || (c != '\0' && strchr("_-.", c))){
463
/* make a URI to be shown */
464
static char *replaceurl(const char *uri){
465
char *turi, *bef, *aft, *pv, *nuri;
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){
476
nuri = est_regex_replace(turi, bef, aft);
485
/* show the input form */
486
static void sendform(void){
487
printf("Content-Type: text/html; charset=UTF-8\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");
503
xmlprintf("body {\n");
504
xmlprintf(" margin: 2em 2em; padding: 0em 0em;\n");
505
xmlprintf(" color: #111111;\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");
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");
515
xmlprintf("label {\n");
516
xmlprintf(" margin-left: 0.8em;\n");
517
xmlprintf(" color: #333333;\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");
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;
554
if(!cbstrfwimatch(url, "file://")) return NULL;
556
if(!(url = strchr(pv, '/'))) return NULL;
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]);
564
wp += sprintf(wp, "\\\\");
565
memcpy(wp, pv, url - pv);
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);
579
return cbmemdup(pbuf, -1);
583
/* get the connection of a URL */
584
static int getlocalconnection(const char *url, int *codep, CBMAP *heads){
585
const char *ext, *pv;
589
cbmapput(heads, "ERROR", -1, "", -1, TRUE);
590
cbmapput(heads, "", -1, "", -1, TRUE);
591
if(!(path = urltopath(url))){
593
cbmapput(heads, "ERROR", -1, "invalid URL", -1, TRUE);
596
if(stat(path, &sbuf) == -1){
599
cbmapput(heads, "ERROR", -1, "forbidden", -1, TRUE);
602
cbmapput(heads, "ERROR", -1, "file not found", -1, TRUE);
605
if(S_ISDIR(sbuf.st_mode)){
607
cbmapput(heads, "ERROR", -1, path, -1, TRUE);
611
if((fd = open(path, O_RDONLY, 0)) == -1){
614
cbmapput(heads, "ERROR", -1, "forbidden", -1, TRUE);
617
cbmapput(heads, "ERROR", -1, "file not found", -1, TRUE);
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);
632
/* send a list of files in a directory */
633
static void senddirlist(const char *path){
636
char *burl, *eurl, *nurl;
638
printf("Content-Type: text/html\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");
655
xmlprintf("body {\n");
656
xmlprintf(" margin: 2em 2em; padding: 0em 0em;\n");
657
xmlprintf(" color: #111111;\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);
666
for(i = 0; i < cblistnum(list); i++){
667
elem = cblistval(list, i, NULL);
668
eurl = cburlencode(elem, -1);
669
nurl = cburlresolve(burl, elem);
671
xmlprintf("<li><a href=\"%@\">%@</a></li>", nurl, elem);
673
xmlprintf("<li><a href=\"%s?url=%?\">%@</a></li>", g_scriptname, nurl, elem);
681
xmlprintf("<p>The directory could not be opened.</p>\n");
683
xmlprintf("</body>\n");
684
xmlprintf("</html>\n");
688
/* read all data of a local connection */
689
static char *readall(int fd, int *sp){
691
char iobuf[SOCKBUFSIZ];
693
datum = cbdatumopen(NULL, -1);
694
while(cbdatumsize(datum) < g_limitsize && (size = read(fd, iobuf, SOCKBUFSIZ)) > 0){
695
cbdatumcat(datum, iobuf, size);
697
return cbdatumtomalloc(datum, sp);
701
/* pass through raw data of a connection */
702
static void passlocalrawdata(int fd){
703
char iobuf[SOCKBUFSIZ];
705
while((size = read(fd, iobuf, SOCKBUFSIZ)) > 0){
706
fwrite(iobuf, 1, size, stdout);
711
/* send the data of local file */
712
static void sendlocaldata(void){
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){
721
senddirlist(cbmapget(heads, "ERROR", -1, NULL));
723
showerror(cbmapget(heads, "ERROR", -1, NULL));
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);
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';
741
if((pv = strstr(vbuf, "charset=")) != NULL || (pv = strstr(vbuf, "CHARSET=")) != NULL){
742
pv = strchr(pv, '=') + 1;
744
enc = cbmemdup(pv, -1);
745
if((pv = strchr(enc, '"')) != NULL) *pv = '\0';
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);
755
printf("Status: %d\r\n", code);
756
cbmapout(heads, "", -1);
757
cbmapout(heads, "ERROR", -1);
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);
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));
775
if(!strcmp(cmd, DRAFTCMD)){
776
rbuf = readall(fd, &rsiz);
777
sendpagefromdraft(rbuf, rsiz, enc);
779
} else if(!strcmp(cmd, TEXTCMD)){
780
rbuf = readall(fd, &rsiz);
781
sendpagefromtext(rbuf, rsiz, enc);
783
} else if(!strcmp(cmd, HTMLCMD)){
784
rbuf = readall(fd, &rsiz);
785
sendpagefromhtml(rbuf, rsiz, enc);
787
} else if(!strcmp(cmd, MIMECMD)){
788
rbuf = readall(fd, &rsiz);
789
sendpagefrommime(rbuf, rsiz, enc);
791
} else if(*cmd != '\0'){
792
rbuf = readall(fd, &rsiz);
793
sendpagewithxcmd(rbuf, rsiz, enc, cmd);
796
passlocalrawdata(fd);
806
/* get the HTTP connection of a URL */
807
static int gethttpconnection(const char *url, int *codep, CBMAP *heads){
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);
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);
834
if((sock = est_get_client_sock(addr, pnum)) == -1){
835
cbmapput(heads, "ERROR", -1, "connection failed", -1, TRUE);
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");
844
tmp = cbbaseencode(auth, -1);
845
wp += sprintf(wp, "Authorization: Basic %s\r\n", tmp);
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);
852
wp += sprintf(wp, "Accept-Language: en,ja\r\n");
855
wp += sprintf(wp, "Accept-Language: ja,en\r\n");
858
wp += sprintf(wp, "Accept-Language: zh,en\r\n");
861
wp += sprintf(wp, "Accept-Language: ko,en\r\n");
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);
874
cbmapput(heads, "", 0, iobuf, size, TRUE);
877
while((size = est_sock_recv_line(sock, iobuf, SOCKBUFSIZ - 1)) > 0){
878
if(iobuf[0] == ' ' || iobuf[0] == '\t'){
881
cbmapputcat(heads, name, nsiz, iobuf, size);
883
} else if((rp = strchr(iobuf, ':')) > iobuf){
885
memcpy(name, iobuf, nsiz);
887
for(pv = name; *pv != '\0'; pv++){
888
if(*pv >= 'A'&& *pv <= 'Z') *pv = *pv + ('a' - 'A');
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);
896
cbmapput(heads, name, nsiz, rp, -1, TRUE);
905
/* receive all data of a networdk connection */
906
static char *recvall(int sock, int *sp){
908
char iobuf[SOCKBUFSIZ];
910
datum = cbdatumopen(NULL, -1);
911
while(cbdatumsize(datum) < g_limitsize && (size = recv(sock, iobuf, SOCKBUFSIZ, 0)) > 0){
912
cbdatumcat(datum, iobuf, size);
914
return cbdatumtomalloc(datum, sp);
918
/* pass through raw data of a connection */
919
static void passhttprawdata(int sock){
920
char iobuf[SOCKBUFSIZ];
922
while((size = recv(sock, iobuf, SOCKBUFSIZ, 0)) > 0){
923
fwrite(iobuf, 1, size, stdout);
928
/* modify a header of location */
929
static void modifylocation(CBMAP *heads, const char *name){
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));
941
cbmapput(heads, name, -1, cbdatumptr(datum), cbdatumsize(datum), TRUE);
947
/* send the data of HTTP connection */
948
static void sendhttpdata(void){
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));
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);
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';
973
if((pv = strstr(vbuf, "charset=")) != NULL || (pv = strstr(vbuf, "CHARSET=")) != NULL){
974
pv = strchr(pv, '=') + 1;
976
enc = cbmemdup(pv, -1);
977
if((pv = strchr(enc, '"')) != NULL) *pv = '\0';
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);
987
printf("Status: %d\r\n", code);
988
cbmapout(heads, "", -1);
989
cbmapout(heads, "ERROR", -1);
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);
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));
1007
if(!strcmp(cmd, DRAFTCMD)){
1008
rbuf = recvall(sock, &rsiz);
1009
sendpagefromdraft(rbuf, rsiz, enc);
1011
} else if(!strcmp(cmd, TEXTCMD)){
1012
rbuf = recvall(sock, &rsiz);
1013
sendpagefromtext(rbuf, rsiz, enc);
1015
} else if(!strcmp(cmd, HTMLCMD)){
1016
rbuf = recvall(sock, &rsiz);
1017
sendpagefromhtml(rbuf, rsiz, enc);
1019
} else if(!strcmp(cmd, MIMECMD)){
1020
rbuf = recvall(sock, &rsiz);
1021
sendpagefrommime(rbuf, rsiz, enc);
1023
} else if(*cmd != '\0'){
1024
rbuf = recvall(sock, &rsiz);
1025
sendpagewithxcmd(rbuf, rsiz, enc, cmd);
1028
passhttprawdata(sock);
1032
est_sock_down(sock);
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;";
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));
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",
1068
xmlprintf("<input type=\"hidden\" name=\"once\" value=\"%d\" id=\"estproxy_once\" />\n",
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));
1082
xmlprintf("</div>\n");
1084
xmlprintf("<div class=\"estproxy_jumpsrc\" style=\"%@ clear: right; text-align: right;\">\n",
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");
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;
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);
1114
if(cblistnum(p_words) < 1){
1115
xmlprintf("%@", str);
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);
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>",
1134
cbmapout(ids, pv, len);
1136
xmlprintf("<strong style=\"color:#000000;background-color:%@;"
1137
"-moz-border-radius: 0.2em;\">%@</strong>",
1142
xmlprintf("%@", line);
1146
if(i < cblistnum(chunks) - 1) xmlprintf("\n");
1148
cblistclose(chunks);
1149
if(tail) xmlprintf("\n");
1153
/* get the language string */
1154
static const char *langstr(void){
1156
case ESTLANGEN: return "en";
1157
case ESTLANGJA: return "ja";
1158
case ESTLANGZH: return "zh";
1159
case ESTLANGKO: return "ko";
1166
/* send the result made from document draft */
1167
static void sendpagefromdraft(const char *buf, int size, const char *penc){
1170
const CBLIST *texts;
1172
const char *lang, *title, *rp;
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;
1180
title = "(no title)";
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",
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");
1198
xmlprintf("body {\n");
1199
xmlprintf(" margin: 1em 1em; padding: 0em 0em;\n");
1200
xmlprintf(" color: #111111;\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");
1207
xmlprintf("span.attrname {\n");
1208
xmlprintf(" font-weight: bold;\n");
1211
xmlprintf(" margin: 0.5em 1em; text-indent: 0.8em;\n");
1213
xmlprintf("p.keywords {\n");
1214
xmlprintf(" margin: 0.5em 1.5em;\n");
1215
xmlprintf(" font-style: italic; color: #333333;\n");
1217
xmlprintf("p.hiddentext {\n");
1218
xmlprintf(" margin: 0.5em 2em;\n");
1219
xmlprintf(" font-size: smaller; font-style: italic; color: #555555;\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));
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));
1246
xmlprintf("</p>\n");
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\">");
1254
xmlprintf("</p>\n");
1256
rp = est_doc_hidden_texts(doc);
1258
xmlprintf("<hr />\n");
1259
xmlprintf("<p class=\"hiddentext\">");
1261
xmlprintf("</p>\n");
1263
xmlprintf("<hr />\n");
1264
xmlprintf("</body>\n");
1265
xmlprintf("</html>\n");
1266
est_doc_delete(doc);
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;
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")){
1282
nbuf = est_iconv(buf, size, enc, "UTF-8", NULL, NULL);
1283
if(nbuf) text = nbuf;
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",
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");
1300
xmlprintf("body {\n");
1301
xmlprintf(" margin: 1em 0.8em; padding: 0em 0em;\n");
1302
xmlprintf(" color: #111111;\n");
1304
xmlprintf("pre {\n");
1305
xmlprintf(" white-space: pre-wrap;\n");
1306
xmlprintf(" white-space: -moz-pre-wrap; word-wrap: break-word;\n");
1308
xmlprintf("</style>\n");
1309
xmlprintf("</head>\n");
1310
xmlprintf("<body>\n");
1311
if(g_shownavi) sendnavibar();
1314
xmlprintf("</pre>\n");
1315
xmlprintf("</body>\n");
1316
xmlprintf("</html>\n");
1322
/* send the result made from HTML */
1323
static void sendpagefromhtml(const char *buf, int size, const char *penc){
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);
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")){
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);
1344
nbuf = est_iconv(buf, size, enc, "UTF-8", NULL, NULL);
1347
if(nbuf) html = nbuf;
1348
if(!html) html = buf;
1350
elems = cbxmlbreak(html, FALSE);
1351
for(i = 0; i < CB_LISTNUM(elems); i++){
1352
elem = CB_LISTVAL2(elems, i, esiz);
1354
if(elem[1] == '?' || elem[1] == '!' || elem[1] == '/'){
1355
xmlprintf("%s", elem);
1358
attrs = cbxmlattrs(elem);
1359
name = cbmapget(attrs, "", -1, NULL);
1360
if(!cbstricmp(name, "title") || !cbstricmp(name, "script") || !cbstricmp(name, "style"))
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\" />");
1374
xmlprintf("%s", elem);
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);
1385
xmlprintf(" %@=\"%@\"", kbuf, nurl);
1387
xmlprintf(" %@=\"%s?url=%?\"", kbuf, g_scriptname, nurl);
1390
} else if(!cbstricmp(kbuf, "action")){
1391
nurl = cburlresolve(p_url, vbuf);
1392
xmlprintf(" %@=\"%@\"", kbuf, nurl);
1394
} else if(strchr(vbuf, '&')){
1395
raw = htmlrawtext(vbuf);
1396
xmlprintf(" %@=\"%@\"", kbuf, raw);
1399
xmlprintf(" %@=\"%@\"", kbuf, vbuf);
1402
if(cbstrbwmatch(elem, "/>")){
1408
if(!cbstricmp(name, "body") && g_shownavi){
1415
xmlprintf("%s", elem);
1417
if(strchr(elem, '&')){
1418
raw = htmlrawtext(elem);
1431
/* get the encoding of an HTML string */
1432
static char *htmlenc(const char *str){
1435
const char *elem, *equiv, *content;
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;
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';
1462
CB_LISTCLOSE(elems);
1466
CB_LISTCLOSE(elems);
1471
/* unescape entity references of HTML */
1472
static char *htmlrawtext(const char *html){
1473
static const char *pairs[] = {
1474
"&", "&", "<", "<", ">", ">", """, "\"", "'", "'",
1475
" ", "\xc2\xa0", "¡", "\xc2\xa1", "¢", "\xc2\xa2",
1476
"£", "\xc2\xa3", "¤", "\xc2\xa4", "¥", "\xc2\xa5",
1477
"¦", "\xc2\xa6", "§", "\xc2\xa7", "¨", "\xc2\xa8",
1478
"©", "\xc2\xa9", "ª", "\xc2\xaa", "«", "\xc2\xab",
1479
"¬", "\xc2\xac", "­", "\xc2\xad", "®", "\xc2\xae",
1480
"¯", "\xc2\xaf", "°", "\xc2\xb0", "±", "\xc2\xb1",
1481
"²", "\xc2\xb2", "³", "\xc2\xb3", "´", "\xc2\xb4",
1482
"µ", "\xc2\xb5", "¶", "\xc2\xb6", "·", "\xc2\xb7",
1483
"¸", "\xc2\xb8", "¹", "\xc2\xb9", "º", "\xc2\xba",
1484
"»", "\xc2\xbb", "¼", "\xc2\xbc", "½", "\xc2\xbd",
1485
"¾", "\xc2\xbe", "¿", "\xc2\xbf", "À", "\xc3\x80",
1486
"Á", "\xc3\x81", "Â", "\xc3\x82", "Ã", "\xc3\x83",
1487
"Ä", "\xc3\x84", "Å", "\xc3\x85", "Æ", "\xc3\x86",
1488
"Ç", "\xc3\x87", "È", "\xc3\x88", "É", "\xc3\x89",
1489
"Ê", "\xc3\x8a", "Ë", "\xc3\x8b", "Ì", "\xc3\x8c",
1490
"Í", "\xc3\x8d", "Î", "\xc3\x8e", "Ï", "\xc3\x8f",
1491
"Ð", "\xc3\x90", "Ñ", "\xc3\x91", "Ò", "\xc3\x92",
1492
"Ó", "\xc3\x93", "Ô", "\xc3\x94", "Õ", "\xc3\x95",
1493
"Ö", "\xc3\x96", "×", "\xc3\x97", "Ø", "\xc3\x98",
1494
"Ù", "\xc3\x99", "Ú", "\xc3\x9a", "Û", "\xc3\x9b",
1495
"Ü", "\xc3\x9c", "Ý", "\xc3\x9d", "Þ", "\xc3\x9e",
1496
"ß", "\xc3\x9f", "à", "\xc3\xa0", "á", "\xc3\xa1",
1497
"â", "\xc3\xa2", "ã", "\xc3\xa3", "ä", "\xc3\xa4",
1498
"å", "\xc3\xa5", "æ", "\xc3\xa6", "ç", "\xc3\xa7",
1499
"è", "\xc3\xa8", "é", "\xc3\xa9", "ê", "\xc3\xaa",
1500
"ë", "\xc3\xab", "ì", "\xc3\xac", "í", "\xc3\xad",
1501
"î", "\xc3\xae", "ï", "\xc3\xaf", "ð", "\xc3\xb0",
1502
"ñ", "\xc3\xb1", "ò", "\xc3\xb2", "ó", "\xc3\xb3",
1503
"ô", "\xc3\xb4", "õ", "\xc3\xb5", "ö", "\xc3\xb6",
1504
"÷", "\xc3\xb7", "ø", "\xc3\xb8", "ù", "\xc3\xb9",
1505
"ú", "\xc3\xba", "û", "\xc3\xbb", "ü", "\xc3\xbc",
1506
"ý", "\xc3\xbd", "þ", "\xc3\xbe", "ÿ", "\xc3\xbf",
1507
"ƒ", "\xc6\x92", "Α", "\xce\x91", "Β", "\xce\x92",
1508
"Γ", "\xce\x93", "Δ", "\xce\x94", "Ε", "\xce\x95",
1509
"Ζ", "\xce\x96", "Η", "\xce\x97", "Θ", "\xce\x98",
1510
"Ι", "\xce\x99", "Κ", "\xce\x9a", "Λ", "\xce\x9b",
1511
"Μ", "\xce\x9c", "Ν", "\xce\x9d", "Ξ", "\xce\x9e",
1512
"Ο", "\xce\x9f", "Π", "\xce\xa0", "Ρ", "\xce\xa1",
1513
"Σ", "\xce\xa3", "Τ", "\xce\xa4", "Υ", "\xce\xa5",
1514
"Φ", "\xce\xa6", "Χ", "\xce\xa7", "Ψ", "\xce\xa8",
1515
"Ω", "\xce\xa9", "α", "\xce\xb1", "β", "\xce\xb2",
1516
"γ", "\xce\xb3", "δ", "\xce\xb4", "ε", "\xce\xb5",
1517
"ζ", "\xce\xb6", "η", "\xce\xb7", "θ", "\xce\xb8",
1518
"ι", "\xce\xb9", "κ", "\xce\xba", "λ", "\xce\xbb",
1519
"μ", "\xce\xbc", "ν", "\xce\xbd", "ξ", "\xce\xbe",
1520
"ο", "\xce\xbf", "π", "\xcf\x80", "ρ", "\xcf\x81",
1521
"ς", "\xcf\x82", "σ", "\xcf\x83", "τ", "\xcf\x84",
1522
"υ", "\xcf\x85", "φ", "\xcf\x86", "χ", "\xcf\x87",
1523
"ψ", "\xcf\x88", "ω", "\xcf\x89", "ϑ", "\xcf\x91",
1524
"ϒ", "\xcf\x92", "ϖ", "\xcf\x96", "•", "\xe2\x80\xa2",
1525
"…", "\xe2\x80\xa6", "′", "\xe2\x80\xb2", "″", "\xe2\x80\xb3",
1526
"‾", "\xe2\x80\xbe", "⁄", "\xe2\x81\x84", "℘", "\xe2\x84\x98",
1527
"ℑ", "\xe2\x84\x91", "ℜ", "\xe2\x84\x9c", "™", "\xe2\x84\xa2",
1528
"ℵ", "\xe2\x84\xb5", "←", "\xe2\x86\x90", "↑", "\xe2\x86\x91",
1529
"→", "\xe2\x86\x92", "↓", "\xe2\x86\x93", "↔", "\xe2\x86\x94",
1530
"↵", "\xe2\x86\xb5", "⇐", "\xe2\x87\x90", "⇑", "\xe2\x87\x91",
1531
"⇒", "\xe2\x87\x92", "⇓", "\xe2\x87\x93", "⇔", "\xe2\x87\x94",
1532
"∀", "\xe2\x88\x80", "∂", "\xe2\x88\x82", "∃", "\xe2\x88\x83",
1533
"∅", "\xe2\x88\x85", "∇", "\xe2\x88\x87", "∈", "\xe2\x88\x88",
1534
"∉", "\xe2\x88\x89", "∋", "\xe2\x88\x8b", "∏", "\xe2\x88\x8f",
1535
"∑", "\xe2\x88\x91", "−", "\xe2\x88\x92", "∗", "\xe2\x88\x97",
1536
"√", "\xe2\x88\x9a", "∝", "\xe2\x88\x9d", "∞", "\xe2\x88\x9e",
1537
"∠", "\xe2\x88\xa0", "∧", "\xe2\x88\xa7", "∨", "\xe2\x88\xa8",
1538
"∩", "\xe2\x88\xa9", "∪", "\xe2\x88\xaa", "∫", "\xe2\x88\xab",
1539
"∴", "\xe2\x88\xb4", "∼", "\xe2\x88\xbc", "≅", "\xe2\x89\x85",
1540
"≈", "\xe2\x89\x88", "≠", "\xe2\x89\xa0", "≡", "\xe2\x89\xa1",
1541
"≤", "\xe2\x89\xa4", "≥", "\xe2\x89\xa5", "⊂", "\xe2\x8a\x82",
1542
"⊃", "\xe2\x8a\x83", "⊄", "\xe2\x8a\x84", "⊆", "\xe2\x8a\x86",
1543
"⊇", "\xe2\x8a\x87", "⊕", "\xe2\x8a\x95", "⊗", "\xe2\x8a\x97",
1544
"⊥", "\xe2\x8a\xa5", "⋅", "\xe2\x8b\x85", "⌈", "\xe2\x8c\x88",
1545
"⌉", "\xe2\x8c\x89", "⌊", "\xe2\x8c\x8a", "⌋", "\xe2\x8c\x8b",
1546
"⟨", "\xe2\x8c\xa9", "⟩", "\xe2\x8c\xaa", "◊", "\xe2\x97\x8a",
1547
"♠", "\xe2\x99\xa0", "♣", "\xe2\x99\xa3", "♥", "\xe2\x99\xa5",
1548
"♦", "\xe2\x99\xa6", "Œ", "\xc5\x92", "œ", "\xc5\x93",
1549
"Š", "\xc5\xa0", "š", "\xc5\xa1", "Ÿ", "\xc5\xb8",
1550
"ˆ", "\xcb\x86", "˜", "\xcb\x9c", " ", "\xe2\x80\x82",
1551
" ", "\xe2\x80\x83", " ", "\xe2\x80\x89", "‌", "\xe2\x80\x8c",
1552
"‍", "\xe2\x80\x8d", "‎", "\xe2\x80\x8e", "‏", "\xe2\x80\x8f",
1553
"–", "\xe2\x80\x93", "—", "\xe2\x80\x94", "‘", "\xe2\x80\x98",
1554
"’", "\xe2\x80\x99", "‚", "\xe2\x80\x9a", "“", "\xe2\x80\x9c",
1555
"”", "\xe2\x80\x9d", "„", "\xe2\x80\x9e", "†", "\xe2\x80\xa0",
1556
"‡", "\xe2\x80\xa1", "‰", "\xe2\x80\xb0", "‹", "\xe2\x80\xb9",
1557
"›", "\xe2\x80\xba", "€", "\xe2\x82\xac",
1560
char *raw, *wp, buf[2], *tmp;
1561
int i, j, hit, num, tsiz;
1562
CB_MALLOC(raw, strlen(html) * 3 + 1);
1564
while(*html != '\0'){
1566
if(*(html + 1) == '#'){
1567
if(*(html + 2) == 'x' || *(html + 2) == 'X'){
1568
num = strtol(html + 3, NULL, 16);
1570
num = atoi(html + 2);
1574
if((tmp = est_uconv_out(buf, 2, &tsiz)) != NULL){
1575
for(j = 0; j < tsiz; j++){
1576
*wp = ((unsigned char *)tmp)[j];
1581
while(*html != ';' && *html != ' ' && *html != '\n' && *html != '\0'){
1584
if(*html == ';') html++;
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]);
1612
/* send the result made from MIME */
1613
static void sendpagefrommime(const char *buf, int size, const char *penc){
1614
CBMAP *attrs, *pattrs;
1616
const char *val, *lang, *bound, *part;
1617
char *body, *title, *raw, *pbody;
1618
int i, bsiz, psiz, pbsiz;
1620
attrs = cbmapopenex(MINIBNUM);
1621
body = cbmimebreak(buf, size, attrs, &bsiz);
1622
if((val = cbmapget(attrs, "subject", -1, NULL)) != NULL){
1623
title = mimestr(val);
1625
title = cbmemdup("(no title)", -1);
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",
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");
1642
xmlprintf("body {\n");
1643
xmlprintf(" margin: 1em 1em; padding: 0em 0em;\n");
1644
xmlprintf(" color: #111111;\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");
1651
xmlprintf("span.attrname {\n");
1652
xmlprintf(" font-weight: bold;\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");
1658
xmlprintf("div.note {\n");
1659
xmlprintf(" color: #888888; font-size: small;\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){
1669
xmlprintf("<div><span class=\"attrname\">From</span>:"
1670
" <span id=\"from\" class=\"attrvalue\">%@</span></div>\n", raw);
1673
if((val = cbmapget(attrs, "to", -1, NULL)) != NULL){
1675
xmlprintf("<div><span class=\"attrname\">To</span>:"
1676
" <span id=\"to\" class=\"attrvalue\">%@</span></div>\n", raw);
1679
if((val = cbmapget(attrs, "cc", -1, NULL)) != NULL){
1681
xmlprintf("<div><span class=\"attrname\">Cc</span>:"
1682
" <span id=\"cc\" class=\"attrvalue\">%@</span></div>\n", raw);
1685
if((val = cbmapget(attrs, "subject", -1, NULL)) != NULL){
1687
xmlprintf("<div><span class=\"attrname\">Subject</span>:"
1688
" <span id=\"subject\" class=\"attrvalue\">%@</span></div>\n", raw);
1691
if((val = cbmapget(attrs, "date", -1, NULL)) != NULL){
1693
xmlprintf("<div><span class=\"attrname\">Date</span>:"
1694
" <span id=\"date\" class=\"attrvalue\">%@</span></div>\n", raw);
1697
if((val = cbmapget(attrs, "x-mailer", -1, NULL)) != NULL){
1699
xmlprintf("<div><span class=\"attrname\">X-Mailer</span>:"
1700
" <span id=\"xmailer\" class=\"attrvalue\">%@</span></div>\n", raw);
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);
1718
sendmimepart(body, bsiz, attrs, penc);
1720
xmlprintf("<hr />\n");
1721
xmlprintf("</body>\n");
1722
xmlprintf("</html>\n");
1729
/* send a part of MIME */
1730
static void sendmimepart(const char *body, int bsiz, CBMAP *attrs, const char *penc){
1732
char *tbuf, *ebuf, *cbuf;
1733
int tsiz, esiz, csiz;
1737
val = cbmapget(attrs, "content-transfer-encoding", -1, NULL);
1738
if(val && cbstrfwimatch(val, "base64")){
1739
tbuf = cbbasedecode(body, &tsiz);
1742
} else if(val && cbstrfwimatch(val, "quoted-printable")){
1743
tbuf = cbquotedecode(body, &tsiz);
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){
1752
} else if(val && (cbstrfwimatch(val, "x-deflate") || cbstrfwimatch(val, "deflate")) &&
1753
(ebuf = cbinflate(body, bsiz, &esiz)) != NULL){
1757
if(penc && (cbuf = est_iconv(body, bsiz, penc, "UTF-8", &csiz, NULL)) != NULL){
1760
} else if((val = cbmapget(attrs, "CHARSET", -1, NULL)) != NULL &&
1761
(cbuf = est_iconv(body, bsiz, val, "UTF-8", &csiz, NULL)) != NULL){
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);
1771
xmlprintf("</pre>\n");
1773
xmlprintf("<div class=\"note\">(%@; not shown)</div>\n", val);
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);
1787
return rbuf ? rbuf : cbmemdup(mime, -1);
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;
1797
if(ESTPATHCHR == '/' && stat("/tmp", &sbuf) == 0){
1799
} else if(ESTPATHCHR == '\\' &&
1800
((pv = getenv("TMP")) != NULL || (pv = getenv("TEMP")) != NULL) &&
1801
stat(pv, &sbuf) == 0){
1804
tmpdir = ESTCDIRSTR;
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);
1815
if(cbstrfwmatch(cmd, "T@")){
1818
} else if(cbstrfwmatch(cmd, "H@")){
1821
} else if(cbstrfwmatch(cmd, "M@")){
1825
cbwritefile(iname, buf, size);
1826
sprintf(cbuf, "%s \"%s\" \"%s\"", cmd, iname, oname);
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);