/*
* $LynxId: HTAlert.c,v 1.94 2010/11/07 21:21:00 tom Exp $
*
* Displaying messages and getting input for Lynx Browser
* ==========================================================
*
* REPLACE THIS MODULE with a GUI version in a GUI environment!
*
* History:
* Jun 92 Created May 1992 By C.T. Barker
* Feb 93 Simplified, portablised TBL
*
*/
#include <HTUtils.h>
#include <HTAlert.h>
#include <LYGlobalDefs.h>
#include <LYCurses.h>
#include <LYStrings.h>
#include <LYUtils.h>
#include <LYClean.h>
#include <GridText.h>
#include <LYCookie.h>
#include <LYHistory.h> /* store statusline messages */
#include <LYLeaks.h>
#include <HTParse.h>
#undef timezone /* U/Win defines this in time.h, hides implementation detail */
#if defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H)
#include <sys/timeb.h>
#endif
/*
* 'napms()' is preferable to 'sleep()' in any case because it does not
* interfere with output, but also because it can be less than a second.
*/
#ifdef HAVE_NAPMS
#define LYSleep(n) napms(n)
#else
#define LYSleep(n) sleep((unsigned)n)
#endif
/* Issue a message about a problem. HTAlert()
* --------------------------------
*/
void HTAlert(const char *Msg)
{
CTRACE((tfp, "\nAlert!: %s\n\n", Msg));
CTRACE_FLUSH(tfp);
_user_message(ALERT_FORMAT, Msg);
LYstore_message2(ALERT_FORMAT, Msg);
if (dump_output_immediately && dump_to_stderr) {
fflush(stdout);
fprintf(stderr, ALERT_FORMAT, Msg);
fputc('\n', stderr);
fflush(stderr);
}
LYSleepAlert();
}
void HTAlwaysAlert(const char *extra_prefix,
const char *Msg)
{
if (!dump_output_immediately && LYCursesON) {
HTAlert(Msg);
} else {
if (extra_prefix) {
fprintf(((TRACE) ? stdout : stderr),
"%s %s!\n",
extra_prefix, Msg);
fflush(stdout);
LYstore_message2(ALERT_FORMAT, Msg);
LYSleepAlert();
} else {
fprintf(((TRACE) ? stdout : stderr), ALERT_FORMAT, NonNull(Msg));
fflush(stdout);
LYstore_message2(ALERT_FORMAT, Msg);
LYSleepAlert();
fprintf(((TRACE) ? stdout : stderr), "\n");
}
CTRACE((tfp, "\nAlert!: %s\n\n", Msg));
CTRACE_FLUSH(tfp);
}
}
/* Issue an informational message. HTInfoMsg()
* --------------------------------
*/
void HTInfoMsg(const char *Msg)
{
_statusline(Msg);
if (non_empty(Msg)) {
CTRACE((tfp, "Info message: %s\n", Msg));
LYstore_message(Msg);
LYSleepInfo();
}
}
void HTInfoMsg2(const char *Msg2, const char *Arg)
{
_user_message(Msg2, Arg);
if (non_empty(Msg2)) {
CTRACE((tfp, "Info message: "));
CTRACE((tfp, Msg2, Arg));
CTRACE((tfp, "\n"));
LYstore_message2(Msg2, Arg);
LYSleepInfo();
}
}
/* Issue an important message. HTUserMsg()
* --------------------------------
*/
void HTUserMsg(const char *Msg)
{
_statusline(Msg);
if (non_empty(Msg)) {
CTRACE((tfp, "User message: %s\n", Msg));
LYstore_message(Msg);
#if !(defined(USE_SLANG) || defined(WIDEC_CURSES))
if (IS_CJK_TTY) {
clearok(curscr, TRUE);
LYrefresh();
}
#endif
LYSleepMsg();
}
}
void HTUserMsg2(const char *Msg2, const char *Arg)
{
_user_message(Msg2, Arg);
if (non_empty(Msg2)) {
CTRACE((tfp, "User message: "));
CTRACE((tfp, Msg2, Arg));
CTRACE((tfp, "\n"));
LYstore_message2(Msg2, Arg);
LYSleepMsg();
}
}
/* Issue a progress message. HTProgress()
* -------------------------
*/
void HTProgress(const char *Msg)
{
statusline(Msg);
LYstore_message(Msg);
CTRACE((tfp, "%s\n", Msg));
LYSleepDelay();
}
const char *HTProgressUnits(int rate)
{
static const char *bunits = 0;
static const char *kbunits = 0;
if (!bunits) {
bunits = gettext("bytes");
kbunits = gettext(LYTransferName);
}
return ((rate == rateKB)
#ifdef USE_READPROGRESS
|| (rate == rateEtaKB)
#endif
)? kbunits : bunits;
}
static const char *sprint_bytes(char *s, off_t n, const char *was_units)
{
static off_t kb_units = 1024;
const char *u = HTProgressUnits(LYTransferRate);
if (LYTransferRate == rateKB || LYTransferRate == rateEtaKB_maybe) {
if (n >= 10 * kb_units) {
sprintf(s, "%" PRI_off_t, CAST_off_t (n / kb_units));
} else if (n > 999) { /* Avoid switching between 1016b/s and 1K/s */
sprintf(s, "%.2g", ((double) n) / (double) kb_units);
} else {
sprintf(s, "%" PRI_off_t, CAST_off_t (n));
u = HTProgressUnits(rateBYTES);
}
} else {
sprintf(s, "%" PRI_off_t, CAST_off_t (n));
}
if (!was_units || was_units != u)
sprintf(s + strlen(s), " %s", u);
return u;
}
#ifdef USE_READPROGRESS
#define TIME_HMS_LENGTH (16)
static char *sprint_tbuf(char *s, long t)
{
if (t > 3600)
sprintf(s, "%ldh%ldm%lds", t / 3600, (t / 60) % 60, t % 60);
else if (t > 60)
sprintf(s, "%ldm%lds", t / 60, t % 60);
else
sprintf(s, "%ld sec", t);
return s;
}
#endif /* USE_READPROGRESS */
/* Issue a read-progress message. HTReadProgress()
* ------------------------------
*/
void HTReadProgress(off_t bytes, off_t total)
{
static off_t bytes_last, total_last;
static off_t transfer_rate = 0;
static char *line = NULL;
char bytesp[80], totalp[80], transferp[80];
int renew = 0;
const char *was_units;
#ifdef HAVE_GETTIMEOFDAY
struct timeval tv;
double now;
static double first, last, last_active;
gettimeofday(&tv, (struct timezone *) 0);
now = (double) tv.tv_sec + (double) tv.tv_usec / 1000000.;
#else
#if defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H)
static double now, first, last, last_active;
struct timeb tb;
ftime(&tb);
now = tb.time + (double) tb.millitm / 1000;
#else
time_t now = time((time_t *) 0); /* once per second */
static time_t first, last, last_active;
#endif
#endif
if (!LYShowTransferRate)
LYTransferRate = rateOFF;
if (bytes == 0) {
first = last = last_active = now;
bytes_last = bytes;
} else if (bytes < 0) { /* stalled */
bytes = bytes_last;
total = total_last;
}
/* 1 sec delay for transfer_rate calculation without g-t-o-d */
if ((bytes > 0) &&
(now > first)) {
if (transfer_rate <= 0) { /* the very first time */
transfer_rate = (off_t) ((double) (bytes) / (now - first));
/* bytes/sec */
}
total_last = total;
/*
* Optimal refresh time: every 0.2 sec
*/
#if defined(HAVE_GETTIMEOFDAY) || (defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H))
if (now >= last + 0.2)
renew = 1;
#else
/*
* Use interpolation. (The transfer rate may be not constant
* when we have partial content in a proxy. We adjust transfer_rate
* once a second to minimize interpolation error below.)
*/
if ((now != last) || ((bytes - bytes_last) > (transfer_rate / 5))) {
renew = 1;
bytes_last += (transfer_rate / 5); /* until we got next second */
}
#endif
if (renew) {
if (now > last) {
last = now;
if (bytes_last != bytes)
last_active = now;
bytes_last = bytes;
transfer_rate = (off_t) ((double) bytes / (now - first)); /* more accurate value */
}
if (total > 0)
was_units = sprint_bytes(totalp, total, 0);
else
was_units = 0;
sprint_bytes(bytesp, bytes, was_units);
switch ((TransferRate) LYTransferRate) {
#ifdef USE_PROGRESSBAR
case rateBAR:
/*
* If we know the total size of the file, we can compute
* a percentage, and show a corresponding progress bar.
*/
HTSprintf0(&line, gettext("Read %s of data"), bytesp);
if (total > 0) {
float percent = (float) bytes / (float) total;
int meter = (int) (((float) LYcolLimit * percent) - 5);
CTRACE((tfp, "rateBAR: bytes: %" PRI_off_t ", total: "
"%" PRI_off_t "\n",
CAST_off_t (bytes),
CAST_off_t (total)));
CTRACE((tfp, "meter = %d\n", meter));
HTSprintf0(&line, "%d%% ", (int) (percent * 100));
while (meter-- > 0)
StrAllocCat(line, "I");
CTRACE((tfp, "%s\n", line));
CTRACE_FLUSH(tfp);
}
break;
#endif
default:
if (total > 0) {
HTSprintf0(&line, gettext("Read %s of %s of data"),
bytesp, totalp);
} else {
HTSprintf0(&line, gettext("Read %s of data"), bytesp);
}
if (LYTransferRate != rateOFF
&& transfer_rate > 0) {
sprint_bytes(transferp, transfer_rate, 0);
HTSprintf(&line, gettext(", %s/sec"), transferp);
}
break;
}
#ifdef USE_READPROGRESS
if (LYTransferRate == rateEtaBYTES
|| LYTransferRate == rateEtaKB) {
char tbuf[TIME_HMS_LENGTH];
if (now - last_active >= 5)
HTSprintf(&line,
gettext(" (stalled for %s)"),
sprint_tbuf(tbuf, (long) (now - last_active)));
if (total > 0 && transfer_rate)
HTSprintf(&line,
gettext(", ETA %s"),
sprint_tbuf(tbuf, (long) ((total - bytes) / transfer_rate)));
}
#endif
switch ((TransferRate) LYTransferRate) {
#ifdef USE_PROGRESSBAR
case rateBAR:
/*
* If we were not able to show a progress bar, just show
* a "." for progress.
*/
if (total <= 0)
StrAllocCat(line, ".");
break;
#endif
default:
StrAllocCat(line, ".");
break;
}
if (total < -1)
StrAllocCat(line, gettext(" (Press 'z' to abort)"));
/* do not store the message for history page. */
statusline(line);
CTRACE((tfp, "%s\n", line));
}
}
#ifdef LY_FIND_LEAKS
FREE(line);
#endif
}
static BOOL conf_cancelled = NO; /* used by HTConfirm only - kw */
BOOL HTLastConfirmCancelled(void)
{
if (conf_cancelled) {
conf_cancelled = NO; /* reset */
return (YES);
} else {
return (NO);
}
}
/*
* Prompt for yes/no response, but let a configuration variable override
* the prompt entirely.
*/
int HTForcedPrompt(int option, const char *msg, int dft)
{
int result = FALSE;
const char *show = NULL;
char *msg2 = NULL;
if (option == FORCE_PROMPT_DFT) {
result = HTConfirmDefault(msg, dft);
} else {
if (option == FORCE_PROMPT_YES) {
show = gettext("yes");
result = YES;
} else if (option == FORCE_PROMPT_NO) {
show = gettext("no");
result = NO;
} else {
return HTConfirmDefault(msg, dft); /* bug... */
}
HTSprintf(&msg2, "%s %s", msg, show);
HTUserMsg(msg2);
free(msg2);
}
return result;
}
#define DFT_CONFIRM ~(YES|NO)
/* Seek confirmation with default answer. HTConfirmDefault()
* --------------------------------------
*/
int HTConfirmDefault(const char *Msg, int Dft)
{
/* Meta-note: don't move the following note from its place right
in front of the first gettext(). As it is now, it should
automatically appear in generated lynx.pot files. - kw
*/
/* NOTE TO TRANSLATORS: If you provide a translation for "yes", lynx
* will take the first byte of the translation as a positive response
* to Yes/No questions. If you provide a translation for "no", lynx
* will take the first byte of the translation as a negative response
* to Yes/No questions. For both, lynx will also try to show the
* first byte in the prompt as a character, instead of (y) or (n),
* respectively. This will not work right for multibyte charsets!
* Don't translate "yes" and "no" for CJK character sets (or translate
* them to "yes" and "no"). For a translation using UTF-8, don't
* translate if the translation would begin with anything but a 7-bit
* (US_ASCII) character. That also means do not translate if the
* translation would begin with anything but a 7-bit character, if
* you use a single-byte character encoding (a charset like ISO-8859-n)
* but anticipate that the message catalog may be used re-encoded in
* UTF-8 form.
* For translations using other character sets, you may also wish to
* leave "yes" and "no" untranslated, if using (y) and (n) is the
* preferred behavior.
* Lynx will also accept y Y n N as responses unless there is a conflict
* with the first letter of the "yes" or "no" translation.
*/
const char *msg_yes = gettext("yes");
const char *msg_no = gettext("no");
int result = -1;
/* If they're not really distinct in the first letter, revert to English */
if (TOUPPER(*msg_yes) == TOUPPER(*msg_no)) {
msg_yes = "yes";
msg_no = "no";
}
conf_cancelled = NO;
if (dump_output_immediately) { /* Non-interactive, can't respond */
if (Dft == DFT_CONFIRM) {
CTRACE((tfp, "Confirm: %s (%c/%c) ", Msg, *msg_yes, *msg_no));
} else {
CTRACE((tfp, "Confirm: %s (%c) ", Msg, (Dft == YES) ? *msg_yes : *msg_no));
}
CTRACE((tfp, "- NO, not interactive.\n"));
result = NO;
} else {
char *msg = NULL;
char fallback_y = 'y'; /* English letter response as fallback */
char fallback_n = 'n'; /* English letter response as fallback */
if (fallback_y == *msg_yes || fallback_y == *msg_no)
fallback_y = '\0'; /* conflict or duplication, don't use */
if (fallback_n == *msg_yes || fallback_n == *msg_no)
fallback_n = '\0'; /* conflict or duplication, don't use */
if (Dft == DFT_CONFIRM)
HTSprintf0(&msg, "%s (%c/%c) ", Msg, *msg_yes, *msg_no);
else
HTSprintf0(&msg, "%s (%c) ", Msg, (Dft == YES) ? *msg_yes : *msg_no);
if (LYTraceLogFP) {
CTRACE((tfp, "Confirm: %s", msg));
}
_statusline(msg);
FREE(msg);
while (result < 0) {
int c = LYgetch_single();
#ifdef VMS
if (HadVMSInterrupt) {
HadVMSInterrupt = FALSE;
c = TOUPPER(*msg_no);
}
#endif /* VMS */
if (c == TOUPPER(*msg_yes)) {
result = YES;
} else if (c == TOUPPER(*msg_no)) {
result = NO;
} else if (fallback_y && c == fallback_y) {
result = YES;
} else if (fallback_n && c == fallback_n) {
result = NO;
} else if (LYCharIsINTERRUPT(c)) { /* remember we had ^G or ^C */
conf_cancelled = YES;
result = NO;
} else if (Dft != DFT_CONFIRM) {
result = Dft;
break;
}
}
CTRACE((tfp, "- %s%s.\n",
(result != NO) ? "YES" : "NO",
conf_cancelled ? ", cancelled" : ""));
}
return (result);
}
/* Seek confirmation. HTConfirm()
* ------------------
*/
BOOL HTConfirm(const char *Msg)
{
return (BOOL) HTConfirmDefault(Msg, DFT_CONFIRM);
}
/*
* Ask a post resubmission prompt with some indication of what would
* be resubmitted, useful especially for going backward in history.
* Try to use parts of the address or, if given, the title, depending
* on how much fits on the statusline.
* if_imgmap and if_file indicate how to handle an address that is
* a "LYNXIMGMAP:", or a "file:" URL (presumably the List Page file),
* respectively: 0: auto-deny, 1: auto-confirm, 2: prompt.
* - kw
*/
BOOL confirm_post_resub(const char *address,
const char *title,
int if_imgmap,
int if_file)
{
size_t len1;
const char *msg = CONFIRM_POST_RESUBMISSION_TO;
char buf[240];
char *temp = NULL;
BOOL res;
size_t maxlen = (size_t) (LYcolLimit - 5);
if (!address) {
return (NO);
} else if (isLYNXIMGMAP(address)) {
if (if_imgmap <= 0)
return (NO);
else if (if_imgmap == 1)
return (YES);
else
msg = CONFIRM_POST_LIST_RELOAD;
} else if (isFILE_URL(address)) {
if (if_file <= 0)
return (NO);
else if (if_file == 1)
return (YES);
else
msg = CONFIRM_POST_LIST_RELOAD;
} else if (dump_output_immediately) {
return (NO);
}
if (maxlen >= sizeof(buf))
maxlen = sizeof(buf) - 1;
if ((len1 = strlen(msg)) +
strlen(address) <= maxlen) {
sprintf(buf, msg, address);
return HTConfirm(buf);
}
if (len1 + strlen(temp = HTParse(address, "",
PARSE_ACCESS + PARSE_HOST + PARSE_PATH
+ PARSE_PUNCTUATION)) <= maxlen) {
sprintf(buf, msg, temp);
res = HTConfirm(buf);
FREE(temp);
return (res);
}
FREE(temp);
if (title && (len1 + strlen(title) <= maxlen)) {
sprintf(buf, msg, title);
return HTConfirm(buf);
}
if (len1 + strlen(temp = HTParse(address, "",
PARSE_ACCESS + PARSE_HOST
+ PARSE_PUNCTUATION)) <= maxlen) {
sprintf(buf, msg, temp);
res = HTConfirm(buf);
FREE(temp);
return (res);
}
FREE(temp);
if ((temp = HTParse(address, "", PARSE_HOST)) && *temp &&
len1 + strlen(temp) <= maxlen) {
sprintf(buf, msg, temp);
res = HTConfirm(buf);
FREE(temp);
return (res);
}
FREE(temp);
return HTConfirm(CONFIRM_POST_RESUBMISSION);
}
/* Prompt for answer and get text back. HTPrompt()
* ------------------------------------
*/
char *HTPrompt(const char *Msg, const char *deflt)
{
char *rep = NULL;
char Tmp[200];
Tmp[0] = '\0';
Tmp[sizeof(Tmp) - 1] = '\0';
_statusline(Msg);
if (deflt)
StrNCpy(Tmp, deflt, sizeof(Tmp) - 1);
if (!dump_output_immediately)
LYGetStr(Tmp, VISIBLE, sizeof(Tmp), NORECALL);
StrAllocCopy(rep, Tmp);
return rep;
}
/*
* Prompt for password without echoing the reply. HTPromptPassword()
* ----------------------------------------------
*/
char *HTPromptPassword(const char *Msg)
{
char *result = NULL;
char pw[120];
pw[0] = '\0';
if (!dump_output_immediately) {
_statusline(Msg ? Msg : PASSWORD_PROMPT);
LYGetStr(pw, HIDDEN, sizeof(pw), NORECALL); /* hidden */
StrAllocCopy(result, pw);
} else {
printf("\n%s\n", PASSWORD_REQUIRED);
StrAllocCopy(result, "");
}
return result;
}
/* Prompt both username and password. HTPromptUsernameAndPassword()
* ----------------------------------
*
* On entry,
* Msg is the prompting message.
* *username and
* *password are char pointers which contain default
* or zero-length strings; they are changed
* to point to result strings.
* IsProxy should be TRUE if this is for
* proxy authentication.
*
* If *username is not NULL, it is taken
* to point to a default value.
* Initial value of *password is
* completely discarded.
*
* On exit,
* *username and *password point to newly allocated
* strings -- original strings pointed to by them
* are NOT freed.
*
*/
void HTPromptUsernameAndPassword(const char *Msg,
char **username,
char **password,
int IsProxy)
{
if ((IsProxy == FALSE &&
authentication_info[0] && authentication_info[1]) ||
(IsProxy == TRUE &&
proxyauth_info[0] && proxyauth_info[1])) {
/*
* The -auth or -pauth parameter gave us both the username
* and password to use for the first realm or proxy server,
* respectively, so just use them without any prompting. - FM
*/
StrAllocCopy(*username, (IsProxy ?
proxyauth_info[0] : authentication_info[0]));
if (IsProxy) {
FREE(proxyauth_info[0]);
} else {
FREE(authentication_info[0]);
}
StrAllocCopy(*password, (IsProxy ?
proxyauth_info[1] : authentication_info[1]));
if (IsProxy) {
FREE(proxyauth_info[1]);
} else {
FREE(authentication_info[1]);
}
} else if (dump_output_immediately) {
/*
* We are not interactive and don't have both the
* username and password from the command line,
* but might have one or the other. - FM
*/
if ((IsProxy == FALSE && authentication_info[0]) ||
(IsProxy == TRUE && proxyauth_info[0])) {
/*
* Use the command line username. - FM
*/
StrAllocCopy(*username, (IsProxy ?
proxyauth_info[0] : authentication_info[0]));
if (IsProxy) {
FREE(proxyauth_info[0]);
} else {
FREE(authentication_info[0]);
}
} else {
/*
* Default to "WWWuser". - FM
*/
StrAllocCopy(*username, "WWWuser");
}
if ((IsProxy == FALSE && authentication_info[1]) ||
(IsProxy == TRUE && proxyauth_info[1])) {
/*
* Use the command line password. - FM
*/
StrAllocCopy(*password, (IsProxy ?
proxyauth_info[1] : authentication_info[1]));
if (IsProxy) {
FREE(proxyauth_info[1]);
} else {
FREE(authentication_info[1]);
}
} else {
/*
* Default to a zero-length string. - FM
*/
StrAllocCopy(*password, "");
}
printf("\n%s\n", USERNAME_PASSWORD_REQUIRED);
} else {
/*
* We are interactive and don't have both the
* username and password from the command line,
* but might have one or the other. - FM
*/
if ((IsProxy == FALSE && authentication_info[0]) ||
(IsProxy == TRUE && proxyauth_info[0])) {
/*
* Offer the command line username in the
* prompt for the first realm. - FM
*/
StrAllocCopy(*username, (IsProxy ?
proxyauth_info[0] : authentication_info[0]));
if (IsProxy) {
FREE(proxyauth_info[0]);
} else {
FREE(authentication_info[0]);
}
}
/*
* Prompt for confirmation or entry of the username. - FM
*/
if (Msg != NULL) {
*username = HTPrompt(Msg, *username);
} else {
*username = HTPrompt(USERNAME_PROMPT, *username);
}
if ((IsProxy == FALSE && authentication_info[1]) ||
(IsProxy == TRUE && proxyauth_info[1])) {
/*
* Use the command line password for the first realm. - FM
*/
StrAllocCopy(*password, (IsProxy ?
proxyauth_info[1] : authentication_info[1]));
if (IsProxy) {
FREE(proxyauth_info[1]);
} else {
FREE(authentication_info[1]);
}
} else if (non_empty(*username)) {
/*
* We have a non-zero length username,
* so prompt for the password. - FM
*/
*password = HTPromptPassword(PASSWORD_PROMPT);
} else {
/*
* Return a zero-length password. - FM
*/
StrAllocCopy(*password, "");
}
}
}
/* Confirm a cookie operation. HTConfirmCookie()
* ---------------------------
*
* On entry,
* server is the server sending the Set-Cookie.
* domain is the domain of the cookie.
* path is the path of the cookie.
* name is the name of the cookie.
* value is the value of the cookie.
*
* On exit,
* Returns FALSE on cancel,
* TRUE if the cookie should be set.
*/
BOOL HTConfirmCookie(domain_entry * de, const char *server,
const char *name,
const char *value)
{
int ch;
const char *prompt = ADVANCED_COOKIE_CONFIRMATION;
if (de == NULL)
return FALSE;
/* If the user has specified a list of domains to allow or deny
* from the config file, then they'll already have de->bv set to
* ACCEPT_ALWAYS or REJECT_ALWAYS so we can relax and let the
* default cookie handling code cope with this fine.
*/
/*
* If the user has specified a constant action, don't prompt at all.
*/
if (de->bv == ACCEPT_ALWAYS)
return TRUE;
if (de->bv == REJECT_ALWAYS)
return FALSE;
if (dump_output_immediately) {
/*
* Non-interactive, can't respond. Use the LYSetCookies value
* based on its compilation or configuration setting, or on the
* command line toggle. - FM
*/
return LYSetCookies;
}
/*
* Estimate how much of the cookie we can show.
*/
if (!LYAcceptAllCookies) {
int namelen, valuelen, space_free, percentage;
char *message = 0;
space_free = (LYcolLimit
- (LYstrCells(prompt)
- 10) /* %s and %.*s and %.*s chars */
-(int) strlen(server));
if (space_free < 0)
space_free = 0;
namelen = (int) strlen(name);
valuelen = (int) strlen(value);
if ((namelen + valuelen) > space_free) {
/*
* Argh... there isn't enough space on our single line for
* the whole cookie. Reduce them both by a percentage.
* This should be smarter.
*/
percentage = (100 * space_free) / (namelen + valuelen);
namelen = (percentage * namelen) / 100;
valuelen = (percentage * valuelen) / 100;
}
HTSprintf(&message, prompt, server, namelen, name, valuelen, value);
_statusline(message);
FREE(message);
}
for (;;) {
if (LYAcceptAllCookies) {
ch = 'A';
} else {
ch = LYgetch_single();
#if defined(LOCALE) && defined(HAVE_GETTEXT)
{
#define L_PAREN '('
#define R_PAREN ')'
/*
* Special-purpose workaround for gettext support (we should do
* this in a more general way) -TD
*
* NOTE TO TRANSLATORS: If the prompt has been rendered into
* another language, and if yes/no are distinct, assume the
* translator can make an ordered list in parentheses with one
* capital letter for each as we assumed in HTConfirmDefault().
* The list has to be in the same order as in the original message,
* and the four capital letters chosen to not match those in the
* original unless they have the same position.
*
* Example:
* (Y/N/Always/neVer) - English (original)
* (O/N/Toujours/Jamais) - French
*/
char *p = gettext("Y/N/A/V"); /* placeholder for comment */
const char *s = "YNAV\007\003"; /* see ADVANCED_COOKIE_CONFIRMATION */
if (strchr(s, ch) == 0
&& isalpha(ch)
&& (p = strrchr(prompt, L_PAREN)) != 0) {
CTRACE((tfp, "Looking for %c in %s\n", ch, p));
while (*p != R_PAREN && *p != 0 && isalpha(UCH(*s))) {
if (isalpha(UCH(*p)) && (*p == TOUPPER(*p))) {
CTRACE((tfp, "...testing %c/%c\n", *p, *s));
if (*p == ch) {
ch = *s;
break;
}
++s;
}
++p;
}
}
}
#endif
}
#ifdef VMS
if (HadVMSInterrupt) {
HadVMSInterrupt = FALSE;
ch = 'N';
}
#endif /* VMS */
switch (ch) {
case 'A':
/*
* Set to accept all cookies for this domain.
*/
de->bv = ACCEPT_ALWAYS;
HTUserMsg2(ALWAYS_ALLOWING_COOKIES, de->domain);
return TRUE;
case 'N':
/*
* Reject the cookie.
*/
reject:
HTUserMsg(REJECTING_COOKIE);
return FALSE;
case 'V':
/*
* Set to reject all cookies from this domain.
*/
de->bv = REJECT_ALWAYS;
HTUserMsg2(NEVER_ALLOWING_COOKIES, de->domain);
return FALSE;
case 'Y':
/*
* Accept the cookie.
*/
HTInfoMsg(ALLOWING_COOKIE);
return TRUE;
default:
if (LYCharIsINTERRUPT(ch))
goto reject;
continue;
}
}
}
/* Confirm redirection of POST. HTConfirmPostRedirect()
* ----------------------------
*
* On entry,
* Redirecting_url is the Location.
* server_status is the server status code.
*
* On exit,
* Returns 0 on cancel,
* 1 for redirect of POST with content,
* 303 for redirect as GET without content
*/
int HTConfirmPostRedirect(const char *Redirecting_url, int server_status)
{
int result = -1;
char *show_POST_url = NULL;
char *StatusInfo = 0;
char *url = 0;
int on_screen = 0; /* 0 - show menu
* 1 - show url
* 2 - menu is already on screen */
if (server_status == 303 ||
server_status == 302) {
/*
* HTTP.c should not have called us for either of
* these because we're treating 302 as historical,
* so just return 303. - FM
*/
return 303;
}
if (dump_output_immediately) {
if (server_status == 301) {
/*
* Treat 301 as historical, i.e., like 303 (GET
* without content), when not interactive. - FM
*/
return 303;
} else {
/*
* Treat anything else (e.g., 305, 306 or 307) as too
* dangerous to redirect without confirmation, and thus
* cancel when not interactive. - FM
*/
return 0;
}
}
if (user_mode == NOVICE_MODE) {
on_screen = 2;
LYmove(LYlines - 2, 0);
HTSprintf0(&StatusInfo, SERVER_ASKED_FOR_REDIRECTION, server_status);
LYaddstr(StatusInfo);
LYclrtoeol();
LYmove(LYlines - 1, 0);
HTSprintf0(&url, "URL: %.*s",
(LYcols < 250 ? LYcolLimit - 5 : 250), Redirecting_url);
LYaddstr(url);
LYclrtoeol();
if (server_status == 301) {
_statusline(PROCEED_GET_CANCEL);
} else {
_statusline(PROCEED_OR_CANCEL);
}
} else {
HTSprintf0(&StatusInfo, "%d %.*s",
server_status,
251,
((server_status == 301) ?
ADVANCED_POST_GET_REDIRECT :
ADVANCED_POST_REDIRECT));
StrAllocCopy(show_POST_url, LOCATION_HEADER);
StrAllocCat(show_POST_url, Redirecting_url);
}
while (result < 0) {
int c;
switch (on_screen) {
case 0:
_statusline(StatusInfo);
break;
case 1:
_statusline(show_POST_url);
}
c = LYgetch_single();
switch (c) {
case 'P':
/*
* Proceed with 301 or 307 redirect of POST
* with same method and POST content. - FM
*/
FREE(show_POST_url);
result = 1;
break;
case 7:
case 'C':
/*
* Cancel request.
*/
FREE(show_POST_url);
result = 0;
break;
case 'U':
/*
* Show URL for intermediate or advanced mode.
*/
if (user_mode != NOVICE_MODE) {
if (on_screen == 1) {
on_screen = 0;
} else {
on_screen = 1;
}
}
break;
case 'G':
if (server_status == 301) {
/*
* Treat as 303 (GET without content).
*/
FREE(show_POST_url);
result = 303;
break;
}
/* fall through to default */
default:
/*
* Get another character.
*/
if (on_screen == 1) {
on_screen = 0;
} else {
on_screen = 2;
}
}
}
FREE(StatusInfo);
FREE(url);
return (result);
}
#define okToSleep() (!crawl && !traversal && LYCursesON && !no_pause)
/*
* Sleep for the given message class's time.
*/
void LYSleepAlert(void)
{
if (okToSleep())
LYSleep(AlertSecs);
}
void LYSleepDelay(void)
{
if (okToSleep())
LYSleep(DelaySecs);
}
void LYSleepInfo(void)
{
if (okToSleep())
LYSleep(InfoSecs);
}
void LYSleepMsg(void)
{
if (okToSleep())
LYSleep(MessageSecs);
}
#ifdef USE_CMD_LOGGING
void LYSleepReplay(void)
{
if (okToSleep())
LYSleep(ReplaySecs);
}
#endif /* USE_CMD_LOGGING */
/*
* LYstrerror emulates the ANSI strerror() function.
*/
#ifndef LYStrerror
char *LYStrerror(int code)
{
static char temp[80];
sprintf(temp, "System errno is %d.\r\n", code);
return temp;
}
#endif /* HAVE_STRERROR */