2
* HTTP protocol client implementation
3
* (c) 2002 Mikulas Patocka
4
* This file is part of the Links project, released under GPL.
6
* Modified by Karl Dahlke for integration with edbrowse,
7
* which is also released under the GPL.
10
* As a special exception, I hereby grant permission to link
11
* the code of this program with the OpenSSL library
12
* (or with modified versions of OpenSSL that use the same license as OpenSSL),
13
* and distribute linked combinations including the two.
14
* You must obey the GNU General Public License in all respects
15
* for all of the code used other than OpenSSL.
16
* If you modify this file, you may extend this exception to your version of the
17
* file, but you are not obligated to do so.
18
* If you do not wish to do so, delete this exception statement from your version.
23
/* You need the open ssl library for secure connections. */
24
/* Hence the openSSL exception above. */
25
#include <openssl/ssl.h>
26
#include <openssl/err.h> /* for error-retrieval */
27
#include <openssl/rand.h>
29
static SSL_CTX *sslcx; /* the overall ssl context */
33
/* Called from main() */
35
ssl_init(bool doConfig)
37
/* I don't understand any of this. */
38
char f_randfile[ABSPATH];
39
if(RAND_egd(RAND_file_name(f_randfile, sizeof (f_randfile))) < 0) {
40
/* Not an EGD, so read and write to it */
41
if(RAND_load_file(f_randfile, -1))
42
RAND_write_file(f_randfile);
44
SSLeay_add_ssl_algorithms();
45
sslcx = SSL_CTX_new(SSLv23_client_method());
46
SSL_CTX_set_options(sslcx, SSL_OP_ALL);
49
Load certificates from the file whose pathname is
51
The third argument to this function is the name of a directory in which
52
certificates are stored, one per file.
53
Both the filename and the directory name may be NULL.
54
Right now, we only support one large file containing all the
55
certificates. This could be changed easily.
58
SSL_CTX_load_verify_locations(sslcx, sslCerts, NULL);
60
verifyCertificates = false;
63
i_puts(MSG_NoCertFile);
66
SSL_CTX_set_default_verify_paths(sslcx);
67
SSL_CTX_set_mode(sslcx, SSL_MODE_AUTO_RETRY);
68
ssl_must_verify(verifyCertificates);
72
ssl_must_verify(bool verify_flag)
74
if(verify_flag == true)
75
SSL_CTX_set_verify(sslcx, SSL_VERIFY_PEER, NULL);
77
SSL_CTX_set_verify(sslcx, SSL_VERIFY_NONE, NULL);
78
} /* ssl_must_verify */
80
/* This is similar to our tcp_readFully in tcp.c */
82
ssl_readFully(SSL * ssl, char *buf, int len)
87
n = SSL_read(ssl, buf + pos, len);
94
return pos; /* filled the whole buffer */
97
/* Read from a socket, 100K at a time. */
98
#define CHUNKSIZE 100000
100
readSocket(SSL * ssl, int fh)
104
char data[CHUNKSIZE];
106
struct CHUNK *chunklist = 0, *lastchunk = 0, *p, *q;
109
bool isprintByte = false;
112
p = allocMem(sizeof (struct CHUNK));
114
n = ssl_readFully(ssl, p->data, CHUNKSIZE);
116
n = tcp_readFully(fh, p->data, CHUNKSIZE);
118
setError(intFlag ? MSG_Interrupted : MSG_WebRead);
120
for(p = chunklist; p; p = q) {
140
} /* loop reading data */
144
/* Put it all together */
145
serverData = data = allocMem(len + 1);
147
debugPrint(4, "%d bytes read from the socket", len);
150
int piece = (len < CHUNKSIZE ? len : CHUNKSIZE);
151
memcpy(data, p->data, piece);
162
/* Pull a keyword: attribute out of an internet header. */
164
extractHeaderItem(const char *head, const char *end,
165
const char *item, const char **ptr)
167
int ilen = strlen(item);
170
for(f = head; f < end - ilen - 1; f++) {
173
if(!memEqualCI(f + 1, item, ilen))
181
for(g = f; g < end && *g >= ' '; g++) ;
182
while(g > f && g[-1] == ' ')
184
h = pullString1(f, g);
190
} /* extractHeaderItem */
193
extractHeaderParam(const char *str, const char *item)
195
int le = strlen(item), lp;
197
/* ; denotes the next param */
198
/* Even the first param has to be preceeded by ; */
199
while(s = strchr(s, ';')) {
200
while(*s && (*s == ';' || (uchar) * s <= ' '))
202
if(!memEqualCI(s, item, le))
205
while(*s && ((uchar) * s <= ' ' || *s == '='))
210
while((uchar) s[lp] >= ' ' && s[lp] != ';')
212
return pullString(s, lp);
215
} /* extractHeaderParam */
217
/* Date format is: Mon, 03 Jan 2000 21:29:33 GMT */
218
/* Or perhaps: Sun Nov 6 08:49:37 1994 */
220
parseHeaderDate(const char *date)
222
static const char *const months[12] = {
223
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
224
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
227
int y; /* remember the type of format */
229
memset(&tm, 0, sizeof (struct tm));
231
/* skip past day of the week */
232
date = strchr(date, ' ');
237
if(isdigitByte(*date)) { /* first format */
239
if(isdigitByte(date[1])) {
240
tm.tm_mday = (date[0] - '0') * 10 + date[1] - '0';
243
tm.tm_mday = *date - '0';
246
if(*date != ' ' && *date != '-')
249
for(tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++)
250
if(memEqualCI(date, months[tm.tm_mon], 3))
257
if(!isdigitByte(date[0]))
259
if(!isdigitByte(date[1]))
261
if(!isdigitByte(date[2]))
263
if(!isdigitByte(date[3]))
266
(date[0] - '0') * 1000 + (date[1] - '0') * 100 + (date[2] -
267
'0') * 10 + date[3] - '0' - 1900;
269
} else if(*date == '-') {
270
/* Sunday, 06-Nov-94 08:49:37 GMT */
272
if(!isdigitByte(date[0]))
274
if(!isdigitByte(date[1]))
276
if(!isdigitByte(date[2])) {
279
'7' ? 1900 : 2000) + (date[0] - '0') * 10 + date[1] - '0' -
283
tm.tm_year = atoi(date) - 1900;
294
for(tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++)
295
if(memEqualCI(date, months[tm.tm_mon], 3))
302
if(!isdigitByte(date[0]))
304
tm.tm_mday = date[0] - '0';
307
if(!isdigitByte(date[0]))
309
tm.tm_mday = tm.tm_mday * 10 + date[0] - '0';
317
/* ready to crack time */
318
if(!isdigitByte(date[0]))
320
if(!isdigitByte(date[1]))
322
tm.tm_hour = (date[0] - '0') * 10 + date[1] - '0';
327
if(!isdigitByte(date[0]))
329
if(!isdigitByte(date[1]))
331
tm.tm_min = (date[0] - '0') * 10 + date[1] - '0';
336
if(!isdigitByte(date[0]))
338
if(!isdigitByte(date[1]))
340
tm.tm_sec = (date[0] - '0') * 10 + date[1] - '0';
344
/* year is at the end */
348
if(!isdigitByte(date[0]))
350
if(!isdigitByte(date[1]))
352
if(!isdigitByte(date[2]))
354
if(!isdigitByte(date[3]))
357
(date[0] - '0') * 1000 + (date[1] - '0') * 100 + (date[2] -
358
'0') * 10 + date[3] - '0' - 1900;
362
if(*date != ' ' && *date)
366
if(t != (time_t) - 1)
371
} /* parseHeaderDate */
374
parseRefresh(char *ref, int *delay_p)
380
while(isdigitByte(*u) || *u == '.')
386
if(memEqualCI(u, "url=", 4)) {
390
if(qc == '"' || qc == '\'')
395
u = ref + strlen(ref);
396
if(u > ref && u[-1] == qc)
399
debugPrint(2, "delay %d", delay);
403
i_printf(MSG_GarbledRefresh, ref);
408
/* Return true if we waited for the duration, false if interrupted.
409
* I don't know how to do this in Windows. */
411
refreshDelay(int sec, const char *u)
413
/* the value 15 seconds is somewhat arbitrary */
416
i_printf(MSG_RedirectDelayed, u, sec);
420
int hcode; /* example, 404 */
421
char herror[32]; /* example, file not found */
424
httpConnect(const char *from, const char *url)
426
int port; /* usually 80 */
428
IP32bit hip; /* host IP */
429
const char *host, *post, *s;
430
char *hdr; /* http header */
433
bool isprox, rc, secure, newurl;
434
int hsock; /* http socket */
435
SSL *hssl; /* for secure connections */
436
int hct; /* content type */
437
int hce; /* content encoding */
438
char *ref, *loc; /* refresh= location= */
439
int delay; /* before we refresh the page */
440
int recount = 0; /* count redirections */
441
char user[MAXUSERPASS], pass[MAXUSERPASS];
448
setError(MSG_BadURL, url);
452
n = fetchHistory(from, url);
454
return false; /* infinite loop */
457
serverData = EMPTYSTRING;
459
return true; /* success, because it's already fetched */
464
hct = CT_HTML; /* the default */
466
isprox = isProxyURL(url);
468
prot = getProtURL(url);
469
secure = stringEqualCI(prot, "https");
470
host = getHostURL(url);
472
i_printfExit(MSG_EmptyHost);
475
setError(MSG_SSLProxyNYI);
478
hip = tcp_name_ip(proxy_host);
480
hip = tcp_name_ip(host);
483
setError((intFlag ? MSG_Interrupted : MSG_IdentifyHost), host);
486
debugPrint(4, "%s -> %s",
487
(proxy_host ? proxy_host : host), tcp_ip_dots(hip));
489
/* See if the protocol is a recognized stream */
490
if(stringEqualCI(prot, "http") || stringEqualCI(prot, "https")) {
492
} else if(stringEqualCI(prot, "ftp")) {
493
return ftpConnect(url);
494
} else if(mt = findMimeByProtocol(prot)) {
496
cmd = pluginCommand(mt, url, 0);
501
setError(MSG_WebProtBad, prot);
505
/* Ok, it's http, but the suffix could force a plugin */
506
post = url + strcspn(url, "?#\1");
507
for(s = post - 1; s >= url && *s != '.' && *s != '/'; --s) ;
510
if(post >= s + sizeof (suffix))
511
post = s + sizeof (suffix) - 1;
512
strncpy(suffix, s, post - s);
513
suffix[post - s] = 0;
514
if((mt = findMimeBySuffix(suffix)) && mt->stream)
518
/* Pull user password out of the url */
519
user[0] = pass[0] = 0;
523
if(strlen(s) >= sizeof (user) - 2) {
524
setError(MSG_UserNameLong, sizeof (user));
531
if(strlen(s) >= sizeof (pass) - 2) {
532
setError(MSG_PasswordLong, sizeof (pass));
537
/* Don't add the authentication record yet;
538
* because I don't know what the method is.
539
* If I assume it's basic, and it's not, I'm sending the password
540
* (essentialy) in the clear, and the user is assuming it's always
541
* encrypted. So just keep it around, and deploy it if necessary. */
545
getPortLocURL(url, &portloc, &port);
546
hsock = tcp_connect(hip, (proxy_host ? proxy_port : port), webTimeout);
548
setError((intFlag ? MSG_Interrupted : MSG_WebConnect), host);
552
debugPrint(4, "connected to port %d/%d", proxy_port, port);
554
debugPrint(4, "connected to port %d", port);
556
hssl = SSL_new(sslcx);
557
SSL_set_fd(hssl, hsock);
559
hssl->options |= SSL_OP_NO_TLSv1;
561
err = SSL_connect(hssl);
563
err = ERR_peek_last_error();
565
if(ERR_GET_REASON(err) != SSL_R_CERTIFICATE_VERIFY_FAILED)
566
setError(MSG_WebConnectSecure, host, err);
568
setError(MSG_NoCertify, host);
573
debugPrint(4, "secure connection established");
576
post = strchr(url, '\1');
580
hdr = initString(&l);
581
stringAndString(&hdr, &l, post ? "POST " : "GET ");
583
stringAndString(&hdr, &l, prot);
584
stringAndString(&hdr, &l, "://");
585
stringAndString(&hdr, &l, host);
586
/* Some proxy servers won't accept :80 after the hostname. Dunno why. */
587
if(secure || port != 80) {
588
stringAndChar(&hdr, &l, ':');
589
stringAndNum(&hdr, &l, port);
592
stringAndChar(&hdr, &l, '/');
597
if(post && s == post - 1)
607
sprintf(buf, "%%%02X", (unsigned char)c);
608
stringAndString(&hdr, &l, buf);
610
stringAndChar(&hdr, &l, c);
613
stringAndString(&hdr, &l, " HTTP/1.0\r\n");
615
stringAndString(&hdr, &l, "Host: ");
616
stringAndString(&hdr, &l, host);
617
if(portloc) { /* port specified */
618
stringAndChar(&hdr, &l, ':');
619
stringAndNum(&hdr, &l, port);
621
stringAndString(&hdr, &l, eol);
623
stringAndString(&hdr, &l, "User-Agent: ");
624
stringAndString(&hdr, &l, currentAgent);
625
stringAndString(&hdr, &l, eol);
627
if(sendReferrer && currentReferrer) {
628
const char *post2 = strchr(currentReferrer, '\1');
629
const char *q = strchr(currentReferrer, '"');
630
/* I just can't handle quote in the referring url */
631
if(!q || post2 && q > post2) {
632
/* I always thought referrer had 4 r's, but not here. */
633
stringAndString(&hdr, &l, "Referer: \"");
635
post2 = currentReferrer + strlen(currentReferrer);
636
if(post2 - currentReferrer >= 7 && !memcmp(post2 - 7, ".browse", 7))
638
stringAndBytes(&hdr, &l, currentReferrer, post2 - currentReferrer);
639
stringAndChar(&hdr, &l, '"');
640
stringAndString(&hdr, &l, eol);
641
cw->referrer = cloneString(currentReferrer);
642
cw->referrer[post2 - currentReferrer] = 0;
645
stringAndString(&hdr, &l, "Accept: */*\r\n");
646
stringAndString(&hdr, &l, (isprox ? "Proxy-Connection: " : "Connection: "));
647
/* Keep-Alive feature not yet implemented */
648
stringAndString(&hdr, &l, "close\r\n");
650
/* Web caching not yet implemented. */
651
stringAndString(&hdr, &l,
652
"Pragma: no-cache\r\nCache-Control: no-cache\r\n");
653
stringAndString(&hdr, &l, "Accept-Encoding: gzip, compress\r\n");
654
stringAndString(&hdr, &l, "Accept-Language: en\r\n");
655
if(u = getAuthString(url)) {
656
stringAndString(&hdr, &l, u);
661
if(strncmp(post, "`mfd~", 5)) {
662
stringAndString(&hdr, &l,
663
"Content-Type: application/x-www-form-urlencoded\r\n");
666
stringAndString(&hdr, &l,
667
"Content-Type: multipart/form-data; boundary=");
668
s = strchr(post, '\r');
669
stringAndBytes(&hdr, &l, post, s - post);
671
stringAndString(&hdr, &l, eol);
673
stringAndString(&hdr, &l, "Content-Length: ");
674
stringAndNum(&hdr, &l, strlen(post));
675
stringAndString(&hdr, &l, eol);
678
sendCookies(&hdr, &l, url, secure);
680
/* Here's the blank line that ends the header. */
681
stringAndString(&hdr, &l, eol);
683
if(debugLevel >= 4) {
684
/* print the header to be sent. */
685
for(u = hdr; *u; ++u) {
693
stringAndString(&hdr, &l, post);
696
n = SSL_write(hssl, hdr, l);
698
n = tcp_write(hsock, hdr, l);
699
debugPrint(4, "http header sent, %d/%d bytes", n, l);
702
setError(intFlag ? MSG_Interrupted : MSG_WebSend);
709
rc = readSocket(hssl, hsock);
716
/* Parse the http header, at the start of the data stream. */
717
if(serverDataLen < 16)
718
goto nohead; /* too short */
720
if((*u++ | 0x20) != 'h')
722
if((*u++ | 0x20) != 't')
724
if((*u++ | 0x20) != 't')
726
if((*u++ | 0x20) != 'p')
730
while(isdigitByte(*u) || *u == '.')
738
hcode = strtol(u, &u, 10);
742
while(*u != '\r' && *u != '\n')
745
if(n >= sizeof (herror))
746
n = sizeof (herror) - 1;
747
strncpy(herror, hdr, n);
749
debugPrint(3, "http code %d %s", hcode, herror);
751
/* set hdr if we find our empty line */
752
while(u < serverData + serverDataLen) {
755
if(u < serverData + serverDataLen - 1)
759
if(c == '\n' && d == '\n') {
763
if(c == '\r' && d == '\n' &&
764
u <= serverData + serverDataLen - 4 &&
765
u[2] == '\r' && u[3] == '\n') {
774
if(debugLevel >= 4) {
775
/* print the header just received. */
776
for(u = serverData; u < hdr; ++u) {
783
/* We need to gather the cookies before we redirect. */
785
while(u = extractHeaderItem(s, hdr, "Set-Cookie", &s)) {
786
rc = receiveCookie(url, u);
788
debugPrint(3, rc ? "accepted" : "rejected");
791
if(hcode == 401) { /* authorization requested */
792
int authmeth = 1; /* basic method by default */
793
if(u = extractHeaderItem(serverData, hdr, "WWW-Authenticate", 0)) {
794
if(!memEqualCI(u, "basic", 5) || isalnumByte(u[5])) {
795
setError(MSG_BadAuthMethod, u);
799
if(!(user[0] | pass[0])) {
800
s = strstr(u, "realm=");
816
if(!(user[0] | pass[0])) {
818
setError(MSG_Authorize2);
821
i_puts(MSG_WebAuthorize);
823
i_printf(MSG_UserName);
826
if(!fgets(user, sizeof (user), stdin))
829
if(n >= sizeof (user) - 1) {
830
i_printf(MSG_UserNameLong, sizeof (user) - 2);
833
if(n && user[n - 1] == '\n')
835
if(stringEqual(user, "x")) {
836
setError(MSG_LoginAbort);
839
i_printf(MSG_Password);
842
if(!fgets(pass, sizeof (pass), stdin))
845
if(n >= sizeof (pass) - 1) {
846
i_printf(MSG_PasswordLong, sizeof (pass) - 2);
849
if(n && pass[n - 1] == '\n')
851
if(stringEqual(pass, "x")) {
852
setError(MSG_LoginAbort);
857
if(!addWebAuthorization(url, 1, user, pass, false))
864
/* 401 authentication */
865
if(u = extractHeaderItem(serverData, hdr, "Content-Encoding", 0)) {
867
if(stringEqualCI(u, "compress"))
869
if(stringEqualCI(u, "gzip"))
871
if(stringEqualCI(u, "7bit"))
873
if(stringEqualCI(u, "8bit"))
876
i_printf(MSG_CompressUnrecognized, u);
880
if(hce && (u = extractHeaderItem(serverData, hdr, "Content-type", 0))) {
881
/* If this isn't text, to be rendered, then don't uncompress it */
882
if(!memEqualCI(u, "text", 4) &&
883
!memEqualCI(u, "application/x-javascript", 24))
890
/* Look for http redirection. Note,
891
* meta http-equiv redirection does not occur unless and until
892
* the page is browsed, i.e. its html interpreted. */
895
if((hcode >= 301 && hcode <= 303 || hcode == 200) && allowRedirection) {
897
ref = extractHeaderItem(serverData, hdr, "refresh", 0);
899
if(parseRefresh(ref, &delay)) {
907
loc = extractHeaderItem(serverData, hdr, "location", 0);
911
i_printf(MSG_RedirectNoURL, hcode);
912
if(hcode >= 301 && hcode <= 303)
919
if(refreshDelay(delay, u)) {
920
n = fetchHistory(url, u);
924
} /* infinite loop */
926
/* success, because it's already fetched */
932
i_puts(MSG_RedirectMany);
935
/* Redirection looks valid, let's run with it. */
940
/* trying to plug a subtle memory leak */
944
url = resolveURL(from, u);
946
changeFileName = (char *)url;
947
debugPrint(2, "redirect %s", url);
951
n = hdr - serverData;
952
if(n >= strlen(u) + 36) {
954
sprintf(rbuf, "<A HREF=%s>Refresh[%d]</A><br>\n", u, delay);
957
memcpy(hdr, rbuf, l);
961
} /* redirection present */
963
/* looking for redirection */
965
i_printf(MSG_HTTPError, hcode, herror);
968
/* Don't need the header any more */
969
n = hdr - serverData;
971
memcpy(serverData, serverData + n, serverDataLen);
976
if(hce) { /* data is compressed */
981
u = edbrowseTempFile + strlen(edbrowseTempFile);
982
if(hce == ENC_COMPRESS)
983
strcpy(suffix, ".Z");
985
strcpy(suffix, ".gz");
987
debugPrint(3, "uncompressing the web page with method %s", suffix);
989
open(edbrowseTempFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC,
992
setError(MSG_TempNoCreate, edbrowseTempFile);
996
if(write(fh, serverData, serverDataLen) < serverDataLen) {
997
setError(MSG_TempNoWrite, edbrowseTempFile);
1007
unlink(edbrowseTempFile);
1008
scmd = allocMem(2 * strlen(edbrowseTempFile) + 20);
1009
sprintf(scmd, "zcat %s%s > %s",
1010
edbrowseTempFile, suffix, edbrowseTempFile);
1013
n = fileSizeByName(edbrowseTempFile);
1015
setError(MSG_TempNoUncompress);
1018
serverData = allocMem(n + 2);
1019
fh = open(edbrowseTempFile, O_RDONLY | O_BINARY);
1021
setError(MSG_TempNoAccess, edbrowseTempFile);
1024
if(read(fh, serverData, n) < n) {
1025
setError(MSG_TempNoRead, edbrowseTempFile);
1032
/* doesn't hurt to clean house, now that everything worked. */
1034
unlink(edbrowseTempFile);
1036
unlink(edbrowseTempFile);
1042
i_puts(MSG_HTTPHeader);
1052
/* Format a line from an ftp ls. */
1056
int l = strlen(line);
1058
/* blank line becomes paragraph break */
1059
if(!l || !memcmp(line, "total ", 6) && stringIsNum(line + 6) > 0) {
1060
stringAndString(&serverData, &serverDataLen, "<P>\n");
1063
for(j = 0; line[j]; ++j)
1064
if(!strchr("-rwxdls", line[j]))
1066
if(j == 10 && line[j] == ' ') { /* long list */
1068
char user[42], group[42];
1070
sscanf(line + j, " %d %40s %40s %d", &nlinks, user, group, &fsize);
1071
q = strchr(line, ':');
1073
for(++q; isdigitByte(*q) || *q == ':'; ++q) ;
1076
if(*q) { /* file name */
1080
stringAndString(&serverData, &serverDataLen, "<br><A HREF=x");
1081
serverData[serverDataLen - 1] = qc;
1082
stringAndString(&serverData, &serverDataLen, q);
1083
stringAndChar(&serverData, &serverDataLen, qc);
1084
stringAndChar(&serverData, &serverDataLen, '>');
1085
stringAndString(&serverData, &serverDataLen, q);
1086
stringAndString(&serverData, &serverDataLen, "</A>");
1088
stringAndChar(&serverData, &serverDataLen, '/');
1089
stringAndString(&serverData, &serverDataLen, ": ");
1090
stringAndNum(&serverData, &serverDataLen, fsize);
1091
stringAndChar(&serverData, &serverDataLen, '\n');
1096
if(!strpbrk(line, "<>&")) {
1097
stringAndString(&serverData, &serverDataLen, line);
1100
for(q = line; c = *q; ++q) {
1109
stringAndString(&serverData, &serverDataLen, meta);
1111
stringAndChar(&serverData, &serverDataLen, c);
1114
stringAndChar(&serverData, &serverDataLen, '\n');
1117
/* Like httpConnect, but for ftp */
1118
/* Basically, a system call to ncftpget */
1120
ftpConnect(const char *url)
1128
static const char npf[] = "not a plain file.";
1129
const int npfsize = strlen(npf);
1135
i_puts(MSG_FTPDownload);
1138
top:cmd = initString(&cmd_l);
1140
stringAndString(&cmd, &cmd_l, "ncftpls -l ");
1142
stringAndString(&cmd, &cmd_l, "ncftpget -r 1 -v -z ");
1144
stringAndString(&cmd, &cmd_l, "-d stdout ");
1148
sprintf(mode, "-%c ", ftpMode);
1149
stringAndString(&cmd, &cmd_l, mode);
1151
/* Quote the url, in case there are spaces in the name. */
1152
stringAndChar(&cmd, &cmd_l, '"');
1153
stringAndString(&cmd, &cmd_l, url);
1155
stringAndChar(&cmd, &cmd_l, '/');
1156
stringAndChar(&cmd, &cmd_l, '"');
1157
stringAndString(&cmd, &cmd_l, " 2>&1");
1158
debugPrint(3, "%s", cmd);
1160
f = popen(cmd, "r");
1162
setError(MSG_TempNoSystem, cmd, errno);
1166
out = initString(&out_l);
1168
serverData = initString(&serverDataLen);
1169
stringAndString(&serverData, &serverDataLen, "<html>\n");
1172
while((c = getc(f)) != EOF) {
1181
if(out_l > npfsize && stringEqual(out + out_l - npfsize, npf)) {
1188
/* Don't print the ETA messages */
1189
if(!strstr(out, " ETA: "))
1193
out = initString(&out_l);
1195
stringAndChar(&out, &out_l, c);
1201
if(out_l) { /* should never happen */
1209
if(rc > 0 && rc <= 11)
1210
setError(MSG_FTPConnect - 1 + rc);
1212
setError(MSG_FTPUnexpected, rc);
1215
i_puts(dirmode + MSG_Success);
1216
if(dirmode) { /* need a final slash */
1217
int l = strlen(url);
1218
changeFileName = allocMem(l + 2);
1219
strcpy(changeFileName, url);
1220
strcat(changeFileName, "/");
1226
/*********************************************************************
1227
Gather up the ip addresses of any domains referenced by this file.
1228
These can be added to firewalls or filters.
1229
Eventually we'll compare these against a blacklist to screen for spam.
1230
This only works on the current buffer.
1231
*********************************************************************/
1236
static IP32bit iplist[5 + 1];
1238
int iptotal = 0, domtotal = 0;
1243
int ln; /* line number */
1244
int ftype, j, k, nf;
1247
for(ln = 1; ln <= cw->dol; ++ln) {
1248
p = (char *)fetchLine(ln, -1);
1249
ftype = 0; /* input stuff doesn't work */
1250
findField(p, ftype, 0, &nf, 0, 0, 0, 0);
1251
for(j = 1; j <= nf; ++j) {
1252
findField(p, ftype, j, &nf, 0, &tagno, &href, 0);
1255
if(dom = getHostURL(href)) {
1256
/* Ok, many times the same domain will be referenced over and over again.
1257
* A waste of time to look it up over and over again.
1258
* So I check for it here. But what am I missing?
1259
* The second time I might have gotten a different ip address,
1260
* something I want to screen for,
1261
* so I should really gather all possible ip addresses on the first go,
1262
* but I don't have a function in tcp.c to do that,
1263
* and I don't have time to write one at this moment. */
1264
for(k = 0; k < domtotal; ++k)
1265
if(stringEqualCI(domlist[k], dom))
1268
domlist[domtotal++] = cloneString(dom);
1269
debugPrint(3, "hip %s", dom);
1271
ip = tcp_dots_ip(dom);
1273
ip = tcp_name_ip(dom);
1275
/* could be a repeat */
1276
for(k = 0; k < iptotal; ++k)
1280
iplist[iptotal++] = ip;
1281
if(ismc && onBlacklist1(ip)) {
1288
/* different domain */
1289
} /* valid domain */
1295
} /* loop over references on this line */
1296
} /* loop over lines */
1299
iplist[iptotal] = NULL_IP;
1300
cw->iplist = iplist;
1301
for(k = 0; k < domtotal; ++k)