~ubuntu-branches/ubuntu/edgy/lynx/edgy

« back to all changes in this revision

Viewing changes to src/HTAlert.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-16 12:14:10 UTC
  • Revision ID: james.westby@ubuntu.com-20040916121410-cz1gu92c4nqfeyrg
Tags: upstream-2.8.5
ImportĀ upstreamĀ versionĀ 2.8.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      Displaying messages and getting input for Lynx Browser
 
2
**      ==========================================================
 
3
**
 
4
**      REPLACE THIS MODULE with a GUI version in a GUI environment!
 
5
**
 
6
** History:
 
7
**         Jun 92 Created May 1992 By C.T. Barker
 
8
**         Feb 93 Simplified, portablised TBL
 
9
**
 
10
*/
 
11
 
 
12
#include <HTUtils.h>
 
13
#include <HTAlert.h>
 
14
#include <LYGlobalDefs.h>
 
15
#include <LYCurses.h>
 
16
#include <LYStrings.h>
 
17
#include <LYUtils.h>
 
18
#include <LYClean.h>
 
19
#include <GridText.h>
 
20
#include <LYCookie.h>
 
21
#include <LYHistory.h> /* store statusline messages */
 
22
 
 
23
#include <LYLeaks.h>
 
24
 
 
25
#include <HTParse.h>
 
26
 
 
27
#undef timezone /* U/Win defines this in time.h, hides implementation detail */
 
28
 
 
29
#if defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H)
 
30
#include <sys/timeb.h>
 
31
#endif
 
32
 
 
33
/*
 
34
 * 'napms()' is preferable to 'sleep()' in any case because it does not
 
35
 * interfere with output, but also because it can be less than a second.
 
36
 */
 
37
#ifdef HAVE_NAPMS
 
38
#define LYSleep(n) napms(n)
 
39
#else
 
40
#define LYSleep(n) sleep(n)
 
41
#endif
 
42
 
 
43
/*      Issue a message about a problem.                HTAlert()
 
44
**      --------------------------------
 
45
*/
 
46
PUBLIC void HTAlert ARGS1(
 
47
        CONST char *,   Msg)
 
48
{
 
49
    CTRACE((tfp, "\nAlert!: %s\n\n", Msg));
 
50
    CTRACE_FLUSH(tfp);
 
51
    _user_message(ALERT_FORMAT, Msg);
 
52
    LYstore_message2(ALERT_FORMAT, Msg);
 
53
 
 
54
    LYSleepAlert();
 
55
}
 
56
 
 
57
PUBLIC void HTAlwaysAlert ARGS2(
 
58
        CONST char *,   extra_prefix,
 
59
        CONST char *,   Msg)
 
60
{
 
61
    if (!dump_output_immediately && LYCursesON) {
 
62
        HTAlert(Msg);
 
63
    } else {
 
64
        if (extra_prefix) {
 
65
            fprintf(((TRACE) ? stdout : stderr),
 
66
                    "%s %s!\n",
 
67
                    extra_prefix, Msg);
 
68
            fflush(stdout);
 
69
            LYstore_message2(ALERT_FORMAT, Msg);
 
70
            LYSleepAlert();
 
71
        } else {
 
72
            fprintf(((TRACE) ? stdout : stderr), ALERT_FORMAT, NonNull(Msg));
 
73
            fflush(stdout);
 
74
            LYstore_message2(ALERT_FORMAT, Msg);
 
75
            LYSleepAlert();
 
76
            fprintf(((TRACE) ? stdout : stderr), "\n");
 
77
        }
 
78
        CTRACE((tfp, "\nAlert!: %s\n\n", Msg));
 
79
        CTRACE_FLUSH(tfp);
 
80
    }
 
81
}
 
82
 
 
83
/*      Issue an informational message.                 HTInfoMsg()
 
84
**      --------------------------------
 
85
*/
 
86
PUBLIC void HTInfoMsg ARGS1(
 
87
        CONST char *,   Msg)
 
88
{
 
89
    _statusline(Msg);
 
90
    if (Msg && *Msg) {
 
91
        CTRACE((tfp, "Info message: %s\n", Msg));
 
92
        LYstore_message(Msg);
 
93
        LYSleepInfo();
 
94
    }
 
95
}
 
96
 
 
97
/*      Issue an important message.                     HTUserMsg()
 
98
**      --------------------------------
 
99
*/
 
100
PUBLIC void HTUserMsg ARGS1(
 
101
        CONST char *,   Msg)
 
102
{
 
103
    _statusline(Msg);
 
104
    if (Msg && *Msg) {
 
105
        CTRACE((tfp, "User message: %s\n", Msg));
 
106
        LYstore_message(Msg);
 
107
#if !(defined(USE_SLANG) || defined(WIDEC_CURSES))
 
108
        if (HTCJK != NOCJK) {
 
109
            clearok(curscr, TRUE);
 
110
            LYrefresh();
 
111
        }
 
112
#endif
 
113
        LYSleepMsg();
 
114
    }
 
115
}
 
116
 
 
117
PUBLIC void HTUserMsg2 ARGS2(
 
118
        CONST char *,   Msg2,
 
119
        CONST char *,   Arg)
 
120
{
 
121
    _user_message(Msg2, Arg);
 
122
    if (Msg2 && *Msg2) {
 
123
        CTRACE((tfp, "User message: "));
 
124
        CTRACE((tfp, Msg2, Arg));
 
125
        CTRACE((tfp, "\n"));
 
126
        LYstore_message2(Msg2, Arg);
 
127
        LYSleepMsg();
 
128
    }
 
129
}
 
130
 
 
131
/*      Issue a progress message.                       HTProgress()
 
132
**      -------------------------
 
133
*/
 
134
PUBLIC void HTProgress ARGS1(
 
135
        CONST char *,   Msg)
 
136
{
 
137
    statusline(Msg);
 
138
    LYstore_message(Msg);
 
139
    CTRACE((tfp, "%s\n", Msg));
 
140
    LYSleepDebug();
 
141
}
 
142
 
 
143
PUBLIC CONST char *HTProgressUnits ARGS1(
 
144
        int,            rate)
 
145
{
 
146
    static CONST char *bunits = 0;
 
147
    static CONST char *kbunits = 0;
 
148
 
 
149
    if (!bunits) {
 
150
        bunits = gettext("bytes");
 
151
        kbunits = gettext(LYTransferName);
 
152
    }
 
153
    return ((rate == rateKB)
 
154
#ifdef USE_READPROGRESS
 
155
            || (rate == rateEtaKB)
 
156
#endif
 
157
            ) ? kbunits : bunits;
 
158
}
 
159
 
 
160
PRIVATE CONST char *sprint_bytes ARGS3(
 
161
        char *,         s,
 
162
        long,           n,
 
163
        CONST char *,   was_units)
 
164
{
 
165
    static long kb_units = 1024;
 
166
    CONST char *u = HTProgressUnits(LYTransferRate);
 
167
 
 
168
    if ( (LYTransferRate == rateKB || LYTransferRate == rateEtaKB_maybe)
 
169
         && (n >= 10 * kb_units) )
 
170
        sprintf(s, "%ld", n/kb_units);
 
171
    else if ((LYTransferRate == rateKB || LYTransferRate == rateEtaKB_maybe)
 
172
             && (n > 999))      /* Avoid switching between 1016b/s and 1K/s */
 
173
        sprintf(s, "%.2g", ((double)n)/kb_units);
 
174
    else {
 
175
        sprintf(s, "%ld", n);
 
176
    }
 
177
 
 
178
    if (!was_units || was_units != u)
 
179
        sprintf(s + strlen(s), " %s", u);
 
180
    return u;
 
181
}
 
182
 
 
183
#ifdef USE_READPROGRESS
 
184
#define TIME_HMS_LENGTH (16)
 
185
PRIVATE char *sprint_tbuf ARGS2(
 
186
        char *,        s,
 
187
        long,          t)
 
188
{
 
189
    if (t > 3600)
 
190
        sprintf (s, "%ldh%ldm%lds", t / 3600, (t / 60) % 60, t % 60);
 
191
    else if (t > 60)
 
192
        sprintf (s, "%ldm%lds", t / 60, t % 60);
 
193
    else
 
194
        sprintf (s, "%ld sec", t);
 
195
    return s;
 
196
}
 
197
#endif /* USE_READPROGRESS */
 
198
 
 
199
/*      Issue a read-progress message.                  HTReadProgress()
 
200
**      ------------------------------
 
201
*/
 
202
PUBLIC void HTReadProgress ARGS2(
 
203
        long,           bytes,
 
204
        long,           total)
 
205
{
 
206
    static long bytes_last, total_last;
 
207
    static long transfer_rate = 0;
 
208
    static char *line = NULL;
 
209
    char bytesp[80], totalp[80], transferp[80];
 
210
    int renew = 0;
 
211
    CONST char *was_units;
 
212
 
 
213
#ifdef HAVE_GETTIMEOFDAY
 
214
    struct timeval tv;
 
215
    double now;
 
216
    static double first, last, last_active;
 
217
    gettimeofday(&tv, (struct timezone *)0);
 
218
    now = tv.tv_sec + tv.tv_usec/1000000. ;
 
219
#else
 
220
#if defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H)
 
221
    static double now, first, last, last_active;
 
222
    struct timeb tb;
 
223
 
 
224
    ftime(&tb);
 
225
    now = tb.time + (double)tb.millitm / 1000;
 
226
#else
 
227
    time_t now = time((time_t *)0);  /* once per second */
 
228
    static time_t first, last, last_active;
 
229
#endif
 
230
#endif
 
231
 
 
232
    if (!LYShowTransferRate)
 
233
        LYTransferRate = rateOFF;
 
234
 
 
235
    if (bytes == 0) {
 
236
        first = last = last_active = now;
 
237
        bytes_last = bytes;
 
238
    } else if (bytes < 0) {     /* stalled */
 
239
        bytes = bytes_last;
 
240
        total = total_last;
 
241
    }
 
242
    if ((bytes > 0) &&
 
243
               (now != first))
 
244
                /* 1 sec delay for transfer_rate calculation without g-t-o-d */ {
 
245
        if (transfer_rate <= 0)    /* the very first time */
 
246
            transfer_rate = (long)((bytes) / (now - first));   /* bytes/sec */
 
247
        total_last = total;
 
248
 
 
249
        /*
 
250
         * Optimal refresh time:  every 0.2 sec
 
251
         */
 
252
#if defined(HAVE_GETTIMEOFDAY) || (defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H))
 
253
        if (now >= last + 0.2)
 
254
            renew = 1;
 
255
#else
 
256
        /*
 
257
         * Use interpolation.  (The transfer rate may be not constant
 
258
         * when we have partial content in a proxy.  We adjust transfer_rate
 
259
         * once a second to minimize interpolation error below.)
 
260
         */
 
261
        if ((now != last) || ((bytes - bytes_last) > (transfer_rate / 5))) {
 
262
            renew = 1;
 
263
            bytes_last += (transfer_rate / 5);  /* until we got next second */
 
264
        }
 
265
#endif
 
266
        if (renew) {
 
267
            if (now != last) {
 
268
                last = now;
 
269
                if (bytes_last != bytes)
 
270
                    last_active = now;
 
271
                bytes_last = bytes;
 
272
                transfer_rate = (long)(bytes / (now - first)); /* more accurate value */
 
273
            }
 
274
 
 
275
            if (total > 0)
 
276
                was_units = sprint_bytes(totalp, total, 0);
 
277
            else
 
278
                was_units = 0;
 
279
            sprint_bytes(bytesp, bytes, was_units);
 
280
 
 
281
            if (total > 0)
 
282
                HTSprintf0 (&line, gettext("Read %s of %s of data"), bytesp, totalp);
 
283
            else
 
284
                HTSprintf0 (&line, gettext("Read %s of data"), bytesp);
 
285
 
 
286
            if (LYTransferRate != rateOFF
 
287
             && transfer_rate > 0) {
 
288
                sprint_bytes(transferp, transfer_rate, 0);
 
289
                HTSprintf (&line, gettext(", %s/sec"), transferp);
 
290
            }
 
291
 
 
292
#ifdef USE_READPROGRESS
 
293
            if (LYTransferRate == rateEtaBYTES
 
294
             || LYTransferRate == rateEtaKB) {
 
295
                char tbuf[TIME_HMS_LENGTH];
 
296
                if (now - last_active >= 5)
 
297
                    HTSprintf (&line,
 
298
                               gettext(" (stalled for %s)"),
 
299
                               sprint_tbuf (tbuf, (long)(now - last_active)));
 
300
                if (total > 0 && transfer_rate)
 
301
                    HTSprintf (&line,
 
302
                               gettext(", ETA %s"),
 
303
                               sprint_tbuf (tbuf, (long)((total - bytes)/transfer_rate)));
 
304
            }
 
305
#endif
 
306
 
 
307
            StrAllocCat (line, ".");
 
308
            if (total < -1)
 
309
                StrAllocCat(line, gettext(" (Press 'z' to abort)"));
 
310
 
 
311
            /* do not store the message for history page. */
 
312
            statusline(line);
 
313
            CTRACE((tfp, "%s\n", line));
 
314
        }
 
315
    }
 
316
#ifdef LY_FIND_LEAKS
 
317
    FREE(line);
 
318
#endif
 
319
}
 
320
 
 
321
PRIVATE BOOL conf_cancelled = NO; /* used by HTConfirm only - kw */
 
322
 
 
323
PUBLIC BOOL HTLastConfirmCancelled NOARGS
 
324
{
 
325
    if (conf_cancelled) {
 
326
        conf_cancelled = NO;    /* reset */
 
327
        return(YES);
 
328
    } else {
 
329
        return(NO);
 
330
    }
 
331
}
 
332
 
 
333
/*
 
334
 * Prompt for yes/no response, but let a configuration variable override
 
335
 * the prompt entirely.
 
336
 */
 
337
PUBLIC int HTForcedPrompt ARGS3(
 
338
        int,            option,
 
339
        CONST char *,   msg,
 
340
        int,            dft)
 
341
{
 
342
    int result = FALSE;
 
343
    char *show = NULL;
 
344
    char *msg2 = NULL;
 
345
 
 
346
    if (option == FORCE_PROMPT_DFT) {
 
347
        result = HTConfirmDefault(msg, dft);
 
348
    } else {
 
349
        if (option == FORCE_PROMPT_YES) {
 
350
            show = gettext("yes");
 
351
            result = YES;
 
352
        } else if (option == FORCE_PROMPT_NO) {
 
353
            show = gettext("no");
 
354
            result = NO;
 
355
        } else {
 
356
            return HTConfirmDefault(msg, dft);  /* bug... */
 
357
        }
 
358
        HTSprintf(&msg2, "%s %s", msg, show);
 
359
        HTUserMsg(msg2);
 
360
        free(msg2);
 
361
    }
 
362
    return result;
 
363
}
 
364
 
 
365
#define DFT_CONFIRM ~(YES|NO)
 
366
 
 
367
/*      Seek confirmation with default answer.          HTConfirmDefault()
 
368
**      --------------------------------------
 
369
*/
 
370
PUBLIC int HTConfirmDefault ARGS2(CONST char *, Msg, int, Dft)
 
371
{
 
372
/* Meta-note: don't move the following note from its place right
 
373
   in front of the first gettext().  As it is now, it should
 
374
   automatically appear in generated lynx.pot files. - kw
 
375
 */
 
376
 
 
377
/*  NOTE TO TRANSLATORS:  If you provide a translation for "yes", lynx
 
378
 *  will take the first byte of the translation as a positive response
 
379
 *  to Yes/No questions.  If you provide a translation for "no", lynx
 
380
 *  will take the first byte of the translation as a negative response
 
381
 *  to Yes/No questions.  For both, lynx will also try to show the
 
382
 *  first byte in the prompt as a character, instead of (y) or (n),
 
383
 *  respectively.  This will not work right for multibyte charsets!
 
384
 *  Don't translate "yes" and "no" for CJK character sets (or translate
 
385
 *  them to "yes" and "no").  For a translation using UTF-8, don't
 
386
 *  translate if the translation would begin with anything but a 7-bit
 
387
 *  (US_ASCII) character.  That also means do not translate if the
 
388
 *  translation would begin with anything but a 7-bit character, if
 
389
 *  you use a single-byte character encoding (a charset like ISO-8859-n)
 
390
 *  but anticipate that the message catalog may be used re-encoded in
 
391
 *  UTF-8 form.
 
392
 *  For translations using other character sets, you may also wish to
 
393
 *  leave "yes" and "no" untranslated, if using (y) and (n) is the
 
394
 *  preferred behavior.
 
395
 *  Lynx will also accept y Y n N as responses unless there is a conflict
 
396
 *  with the first letter of the "yes" or "no" translation.
 
397
 */
 
398
    char *msg_yes = gettext("yes");
 
399
    char *msg_no  = gettext("no");
 
400
    int result = -1;
 
401
 
 
402
    /* If they're not really distinct in the first letter, revert to English */
 
403
    if (TOUPPER(*msg_yes) == TOUPPER(*msg_no)) {
 
404
        msg_yes = "yes";
 
405
        msg_no = "no";
 
406
    }
 
407
 
 
408
    conf_cancelled = NO;
 
409
    if (dump_output_immediately) { /* Non-interactive, can't respond */
 
410
        if (Dft == DFT_CONFIRM) {
 
411
            CTRACE((tfp, "Confirm: %s (%c/%c) ", Msg, *msg_yes, *msg_no));
 
412
        } else {
 
413
            CTRACE((tfp, "Confirm: %s (%c) ", Msg, (Dft == YES) ? *msg_yes : *msg_no));
 
414
        }
 
415
        CTRACE((tfp, "- NO, not interactive.\n"));
 
416
        result = NO;
 
417
    } else {
 
418
        char *msg = NULL;
 
419
        char fallback_y = 'y';  /* English letter response as fallback */
 
420
        char fallback_n = 'n';  /* English letter response as fallback */
 
421
 
 
422
        if (fallback_y == *msg_yes || fallback_y == *msg_no)
 
423
            fallback_y = '\0';  /* conflict or duplication, don't use */
 
424
        if (fallback_n == *msg_yes || fallback_n == *msg_no)
 
425
            fallback_n = '\0';  /* conflict or duplication, don't use */
 
426
 
 
427
        if (Dft == DFT_CONFIRM)
 
428
            HTSprintf0(&msg, "%s (%c/%c) ", Msg, *msg_yes, *msg_no);
 
429
        else
 
430
            HTSprintf0(&msg, "%s (%c) ", Msg, (Dft == YES) ? *msg_yes : *msg_no);
 
431
        if (LYTraceLogFP) {
 
432
            CTRACE((tfp, "Confirm: %s", msg));
 
433
        }
 
434
        _statusline(msg);
 
435
        FREE(msg);
 
436
 
 
437
        while (result < 0) {
 
438
            int c = LYgetch_single();
 
439
#ifdef VMS
 
440
            if (HadVMSInterrupt) {
 
441
                HadVMSInterrupt = FALSE;
 
442
                c = TOUPPER(*msg_no);
 
443
            }
 
444
#endif /* VMS */
 
445
            if (c == TOUPPER(*msg_yes)) {
 
446
                result = YES;
 
447
            } else if (c == TOUPPER(*msg_no)) {
 
448
                result = NO;
 
449
            } else if (fallback_y && c == fallback_y) {
 
450
                result = YES;
 
451
            } else if (fallback_n && c == fallback_n) {
 
452
                result = NO;
 
453
            } else if (LYCharIsINTERRUPT(c)) { /* remember we had ^G or ^C */
 
454
                conf_cancelled = YES;
 
455
                result = NO;
 
456
            } else if (Dft != DFT_CONFIRM) {
 
457
                result = Dft;
 
458
                break;
 
459
            }
 
460
        }
 
461
        CTRACE((tfp, "- %s%s.\n",
 
462
               (result != NO) ? "YES" : "NO",
 
463
               conf_cancelled ? ", cancelled" : ""));
 
464
    }
 
465
    return (result);
 
466
}
 
467
 
 
468
/*      Seek confirmation.                              HTConfirm()
 
469
**      ------------------
 
470
*/
 
471
PUBLIC BOOL HTConfirm ARGS1(CONST char *, Msg)
 
472
{
 
473
    return (BOOL) HTConfirmDefault(Msg, DFT_CONFIRM);
 
474
}
 
475
 
 
476
/*
 
477
 *  Ask a post resubmission prompt with some indication of what would
 
478
 *  be resubmitted, useful especially for going backward in history.
 
479
 *  Try to use parts of the address or, if given, the title, depending
 
480
 *  on how much fits on the statusline.
 
481
 *  if_imgmap and if_file indicate how to handle an address that is
 
482
 *  a "LYNXIMGMAP:", or a "file:" URL (presumably the List Page file),
 
483
 *  respectively: 0: auto-deny, 1: auto-confirm, 2: prompt.
 
484
 *  - kw
 
485
 */
 
486
 
 
487
PUBLIC BOOL confirm_post_resub ARGS4(
 
488
    CONST char*,        address,
 
489
    CONST char*,        title,
 
490
    int,                if_imgmap,
 
491
    int,                if_file)
 
492
{
 
493
    size_t len1;
 
494
    CONST char *msg = CONFIRM_POST_RESUBMISSION_TO;
 
495
    char buf[240];
 
496
    char *temp = NULL;
 
497
    BOOL res;
 
498
    size_t maxlen = LYcols - 6;
 
499
    if (!address) {
 
500
        return(NO);
 
501
    } else if (isLYNXIMGMAP(address)) {
 
502
        if (if_imgmap <= 0)
 
503
            return(NO);
 
504
        else if (if_imgmap == 1)
 
505
            return(YES);
 
506
        else
 
507
            msg = CONFIRM_POST_LIST_RELOAD;
 
508
    } else if (isFILE_URL(address)) {
 
509
        if (if_file <= 0)
 
510
            return(NO);
 
511
        else if (if_file == 1)
 
512
            return(YES);
 
513
        else
 
514
            msg = CONFIRM_POST_LIST_RELOAD;
 
515
    } else if (dump_output_immediately) {
 
516
        return(NO);
 
517
    }
 
518
    if (maxlen >= sizeof(buf))
 
519
        maxlen = sizeof(buf) - 1;
 
520
    if ((len1 = strlen(msg)) +
 
521
        strlen(address) <= maxlen) {
 
522
        sprintf(buf, msg, address);
 
523
        return HTConfirm(buf);
 
524
    }
 
525
    if (len1 + strlen(temp = HTParse(address, "",
 
526
                                     PARSE_ACCESS+PARSE_HOST+PARSE_PATH
 
527
                                     +PARSE_PUNCTUATION)) <= maxlen) {
 
528
        sprintf(buf, msg, temp);
 
529
        res = HTConfirm(buf);
 
530
        FREE(temp);
 
531
        return(res);
 
532
    }
 
533
    FREE(temp);
 
534
    if (title && (len1 + strlen(title) <= maxlen)) {
 
535
        sprintf(buf, msg, title);
 
536
        return HTConfirm(buf);
 
537
    }
 
538
    if (len1 + strlen(temp = HTParse(address, "",
 
539
                                     PARSE_ACCESS+PARSE_HOST
 
540
                                     +PARSE_PUNCTUATION)) <= maxlen) {
 
541
        sprintf(buf, msg, temp);
 
542
        res = HTConfirm(buf);
 
543
        FREE(temp);
 
544
        return(res);
 
545
    }
 
546
    FREE(temp);
 
547
    if ((temp = HTParse(address, "", PARSE_HOST)) && *temp &&
 
548
        len1 + strlen(temp) <= maxlen) {
 
549
        sprintf(buf, msg, temp);
 
550
        res = HTConfirm(buf);
 
551
        FREE(temp);
 
552
        return(res);
 
553
    }
 
554
    FREE(temp);
 
555
    return HTConfirm(CONFIRM_POST_RESUBMISSION);
 
556
}
 
557
 
 
558
/*      Prompt for answer and get text back.            HTPrompt()
 
559
**      ------------------------------------
 
560
*/
 
561
PUBLIC char * HTPrompt ARGS2(
 
562
        CONST char *,   Msg,
 
563
        CONST char *,   deflt)
 
564
{
 
565
    char * rep = NULL;
 
566
    char Tmp[200];
 
567
 
 
568
    Tmp[0] = '\0';
 
569
    Tmp[sizeof(Tmp)-1] = '\0';
 
570
 
 
571
    _statusline(Msg);
 
572
    if (deflt)
 
573
        strncpy(Tmp, deflt, sizeof(Tmp)-1);
 
574
 
 
575
    if (!dump_output_immediately)
 
576
        LYgetstr(Tmp, VISIBLE, sizeof(Tmp), NORECALL);
 
577
 
 
578
    StrAllocCopy(rep, Tmp);
 
579
 
 
580
    return rep;
 
581
}
 
582
 
 
583
/*
 
584
**      Prompt for password without echoing the reply.  HTPromptPassword()
 
585
**      ----------------------------------------------
 
586
*/
 
587
PUBLIC char * HTPromptPassword ARGS1(
 
588
        CONST char *,   Msg)
 
589
{
 
590
    char *result = NULL;
 
591
    char pw[120];
 
592
 
 
593
    pw[0] = '\0';
 
594
 
 
595
    if (!dump_output_immediately) {
 
596
        _statusline(Msg ? Msg : PASSWORD_PROMPT);
 
597
        LYgetstr(pw, HIDDEN, sizeof(pw), NORECALL); /* hidden */
 
598
        StrAllocCopy(result, pw);
 
599
    } else {
 
600
        printf("\n%s\n", PASSWORD_REQUIRED);
 
601
        StrAllocCopy(result, "");
 
602
    }
 
603
    return result;
 
604
}
 
605
 
 
606
/*      Prompt both username and password.       HTPromptUsernameAndPassword()
 
607
**      ----------------------------------
 
608
**
 
609
**  On entry,
 
610
**      Msg             is the prompting message.
 
611
**      *username and
 
612
**      *password       are char pointers which contain default
 
613
**                      or zero-length strings; they are changed
 
614
**                      to point to result strings.
 
615
**      IsProxy         should be TRUE if this is for
 
616
**                      proxy authentication.
 
617
**
 
618
**                      If *username is not NULL, it is taken
 
619
**                      to point to a default value.
 
620
**                      Initial value of *password is
 
621
**                      completely discarded.
 
622
**
 
623
**  On exit,
 
624
**      *username and *password point to newly allocated
 
625
**      strings -- original strings pointed to by them
 
626
**      are NOT freed.
 
627
**
 
628
*/
 
629
PUBLIC void HTPromptUsernameAndPassword ARGS4(
 
630
        CONST char *,   Msg,
 
631
        char **,        username,
 
632
        char **,        password,
 
633
        BOOL,           IsProxy)
 
634
{
 
635
    if ((IsProxy == FALSE &&
 
636
         authentication_info[0] && authentication_info[1]) ||
 
637
        (IsProxy == TRUE &&
 
638
         proxyauth_info[0] && proxyauth_info[1])) {
 
639
        /*
 
640
        **  The -auth or -pauth parameter gave us both the username
 
641
        **  and password to use for the first realm or proxy server,
 
642
        **  respectively, so just use them without any prompting. - FM
 
643
        */
 
644
        StrAllocCopy(*username, (IsProxy ?
 
645
                       proxyauth_info[0] : authentication_info[0]));
 
646
        if (IsProxy) {
 
647
            FREE(proxyauth_info[0]);
 
648
        } else {
 
649
            FREE(authentication_info[0]);
 
650
        }
 
651
        StrAllocCopy(*password, (IsProxy ?
 
652
                       proxyauth_info[1] : authentication_info[1]));
 
653
        if (IsProxy) {
 
654
            FREE(proxyauth_info[1]);
 
655
        } else {
 
656
            FREE(authentication_info[1]);
 
657
        }
 
658
    } else if (dump_output_immediately) {
 
659
        /*
 
660
         *  We are not interactive and don't have both the
 
661
         *  username and password from the command line,
 
662
         *  but might have one or the other. - FM
 
663
         */
 
664
        if ((IsProxy == FALSE && authentication_info[0]) ||
 
665
            (IsProxy == TRUE && proxyauth_info[0])) {
 
666
            /*
 
667
            **  Use the command line username. - FM
 
668
            */
 
669
            StrAllocCopy(*username, (IsProxy ?
 
670
                           proxyauth_info[0] : authentication_info[0]));
 
671
            if (IsProxy) {
 
672
                FREE(proxyauth_info[0]);
 
673
            } else {
 
674
                FREE(authentication_info[0]);
 
675
            }
 
676
        } else {
 
677
            /*
 
678
            **  Default to "WWWuser". - FM
 
679
            */
 
680
            StrAllocCopy(*username, "WWWuser");
 
681
        }
 
682
        if ((IsProxy == FALSE && authentication_info[1]) ||
 
683
            (IsProxy == TRUE && proxyauth_info[1])) {
 
684
            /*
 
685
            **  Use the command line password. - FM
 
686
            */
 
687
            StrAllocCopy(*password, (IsProxy ?
 
688
                           proxyauth_info[1] : authentication_info[1]));
 
689
            if (IsProxy) {
 
690
                FREE(proxyauth_info[1]);
 
691
            } else {
 
692
                FREE(authentication_info[1]);
 
693
            }
 
694
        } else {
 
695
            /*
 
696
            **  Default to a zero-length string. - FM
 
697
            */
 
698
            StrAllocCopy(*password, "");
 
699
        }
 
700
        printf("\n%s\n", USERNAME_PASSWORD_REQUIRED);
 
701
 
 
702
    } else {
 
703
        /*
 
704
         *  We are interactive and don't have both the
 
705
         *  username and password from the command line,
 
706
         *  but might have one or the other. - FM
 
707
         */
 
708
        if ((IsProxy == FALSE && authentication_info[0]) ||
 
709
            (IsProxy == TRUE && proxyauth_info[0])) {
 
710
            /*
 
711
            **  Offer the command line username in the
 
712
            **  prompt for the first realm. - FM
 
713
            */
 
714
            StrAllocCopy(*username, (IsProxy ?
 
715
                           proxyauth_info[0] : authentication_info[0]));
 
716
            if (IsProxy) {
 
717
                FREE(proxyauth_info[0]);
 
718
            } else {
 
719
                FREE(authentication_info[0]);
 
720
            }
 
721
        }
 
722
        /*
 
723
         *  Prompt for confirmation or entry of the username. - FM
 
724
         */
 
725
        if (Msg != NULL) {
 
726
            *username = HTPrompt(Msg, *username);
 
727
        } else {
 
728
            *username = HTPrompt(USERNAME_PROMPT, *username);
 
729
        }
 
730
        if ((IsProxy == FALSE && authentication_info[1]) ||
 
731
            (IsProxy == TRUE && proxyauth_info[1])) {
 
732
            /*
 
733
            **  Use the command line password for the first realm. - FM
 
734
            */
 
735
            StrAllocCopy(*password, (IsProxy ?
 
736
                           proxyauth_info[1] : authentication_info[1]));
 
737
            if (IsProxy) {
 
738
                FREE(proxyauth_info[1]);
 
739
            } else {
 
740
                FREE(authentication_info[1]);
 
741
            }
 
742
        } else if (*username != NULL && *username[0] != '\0') {
 
743
            /*
 
744
            **  We have a non-zero length username,
 
745
            **  so prompt for the password. - FM
 
746
            */
 
747
            *password = HTPromptPassword(PASSWORD_PROMPT);
 
748
        } else {
 
749
            /*
 
750
            **  Return a zero-length password. - FM
 
751
            */
 
752
            StrAllocCopy(*password, "");
 
753
        }
 
754
    }
 
755
}
 
756
 
 
757
/*      Confirm a cookie operation.                     HTConfirmCookie()
 
758
**      ---------------------------
 
759
**
 
760
**  On entry,
 
761
**      server                  is the server sending the Set-Cookie.
 
762
**      domain                  is the domain of the cookie.
 
763
**      path                    is the path of the cookie.
 
764
**      name                    is the name of the cookie.
 
765
**      value                   is the value of the cookie.
 
766
**
 
767
**  On exit,
 
768
**      Returns FALSE on cancel,
 
769
**              TRUE if the cookie should be set.
 
770
*/
 
771
PUBLIC BOOL HTConfirmCookie ARGS4(
 
772
        domain_entry *, de,
 
773
        CONST char *,   server,
 
774
        CONST char *,   name,
 
775
        CONST char *,   value)
 
776
{
 
777
    int ch;
 
778
    char *prompt = ADVANCED_COOKIE_CONFIRMATION;
 
779
 
 
780
    if (de == NULL)
 
781
        return FALSE;
 
782
 
 
783
    /*  If the user has specified a list of domains to allow or deny
 
784
    **  from the config file, then they'll already have de->bv set to
 
785
    **  ACCEPT_ALWAYS or REJECT_ALWAYS so we can relax and let the
 
786
    **  default cookie handling code cope with this fine.
 
787
    */
 
788
 
 
789
    /*
 
790
    **  If the user has specified a constant action, don't prompt at all.
 
791
    */
 
792
    if (de->bv == ACCEPT_ALWAYS)
 
793
        return TRUE;
 
794
    if (de->bv == REJECT_ALWAYS)
 
795
        return FALSE;
 
796
 
 
797
    if (dump_output_immediately) {
 
798
        /*
 
799
        **  Non-interactive, can't respond.  Use the LYSetCookies value
 
800
        *   based on its compilation or configuration setting, or on the
 
801
        **  command line toggle. - FM
 
802
        */
 
803
        return LYSetCookies;
 
804
    }
 
805
 
 
806
    /*
 
807
    **  Estimate how much of the cookie we can show.
 
808
    */
 
809
    if(!LYAcceptAllCookies) {
 
810
        int namelen, valuelen, space_free, percentage;
 
811
        char *message = 0;
 
812
 
 
813
        space_free = ((LYcols - 1)
 
814
                      - (strlen(prompt)
 
815
                         - 10)          /* %s and %.*s and %.*s chars */
 
816
                      - strlen(server));
 
817
        if (space_free < 0)
 
818
            space_free = 0;
 
819
        namelen = strlen(name);
 
820
        valuelen = strlen(value);
 
821
        if ((namelen + valuelen) > space_free) {
 
822
            /*
 
823
            **  Argh... there isn't enough space on our single line for
 
824
            **  the whole cookie.  Reduce them both by a percentage.
 
825
            **  This should be smarter.
 
826
            */
 
827
            percentage = (100 * space_free) / (namelen + valuelen);
 
828
            namelen = (percentage * namelen) / 100;
 
829
            valuelen = (percentage * valuelen) / 100;
 
830
        }
 
831
        HTSprintf(&message, prompt, server, namelen, name, valuelen, value);
 
832
        _statusline(message);
 
833
        FREE(message);
 
834
    }
 
835
    for (;;) {
 
836
        if(LYAcceptAllCookies) {
 
837
            ch = 'A';
 
838
        } else {
 
839
            ch = LYgetch_single();
 
840
#if defined(LOCALE) && defined(HAVE_GETTEXT) && !defined(gettext)
 
841
            /*
 
842
             * Special-purpose workaround for gettext support (we should do
 
843
             * this in a more general way -- after 2.8.3).
 
844
             *
 
845
             * NOTE TO TRANSLATORS:  If the prompt has been rendered into
 
846
             * another language, and if yes/no are distinct, assume the
 
847
             * translator can make an ordered list in parentheses with one
 
848
             * capital letter for each as we assumed in HTConfirmDefault().
 
849
             * The list has to be in the same order as in the original message,
 
850
             * and the four capital letters chosen to not match those in the
 
851
             * original unless they have the same position.
 
852
             *
 
853
             * Example:
 
854
             *  (Y/N/Always/neVer)              - English (original)
 
855
             *  (O/N/Toujours/Jamais)           - French
 
856
             */
 
857
            {
 
858
#define L_PAREN '('
 
859
#define R_PAREN ')'
 
860
                char *p;
 
861
                char *s = "YNAV\007\003"; /* see ADVANCED_COOKIE_CONFIRMATION */
 
862
 
 
863
                if (strchr(s, ch) == 0
 
864
                 && isalpha(ch)
 
865
                 && (p = strrchr(prompt, L_PAREN)) != 0) {
 
866
 
 
867
                    CTRACE((tfp, "Looking for %c in %s\n", ch, p));
 
868
                    while (*p != R_PAREN && *p != 0 && isalpha(UCH(*s))) {
 
869
                        if (isalpha(UCH(*p)) && (*p == TOUPPER(*p))) {
 
870
                            CTRACE((tfp, "...testing %c/%c\n", *p, *s));
 
871
                            if (*p == ch) {
 
872
                                ch = *s;
 
873
                                break;
 
874
                            }
 
875
                            ++s;
 
876
                        }
 
877
                        ++p;
 
878
                    }
 
879
                }
 
880
            }
 
881
#endif
 
882
        }
 
883
#ifdef VMS
 
884
        if (HadVMSInterrupt) {
 
885
            HadVMSInterrupt = FALSE;
 
886
            ch = 'N';
 
887
        }
 
888
#endif /* VMS */
 
889
        switch(ch) {
 
890
            case 'A':
 
891
                /*
 
892
                **  Set to accept all cookies for this domain.
 
893
                */
 
894
                de->bv = ACCEPT_ALWAYS;
 
895
                HTUserMsg2(ALWAYS_ALLOWING_COOKIES, de->domain);
 
896
                return TRUE;
 
897
 
 
898
            case 'N':
 
899
                /*
 
900
                **  Reject the cookie.
 
901
                */
 
902
              reject:
 
903
                HTUserMsg(REJECTING_COOKIE);
 
904
                return FALSE;
 
905
 
 
906
            case 'V':
 
907
                /*
 
908
                **  Set to reject all cookies from this domain.
 
909
                */
 
910
                de->bv = REJECT_ALWAYS;
 
911
                HTUserMsg2(NEVER_ALLOWING_COOKIES, de->domain);
 
912
                return FALSE;
 
913
 
 
914
            case 'Y':
 
915
                /*
 
916
                **  Accept the cookie.
 
917
                */
 
918
                HTInfoMsg(ALLOWING_COOKIE);
 
919
                return TRUE;
 
920
 
 
921
            default:
 
922
                if (LYCharIsINTERRUPT(ch))
 
923
                    goto reject;
 
924
                continue;
 
925
        }
 
926
    }
 
927
}
 
928
 
 
929
/*      Confirm redirection of POST.            HTConfirmPostRedirect()
 
930
**      ----------------------------
 
931
**
 
932
**  On entry,
 
933
**      Redirecting_url             is the Location.
 
934
**      server_status               is the server status code.
 
935
**
 
936
**  On exit,
 
937
**      Returns 0 on cancel,
 
938
**        1 for redirect of POST with content,
 
939
**      303 for redirect as GET without content
 
940
*/
 
941
PUBLIC int HTConfirmPostRedirect ARGS2(
 
942
        CONST char *,   Redirecting_url,
 
943
        int,            server_status)
 
944
{
 
945
    int result = -1;
 
946
    char *show_POST_url = NULL;
 
947
    char *StatusInfo = 0;
 
948
    char *url = 0;
 
949
    int on_screen = 0;  /* 0 - show menu
 
950
                         * 1 - show url
 
951
                         * 2 - menu is already on screen */
 
952
 
 
953
    if (server_status == 303 ||
 
954
        server_status == 302) {
 
955
        /*
 
956
         *  HTTP.c should not have called us for either of
 
957
         *  these because we're treating 302 as historical,
 
958
         *  so just return 303. - FM
 
959
         */
 
960
        return 303;
 
961
    }
 
962
 
 
963
    if (dump_output_immediately) {
 
964
        if (server_status == 301) {
 
965
            /*
 
966
            **  Treat 301 as historical, i.e., like 303 (GET
 
967
            **  without content), when not interactive. - FM
 
968
            */
 
969
            return 303;
 
970
        } else {
 
971
            /*
 
972
            **  Treat anything else (e.g., 305, 306 or 307) as too
 
973
            **  dangerous to redirect without confirmation, and thus
 
974
            **  cancel when not interactive. - FM
 
975
            */
 
976
            return 0;
 
977
        }
 
978
    }
 
979
 
 
980
    if (user_mode == NOVICE_MODE) {
 
981
        on_screen = 2;
 
982
        LYmove(LYlines-2, 0);
 
983
        HTSprintf0(&StatusInfo, SERVER_ASKED_FOR_REDIRECTION, server_status);
 
984
        LYaddstr(StatusInfo);
 
985
        LYclrtoeol();
 
986
        LYmove(LYlines-1, 0);
 
987
        HTSprintf0(&url, "URL: %.*s",
 
988
                    (LYcols < 250 ? LYcols-6 : 250), Redirecting_url);
 
989
        LYaddstr(url);
 
990
        LYclrtoeol();
 
991
        if (server_status == 301) {
 
992
            _statusline(PROCEED_GET_CANCEL);
 
993
        } else {
 
994
            _statusline(PROCEED_OR_CANCEL);
 
995
        }
 
996
    } else {
 
997
        HTSprintf0(&StatusInfo, "%d %.*s",
 
998
                            server_status,
 
999
                            251,
 
1000
                            ((server_status == 301) ?
 
1001
                         ADVANCED_POST_GET_REDIRECT :
 
1002
                         ADVANCED_POST_REDIRECT));
 
1003
        StrAllocCopy(show_POST_url, LOCATION_HEADER);
 
1004
        StrAllocCat(show_POST_url, Redirecting_url);
 
1005
    }
 
1006
    while (result < 0) {
 
1007
        int c;
 
1008
 
 
1009
        switch (on_screen) {
 
1010
            case 0:
 
1011
                _statusline(StatusInfo);
 
1012
                break;
 
1013
            case 1:
 
1014
                _statusline(show_POST_url);
 
1015
        }
 
1016
        c = LYgetch_single();
 
1017
        switch (c) {
 
1018
            case 'P':
 
1019
                /*
 
1020
                **  Proceed with 301 or 307 redirect of POST
 
1021
                **  with same method and POST content. - FM
 
1022
                */
 
1023
                FREE(show_POST_url);
 
1024
                result = 1;
 
1025
                break;
 
1026
 
 
1027
            case 7:
 
1028
            case 'C':
 
1029
                /*
 
1030
                **  Cancel request.
 
1031
                */
 
1032
                FREE(show_POST_url);
 
1033
                result = 0;
 
1034
                break;
 
1035
 
 
1036
            case 'U':
 
1037
                /*
 
1038
                **  Show URL for intermediate or advanced mode.
 
1039
                */
 
1040
                if (user_mode != NOVICE_MODE) {
 
1041
                    if (on_screen == 1) {
 
1042
                        on_screen = 0;
 
1043
                    } else {
 
1044
                        on_screen = 1;
 
1045
                    }
 
1046
                }
 
1047
                break;
 
1048
 
 
1049
            case 'G':
 
1050
                if (server_status == 301) {
 
1051
                    /*
 
1052
                    **  Treat as 303 (GET without content).
 
1053
                    */
 
1054
                    FREE(show_POST_url);
 
1055
                    result = 303;
 
1056
                    break;
 
1057
                }
 
1058
                /* fall through to default */
 
1059
 
 
1060
            default:
 
1061
                /*
 
1062
                **  Get another character.
 
1063
                */
 
1064
                if (on_screen == 1) {
 
1065
                    on_screen = 0;
 
1066
                } else {
 
1067
                    on_screen = 2;
 
1068
                }
 
1069
        }
 
1070
    }
 
1071
    FREE(StatusInfo);
 
1072
    FREE(url);
 
1073
    return (result);
 
1074
}
 
1075
 
 
1076
#define okToSleep() (!crawl && !traversal && LYCursesON)
 
1077
 
 
1078
/*
 
1079
 * Sleep for the given message class's time.
 
1080
 */
 
1081
PUBLIC void LYSleepAlert NOARGS
 
1082
{
 
1083
    if (okToSleep())
 
1084
        LYSleep(AlertSecs);
 
1085
}
 
1086
 
 
1087
PUBLIC void LYSleepDebug NOARGS
 
1088
{
 
1089
    if (okToSleep())
 
1090
        LYSleep(DebugSecs);
 
1091
}
 
1092
 
 
1093
PUBLIC void LYSleepInfo NOARGS
 
1094
{
 
1095
    if (okToSleep())
 
1096
        LYSleep(InfoSecs);
 
1097
}
 
1098
 
 
1099
PUBLIC void LYSleepMsg NOARGS
 
1100
{
 
1101
    if (okToSleep())
 
1102
        LYSleep(MessageSecs);
 
1103
}
 
1104
 
 
1105
#ifdef EXP_CMD_LOGGING
 
1106
PUBLIC void LYSleepReplay NOARGS
 
1107
{
 
1108
    if (okToSleep())
 
1109
        LYSleep(ReplaySecs);
 
1110
}
 
1111
#endif /* EXP_CMD_LOGGING */
 
1112
 
 
1113
/*
 
1114
 *  LYstrerror emulates the ANSI strerror() function.
 
1115
 */
 
1116
#ifdef LYStrerror
 
1117
    /* defined as macro in .h file. */
 
1118
#else
 
1119
PUBLIC char *LYStrerror ARGS1(int, code)
 
1120
{
 
1121
    static char temp[80];
 
1122
    sprintf(temp, "System errno is %d.\r\n", code);
 
1123
    return temp;
 
1124
}
 
1125
#endif /* HAVE_STRERROR */