~ubuntu-branches/ubuntu/raring/edbrowse/raring

« back to all changes in this revision

Viewing changes to main.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
 
/* main.c
2
 
 * Entry point, arguments and options.
3
 
 * Copyright (c) Karl Dahlke, 2006
4
 
 * This file is part of the edbrowse project, released under GPL.
5
 
 */
6
 
 
7
 
#include "eb.h"
8
 
 
9
 
#include <signal.h>
10
 
#include <pcre.h>
11
 
 
12
 
/* Define the globals that are declared in eb.h. */
13
 
/* See eb.h for descriptive comments. */
14
 
 
15
 
const char *version = "3.3.1";
16
 
char *userAgents[10], *currentAgent, *currentReferrer;
17
 
const char eol[] = "\r\n";
18
 
char EMPTYSTRING[] = "";
19
 
int debugLevel = 1;
20
 
int webTimeout = 20, mailTimeout = 0;
21
 
bool ismc, browseLocal, zapMail, unformatMail, passMail, errorExit;
22
 
bool isInteractive, intFlag, inInput;
23
 
int fileSize, maxFileSize = 50000000;
24
 
int localAccount, maxAccount;
25
 
struct MACCOUNT accounts[MAXACCOUNT];
26
 
int maxMime;
27
 
struct MIMETYPE mimetypes[MAXMIME];
28
 
static int maxTables;
29
 
static struct DBTABLE dbtables[MAXDBT];
30
 
char *dbarea, *dblogin, *dbpw;  /* to log into the database */
31
 
char *proxy_host;
32
 
int proxy_port;
33
 
bool caseInsensitive, searchStringsAll;
34
 
bool textAreaDosNewlines = true, undoable;
35
 
bool allowRedirection = true, allowJS = true, sendReferrer = false;
36
 
bool verifyCertificates = true, binaryDetect = true;
37
 
char ftpMode;
38
 
bool showHiddenFiles, helpMessagesOn;
39
 
uchar dirWrite, endMarks;
40
 
int context = 1;
41
 
uchar linePending[MAXTTYLINE];
42
 
char *changeFileName, *mailDir;
43
 
char *addressFile, *ipbFile;
44
 
char *home, *recycleBin, *configFile, *sigFile;
45
 
char *sslCerts, *cookieFile, *edbrowseTempFile, *spamCan;
46
 
pst *textLines;
47
 
int textLinesMax, textLinesCount;
48
 
struct ebWindow *cw;
49
 
struct ebSession sessionList[MAXSESSION], *cs;
50
 
 
51
 
/* Edbrowse functions, defined in the config file */
52
 
#define MAXEBSCRIPT 500
53
 
#define MAXNEST 20
54
 
static char *ebScript[MAXEBSCRIPT + 1];
55
 
static char *ebScriptName[MAXEBSCRIPT + 1];
56
 
#define MAXNOJS 500
57
 
static const char *javaDis[MAXNOJS];
58
 
static int javaDisCount;
59
 
#define MAXFILTER 500
60
 
struct FILTERDESC {
61
 
    const char *match;
62
 
    const char *redirect;
63
 
    char type;
64
 
    long expire;
65
 
};
66
 
static struct FILTERDESC filters[MAXFILTER];
67
 
static int n_filters;
68
 
static int subjstart = 0;
69
 
static char *cfgcopy;
70
 
static int cfglen;
71
 
static long nowday;
72
 
 
73
 
static void
74
 
setNowDay(void)
75
 
{
76
 
    time_t now;
77
 
    time(&now);
78
 
    now /= (60 * 60 * 24);      /* convert to days */
79
 
    now -= 30 * 365;
80
 
    now -= 7;                   /* leap years */
81
 
    nowday = now;
82
 
}                               /* setNowDay */
83
 
 
84
 
static void
85
 
updateConfig(void)
86
 
{
87
 
    int fh = open(configFile, O_WRONLY | O_TRUNC, 0);
88
 
    if(fh < 0) {
89
 
        debugPrint(0, "warning: cannot update config file");
90
 
        return;
91
 
    }
92
 
    if(write(fh, cfgcopy, cfglen) < cfglen)
93
 
        i_printfExit(MSG_ERBC_NoWrite);
94
 
    close(fh);
95
 
}                               /* updateConfig */
96
 
 
97
 
bool
98
 
junkSubject(const char *s, char key)
99
 
{
100
 
    int l, n;
101
 
    char *new;
102
 
    long exp = nowday;
103
 
    if(!s || !*s) {
104
 
        i_puts(MSG_NoSubject);
105
 
        return false;
106
 
    }
107
 
    if(!cfgcopy) {
108
 
        i_puts(MSG_NoConfig);
109
 
        return false;
110
 
    }
111
 
    if(!subjstart) {
112
 
        i_puts(MSG_NoSubjFilter);
113
 
        return false;
114
 
    }
115
 
    if(key == 'j')
116
 
        exp += 10;
117
 
    if(key == 'J')
118
 
        exp += 365;
119
 
    l = strlen(s) + 10;
120
 
    if(exp > 9999)
121
 
        ++l;
122
 
    n = cfglen + l;
123
 
    new = allocMem(n);
124
 
    memcpy(new, cfgcopy, subjstart);
125
 
    sprintf(new + subjstart, "%d`%s > x\n", exp, s);
126
 
    memcpy(new + subjstart + l, cfgcopy + subjstart, cfglen - subjstart);
127
 
    nzFree(cfgcopy);
128
 
    cfgcopy = new;
129
 
    cfglen = n;
130
 
    updateConfig();
131
 
    if(n_filters < MAXFILTER - 1) {
132
 
        filters[n_filters].type = 4;
133
 
        filters[n_filters].match = cloneString(s);
134
 
        filters[n_filters].redirect = "x";
135
 
        ++n_filters;
136
 
    }
137
 
    return true;
138
 
}                               /* junkSubject */
139
 
 
140
 
/* This routine succeeds, or aborts via i_printfExit */
141
 
static void
142
 
readConfigFile(void)
143
 
{
144
 
    char *buf, *s, *t, *v, *q;
145
 
    char *cfglp, *cfgnlp;
146
 
    int buflen, n;
147
 
    char c, ftype;
148
 
    bool cmt = false;
149
 
    bool startline = true;
150
 
    bool cfgmodify = false;
151
 
    uchar mailblock = 0, mimeblock = 0, tabblock = 0;
152
 
    int nest, ln, j;
153
 
    int sn = 0;                 /* script number */
154
 
    char stack[MAXNEST];
155
 
    char last[24];
156
 
    int lidx = 0;
157
 
    struct MACCOUNT *act;
158
 
    struct MIMETYPE *mt;
159
 
    struct DBTABLE *td;
160
 
    static const char *const keywords[] = {
161
 
        "inserver", "outserver", "login", "password", "from", "reply",
162
 
        "inport", "outport",
163
 
        "type", "desc", "suffix", "protocol", "program",
164
 
        "tname", "tshort", "cols", "keycol",
165
 
        "adbook", "ipblack", "maildir", "agent",
166
 
        "jar", "nojs", "spamcan",
167
 
        "webtimer", "mailtimer", "certfile", "database", "proxy",
168
 
        0
169
 
    };
170
 
 
171
 
    if(!fileTypeByName(configFile, false))
172
 
        return;                 /* config file not present */
173
 
    if(!fileIntoMemory(configFile, &buf, &buflen))
174
 
        showErrorAbort();
175
 
/* An extra newline won't hurt. */
176
 
    if(buflen && buf[buflen - 1] != '\n')
177
 
        buf[buflen++] = '\n';
178
 
/* make copy */
179
 
    cfgcopy = allocMem(buflen + 1);
180
 
    memcpy(cfgcopy, buf, (cfglen = buflen));
181
 
 
182
 
/* Undos, uncomment, watch for nulls */
183
 
/* Encode mail{ as hex 81 m, and other encodings. */
184
 
    ln = 1;
185
 
    for(s = t = v = buf; s < buf + buflen; ++s) {
186
 
        c = *s;
187
 
        if(c == '\0')
188
 
            i_printfExit(MSG_ERBC_Nulls, ln);
189
 
        if(c == '\r' && s[1] == '\n')
190
 
            continue;
191
 
        if(cmt) {
192
 
            if(c != '\n')
193
 
                continue;
194
 
            cmt = false;
195
 
        }
196
 
        if(c == '#' && startline) {
197
 
            cmt = true;
198
 
            goto putc;
199
 
        }
200
 
        if(c == '\n') {
201
 
            last[lidx] = 0;
202
 
            lidx = 0;
203
 
            if(stringEqual(last, "}")) {
204
 
                *v = '\x82';
205
 
                t = v + 1;
206
 
            }
207
 
            if(stringEqual(last, "}else{")) {
208
 
                *v = '\x83';
209
 
                t = v + 1;
210
 
            }
211
 
            if(stringEqual(last, "mail{")) {
212
 
                *v = '\x81';
213
 
                v[1] = 'm';
214
 
                t = v + 2;
215
 
            }
216
 
            if(stringEqual(last, "mime{")) {
217
 
                *v = '\x81';
218
 
                v[1] = 'e';
219
 
                t = v + 2;
220
 
            }
221
 
            if(stringEqual(last, "table{")) {
222
 
                *v = '\x81';
223
 
                v[1] = 'b';
224
 
                t = v + 2;
225
 
            }
226
 
            if(stringEqual(last, "fromfilter{")) {
227
 
                *v = '\x81';
228
 
                v[1] = 'r';
229
 
                t = v + 2;
230
 
            }
231
 
            if(stringEqual(last, "tofilter{")) {
232
 
                *v = '\x81';
233
 
                v[1] = 't';
234
 
                t = v + 2;
235
 
            }
236
 
            if(stringEqual(last, "subjfilter{")) {
237
 
                *v = '\x81';
238
 
                v[1] = 's';
239
 
                t = v + 2;
240
 
                if(!subjstart)
241
 
                    subjstart = s + 1 - buf;
242
 
            }
243
 
            if(stringEqual(last, "if(*){")) {
244
 
                *v = '\x81';
245
 
                v[1] = 'I';
246
 
                t = v + 2;
247
 
            }
248
 
            if(stringEqual(last, "if(?){")) {
249
 
                *v = '\x81';
250
 
                v[1] = 'i';
251
 
                t = v + 2;
252
 
            }
253
 
            if(stringEqual(last, "while(*){")) {
254
 
                *v = '\x81';
255
 
                v[1] = 'W';
256
 
                t = v + 2;
257
 
            }
258
 
            if(stringEqual(last, "while(?){")) {
259
 
                *v = '\x81';
260
 
                v[1] = 'w';
261
 
                t = v + 2;
262
 
            }
263
 
            if(stringEqual(last, "until(*){")) {
264
 
                *v = '\x81';
265
 
                v[1] = 'U';
266
 
                t = v + 2;
267
 
            }
268
 
            if(stringEqual(last, "until(?){")) {
269
 
                *v = '\x81';
270
 
                v[1] = 'u';
271
 
                t = v + 2;
272
 
            }
273
 
            if(!strncmp(last, "loop(", 5) && isdigitByte(last[5])) {
274
 
                q = last + 6;
275
 
                while(isdigitByte(*q))
276
 
                    ++q;
277
 
                if(stringEqual(q, "){")) {
278
 
                    *q = 0;
279
 
                    last[4] = 'l';
280
 
                    last[3] = '\x81';
281
 
                    strcpy(v, last + 3);
282
 
                    t = v + strlen(v);
283
 
                }
284
 
            }
285
 
            if(!strncmp(last, "function", 8) &&
286
 
               (last[8] == '+' || last[8] == ':')) {
287
 
                q = last + 9;
288
 
                if(*q == 0 || *q == '{' || *q == '(')
289
 
                    i_printfExit(MSG_ERBC_NoFnName, ln);
290
 
                if(isdigitByte(*q))
291
 
                    i_printfExit(MSG_ERBC_FnDigit, ln);
292
 
                while(isalnumByte(*q))
293
 
                    ++q;
294
 
                if(q - last - 9 > 10)
295
 
                    i_printfExit(MSG_ERBC_FnTooLong, ln);
296
 
                if(*q != '{' || q[1])
297
 
                    i_printfExit(MSG_ERBC_SyntaxErr, ln);
298
 
                last[7] = 'f';
299
 
                last[6] = '\x81';
300
 
                strcpy(v, last + 6);
301
 
                t = v + strlen(v);
302
 
            }
303
 
            *t++ = c;
304
 
            v = t;
305
 
            ++ln;
306
 
            startline = true;
307
 
            continue;
308
 
        }
309
 
        if(c == ' ' || c == '\t') {
310
 
            if(startline)
311
 
                continue;
312
 
        } else {
313
 
            if(lidx < sizeof (last) - 1)
314
 
                last[lidx++] = c;
315
 
            startline = false;
316
 
        }
317
 
      putc:
318
 
        *t++ = c;
319
 
    }
320
 
    *t = 0;                     /* now it's a string */
321
 
 
322
 
/* Go line by line */
323
 
    ln = 1;
324
 
    nest = 0;
325
 
    stack[0] = ' ';
326
 
 
327
 
    for(s = buf, cfglp = cfgcopy; *s; s = t + 1, cfglp = cfgnlp, ++ln) {
328
 
        cfgnlp = strchr(cfglp, '\n') + 1;
329
 
        t = strchr(s, '\n');
330
 
        if(t == s)
331
 
            continue;           /* empty line */
332
 
        if(t == s + 1 && *s == '#')
333
 
            continue;           /* comment */
334
 
        *t = 0;                 /* I'll put it back later */
335
 
 
336
 
/* Gather the filters in a mail filter block */
337
 
        if(mailblock > 1 && !strchr("\x81\x82\x83", *s)) {
338
 
            v = strchr(s, '>');
339
 
            if(!v)
340
 
                i_printfExit(MSG_ERBC_NoCondFile, ln);
341
 
            while(v > s && (v[-1] == ' ' || v[-1] == '\t'))
342
 
                --v;
343
 
            if(v == s)
344
 
                i_printfExit(MSG_ERBC_NoMatchStr, ln);
345
 
            c = *v, *v++ = 0;
346
 
            if(c != '>') {
347
 
                while(*v != '>')
348
 
                    ++v;
349
 
                ++v;
350
 
            }
351
 
            while(*v == ' ' || *v == '\t')
352
 
                ++v;
353
 
            if(!*v)
354
 
                i_printfExit(MSG_ERBC_MatchNowh, ln, s);
355
 
            if(n_filters == MAXFILTER - 1)
356
 
                i_printfExit(MSG_ERBC_Filters, ln);
357
 
            filters[n_filters].redirect = v;
358
 
            if(mailblock >= 2) {
359
 
                long exp = strtol(s, &v, 10);
360
 
                if(exp > 0 && *v == '`' && v[1]) {
361
 
                    s = v + 1;
362
 
                    filters[n_filters].expire = exp;
363
 
                    if(exp <= nowday) {
364
 
                        cfgmodify = true;
365
 
                        memcpy(cfglp, cfgnlp, cfgcopy + cfglen - cfgnlp);
366
 
                        cfglen -= (cfgnlp - cfglp);
367
 
                        cfgnlp = cfglp;
368
 
                        continue;
369
 
                    }           /* filter rule out of date */
370
 
                }
371
 
            }
372
 
            filters[n_filters].match = s;
373
 
            filters[n_filters].type = mailblock;
374
 
            ++n_filters;
375
 
            continue;
376
 
        }
377
 
 
378
 
        v = strchr(s, '=');
379
 
        if(!v)
380
 
            goto nokeyword;
381
 
 
382
 
        while(v > s && (v[-1] == ' ' || v[-1] == '\t'))
383
 
            --v;
384
 
        if(v == s)
385
 
            goto nokeyword;
386
 
        c = *v, *v = 0;
387
 
        for(q = s; q < v; ++q)
388
 
            if(!isalphaByte(*q)) {
389
 
                *v = c;
390
 
                goto nokeyword;
391
 
            }
392
 
 
393
 
        n = stringInList(keywords, s);
394
 
        if(n < 0) {
395
 
            if(!nest)
396
 
                i_printfExit(MSG_ERBC_BadKeyword, s, ln);
397
 
            *v = c;             /* put it back */
398
 
            goto nokeyword;
399
 
        }
400
 
 
401
 
        if(n < 8 && mailblock != 1)
402
 
            i_printfExit(MSG_ERBC_MailAttrOut, ln, s);
403
 
 
404
 
        if(n >= 8 && n < 13 && mimeblock != 1)
405
 
            i_printfExit(MSG_ERBC_MimeAttrOut, ln, s);
406
 
 
407
 
        if(n >= 13 && n < 17 && tabblock != 1)
408
 
            i_printfExit(MSG_ERBC_TableAttrOut, ln, s);
409
 
 
410
 
        if(n >= 8 && mailblock)
411
 
            i_printfExit(MSG_ERBC_MailAttrIn, ln, s);
412
 
 
413
 
        if((n < 8 || n >= 13) && mimeblock)
414
 
            i_printfExit(MSG_ERBC_MimeAttrIn, ln, s);
415
 
 
416
 
        if((n < 13 || n >= 17) && tabblock)
417
 
            i_printfExit(MSG_ERBC_TableAttrIn, ln, s);
418
 
 
419
 
/* act upon the keywords */
420
 
        ++v;
421
 
        if(c != '=') {
422
 
            while(*v != '=')
423
 
                ++v;
424
 
            ++v;
425
 
        }
426
 
        while(*v == ' ' || *v == '\t')
427
 
            ++v;
428
 
        if(!*v)
429
 
            i_printfExit(MSG_ERBC_NoAttr, ln, s);
430
 
 
431
 
        switch (n) {
432
 
        case 0:
433
 
            act->inurl = v;
434
 
            continue;
435
 
 
436
 
        case 1:
437
 
            act->outurl = v;
438
 
            continue;
439
 
 
440
 
        case 2:
441
 
            act->login = v;
442
 
            continue;
443
 
 
444
 
        case 3:
445
 
            act->password = v;
446
 
            continue;
447
 
 
448
 
        case 4:
449
 
            act->from = v;
450
 
            continue;
451
 
 
452
 
        case 5:
453
 
            act->reply = v;
454
 
            continue;
455
 
 
456
 
        case 6:
457
 
            act->inport = atoi(v);
458
 
            continue;
459
 
 
460
 
        case 7:
461
 
            act->outport = atoi(v);
462
 
            continue;
463
 
 
464
 
        case 8:
465
 
            if(*v == '<')
466
 
                mt->stream = true, ++v;
467
 
            mt->type = v;
468
 
            continue;
469
 
 
470
 
        case 9:
471
 
            mt->desc = v;
472
 
            continue;
473
 
 
474
 
        case 10:
475
 
            mt->suffix = v;
476
 
            continue;
477
 
 
478
 
        case 11:
479
 
            mt->prot = v;
480
 
            continue;
481
 
 
482
 
        case 12:
483
 
            mt->program = v;
484
 
            continue;
485
 
 
486
 
        case 13:
487
 
            td->name = v;
488
 
            continue;
489
 
 
490
 
        case 14:
491
 
            td->shortname = v;
492
 
            continue;
493
 
 
494
 
        case 15:
495
 
            while(*v) {
496
 
                if(td->ncols == MAXTCOLS)
497
 
                    i_printfExit(MSG_ERBC_ManyCols, ln, MAXTCOLS);
498
 
                td->cols[td->ncols++] = v;
499
 
                q = strchr(v, ',');
500
 
                if(!q)
501
 
                    break;
502
 
                *q = 0;
503
 
                v = q + 1;
504
 
            }
505
 
            continue;
506
 
 
507
 
        case 16:
508
 
            if(!isdigitByte(*v))
509
 
                i_printfExit(MSG_ERBC_KeyNotNb, ln);
510
 
            td->key1 = strtol(v, &v, 10);
511
 
            if(*v == ',' && isdigitByte(v[1]))
512
 
                td->key2 = strtol(v + 1, &v, 10);
513
 
            if(td->key1 > td->ncols || td->key2 > td->ncols)
514
 
                i_printfExit(MSG_ERBC_KeyOutRange, ln, td->ncols);
515
 
            continue;
516
 
 
517
 
        case 17:
518
 
            addressFile = v;
519
 
            ftype = fileTypeByName(v, false);
520
 
            if(ftype && ftype != 'f')
521
 
                i_printfExit(MSG_ERBC_AbNotFile, v);
522
 
            continue;
523
 
 
524
 
        case 18:
525
 
            ipbFile = v;
526
 
            ftype = fileTypeByName(v, false);
527
 
            if(ftype && ftype != 'f')
528
 
                i_printfExit(MSG_ERBC_IPNotFile, v);
529
 
            continue;
530
 
 
531
 
        case 19:
532
 
            mailDir = v;
533
 
            if(fileTypeByName(v, false) != 'd')
534
 
                i_printfExit(MSG_ERBC_NotDir, v);
535
 
            continue;
536
 
 
537
 
        case 20:
538
 
            for(j = 0; j < 10; ++j)
539
 
                if(!userAgents[j])
540
 
                    break;
541
 
            if(j == 10)
542
 
                i_printfExit(MSG_ERBC_ManyAgents, ln);
543
 
            userAgents[j] = v;
544
 
            continue;
545
 
 
546
 
        case 21:
547
 
            cookieFile = v;
548
 
            ftype = fileTypeByName(v, false);
549
 
            if(ftype && ftype != 'f')
550
 
                i_printfExit(MSG_ERBC_JarNotFile, v);
551
 
            j = open(v, O_WRONLY | O_APPEND | O_CREAT, 0600);
552
 
            if(j < 0)
553
 
                i_printfExit(MSG_ERBC_JarNoWrite, v);
554
 
            close(j);
555
 
            continue;
556
 
 
557
 
        case 22:
558
 
            if(javaDisCount == MAXNOJS)
559
 
                i_printfExit(MSG_ERBC_NoJS, MAXNOJS);
560
 
            if(*v == '.')
561
 
                ++v;
562
 
            q = strchr(v, '.');
563
 
            if(!q || q[1] == 0)
564
 
                i_printfExit(MSG_ERBC_DomainDot, ln, v);
565
 
            javaDis[javaDisCount++] = v;
566
 
            continue;
567
 
 
568
 
        case 23:
569
 
            spamCan = v;
570
 
            ftype = fileTypeByName(v, false);
571
 
            if(ftype && ftype != 'f')
572
 
                i_printfExit(MSG_ERBC_TrashNotFile, v);
573
 
            continue;
574
 
 
575
 
        case 24:
576
 
            webTimeout = atoi(v);
577
 
            continue;
578
 
 
579
 
        case 25:
580
 
            mailTimeout = atoi(v);
581
 
            continue;
582
 
 
583
 
        case 26:
584
 
            sslCerts = v;
585
 
            ftype = fileTypeByName(v, false);
586
 
            if(ftype && ftype != 'f')
587
 
                i_printfExit(MSG_ERBC_SSLNoFile, v);
588
 
            j = open(v, O_RDONLY);
589
 
            if(j < 0)
590
 
                i_printfExit(MSG_ERBC_SSLNoRead, v);
591
 
            close(j);
592
 
            continue;
593
 
 
594
 
        case 27:
595
 
            dbarea = v;
596
 
            v = strchr(v, ',');
597
 
            if(!v)
598
 
                continue;
599
 
            *v++ = 0;
600
 
            dblogin = v;
601
 
            v = strchr(v, ',');
602
 
            if(!v)
603
 
                continue;
604
 
            *v++ = 0;
605
 
            dbpw = v;
606
 
            continue;
607
 
 
608
 
        case 28:                /* proxy */
609
 
            proxy_host = v;
610
 
            proxy_port = 80;
611
 
            v = strchr(v, ':');
612
 
            if(v) {
613
 
                *v++ = 0;
614
 
                proxy_port = atoi(v);
615
 
            }
616
 
            continue;
617
 
 
618
 
        default:
619
 
            i_printfExit(MSG_ERBC_KeywordNYI, ln, s);
620
 
        }                       /* switch */
621
 
 
622
 
      nokeyword:
623
 
 
624
 
        if(stringEqual(s, "default") && mailblock == 1) {
625
 
            if(localAccount == maxAccount + 1)
626
 
                continue;
627
 
            if(localAccount)
628
 
                i_printfExit(MSG_ERBC_SevDefaults);
629
 
            localAccount = maxAccount + 1;
630
 
            continue;
631
 
        }
632
 
 
633
 
        if(*s == '\x82' && s[1] == 0) {
634
 
            if(mailblock == 1) {
635
 
                ++maxAccount;
636
 
                mailblock = 0;
637
 
                if(!act->inurl)
638
 
                    i_printfExit(MSG_ERBC_NoInserver, ln);
639
 
                if(!act->outurl)
640
 
                    i_printfExit(MSG_ERBC_NoOutserver, ln);
641
 
                if(!act->login)
642
 
                    i_printfExit(MSG_ERBC_NoLogin, ln);
643
 
                if(!act->password)
644
 
                    i_printfExit(MSG_ERBC_NPasswd, ln);
645
 
                if(!act->from)
646
 
                    i_printfExit(MSG_ERBC_NoFrom, ln);
647
 
                if(!act->reply)
648
 
                    i_printfExit(MSG_ERBC_NoReply, ln);
649
 
                if(!act->inport)
650
 
                    act->inport = 110;
651
 
                if(!act->outport)
652
 
                    act->outport = 25;
653
 
                continue;
654
 
            }
655
 
 
656
 
            if(mailblock) {
657
 
                mailblock = 0;
658
 
                continue;
659
 
            }
660
 
 
661
 
            if(mimeblock == 1) {
662
 
                ++maxMime;
663
 
                mimeblock = 0;
664
 
                if(!mt->type)
665
 
                    i_printfExit(MSG_ERBC_NoType, ln);
666
 
                if(!mt->desc)
667
 
                    i_printfExit(MSG_ERBC_NDesc, ln);
668
 
                if(!mt->suffix && !mt->prot)
669
 
                    i_printfExit(MSG_ERBC_NoSuffix, ln);
670
 
                if(!mt->program)
671
 
                    i_printfExit(MSG_ERBC_NoProgram, ln);
672
 
                continue;
673
 
            }
674
 
 
675
 
            if(tabblock == 1) {
676
 
                ++maxTables;
677
 
                tabblock = 0;
678
 
                if(!td->name)
679
 
                    i_printfExit(MSG_ERBC_NoTblName, ln);
680
 
                if(!td->shortname)
681
 
                    i_printfExit(MSG_ERBC_NoShortName, ln);
682
 
                if(!td->ncols)
683
 
                    i_printfExit(MSG_ERBC_NColumns, ln);
684
 
                continue;
685
 
            }
686
 
 
687
 
            if(--nest < 0)
688
 
                i_printfExit(MSG_ERBC_UnexpBrace, ln);
689
 
            if(nest)
690
 
                goto putback;
691
 
/* This ends the function */
692
 
            *s = 0;             /* null terminate the script */
693
 
            ++sn;
694
 
            continue;
695
 
        }
696
 
 
697
 
        if(*s == '\x83' && s[1] == 0) {
698
 
/* Does else make sense here? */
699
 
            c = toupper(stack[nest]);
700
 
            if(c != 'I')
701
 
                i_printfExit(MSG_ERBC_UnexElse, ln);
702
 
            goto putback;
703
 
        }
704
 
 
705
 
        if(*s != '\x81') {
706
 
            if(!nest)
707
 
                i_printfExit(MSG_ERBC_GarblText, ln);
708
 
            goto putback;
709
 
        }
710
 
 
711
 
/* Starting something */
712
 
        c = s[1];
713
 
        if((nest || mailblock || mimeblock) && strchr("fmerts", c)) {
714
 
            const char *curblock = "another function";
715
 
            if(mailblock)
716
 
                curblock = "a mail descriptor";
717
 
            if(mailblock > 1)
718
 
                curblock = "a filter block";
719
 
            if(mimeblock)
720
 
                curblock = "a mime descriptor";
721
 
            i_printfExit(MSG_ERBC_FnNotStart, ln, curblock);
722
 
        }
723
 
 
724
 
        if(!strchr("fmertsb", c) && !nest)
725
 
            i_printfExit(MSG_ERBC_StatNotInFn, ln);
726
 
 
727
 
        if(c == 'm') {
728
 
            mailblock = 1;
729
 
            if(maxAccount == MAXACCOUNT)
730
 
                i_printfExit(MSG_ERBC_ManyAcc, MAXACCOUNT);
731
 
            act = accounts + maxAccount;
732
 
            continue;
733
 
        }
734
 
 
735
 
        if(c == 'e') {
736
 
            mimeblock = 1;
737
 
            if(maxMime == MAXMIME)
738
 
                i_printfExit(MSG_ERBC_ManyTypes, MAXMIME);
739
 
            mt = mimetypes + maxMime;
740
 
            continue;
741
 
        }
742
 
 
743
 
        if(c == 'b') {
744
 
            tabblock = 1;
745
 
            if(maxTables == MAXDBT)
746
 
                i_printfExit(MSG_ERBC_ManyTables, MAXDBT);
747
 
            td = dbtables + maxTables;
748
 
            continue;
749
 
        }
750
 
 
751
 
        if(c == 'r') {
752
 
            mailblock = 2;
753
 
            continue;
754
 
        }
755
 
 
756
 
        if(c == 't') {
757
 
            mailblock = 3;
758
 
            continue;
759
 
        }
760
 
 
761
 
        if(c == 's') {
762
 
            mailblock = 4;
763
 
            continue;
764
 
        }
765
 
 
766
 
        if(c == 'f') {
767
 
            stack[++nest] = c;
768
 
            if(sn == MAXEBSCRIPT)
769
 
                i_printfExit(MSG_ERBC_ManyFn, sn);
770
 
            ebScriptName[sn] = s + 2;
771
 
            t[-1] = 0;
772
 
            ebScript[sn] = t;
773
 
            goto putback;
774
 
        }
775
 
 
776
 
        if(++nest >= sizeof (stack))
777
 
            i_printfExit(MSG_ERBC_TooDeeply, ln);
778
 
        stack[nest] = c;
779
 
 
780
 
      putback:
781
 
        *t = '\n';
782
 
    }                           /* loop over lines */
783
 
 
784
 
    if(nest)
785
 
        i_printfExit(MSG_ERBC_FnNotClosed, ebScriptName[sn]);
786
 
 
787
 
    if(mailblock | mimeblock)
788
 
        i_printfExit(MSG_ERBC_MNotClosed);
789
 
 
790
 
    if(cfgmodify)
791
 
        updateConfig();
792
 
}                               /* readConfigFile */
793
 
 
794
 
 
795
 
/*********************************************************************
796
 
Redirect the incoming mail into a file, based on the subject or the sender.
797
 
Along with the filters in .ebrc, this routine dips into your addressbook,
798
 
to see if the sender (by email) is one of your established aliases.
799
 
If it is, we save it in a file of the same name.
800
 
This is saved formatted, unless you put a minus sign
801
 
at the start of the alias in your address book.
802
 
This is the same convention as the from filters in .ebrc.
803
 
If you don't want an alias to act as a redirect filter,
804
 
put a ! at the beginning of the alias name.
805
 
*********************************************************************/
806
 
 
807
 
const char *
808
 
mailRedirect(const char *to, const char *from,
809
 
   const char *reply, const char *subj)
810
 
{
811
 
    int rlen = strlen(reply);
812
 
    int slen = strlen(subj);
813
 
    int tlen = strlen(to);
814
 
    struct FILTERDESC *f;
815
 
    const char *r;
816
 
 
817
 
    for(f = filters; f->match; ++f) {
818
 
        const char *m = f->match;
819
 
        int mlen = strlen(m);
820
 
        r = f->redirect;
821
 
        int j, k;
822
 
 
823
 
        switch (f->type) {
824
 
        case 2:
825
 
            if(stringEqualCI(m, from))
826
 
                return r;
827
 
            if(stringEqualCI(m, reply))
828
 
                return r;
829
 
            if(*m == '@' && mlen < rlen &&
830
 
               stringEqualCI(m, reply + rlen - mlen))
831
 
                return r;
832
 
            break;
833
 
 
834
 
        case 3:
835
 
            if(stringEqualCI(m, to))
836
 
                return r;
837
 
            if(*m == '@' && mlen < tlen && stringEqualCI(m, to + tlen - mlen))
838
 
                return r;
839
 
            break;
840
 
 
841
 
        case 4:
842
 
            if(stringEqualCI(m, subj))
843
 
                return r;
844
 
/* a prefix match is ok */
845
 
            if(slen < 16 || mlen < 16)
846
 
                break;          /* too short */
847
 
            j = k = 0;
848
 
            while(true) {
849
 
                char c = subj[j];
850
 
                char d = m[k];
851
 
                if(isupperByte(c))
852
 
                    c = tolower(c);
853
 
                if(isupperByte(d))
854
 
                    d = tolower(d);
855
 
                if(!c || !d)
856
 
                    break;
857
 
                if(c != d)
858
 
                    break;
859
 
                for(++j; c == subj[j]; ++j) ;
860
 
                for(++k; d == m[k]; ++k) ;
861
 
            }
862
 
/* must match at least 2/3 of either string */
863
 
            if(k > j)
864
 
                j = k;
865
 
            if(j >= 2 * mlen / 3 || j >= 2 * slen / 3) {
866
 
                return r;
867
 
            }
868
 
            break;
869
 
        }                       /* switch */
870
 
    }                           /* loop */
871
 
 
872
 
    r = reverseAlias(reply);
873
 
    return r;
874
 
}                               /* mailRedirect */
875
 
 
876
 
 
877
 
/*********************************************************************
878
 
Are we ok to parse and execute javascript?
879
 
*********************************************************************/
880
 
 
881
 
bool
882
 
javaOK(const char *url)
883
 
{
884
 
    int j, hl, dl;
885
 
    const char *h, *d, *q, *path;
886
 
    if(!allowJS)
887
 
        return false;
888
 
    if(!url)
889
 
        return true;
890
 
    h = getHostURL(url);
891
 
    if(!h)
892
 
        return true;
893
 
    hl = strlen(h);
894
 
    path = getDataURL(url);
895
 
    for(j = 0; j < javaDisCount; ++j) {
896
 
        d = javaDis[j];
897
 
        q = strchr(d, '/');
898
 
        if(!q)
899
 
            q = d + strlen(d);
900
 
        dl = q - d;
901
 
        if(dl > hl)
902
 
            continue;
903
 
        if(!memEqualCI(d, h + hl - dl, dl))
904
 
            continue;
905
 
        if(*q == '/') {
906
 
            ++q;
907
 
            if(hl != dl)
908
 
                continue;
909
 
            if(!path)
910
 
                continue;
911
 
            if(strncmp(q, path, strlen(q)))
912
 
                continue;
913
 
            return false;
914
 
        }                       /* domain/path was specified */
915
 
        if(hl == dl)
916
 
            return false;
917
 
        if(h[hl - dl - 1] == '.')
918
 
            return false;
919
 
    }
920
 
    return true;
921
 
}                               /* javaOK */
922
 
 
923
 
/* Catch interrupt and react appropriately. */
924
 
static void
925
 
catchSig(int n)
926
 
{
927
 
    intFlag = true;
928
 
    if(inInput)
929
 
        i_puts(MSG_EnterInterrupt);
930
 
/* If we were reading from a file, or socket, this signal should
931
 
 * cause the read to fail.  Check for intFlag, so we know it was
932
 
 * interrupted, and not an io failure.
933
 
 * Then clean up appropriately. */
934
 
    signal(SIGINT, catchSig);
935
 
}                               /* catchSig */
936
 
 
937
 
void
938
 
ebClose(int n)
939
 
{
940
 
    dbClose();
941
 
    exit(n);
942
 
}                               /* ebClose */
943
 
 
944
 
void
945
 
eeCheck(void)
946
 
{
947
 
    if(errorExit)
948
 
        ebClose(1);
949
 
}
950
 
 
951
 
/* I'm not going to expand wild card arguments here.
952
 
 * I don't need to on Unix, and on Windows there is a
953
 
 * setargv.obj, or something like that, that performs the expansion.
954
 
 * I'll assume you have folded that object into libc.lib.
955
 
 * So now you can edit *.c, on any operating system,
956
 
 * and it will do the right thing, with no work on my part. */
957
 
 
958
 
int
959
 
main(int argc, char **argv)
960
 
{
961
 
    int cx, account;
962
 
    bool rc, doConfig = true;
963
 
 
964
 
    selectLanguage();
965
 
 
966
 
    ttySaveSettings();
967
 
 
968
 
/* Let's everybody use my malloc and free routines */
969
 
    pcre_malloc = allocMem;
970
 
    pcre_free = nzFree;
971
 
 
972
 
/* Establish the home directory, and standard edbrowse files thereunder. */
973
 
    home = getenv("HOME");
974
 
/* Empty is the same as missing. */
975
 
    if(home && !*home)
976
 
        home = 0;
977
 
/* I require this, though I'm not sure what this means for non-Unix OS's */
978
 
    if(!home)
979
 
        i_printfExit(MSG_NotHome);
980
 
    if(fileTypeByName(home, false) != 'd')
981
 
        i_printfExit(MSG_NotDir, home);
982
 
 
983
 
/* See sample.ebrc in this directory for a sample config file. */
984
 
    configFile = allocMem(strlen(home) + 7);
985
 
    sprintf(configFile, "%s/.ebrc", home);
986
 
 
987
 
    recycleBin = allocMem(strlen(home) + 10);
988
 
    sprintf(recycleBin, "%s/.recycle", home);
989
 
    edbrowseTempFile = allocMem(strlen(recycleBin) + 8 + 6);
990
 
/* The extra 6 is for the suffix */
991
 
    sprintf(edbrowseTempFile, "%s/eb_tmp", recycleBin);
992
 
    if(fileTypeByName(recycleBin, false) != 'd') {
993
 
        if(mkdir(recycleBin, 0700)) {
994
 
            free(recycleBin);
995
 
            recycleBin = 0;
996
 
        }
997
 
    }
998
 
 
999
 
    sigFile = allocMem(strlen(home) + 12);
1000
 
    sprintf(sigFile, "%s/.signature", home);
1001
 
 
1002
 
    {
1003
 
        static char agent0[32] = "edbrowse/";
1004
 
        strcat(agent0, version);
1005
 
        userAgents[0] = currentAgent = agent0;
1006
 
    }
1007
 
 
1008
 
    setNowDay();
1009
 
 
1010
 
    ++argv, --argc;
1011
 
    if(argc && stringEqual(argv[0], "-c")) {
1012
 
        if(argc == 1)
1013
 
            *argv = configFile;
1014
 
        else
1015
 
            ++argv, --argc;
1016
 
        doConfig = false;
1017
 
    } else {
1018
 
        readConfigFile();
1019
 
        if(maxAccount && !localAccount)
1020
 
            localAccount = 1;
1021
 
    }
1022
 
    account = localAccount;
1023
 
 
1024
 
    for(; argc && argv[0][0] == '-'; ++argv, --argc) {
1025
 
        char *s = *argv;
1026
 
        ++s;
1027
 
        if(stringEqual(s, "v")) {
1028
 
            puts(version);
1029
 
            exit(0);
1030
 
        }
1031
 
        if(stringEqual(s, "d")) {
1032
 
            debugLevel = 4;
1033
 
            continue;
1034
 
        }
1035
 
        if(*s == 'd' && isdigitByte(s[1]) && !s[2]) {
1036
 
            debugLevel = s[1] - '0';
1037
 
            continue;
1038
 
        }
1039
 
        if(stringEqual(s, "e")) {
1040
 
            errorExit = true;
1041
 
            continue;
1042
 
        }
1043
 
        if(*s == 'u')
1044
 
            ++s, unformatMail = true;
1045
 
        if(*s == 'p')
1046
 
            ++s, passMail = true;
1047
 
        if(*s == 'm' && isdigitByte(s[1])) {
1048
 
            if(!maxAccount)
1049
 
                i_printfExit(MSG_NoMailAcc);
1050
 
            account = strtol(s + 1, &s, 10);
1051
 
            if(account == 0 || account > maxAccount)
1052
 
                i_printfExit(MSG_BadAccNb, maxAccount);
1053
 
            if(!*s) {
1054
 
                ismc = true;    /* running as a mail client */
1055
 
                allowJS = false;        /* no javascript in mail client */
1056
 
                ++argv, --argc; /* we're going to break out */
1057
 
                if(argc && stringEqual(argv[0], "-Zap"))
1058
 
                    ++argv, --argc, zapMail = true;
1059
 
                break;
1060
 
            }
1061
 
        }
1062
 
        i_printfExit(MSG_Usage);
1063
 
    }                           /* options */
1064
 
 
1065
 
    if(tcp_init() < 0)
1066
 
        debugPrint(4, "tcp failure, could not identify this machine");
1067
 
    else
1068
 
        debugPrint(4, "host info established for %s, %s",
1069
 
           tcp_thisMachineName, tcp_thisMachineDots);
1070
 
 
1071
 
    ssl_init(doConfig);
1072
 
 
1073
 
    srand(time(0));
1074
 
 
1075
 
    loadBlacklist();
1076
 
 
1077
 
    if(ismc) {
1078
 
        char **reclist, **atlist;
1079
 
        char *s, *body;
1080
 
        int nat, nalt, nrec;
1081
 
        if(!argc)
1082
 
            fetchMail(account);
1083
 
        if(argc == 1)
1084
 
            i_printfExit(MSG_MinOneRec);
1085
 
/* I don't know that argv[argc] is 0, or that I can set it to 0,
1086
 
 * so I back everything up by 1. */
1087
 
        reclist = argv - 1;
1088
 
        for(nat = nalt = 0; nat < argc; ++nat) {
1089
 
            s = argv[argc - 1 - nat];
1090
 
            if(*s != '+' && *s != '-')
1091
 
                break;
1092
 
            if(*s == '-')
1093
 
                ++nalt;
1094
 
            strcpy(s, s + 1);
1095
 
        }
1096
 
        atlist = argv + argc - nat - 1;
1097
 
        if(atlist <= argv)
1098
 
            i_printfExit(MSG_MinOneRecBefAtt);
1099
 
        body = *atlist;
1100
 
        if(nat)
1101
 
            memcpy(atlist, atlist + 1, sizeof (char *) * nat);
1102
 
        atlist[nat] = 0;
1103
 
        nrec = atlist - argv;
1104
 
        memcpy(reclist, reclist + 1, sizeof (char *) * nrec);
1105
 
        atlist[-1] = 0;
1106
 
        if(sendMail(account, (const char **)reclist, body, 1,
1107
 
           (const char **)atlist, nalt, true))
1108
 
            exit(0);
1109
 
        showError();
1110
 
        exit(1);
1111
 
    }
1112
 
 
1113
 
    cookiesFromJar();
1114
 
 
1115
 
    signal(SIGINT, catchSig);
1116
 
    siginterrupt(SIGINT, 1);
1117
 
    signal(SIGPIPE, SIG_IGN);
1118
 
 
1119
 
 
1120
 
    cx = 0;
1121
 
    while(argc) {
1122
 
        char *file = *argv;
1123
 
        ++cx;
1124
 
        if(cx == MAXSESSION)
1125
 
            i_printfExit(MSG_ManyOpen, MAXSESSION);
1126
 
        cxSwitch(cx, false);
1127
 
        if(cx == 1)
1128
 
            runEbFunction("init");
1129
 
        changeFileName = 0;
1130
 
        fetchHistory(0, 0);     /* reset history */
1131
 
        cw->fileName = cloneString(file);
1132
 
        if(isSQL(file))
1133
 
            cw->sqlMode = true;
1134
 
        rc = readFile(file, "");
1135
 
        if(fileSize >= 0)
1136
 
            debugPrint(1, "%d", fileSize);
1137
 
        fileSize = -1;
1138
 
        if(!rc) {
1139
 
            showError();
1140
 
        } else if(changeFileName) {
1141
 
            nzFree(cw->fileName);
1142
 
            cw->fileName = changeFileName;
1143
 
            changeFileName = 0;
1144
 
        }
1145
 
        if(cw->fileName && memEqualCI(cw->fileName, "ftp://", 6)) {
1146
 
            nzFree(cw->fileName);
1147
 
            cw->fileName = 0;
1148
 
        }
1149
 
        cw->firstOpMode = cw->changeMode = false;
1150
 
/* Browse the text if it's a url */
1151
 
        if(rc && !(cw->binMode | cw->dirMode) && cw->dol && isURL(cw->fileName)) {
1152
 
            if(runCommand("b"))
1153
 
                debugPrint(1, "%d", fileSize);
1154
 
            else
1155
 
                showError();
1156
 
        }
1157
 
        ++argv, --argc;
1158
 
    }                           /* loop over files */
1159
 
    if(!cx) {                   /* no files */
1160
 
        ++cx;
1161
 
        cxSwitch(cx, false);
1162
 
        runEbFunction("init");
1163
 
        i_puts(MSG_Ready);
1164
 
    }
1165
 
    if(cx > 1)
1166
 
        cxSwitch(1, false);
1167
 
    undoable = false;
1168
 
 
1169
 
    while(true) {
1170
 
        uchar saveline[MAXTTYLINE];
1171
 
        pst p = inputLine();
1172
 
        copyPstring(saveline, p);
1173
 
        if(perl2c((char *)p))
1174
 
            i_puts(MSG_EnterNull);
1175
 
        else
1176
 
            edbrowseCommand((char *)p, false);
1177
 
        copyPstring(linePending, saveline);
1178
 
    }                           /* infinite loop */
1179
 
}                               /* main */
1180
 
 
1181
 
/* Find the balancing brace in an edbrowse function */
1182
 
static const char *
1183
 
balance(const char *ip, int direction)
1184
 
{
1185
 
    int nest = 0;
1186
 
    uchar code;
1187
 
 
1188
 
    while(true) {
1189
 
        if(direction > 0) {
1190
 
            ip = strchr(ip, '\n') + 1;
1191
 
        } else {
1192
 
            for(ip -= 2; *ip != '\n'; --ip) ;
1193
 
            ++ip;
1194
 
        }
1195
 
        code = *ip;
1196
 
        if(code == 0x83) {
1197
 
            if(nest)
1198
 
                continue;
1199
 
            break;
1200
 
        }
1201
 
        if(code == 0x81)
1202
 
            nest += direction;
1203
 
        if(code == 0x82)
1204
 
            nest -= direction;
1205
 
        if(nest < 0)
1206
 
            break;
1207
 
    }
1208
 
 
1209
 
    return ip;
1210
 
}                               /* balance */
1211
 
 
1212
 
/* Run an edbrowse function, as defined in the config file. */
1213
 
bool
1214
 
runEbFunction(const char *line)
1215
 
{
1216
 
    char *linecopy = cloneString(line);
1217
 
    const char *args[10];
1218
 
    int argl[10];               /* lengths of args */
1219
 
    int argtl;                  /* total length */
1220
 
    const char *s;
1221
 
    char *t, *new;
1222
 
    int j, l, nest;
1223
 
    const char *ip;             /* think instruction pointer */
1224
 
    const char *endl;           /* end of line to be processed */
1225
 
    bool nofail, ok;
1226
 
    uchar code;
1227
 
    char stack[MAXNEST];
1228
 
    int loopcnt[MAXNEST];
1229
 
 
1230
 
/* Separate function name and arguments */
1231
 
    spaceCrunch(linecopy, true, false);
1232
 
    if(linecopy[0] == 0) {
1233
 
        setError(MSG_NoFunction);
1234
 
        goto fail;
1235
 
    }
1236
 
    memset(args, 0, sizeof (args));
1237
 
    memset(argl, 0, sizeof (argl));
1238
 
    argtl = 0;
1239
 
    t = strchr(linecopy, ' ');
1240
 
    if(t)
1241
 
        *t = 0;
1242
 
    for(s = linecopy; *s; ++s)
1243
 
        if(!isalnumByte(*s)) {
1244
 
            setError(MSG_BadFunctionName);
1245
 
            goto fail;
1246
 
        }
1247
 
    for(j = 0; ebScript[j]; ++j)
1248
 
        if(stringEqual(linecopy, ebScriptName[j] + 1))
1249
 
            break;
1250
 
    if(!ebScript[j]) {
1251
 
        setError(MSG_NoSuchFunction, linecopy);
1252
 
        goto fail;
1253
 
    }
1254
 
 
1255
 
/* skip past the leading \n */
1256
 
    ip = ebScript[j] + 1;
1257
 
    nofail = (ebScriptName[j][0] == '+');
1258
 
    nest = 0;
1259
 
    ok = true;
1260
 
 
1261
 
/* collect arguments */
1262
 
    j = 0;
1263
 
    for(s = t; s; s = t) {
1264
 
        if(++j >= 10) {
1265
 
            setError(MSG_ManyArgs);
1266
 
            goto fail;
1267
 
        }
1268
 
        args[j] = ++s;
1269
 
        t = strchr(s, ' ');
1270
 
        if(t)
1271
 
            *t = 0;
1272
 
        if(argtl)
1273
 
            ++argtl;
1274
 
        argtl += (argl[j] = strlen(s));
1275
 
    }
1276
 
    argl[0] = argtl;
1277
 
 
1278
 
    while(code = *ip) {
1279
 
        if(intFlag) {
1280
 
            setError(MSG_Interrupted);
1281
 
            goto fail;
1282
 
        }
1283
 
        endl = strchr(ip, '\n');
1284
 
 
1285
 
        if(code == 0x83) {
1286
 
            ip = balance(ip, 1) + 2;
1287
 
            --nest;
1288
 
            continue;
1289
 
        }
1290
 
 
1291
 
        if(code == 0x82) {
1292
 
            char control = stack[nest];
1293
 
            char ucontrol = toupper(control);
1294
 
            const char *start = balance(ip, -1);
1295
 
            start = strchr(start, '\n') + 1;
1296
 
            if(ucontrol == 'L') {       /* loop */
1297
 
                if(--loopcnt[nest])
1298
 
                    ip = start;
1299
 
                else
1300
 
                    ip = endl + 1, --nest;
1301
 
                continue;
1302
 
            }
1303
 
            if(ucontrol == 'W' || ucontrol == 'U') {
1304
 
                bool jump = ok;
1305
 
                if(islowerByte(control))
1306
 
                    jump ^= true;
1307
 
                if(ucontrol == 'U')
1308
 
                    jump ^= true;
1309
 
                ok = true;
1310
 
                if(jump)
1311
 
                    ip = start;
1312
 
                else
1313
 
                    ip = endl + 1, --nest;
1314
 
                continue;
1315
 
            }
1316
 
/* Apparently it's the close of an if or an else, just fall through */
1317
 
            goto nextline;
1318
 
        }
1319
 
 
1320
 
        if(code == 0x81) {
1321
 
            const char *skip = balance(ip, 1);
1322
 
            bool jump;
1323
 
            char control = ip[1];
1324
 
            char ucontrol = toupper(control);
1325
 
            stack[++nest] = control;
1326
 
            if(ucontrol == 'L') {
1327
 
                loopcnt[nest] = j = atoi(ip + 2);
1328
 
                if(j)
1329
 
                    goto nextline;
1330
 
              ahead:
1331
 
                if(*skip == (char)0x82)
1332
 
                    --nest;
1333
 
                ip = skip + 2;
1334
 
                continue;
1335
 
            }
1336
 
            if(ucontrol == 'U')
1337
 
                goto nextline;
1338
 
/* if or while, test on ok */
1339
 
            jump = ok;
1340
 
            if(isupperByte(control))
1341
 
                jump ^= true;
1342
 
            ok = true;
1343
 
            if(jump)
1344
 
                goto ahead;
1345
 
            goto nextline;
1346
 
        }
1347
 
 
1348
 
        if(!ok && nofail)
1349
 
            goto fail;
1350
 
 
1351
 
/* compute length of line, then build the line */
1352
 
        l = endl - ip;
1353
 
        for(s = ip; s < endl; ++s)
1354
 
            if(*s == '~' && isdigitByte(s[1]))
1355
 
                l += argl[s[1] - '0'];
1356
 
        t = new = allocMem(l + 1);
1357
 
        for(s = ip; s < endl; ++s) {
1358
 
            if(*s == '~' && isdigitByte(s[1])) {
1359
 
                j = *++s - '0';
1360
 
                if(j) {
1361
 
                    if(!args[j]) {
1362
 
                        setError(MSG_NoArgument, j);
1363
 
                        nzFree(new);
1364
 
                        goto fail;
1365
 
                    }
1366
 
                    strcpy(t, args[j]);
1367
 
                    t += argl[j];
1368
 
                    continue;
1369
 
                }
1370
 
/* ~0 is all args together */
1371
 
                for(j = 1; j <= 9 && args[j]; ++j) {
1372
 
                    if(j > 1)
1373
 
                        *t++ = ' ';
1374
 
                    strcpy(t, args[j]);
1375
 
                    t += argl[j];
1376
 
                }
1377
 
                continue;
1378
 
            }
1379
 
            *t++ = *s;
1380
 
        }
1381
 
        *t = 0;
1382
 
 
1383
 
/* Here we go! */
1384
 
        debugPrint(3, "< %s", new);
1385
 
        ok = edbrowseCommand(new, true);
1386
 
        free(new);
1387
 
 
1388
 
      nextline:
1389
 
        ip = endl + 1;
1390
 
    }
1391
 
 
1392
 
    if(!ok && nofail)
1393
 
        goto fail;
1394
 
 
1395
 
    nzFree(linecopy);
1396
 
    return true;
1397
 
 
1398
 
  fail:
1399
 
    nzFree(linecopy);
1400
 
    return false;
1401
 
}                               /* runEbFunction */
1402
 
 
1403
 
/* Send the contents of the current buffer to a running program */
1404
 
bool
1405
 
bufferToProgram(const char *cmd, const char *suffix, bool trailPercent)
1406
 
{
1407
 
    FILE *f;
1408
 
    char *buf = 0;
1409
 
    int buflen, n;
1410
 
    int size1, size2;
1411
 
    char *u = edbrowseTempFile + strlen(edbrowseTempFile);
1412
 
 
1413
 
    if(!trailPercent) {
1414
 
/* pipe the buffer into the program */
1415
 
        f = popen(cmd, "w");
1416
 
        if(!f) {
1417
 
            setError(MSG_NoSpawn, cmd, errno);
1418
 
            return false;
1419
 
        }
1420
 
        if(!unfoldBuffer(context, false, &buf, &buflen)) {
1421
 
            pclose(f);
1422
 
            return false;       /* should never happen */
1423
 
        }
1424
 
        n = fwrite(buf, buflen, 1, f);
1425
 
        pclose(f);
1426
 
    } else {
1427
 
        sprintf(u, ".%s", suffix);
1428
 
        size1 = currentBufferSize();
1429
 
        size2 = fileSizeByName(edbrowseTempFile);
1430
 
        if(size1 == size2) {
1431
 
/* assume it's the same data */
1432
 
            *u = 0;
1433
 
        } else {
1434
 
            f = fopen(edbrowseTempFile, "w");
1435
 
            if(!f) {
1436
 
                setError(MSG_TempNoCreate2, edbrowseTempFile, errno);
1437
 
                *u = 0;
1438
 
                return false;
1439
 
            }
1440
 
            *u = 0;
1441
 
            if(!unfoldBuffer(context, false, &buf, &buflen)) {
1442
 
                fclose(f);
1443
 
                return false;   /* should never happen */
1444
 
            }
1445
 
            n = fwrite(buf, buflen, 1, f);
1446
 
            fclose(f);
1447
 
        }
1448
 
        system(cmd);
1449
 
    }
1450
 
 
1451
 
    nzFree(buf);
1452
 
    return true;
1453
 
}                               /* bufferToProgram */
1454
 
 
1455
 
struct DBTABLE *
1456
 
findTableDescriptor(const char *sn)
1457
 
{
1458
 
    int i;
1459
 
    struct DBTABLE *td = dbtables;
1460
 
    for(i = 0; i < maxTables; ++i, ++td)
1461
 
        if(stringEqual(td->shortname, sn))
1462
 
            return td;
1463
 
    return 0;
1464
 
}                               /* findTableDescriptor */
1465
 
 
1466
 
struct DBTABLE *
1467
 
newTableDescriptor(const char *name)
1468
 
{
1469
 
    struct DBTABLE *td;
1470
 
    if(maxTables == MAXDBT) {
1471
 
        setError(MSG_ManyTables, MAXDBT);
1472
 
        return 0;
1473
 
    }
1474
 
    td = dbtables + maxTables++;
1475
 
    td->name = td->shortname = cloneString(name);
1476
 
    td->ncols = 0;              /* it's already 0 */
1477
 
    return td;
1478
 
}                               /* newTableDescriptor */
1479
 
 
1480
 
struct MIMETYPE *
1481
 
findMimeBySuffix(const char *suffix)
1482
 
{
1483
 
    int i;
1484
 
    int len = strlen(suffix);
1485
 
    struct MIMETYPE *m = mimetypes;
1486
 
 
1487
 
    for(i = 0; i < maxMime; ++i, ++m) {
1488
 
        const char *s = m->suffix, *t;
1489
 
        if(!s)
1490
 
            continue;
1491
 
        while(*s) {
1492
 
            t = strchr(s, ',');
1493
 
            if(!t)
1494
 
                t = s + strlen(s);
1495
 
            if(t - s == len && memEqualCI(s, suffix, len))
1496
 
                return m;
1497
 
            if(*t)
1498
 
                ++t;
1499
 
            s = t;
1500
 
        }
1501
 
    }
1502
 
 
1503
 
    return 0;
1504
 
}                               /* findMimeBySuffix */
1505
 
 
1506
 
struct MIMETYPE *
1507
 
findMimeByProtocol(const char *prot)
1508
 
{
1509
 
    int i;
1510
 
    int len = strlen(prot);
1511
 
    struct MIMETYPE *m = mimetypes;
1512
 
 
1513
 
    for(i = 0; i < maxMime; ++i, ++m) {
1514
 
        const char *s = m->prot, *t;
1515
 
        if(!s)
1516
 
            continue;
1517
 
        while(*s) {
1518
 
            t = strchr(s, ',');
1519
 
            if(!t)
1520
 
                t = s + strlen(s);
1521
 
            if(t - s == len && memEqualCI(s, prot, len))
1522
 
                return m;
1523
 
            if(*t)
1524
 
                ++t;
1525
 
            s = t;
1526
 
        }
1527
 
    }
1528
 
 
1529
 
    return 0;
1530
 
}                               /* findMimeByProtocol */
1531
 
 
1532
 
/* The result is allocated */
1533
 
char *
1534
 
pluginCommand(const struct MIMETYPE *m, const char *file, const char *suffix)
1535
 
{
1536
 
    int len, suflen;
1537
 
    const char *s;
1538
 
    char *cmd, *t;
1539
 
    bool trailPercent = false;
1540
 
 
1541
 
/* leave rooom for space quote quote null */
1542
 
    len = strlen(m->program) + 4;
1543
 
    if(file) {
1544
 
        len += strlen(file);
1545
 
    } else if(m->program[strlen(m->program) - 1] == '%') {
1546
 
        trailPercent = true;
1547
 
        len += strlen(edbrowseTempFile) + 6;
1548
 
    }
1549
 
 
1550
 
    suflen = 0;
1551
 
    if(suffix) {
1552
 
        suflen = strlen(suffix);
1553
 
        for(s = m->program; *s; ++s)
1554
 
            if(*s == '*')
1555
 
                len += suflen - 1;
1556
 
    }
1557
 
 
1558
 
    cmd = allocMem(len);
1559
 
    t = cmd;
1560
 
    for(s = m->program; *s; ++s) {
1561
 
        if(suffix && *s == '*') {
1562
 
            strcpy(t, suffix);
1563
 
            t += suflen;
1564
 
        } else {
1565
 
            *t++ = *s;
1566
 
        }
1567
 
    }
1568
 
    *t = 0;
1569
 
 
1570
 
    if(file) {
1571
 
        sprintf(t, " \"%s\"", file);
1572
 
    } else if(trailPercent) {
1573
 
        sprintf(t - 1, " \"%s.%s\"", edbrowseTempFile, suffix);
1574
 
    }
1575
 
 
1576
 
    debugPrint(3, "%s", cmd);
1577
 
    return cmd;
1578
 
}                               /* pluginCommand */