~ubuntu-branches/ubuntu/jaunty/edbrowse/jaunty-security

« back to all changes in this revision

Viewing changes to http.c

  • Committer: Bazaar Package Importer
  • Author(s): Kapil Hari Paranjape
  • Date: 2008-04-09 18:55:23 UTC
  • mfrom: (1.1.4 upstream) (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080409185523-dqokcloumyn1ibn4
Tags: 3.3.4-1
* New upstream version (3.3.4).
 - Convert between iso8859-1 and utf-8 on the fly.
 - Support reading of pdf using pdftohtml.
 - French translation of html documentation.
 - Old html documentation renamed to usersguide.
 - Additional documentation on philosophy.
* debian/control:
 - Changed homepage to sourcefource site.
 - Moved homepage from description to its own field.
 - Added "poppler-utils | xpdf-utils" to Recommends.
 - Added "www-browser", "mail-reader" and "editor" to Provides. 
 - Removed "XS-" from Vcs-Svn tag.
 - Standards-Version: 3.7.3
* debian/docs: Added new documentation files
  from "doc/" subdirectory.
* debian/watch: Updated to use sourceforge site.
* debian/edbrowse.doc-base:
  - Changed name of upstream provided html documentation from
    "ebdoc.html" to "usersguide.html".
  - Changed section from "net" to "Network/Web Browsing".
* debian/install: Compiled binary is now in "src/".

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* http.c
2
 
 * HTTP protocol client implementation
3
 
 * (c) 2002 Mikulas Patocka
4
 
 * This file is part of the Links project, released under GPL.
5
 
 *
6
 
 * Modified by Karl Dahlke for integration with edbrowse,
7
 
 * which is also released under the GPL.
8
 
 * 
9
 
 * OpenSSL exception:
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.
19
 
 */
20
 
 
21
 
#include "eb.h"
22
 
 
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>
28
 
 
29
 
static SSL_CTX *sslcx;          /* the overall ssl context */
30
 
char *serverData;
31
 
int serverDataLen;
32
 
 
33
 
/* Called from main() */
34
 
void
35
 
ssl_init(bool doConfig)
36
 
{
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);
43
 
    }
44
 
    SSLeay_add_ssl_algorithms();
45
 
    sslcx = SSL_CTX_new(SSLv23_client_method());
46
 
    SSL_CTX_set_options(sslcx, SSL_OP_ALL);
47
 
 
48
 
    /*
49
 
       Load certificates from the file whose pathname is
50
 
       sslCerts.
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.
56
 
     */
57
 
 
58
 
    SSL_CTX_load_verify_locations(sslcx, sslCerts, NULL);
59
 
    if(!sslCerts) {
60
 
        verifyCertificates = false;
61
 
        if(doConfig)
62
 
            if(debugLevel >= 1)
63
 
                i_puts(MSG_NoCertFile);
64
 
    }
65
 
 
66
 
    SSL_CTX_set_default_verify_paths(sslcx);
67
 
    SSL_CTX_set_mode(sslcx, SSL_MODE_AUTO_RETRY);
68
 
    ssl_must_verify(verifyCertificates);
69
 
}                               /* ssl_init */
70
 
 
71
 
void
72
 
ssl_must_verify(bool verify_flag)
73
 
{
74
 
    if(verify_flag == true)
75
 
        SSL_CTX_set_verify(sslcx, SSL_VERIFY_PEER, NULL);
76
 
    else
77
 
        SSL_CTX_set_verify(sslcx, SSL_VERIFY_NONE, NULL);
78
 
}                               /* ssl_must_verify */
79
 
 
80
 
/* This is similar to our tcp_readFully in tcp.c */
81
 
static int
82
 
ssl_readFully(SSL * ssl, char *buf, int len)
83
 
{
84
 
    int pos = 0;
85
 
    int n;
86
 
    while(len) {
87
 
        n = SSL_read(ssl, buf + pos, len);
88
 
        if(n < 0)
89
 
            return n;
90
 
        if(!n)
91
 
            return pos;
92
 
        len -= n, pos += n;
93
 
    }
94
 
    return pos;                 /* filled the whole buffer */
95
 
}                               /* ssl_readFully */
96
 
 
97
 
/* Read from a socket, 100K at a time. */
98
 
#define CHUNKSIZE 100000
99
 
static bool
100
 
readSocket(SSL * ssl, int fh)
101
 
{
102
 
    struct CHUNK {
103
 
        struct CHUNK *next;
104
 
        char data[CHUNKSIZE];
105
 
    };
106
 
    struct CHUNK *chunklist = 0, *lastchunk = 0, *p, *q;
107
 
    int n, len = 0;
108
 
    char *data;
109
 
    bool isprintByte = false;
110
 
 
111
 
    while(true) {
112
 
        p = allocMem(sizeof (struct CHUNK));
113
 
        if(ssl)
114
 
            n = ssl_readFully(ssl, p->data, CHUNKSIZE);
115
 
        else
116
 
            n = tcp_readFully(fh, p->data, CHUNKSIZE);
117
 
        if(n < 0) {
118
 
            setError(intFlag ? MSG_Interrupted : MSG_WebRead);
119
 
            free(p);
120
 
            for(p = chunklist; p; p = q) {
121
 
                q = p->next;
122
 
                free(p);
123
 
            }
124
 
            return false;
125
 
        }                       /* error */
126
 
        len += n;
127
 
        if(n) {
128
 
            if(lastchunk)
129
 
                lastchunk->next = p;
130
 
            else
131
 
                chunklist = p;
132
 
            lastchunk = p;
133
 
        } else
134
 
            free(p);
135
 
        if(n < CHUNKSIZE)
136
 
            break;
137
 
        printf(".");
138
 
        fflush(stdout);
139
 
        isprintByte = true;
140
 
    }                           /* loop reading data */
141
 
    if(isprintByte)
142
 
        nl();
143
 
 
144
 
/* Put it all together */
145
 
    serverData = data = allocMem(len + 1);
146
 
    serverDataLen = len;
147
 
    debugPrint(4, "%d bytes read from the socket", len);
148
 
    p = chunklist;
149
 
    while(len) {
150
 
        int piece = (len < CHUNKSIZE ? len : CHUNKSIZE);
151
 
        memcpy(data, p->data, piece);
152
 
        data += piece;
153
 
        len -= piece;
154
 
        q = p->next;
155
 
        free(p);
156
 
        p = q;
157
 
    }
158
 
 
159
 
    return true;
160
 
}                               /* readSocket */
161
 
 
162
 
/* Pull a keyword: attribute out of an internet header. */
163
 
char *
164
 
extractHeaderItem(const char *head, const char *end,
165
 
   const char *item, const char **ptr)
166
 
{
167
 
    int ilen = strlen(item);
168
 
    const char *f, *g;
169
 
    char *h = 0;
170
 
    for(f = head; f < end - ilen - 1; f++) {
171
 
        if(*f != '\n')
172
 
            continue;
173
 
        if(!memEqualCI(f + 1, item, ilen))
174
 
            continue;
175
 
        f += ilen;
176
 
        if(f[1] != ':')
177
 
            continue;
178
 
        f += 2;
179
 
        while(*f == ' ')
180
 
            ++f;
181
 
        for(g = f; g < end && *g >= ' '; g++) ;
182
 
        while(g > f && g[-1] == ' ')
183
 
            --g;
184
 
        h = pullString1(f, g);
185
 
        if(ptr)
186
 
            *ptr = f;
187
 
        break;
188
 
    }
189
 
    return h;
190
 
}                               /* extractHeaderItem */
191
 
 
192
 
char *
193
 
extractHeaderParam(const char *str, const char *item)
194
 
{
195
 
    int le = strlen(item), lp;
196
 
    const char *s = str;
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 <= ' '))
201
 
            s++;
202
 
        if(!memEqualCI(s, item, le))
203
 
            continue;
204
 
        s += le;
205
 
        while(*s && ((uchar) * s <= ' ' || *s == '='))
206
 
            s++;
207
 
        if(!*s)
208
 
            return EMPTYSTRING;
209
 
        lp = 0;
210
 
        while((uchar) s[lp] >= ' ' && s[lp] != ';')
211
 
            lp++;
212
 
        return pullString(s, lp);
213
 
    }
214
 
    return NULL;
215
 
}                               /* extractHeaderParam */
216
 
 
217
 
/* Date format is:    Mon, 03 Jan 2000 21:29:33 GMT */
218
 
                        /* Or perhaps:     Sun Nov  6 08:49:37 1994 */
219
 
time_t
220
 
parseHeaderDate(const char *date)
221
 
{
222
 
    static const char *const months[12] = {
223
 
        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
224
 
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
225
 
    };
226
 
    time_t t = 0;
227
 
    int y;                      /* remember the type of format */
228
 
    struct tm tm;
229
 
    memset(&tm, 0, sizeof (struct tm));
230
 
 
231
 
/* skip past day of the week */
232
 
    date = strchr(date, ' ');
233
 
    if(!date)
234
 
        goto fail;
235
 
    date++;
236
 
 
237
 
    if(isdigitByte(*date)) {    /* first format */
238
 
        y = 0;
239
 
        if(isdigitByte(date[1])) {
240
 
            tm.tm_mday = (date[0] - '0') * 10 + date[1] - '0';
241
 
            date += 2;
242
 
        } else {
243
 
            tm.tm_mday = *date - '0';
244
 
            ++date;
245
 
        }
246
 
        if(*date != ' ' && *date != '-')
247
 
            goto fail;
248
 
        ++date;
249
 
        for(tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++)
250
 
            if(memEqualCI(date, months[tm.tm_mon], 3))
251
 
                goto f1;
252
 
        goto fail;
253
 
      f1:
254
 
        date += 3;
255
 
        if(*date == ' ') {
256
 
            date++;
257
 
            if(!isdigitByte(date[0]))
258
 
                goto fail;
259
 
            if(!isdigitByte(date[1]))
260
 
                goto fail;
261
 
            if(!isdigitByte(date[2]))
262
 
                goto fail;
263
 
            if(!isdigitByte(date[3]))
264
 
                goto fail;
265
 
            tm.tm_year =
266
 
               (date[0] - '0') * 1000 + (date[1] - '0') * 100 + (date[2] -
267
 
               '0') * 10 + date[3] - '0' - 1900;
268
 
            date += 4;
269
 
        } else if(*date == '-') {
270
 
            /* Sunday, 06-Nov-94 08:49:37 GMT */
271
 
            date++;
272
 
            if(!isdigitByte(date[0]))
273
 
                goto fail;
274
 
            if(!isdigitByte(date[1]))
275
 
                goto fail;
276
 
            if(!isdigitByte(date[2])) {
277
 
                tm.tm_year =
278
 
                   (date[0] >=
279
 
                   '7' ? 1900 : 2000) + (date[0] - '0') * 10 + date[1] - '0' -
280
 
                   1900;
281
 
                date += 2;
282
 
            } else {
283
 
                tm.tm_year = atoi(date) - 1900;
284
 
                date += 4;
285
 
            }
286
 
        } else
287
 
            goto fail;
288
 
        if(*date != ' ')
289
 
            goto fail;
290
 
        date++;
291
 
    } else {
292
 
/* second format */
293
 
        y = 1;
294
 
        for(tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++)
295
 
            if(memEqualCI(date, months[tm.tm_mon], 3))
296
 
                goto f2;
297
 
        goto fail;
298
 
      f2:
299
 
        date += 3;
300
 
        while(*date == ' ')
301
 
            date++;
302
 
        if(!isdigitByte(date[0]))
303
 
            goto fail;
304
 
        tm.tm_mday = date[0] - '0';
305
 
        date++;
306
 
        if(*date != ' ') {
307
 
            if(!isdigitByte(date[0]))
308
 
                goto fail;
309
 
            tm.tm_mday = tm.tm_mday * 10 + date[0] - '0';
310
 
            date++;
311
 
        }
312
 
        if(*date != ' ')
313
 
            goto fail;
314
 
        date++;
315
 
    }
316
 
 
317
 
/* ready to crack time */
318
 
    if(!isdigitByte(date[0]))
319
 
        goto fail;
320
 
    if(!isdigitByte(date[1]))
321
 
        goto fail;
322
 
    tm.tm_hour = (date[0] - '0') * 10 + date[1] - '0';
323
 
    date += 2;
324
 
    if(*date != ':')
325
 
        goto fail;
326
 
    date++;
327
 
    if(!isdigitByte(date[0]))
328
 
        goto fail;
329
 
    if(!isdigitByte(date[1]))
330
 
        goto fail;
331
 
    tm.tm_min = (date[0] - '0') * 10 + date[1] - '0';
332
 
    date += 2;
333
 
    if(*date != ':')
334
 
        goto fail;
335
 
    date++;
336
 
    if(!isdigitByte(date[0]))
337
 
        goto fail;
338
 
    if(!isdigitByte(date[1]))
339
 
        goto fail;
340
 
    tm.tm_sec = (date[0] - '0') * 10 + date[1] - '0';
341
 
    date += 2;
342
 
 
343
 
    if(y) {
344
 
/* year is at the end */
345
 
        if(*date != ' ')
346
 
            goto fail;
347
 
        date++;
348
 
        if(!isdigitByte(date[0]))
349
 
            goto fail;
350
 
        if(!isdigitByte(date[1]))
351
 
            goto fail;
352
 
        if(!isdigitByte(date[2]))
353
 
            goto fail;
354
 
        if(!isdigitByte(date[3]))
355
 
            goto fail;
356
 
        tm.tm_year =
357
 
           (date[0] - '0') * 1000 + (date[1] - '0') * 100 + (date[2] -
358
 
           '0') * 10 + date[3] - '0' - 1900;
359
 
        date += 4;
360
 
    }
361
 
 
362
 
    if(*date != ' ' && *date)
363
 
        goto fail;
364
 
 
365
 
    t = mktime(&tm);
366
 
    if(t != (time_t) - 1)
367
 
        return t;
368
 
 
369
 
  fail:
370
 
    return 0;
371
 
}                               /* parseHeaderDate */
372
 
 
373
 
bool
374
 
parseRefresh(char *ref, int *delay_p)
375
 
{
376
 
    int delay = 0;
377
 
    char *u = ref;
378
 
    if(isdigitByte(*u))
379
 
        delay = atoi(u);
380
 
    while(isdigitByte(*u) || *u == '.')
381
 
        ++u;
382
 
    if(*u == ';')
383
 
        ++u;
384
 
    while(*u == ' ')
385
 
        ++u;
386
 
    if(memEqualCI(u, "url=", 4)) {
387
 
        char qc;
388
 
        u += 4;
389
 
        qc = *u;
390
 
        if(qc == '"' || qc == '\'')
391
 
            ++u;
392
 
        else
393
 
            qc = 0;
394
 
        strcpy(ref, u);
395
 
        u = ref + strlen(ref);
396
 
        if(u > ref && u[-1] == qc)
397
 
            u[-1] = 0;
398
 
        if(delay)
399
 
            debugPrint(2, "delay %d", delay);
400
 
        *delay_p = delay;
401
 
        return true;
402
 
    }
403
 
    i_printf(MSG_GarbledRefresh, ref);
404
 
    *delay_p = 0;
405
 
    return false;
406
 
}                               /* parseRefresh */
407
 
 
408
 
/* Return true if we waited for the duration, false if interrupted.
409
 
 * I don't know how to do this in Windows. */
410
 
bool
411
 
refreshDelay(int sec, const char *u)
412
 
{
413
 
/* the value 15 seconds is somewhat arbitrary */
414
 
    if(sec < 15)
415
 
        return true;
416
 
    i_printf(MSG_RedirectDelayed, u, sec);
417
 
    return false;
418
 
}                               /* refreshDelay */
419
 
 
420
 
int hcode;                      /* example, 404 */
421
 
char herror[32];                /* example, file not found */
422
 
 
423
 
bool
424
 
httpConnect(const char *from, const char *url)
425
 
{
426
 
    int port;                   /* usually 80 */
427
 
    const char *portloc;
428
 
    IP32bit hip;                /* host IP */
429
 
    const char *host, *post, *s;
430
 
    char *hdr;                  /* http header */
431
 
    char *u;
432
 
    int l, n, err;
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];
442
 
    struct MIMETYPE *mt;
443
 
    const char *prot;
444
 
    char *cmd;
445
 
    char suffix[12];
446
 
 
447
 
    if(!isURL(url)) {
448
 
        setError(MSG_BadURL, url);
449
 
        return false;
450
 
    }
451
 
 
452
 
    n = fetchHistory(from, url);
453
 
    if(n < 0)
454
 
        return false;           /* infinite loop */
455
 
    if(n == false) {
456
 
      already:
457
 
        serverData = EMPTYSTRING;
458
 
        serverDataLen = 0;
459
 
        return true;            /* success, because it's already fetched */
460
 
    }
461
 
    newurl = true;
462
 
 
463
 
  restart:
464
 
    hct = CT_HTML;              /* the default */
465
 
    hce = ENC_PLAIN;
466
 
    isprox = isProxyURL(url);
467
 
    hssl = 0;
468
 
    prot = getProtURL(url);
469
 
    secure = stringEqualCI(prot, "https");
470
 
    host = getHostURL(url);
471
 
    if(!host)
472
 
        i_printfExit(MSG_EmptyHost);
473
 
    if(proxy_host) {
474
 
        if(secure) {
475
 
            setError(MSG_SSLProxyNYI);
476
 
            return false;
477
 
        }
478
 
        hip = tcp_name_ip(proxy_host);
479
 
    } else {
480
 
        hip = tcp_name_ip(host);
481
 
    }
482
 
    if(hip == -1) {
483
 
        setError((intFlag ? MSG_Interrupted : MSG_IdentifyHost), host);
484
 
        return false;
485
 
    }
486
 
    debugPrint(4, "%s -> %s",
487
 
       (proxy_host ? proxy_host : host), tcp_ip_dots(hip));
488
 
 
489
 
/* See if the protocol is a recognized stream */
490
 
    if(stringEqualCI(prot, "http") || stringEqualCI(prot, "https")) {
491
 
        ;                       /* ok for now */
492
 
    } else if(stringEqualCI(prot, "ftp")) {
493
 
        return ftpConnect(url);
494
 
    } else if(mt = findMimeByProtocol(prot)) {
495
 
      mimeProcess:
496
 
        cmd = pluginCommand(mt, url, 0);
497
 
        system(cmd);
498
 
        nzFree(cmd);
499
 
        return true;
500
 
    } else {
501
 
        setError(MSG_WebProtBad, prot);
502
 
        return false;
503
 
    }
504
 
 
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) ;
508
 
    if(*s == '.') {
509
 
        ++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)
515
 
            goto mimeProcess;
516
 
    }
517
 
 
518
 
/* Pull user password out of the url */
519
 
    user[0] = pass[0] = 0;
520
 
    if(newurl) {
521
 
        s = getUserURL(url);
522
 
        if(s) {
523
 
            if(strlen(s) >= sizeof (user) - 2) {
524
 
                setError(MSG_UserNameLong, sizeof (user));
525
 
                return false;
526
 
            }
527
 
            strcpy(user, s);
528
 
        }
529
 
        s = getPassURL(url);
530
 
        if(s) {
531
 
            if(strlen(s) >= sizeof (pass) - 2) {
532
 
                setError(MSG_PasswordLong, sizeof (pass));
533
 
                return false;
534
 
            }
535
 
            strcpy(pass, s);
536
 
        }
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. */
542
 
    }
543
 
    newurl = false;
544
 
 
545
 
    getPortLocURL(url, &portloc, &port);
546
 
    hsock = tcp_connect(hip, (proxy_host ? proxy_port : port), webTimeout);
547
 
    if(hsock < 0) {
548
 
        setError((intFlag ? MSG_Interrupted : MSG_WebConnect), host);
549
 
        return false;
550
 
    }
551
 
    if(proxy_host)
552
 
        debugPrint(4, "connected to port %d/%d", proxy_port, port);
553
 
    else
554
 
        debugPrint(4, "connected to port %d", port);
555
 
    if(secure) {
556
 
        hssl = SSL_new(sslcx);
557
 
        SSL_set_fd(hssl, hsock);
558
 
/* Do we need this?
559
 
hssl->options |= SSL_OP_NO_TLSv1;
560
 
*/
561
 
        err = SSL_connect(hssl);
562
 
        if(err != 1) {
563
 
            err = ERR_peek_last_error();
564
 
            ERR_clear_error();
565
 
            if(ERR_GET_REASON(err) != SSL_R_CERTIFICATE_VERIFY_FAILED)
566
 
                setError(MSG_WebConnectSecure, host, err);
567
 
            else
568
 
                setError(MSG_NoCertify, host);
569
 
            SSL_free(hssl);
570
 
            close(hsock);
571
 
            return false;
572
 
        }
573
 
        debugPrint(4, "secure connection established");
574
 
    }
575
 
 
576
 
    post = strchr(url, '\1');
577
 
    if(post)
578
 
        post++;
579
 
 
580
 
    hdr = initString(&l);
581
 
    stringAndString(&hdr, &l, post ? "POST " : "GET ");
582
 
    if(proxy_host) {
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);
590
 
        }
591
 
    }
592
 
    stringAndChar(&hdr, &l, '/');
593
 
 
594
 
    s = getDataURL(url);
595
 
    while(true) {
596
 
        char c, buf[4];
597
 
        if(post && s == post - 1)
598
 
            break;
599
 
        c = *s;
600
 
        if(!c)
601
 
            break;
602
 
        if(c == '#')
603
 
            break;
604
 
        if(c == '\\')
605
 
            c = '/';
606
 
        if(c <= ' ') {
607
 
            sprintf(buf, "%%%02X", (unsigned char)c);
608
 
            stringAndString(&hdr, &l, buf);
609
 
        } else
610
 
            stringAndChar(&hdr, &l, c);
611
 
        ++s;
612
 
    }
613
 
    stringAndString(&hdr, &l, " HTTP/1.0\r\n");
614
 
 
615
 
    stringAndString(&hdr, &l, "Host: ");
616
 
    stringAndString(&hdr, &l, host);
617
 
    if(portloc) {               /* port specified */
618
 
        stringAndChar(&hdr, &l, ':');
619
 
        stringAndNum(&hdr, &l, port);
620
 
    }
621
 
    stringAndString(&hdr, &l, eol);
622
 
 
623
 
    stringAndString(&hdr, &l, "User-Agent: ");
624
 
    stringAndString(&hdr, &l, currentAgent);
625
 
    stringAndString(&hdr, &l, eol);
626
 
 
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: \"");
634
 
            if(!post2)
635
 
                post2 = currentReferrer + strlen(currentReferrer);
636
 
            if(post2 - currentReferrer >= 7 && !memcmp(post2 - 7, ".browse", 7))
637
 
                post2 -= 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;
643
 
        }
644
 
    }
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");
649
 
 
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);
657
 
        free(u);
658
 
    }
659
 
 
660
 
    if(post) {
661
 
        if(strncmp(post, "`mfd~", 5)) {
662
 
            stringAndString(&hdr, &l,
663
 
               "Content-Type: application/x-www-form-urlencoded\r\n");
664
 
        } else {
665
 
            post += 5;
666
 
            stringAndString(&hdr, &l,
667
 
               "Content-Type: multipart/form-data; boundary=");
668
 
            s = strchr(post, '\r');
669
 
            stringAndBytes(&hdr, &l, post, s - post);
670
 
            post = s + 2;
671
 
            stringAndString(&hdr, &l, eol);
672
 
        }
673
 
        stringAndString(&hdr, &l, "Content-Length: ");
674
 
        stringAndNum(&hdr, &l, strlen(post));
675
 
        stringAndString(&hdr, &l, eol);
676
 
    }
677
 
    /* post */
678
 
    sendCookies(&hdr, &l, url, secure);
679
 
 
680
 
/* Here's the blank line that ends the header. */
681
 
    stringAndString(&hdr, &l, eol);
682
 
 
683
 
    if(debugLevel >= 4) {
684
 
/* print the header to be sent. */
685
 
        for(u = hdr; *u; ++u) {
686
 
            char c = *u;
687
 
            if(c != '\r')
688
 
                putchar(c);
689
 
        }
690
 
    }
691
 
 
692
 
    if(post)
693
 
        stringAndString(&hdr, &l, post);
694
 
 
695
 
    if(secure)
696
 
        n = SSL_write(hssl, hdr, l);
697
 
    else
698
 
        n = tcp_write(hsock, hdr, l);
699
 
    debugPrint(4, "http header sent, %d/%d bytes", n, l);
700
 
    free(hdr);
701
 
    if(n < l) {
702
 
        setError(intFlag ? MSG_Interrupted : MSG_WebSend);
703
 
        if(secure)
704
 
            SSL_free(hssl);
705
 
        close(hsock);
706
 
        return false;
707
 
    }
708
 
 
709
 
    rc = readSocket(hssl, hsock);
710
 
    if(secure)
711
 
        SSL_free(hssl);
712
 
    close(hsock);
713
 
    if(!rc)
714
 
        goto abort;
715
 
 
716
 
/* Parse the http header, at the start of the data stream. */
717
 
    if(serverDataLen < 16)
718
 
        goto nohead;            /* too short */
719
 
    u = serverData;
720
 
    if((*u++ | 0x20) != 'h')
721
 
        goto nohead;
722
 
    if((*u++ | 0x20) != 't')
723
 
        goto nohead;
724
 
    if((*u++ | 0x20) != 't')
725
 
        goto nohead;
726
 
    if((*u++ | 0x20) != 'p')
727
 
        goto nohead;
728
 
    if(*u++ != '/')
729
 
        goto nohead;
730
 
    while(isdigitByte(*u) || *u == '.')
731
 
        ++u;
732
 
    if(*u != ' ')
733
 
        goto nohead;
734
 
    while(*u == ' ')
735
 
        ++u;
736
 
    if(!isdigitByte(*u))
737
 
        goto nohead;
738
 
    hcode = strtol(u, &u, 10);
739
 
    while(*u == ' ')
740
 
        ++u;
741
 
    hdr = u;
742
 
    while(*u != '\r' && *u != '\n')
743
 
        ++u;
744
 
    n = u - hdr;
745
 
    if(n >= sizeof (herror))
746
 
        n = sizeof (herror) - 1;
747
 
    strncpy(herror, hdr, n);
748
 
    herror[n] = 0;
749
 
    debugPrint(3, "http code %d %s", hcode, herror);
750
 
    hdr = 0;
751
 
/* set hdr if we find our empty line */
752
 
    while(u < serverData + serverDataLen) {
753
 
        char c = *u;
754
 
        char d = 0;
755
 
        if(u < serverData + serverDataLen - 1)
756
 
            d = u[1];
757
 
        if(!c)
758
 
            break;
759
 
        if(c == '\n' && d == '\n') {
760
 
            hdr = u + 2;
761
 
            break;
762
 
        }
763
 
        if(c == '\r' && d == '\n' &&
764
 
           u <= serverData + serverDataLen - 4 &&
765
 
           u[2] == '\r' && u[3] == '\n') {
766
 
            hdr = u + 4;
767
 
            break;
768
 
        }
769
 
        ++u;
770
 
    }
771
 
    if(!hdr)
772
 
        goto nohead;
773
 
 
774
 
    if(debugLevel >= 4) {
775
 
/* print the header just received. */
776
 
        for(u = serverData; u < hdr; ++u) {
777
 
            char c = *u;
778
 
            if(c != '\r')
779
 
                putchar(c);
780
 
        }
781
 
    }
782
 
 
783
 
/* We need to gather the cookies before we redirect. */
784
 
    s = serverData;
785
 
    while(u = extractHeaderItem(s, hdr, "Set-Cookie", &s)) {
786
 
        rc = receiveCookie(url, u);
787
 
        free(u);
788
 
        debugPrint(3, rc ? "accepted" : "rejected");
789
 
    }
790
 
 
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);
796
 
                nzFree(u);
797
 
                goto abort;
798
 
            }
799
 
            if(!(user[0] | pass[0])) {
800
 
                s = strstr(u, "realm=");
801
 
                if(s) {
802
 
                    char q = 0;
803
 
                    char *v = 0;
804
 
                    s += 6;
805
 
                    if(isquote(*s))
806
 
                        q = *s++;
807
 
                    if(q)
808
 
                        v = strchr(s, q);
809
 
                    if(v)
810
 
                        *v = 0;
811
 
                    puts(s);
812
 
                }
813
 
            }
814
 
            nzFree(u);
815
 
        }
816
 
        if(!(user[0] | pass[0])) {
817
 
            if(!isInteractive) {
818
 
                setError(MSG_Authorize2);
819
 
                goto abort;
820
 
            }
821
 
            i_puts(MSG_WebAuthorize);
822
 
          getlogin:
823
 
            i_printf(MSG_UserName);
824
 
            fflush(stdout);
825
 
            fflush(stdin);
826
 
            if(!fgets(user, sizeof (user), stdin))
827
 
                ebClose(0);
828
 
            n = strlen(user);
829
 
            if(n >= sizeof (user) - 1) {
830
 
                i_printf(MSG_UserNameLong, sizeof (user) - 2);
831
 
                goto getlogin;
832
 
            }
833
 
            if(n && user[n - 1] == '\n')
834
 
                user[--n] = 0;
835
 
            if(stringEqual(user, "x")) {
836
 
                setError(MSG_LoginAbort);
837
 
                goto abort;
838
 
            }
839
 
            i_printf(MSG_Password);
840
 
            fflush(stdout);
841
 
            fflush(stdin);
842
 
            if(!fgets(pass, sizeof (pass), stdin))
843
 
                ebClose(0);
844
 
            n = strlen(pass);
845
 
            if(n >= sizeof (pass) - 1) {
846
 
                i_printf(MSG_PasswordLong, sizeof (pass) - 2);
847
 
                goto getlogin;
848
 
            }
849
 
            if(n && pass[n - 1] == '\n')
850
 
                pass[--n] = 0;
851
 
            if(stringEqual(pass, "x")) {
852
 
                setError(MSG_LoginAbort);
853
 
                goto abort;
854
 
            }
855
 
        }
856
 
        intFlag = false;
857
 
        if(!addWebAuthorization(url, 1, user, pass, false))
858
 
            goto abort;
859
 
        nzFree(serverData);
860
 
        serverData = 0;
861
 
        serverDataLen = 0;
862
 
        goto restart;
863
 
    }
864
 
    /* 401 authentication */
865
 
    if(u = extractHeaderItem(serverData, hdr, "Content-Encoding", 0)) {
866
 
        hce = -1;
867
 
        if(stringEqualCI(u, "compress"))
868
 
            hce = ENC_COMPRESS;
869
 
        if(stringEqualCI(u, "gzip"))
870
 
            hce = ENC_GZIP;
871
 
        if(stringEqualCI(u, "7bit"))
872
 
            hce = 0;
873
 
        if(stringEqualCI(u, "8bit"))
874
 
            hce = 0;
875
 
        if(hce < 0) {
876
 
            i_printf(MSG_CompressUnrecognized, u);
877
 
            hce = 0;
878
 
        }
879
 
        nzFree(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))
884
 
                hce = 0;
885
 
            free(u);
886
 
        }
887
 
    }
888
 
 
889
 
    /* compressed */
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. */
893
 
    delay = 0;
894
 
    ref = loc = u = 0;
895
 
    if((hcode >= 301 && hcode <= 303 || hcode == 200) && allowRedirection) {
896
 
        if(hcode == 200) {
897
 
            ref = extractHeaderItem(serverData, hdr, "refresh", 0);
898
 
            if(ref) {
899
 
                if(parseRefresh(ref, &delay)) {
900
 
                    u = ref;
901
 
                } else {
902
 
                    free(ref);
903
 
                    ref = 0;
904
 
                }
905
 
            }
906
 
        } else {
907
 
            loc = extractHeaderItem(serverData, hdr, "location", 0);
908
 
            if(!loc[0])
909
 
                loc = 0;
910
 
            if(!loc) {
911
 
                i_printf(MSG_RedirectNoURL, hcode);
912
 
                if(hcode >= 301 && hcode <= 303)
913
 
                    hcode = 200;
914
 
            } else
915
 
                u = loc;
916
 
        }
917
 
        if(u) {
918
 
            unpercentURL(u);
919
 
            if(refreshDelay(delay, u)) {
920
 
                n = fetchHistory(url, u);
921
 
                if(n < 0) {
922
 
                    free(u);
923
 
                    goto abort;
924
 
                }               /* infinite loop */
925
 
                if(n == false) {
926
 
/* success, because it's already fetched */
927
 
                    free(u);
928
 
                    goto already;
929
 
                }
930
 
                if(recount >= 10) {
931
 
                    free(u);
932
 
                    i_puts(MSG_RedirectMany);
933
 
                    goto gotFile;
934
 
                }
935
 
/* Redirection looks valid, let's run with it. */
936
 
                ++recount;
937
 
                free(serverData);
938
 
                serverData = 0;
939
 
                serverDataLen = 0;
940
 
/* trying to plug a subtle memory leak */
941
 
                if(recount > 2)
942
 
                    free((void *)from);
943
 
                from = url;
944
 
                url = resolveURL(from, u);
945
 
                nzFree(u);
946
 
                changeFileName = (char *)url;
947
 
                debugPrint(2, "redirect %s", url);
948
 
                newurl = true;
949
 
                goto restart;
950
 
            } else {
951
 
                n = hdr - serverData;
952
 
                if(n >= strlen(u) + 36) {
953
 
                    char rbuf[36];
954
 
                    sprintf(rbuf, "<A HREF=%s>Refresh[%d]</A><br>\n", u, delay);
955
 
                    l = strlen(rbuf);
956
 
                    hdr -= l;
957
 
                    memcpy(hdr, rbuf, l);
958
 
                }               /* enough room */
959
 
                free(u);
960
 
            }
961
 
        }                       /* redirection present */
962
 
    }
963
 
    /* looking for redirection */
964
 
    if(hcode != 200)
965
 
        i_printf(MSG_HTTPError, hcode, herror);
966
 
 
967
 
  gotFile:
968
 
/* Don't need the header any more */
969
 
    n = hdr - serverData;
970
 
    serverDataLen -= n;
971
 
    memcpy(serverData, serverData + n, serverDataLen);
972
 
 
973
 
    if(!serverDataLen)
974
 
        return true;
975
 
 
976
 
    if(hce) {                   /* data is compressed */
977
 
        int fh;
978
 
        char *scmd;
979
 
        char suffix[4];
980
 
        suffix[0] = 0;
981
 
        u = edbrowseTempFile + strlen(edbrowseTempFile);
982
 
        if(hce == ENC_COMPRESS)
983
 
            strcpy(suffix, ".Z");
984
 
        if(hce == ENC_GZIP)
985
 
            strcpy(suffix, ".gz");
986
 
        strcpy(u, suffix);
987
 
        debugPrint(3, "uncompressing the web page with method %s", suffix);
988
 
        fh =
989
 
           open(edbrowseTempFile, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC,
990
 
           0666);
991
 
        if(fh < 0) {
992
 
            setError(MSG_TempNoCreate, edbrowseTempFile);
993
 
            *u = 0;
994
 
            goto abort;
995
 
        }
996
 
        if(write(fh, serverData, serverDataLen) < serverDataLen) {
997
 
            setError(MSG_TempNoWrite, edbrowseTempFile);
998
 
            close(fh);
999
 
            *u = 0;
1000
 
            goto abort;
1001
 
        }
1002
 
        close(fh);
1003
 
        *u = 0;
1004
 
        nzFree(serverData);
1005
 
        serverData = 0;
1006
 
        serverDataLen = 0;
1007
 
        unlink(edbrowseTempFile);
1008
 
        scmd = allocMem(2 * strlen(edbrowseTempFile) + 20);
1009
 
        sprintf(scmd, "zcat %s%s > %s",
1010
 
           edbrowseTempFile, suffix, edbrowseTempFile);
1011
 
        system(scmd);
1012
 
        free(scmd);
1013
 
        n = fileSizeByName(edbrowseTempFile);
1014
 
        if(n <= 0) {
1015
 
            setError(MSG_TempNoUncompress);
1016
 
            return false;
1017
 
        }
1018
 
        serverData = allocMem(n + 2);
1019
 
        fh = open(edbrowseTempFile, O_RDONLY | O_BINARY);
1020
 
        if(fh < 0) {
1021
 
            setError(MSG_TempNoAccess, edbrowseTempFile);
1022
 
            goto abort;
1023
 
        }
1024
 
        if(read(fh, serverData, n) < n) {
1025
 
            setError(MSG_TempNoRead, edbrowseTempFile);
1026
 
            close(fh);
1027
 
            goto abort;
1028
 
        }
1029
 
        close(fh);
1030
 
        serverDataLen = n;
1031
 
        serverData[n] = 0;
1032
 
/* doesn't hurt to clean house, now that everything worked. */
1033
 
        strcpy(u, suffix);
1034
 
        unlink(edbrowseTempFile);
1035
 
        *u = 0;
1036
 
        unlink(edbrowseTempFile);
1037
 
    }
1038
 
 
1039
 
    return true;
1040
 
 
1041
 
  nohead:
1042
 
    i_puts(MSG_HTTPHeader);
1043
 
    return true;
1044
 
 
1045
 
  abort:
1046
 
    nzFree(serverData);
1047
 
    serverData = 0;
1048
 
    serverDataLen = 0;
1049
 
    return false;
1050
 
}                               /* httpConnect */
1051
 
 
1052
 
/* Format a line from an ftp ls. */
1053
 
static void
1054
 
ftpls(char *line)
1055
 
{
1056
 
    int l = strlen(line);
1057
 
    int j;
1058
 
/* blank line becomes paragraph break */
1059
 
    if(!l || !memcmp(line, "total ", 6) && stringIsNum(line + 6) > 0) {
1060
 
        stringAndString(&serverData, &serverDataLen, "<P>\n");
1061
 
        return;
1062
 
    }
1063
 
    for(j = 0; line[j]; ++j)
1064
 
        if(!strchr("-rwxdls", line[j]))
1065
 
            break;
1066
 
    if(j == 10 && line[j] == ' ') {     /* long list */
1067
 
        int fsize, nlinks;
1068
 
        char user[42], group[42];
1069
 
        char *q;
1070
 
        sscanf(line + j, " %d %40s %40s %d", &nlinks, user, group, &fsize);
1071
 
        q = strchr(line, ':');
1072
 
        if(q) {
1073
 
            for(++q; isdigitByte(*q) || *q == ':'; ++q) ;
1074
 
            while(*q == ' ')
1075
 
                ++q;
1076
 
            if(*q) {            /* file name */
1077
 
                char qc = '"';
1078
 
                if(strchr(q, qc))
1079
 
                    qc = '\'';
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>");
1087
 
                if(line[0] == 'd')
1088
 
                    stringAndChar(&serverData, &serverDataLen, '/');
1089
 
                stringAndString(&serverData, &serverDataLen, ": ");
1090
 
                stringAndNum(&serverData, &serverDataLen, fsize);
1091
 
                stringAndChar(&serverData, &serverDataLen, '\n');
1092
 
                return;
1093
 
            }
1094
 
        }
1095
 
    }
1096
 
    if(!strpbrk(line, "<>&")) {
1097
 
        stringAndString(&serverData, &serverDataLen, line);
1098
 
    } else {
1099
 
        char c, *q;
1100
 
        for(q = line; c = *q; ++q) {
1101
 
            char *meta = 0;
1102
 
            if(c == '<')
1103
 
                meta = "&lt;";
1104
 
            if(c == '>')
1105
 
                meta = "&gt;";
1106
 
            if(c == '&')
1107
 
                meta = "&amp;";
1108
 
            if(meta)
1109
 
                stringAndString(&serverData, &serverDataLen, meta);
1110
 
            else
1111
 
                stringAndChar(&serverData, &serverDataLen, c);
1112
 
        }
1113
 
    }
1114
 
    stringAndChar(&serverData, &serverDataLen, '\n');
1115
 
}                               /* ftpls */
1116
 
 
1117
 
/* Like httpConnect, but for ftp */
1118
 
/* Basically, a system call to ncftpget */
1119
 
bool
1120
 
ftpConnect(const char *url)
1121
 
{
1122
 
    FILE *f;
1123
 
    char *cmd, *out;
1124
 
    int cmd_l, out_l;
1125
 
    int rc;
1126
 
    bool dirmode;
1127
 
    int c;
1128
 
    static const char npf[] = "not a plain file.";
1129
 
    const int npfsize = strlen(npf);
1130
 
 
1131
 
    serverData = 0;
1132
 
    serverDataLen = 0;
1133
 
    fileSize = -1;
1134
 
    if(debugLevel >= 1)
1135
 
        i_puts(MSG_FTPDownload);
1136
 
    dirmode = false;
1137
 
 
1138
 
  top:cmd = initString(&cmd_l);
1139
 
    if(dirmode) {
1140
 
        stringAndString(&cmd, &cmd_l, "ncftpls -l ");
1141
 
    } else {
1142
 
        stringAndString(&cmd, &cmd_l, "ncftpget -r 1 -v -z ");
1143
 
        if(debugLevel >= 4)
1144
 
            stringAndString(&cmd, &cmd_l, "-d stdout ");
1145
 
    }
1146
 
    if(ftpMode) {
1147
 
        char mode[4];
1148
 
        sprintf(mode, "-%c ", ftpMode);
1149
 
        stringAndString(&cmd, &cmd_l, mode);
1150
 
    }
1151
 
/* Quote the url, in case there are spaces in the name. */
1152
 
    stringAndChar(&cmd, &cmd_l, '"');
1153
 
    stringAndString(&cmd, &cmd_l, url);
1154
 
    if(dirmode)
1155
 
        stringAndChar(&cmd, &cmd_l, '/');
1156
 
    stringAndChar(&cmd, &cmd_l, '"');
1157
 
    stringAndString(&cmd, &cmd_l, " 2>&1");
1158
 
    debugPrint(3, "%s", cmd);
1159
 
 
1160
 
    f = popen(cmd, "r");
1161
 
    if(!f) {
1162
 
        setError(MSG_TempNoSystem, cmd, errno);
1163
 
        nzFree(cmd);
1164
 
        return false;
1165
 
    }
1166
 
    out = initString(&out_l);
1167
 
    if(dirmode) {
1168
 
        serverData = initString(&serverDataLen);
1169
 
        stringAndString(&serverData, &serverDataLen, "<html>\n");
1170
 
    }
1171
 
 
1172
 
    while((c = getc(f)) != EOF) {
1173
 
        if(c == '\r')
1174
 
            c = '\n';
1175
 
        if(c == '\n') {
1176
 
            if(dirmode)
1177
 
                ftpls(out);
1178
 
            else {
1179
 
                if(!out_l)
1180
 
                    continue;
1181
 
                if(out_l > npfsize && stringEqual(out + out_l - npfsize, npf)) {
1182
 
                    pclose(f);
1183
 
                    nzFree(cmd);
1184
 
                    nzFree(out);
1185
 
                    dirmode = true;
1186
 
                    goto top;
1187
 
                }
1188
 
/* Don't print the ETA messages */
1189
 
                if(!strstr(out, " ETA: "))
1190
 
                    puts(out);
1191
 
            }
1192
 
            nzFree(out);
1193
 
            out = initString(&out_l);
1194
 
        } else
1195
 
            stringAndChar(&out, &out_l, c);
1196
 
    }
1197
 
 
1198
 
    rc = pclose(f);
1199
 
    nzFree(cmd);
1200
 
 
1201
 
    if(out_l) {                 /* should never happen */
1202
 
        puts(out);
1203
 
        nzFree(out);
1204
 
    }
1205
 
 
1206
 
    if(rc) {
1207
 
        if(!(rc & 0xff))
1208
 
            rc >>= 8;
1209
 
        if(rc > 0 && rc <= 11)
1210
 
            setError(MSG_FTPConnect - 1 + rc);
1211
 
        else
1212
 
            setError(MSG_FTPUnexpected, rc);
1213
 
        return false;
1214
 
    }
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, "/");
1221
 
    }
1222
 
    return true;
1223
 
}                               /* ftpConnect */
1224
 
 
1225
 
 
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
 
*********************************************************************/
1232
 
 
1233
 
void
1234
 
allIPs(void)
1235
 
{
1236
 
    static IP32bit iplist[5 + 1];
1237
 
    char *domlist[8];
1238
 
    int iptotal = 0, domtotal = 0;
1239
 
    IP32bit ip;
1240
 
    int ntags, tagno;
1241
 
    char *href;
1242
 
    const char *dom;
1243
 
    int ln;                     /* line number */
1244
 
    int ftype, j, k, nf;
1245
 
    char *p;
1246
 
 
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);
1253
 
            if(!href)
1254
 
                continue;
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))
1266
 
                        break;
1267
 
                if(k == domtotal) {
1268
 
                    domlist[domtotal++] = cloneString(dom);
1269
 
                    debugPrint(3, "hip %s", dom);
1270
 
                    if(tcp_isDots(dom))
1271
 
                        ip = tcp_dots_ip(dom);
1272
 
                    else
1273
 
                        ip = tcp_name_ip(dom);
1274
 
                    if(ip != NULL_IP) {
1275
 
/* could be a repeat */
1276
 
                        for(k = 0; k < iptotal; ++k)
1277
 
                            if(iplist[k] == ip)
1278
 
                                break;
1279
 
                        if(k == iptotal) {
1280
 
                            iplist[iptotal++] = ip;
1281
 
                            if(ismc && onBlacklist1(ip)) {
1282
 
                                nzFree(href);
1283
 
                                goto done;
1284
 
                            }
1285
 
                        }
1286
 
                    }           /* valid ip */
1287
 
                }
1288
 
                /* different domain */
1289
 
            }                   /* valid domain */
1290
 
            nzFree(href);
1291
 
            if(iptotal == 5)
1292
 
                goto done;
1293
 
            if(domtotal == 8)
1294
 
                goto done;
1295
 
        }                       /* loop over references on this line */
1296
 
    }                           /* loop over lines */
1297
 
 
1298
 
  done:
1299
 
    iplist[iptotal] = NULL_IP;
1300
 
    cw->iplist = iplist;
1301
 
    for(k = 0; k < domtotal; ++k)
1302
 
        nzFree(domlist[k]);
1303
 
}                               /* allIPs */