about summary refs log blame commit diff stats
path: root/src/LYExtern.c
blob: 7809ca5fff8859c4ef92b565c4080468bf50b363 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef LYMAINLOOP_H
#define LYMAINLOOP_H

#ifndef HTUTILS_H
#include <HTUtils.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif
#ifdef DISP_PARTIAL
    extern BOOL LYMainLoop_pageDisplay(int line_num);
#endif

    extern BOOLEAN LYOpenTraceLog(void);
    extern const char *LYDownLoadAddress(void);
    extern int LYGetNewline(void);
    extern int mainloop(void);
    extern void HTAddGotoURL(char *url);
    extern void LYChgNewline(int adjust);
    extern void LYCloseTracelog(void);
    extern void LYSetNewline(int value);
    extern void handle_LYK_TRACE_TOGGLE(void);
    extern void handle_LYK_WHEREIS(int cmd, BOOLEAN *refresh_screen);
    extern void repaint_main_statusline(int for_what);

#ifdef SUPPORT_CHDIR
    extern void handle_LYK_CHDIR(void);
#endif

#ifdef __cplusplus
}
#endif
#endif				/* LYMAINLOOP_H */
339'>339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426









































































































































































































































































































































































































































                                                                                
/*
 * $LynxId: LYExtern.c,v 1.48 2010/12/11 13:08:13 tom Exp $
 *
 External application support.
 This feature allows lynx to pass a given URL to an external program.
 It was written for three reasons.
 1) To overcome the deficiency	of Lynx_386 not supporting ftp and news.
    External programs can be used instead by passing the URL.

 2) To allow for background transfers in multitasking systems.
    I use wget for http and ftp transfers via the external command.

 3) To allow for new URLs to be used through lynx.
    URLs can be made up such as mymail: to spawn desired applications
    via the external command.

 See lynx.cfg for other info.
*/

#include <LYUtils.h>

#ifdef USE_EXTERNALS

#include <HTAlert.h>
#include <LYGlobalDefs.h>
#include <LYExtern.h>
#include <LYLeaks.h>
#include <LYCurses.h>
#include <LYReadCFG.h>
#include <LYStrings.h>

#ifdef WIN_EX
/* ASCII char -> HEX digit */
#define ASC2HEXD(x) (((x) >= '0' && (x) <= '9') ?               \
		     ((x) - '0') : (toupper(x) - 'A' + 10))

/* Decodes the forms %xy in a URL to the character the hexadecimal
   code of which is xy. xy are hexadecimal digits from
   [0123456789ABCDEF] (case-insensitive). If x or y are not hex-digits
   or '%' is near '\0', the whole sequence is inserted literally. */

static char *decode_string(char *s)
{
    char *save_s;
    char *p = s;

    save_s = s;
    for (; *s; s++, p++) {
	if (*s != '%')
	    *p = *s;
	else {
	    /* Do nothing if at the end of the string. Or if the chars
	       are not hex-digits. */
	    if (!*(s + 1) || !*(s + 2)
		|| !(isxdigit(UCH(*(s + 1))) && isxdigit(UCH(*(s + 2))))) {
		*p = *s;
		continue;
	    }
	    *p = (char) ((ASC2HEXD(*(s + 1)) << 4) + ASC2HEXD(*(s + 2)));
	    s += 2;
	}
    }
    *p = '\0';
    return save_s;
}
#endif /* WIN_EX */

#ifdef WIN_EX
/*
 *  Delete dangerous characters as local path.
 *  We delete '<>|' and also '%"'.
 *  '%' should be deleted because it's difficut to escape for all cases.
 *  So we can't treat paths which include '%'.
 *  '"' should be deleted because it's a obstacle to quote whole path.
 */
static void delete_danger_characters(char *src)
{
    char *dst;

    for (dst = src; *src != '\0'; src++) {
	if (strchr("<>|%\"", *src) == NULL) {
	    *dst = *src;
	    dst++;
	}
    }
    *dst = '\0';
}

static char *escapeParameter(CONST char *parameter)
{
    size_t i;
    size_t last = strlen(parameter);
    size_t n = 0;
    size_t encoded = 0;
    size_t escaped = 0;
    char *result;
    char *needs_encoded = "<>|";
    char *needs_escaped = "%";
    char *needs_escaped_NT = "%&^";

    for (i = 0; i < last; ++i) {
	if (strchr(needs_encoded, parameter[i]) != NULL) {
	    ++encoded;
	}
	if (system_is_NT) {
	    if (strchr(needs_escaped_NT, parameter[i]) != NULL) {
		++escaped;
	    }
	} else if (strchr(needs_escaped, parameter[i]) != NULL) {
	    ++escaped;
	}
    }

    result = (char *) malloc(last + encoded * 2 + escaped + 1);
    if (result == NULL)
	outofmem(__FILE__, "escapeParameter");

    n = 0;
    for (i = 0; i < last; i++) {
	if (strchr(needs_encoded, parameter[i]) != NULL) {
	    sprintf(result + n, "%%%02X", (unsigned char) parameter[i]);
	    n += 3;
	    continue;
	}
	if (system_is_NT) {
	    if (strchr(needs_escaped_NT, parameter[i]) != NULL) {
		result[n++] = '^';
		result[n++] = parameter[i];
		continue;
	    }
	} else if (strchr(needs_escaped, parameter[i]) != NULL) {
	    result[n++] = '%';	/* parameter[i] is '%' */
	    result[n++] = parameter[i];
	    continue;
	}
	result[n++] = parameter[i];
    }
    result[n] = '\0';

    return result;
}
#endif /* WIN_EX */

static void format(char **result,
		   char *fmt,
		   char *parm)
{
    *result = NULL;
    HTAddParam(result, fmt, 1, parm);
    HTEndParam(result, fmt, 1);
}

/*
 * Format the given command into a buffer, returning the resulting string.
 *
 * It is too dangerous to leave any URL that may come along unquoted.  They
 * often contain '&', ';', and '?' chars, and who knows what else may occur.
 * Prevent spoofing of the shell.  Dunno how this needs to be modified for VMS
 * or DOS.  - kw
 */
static char *format_command(char *command,
			    char *param)
{
    char *cmdbuf = NULL;

#if defined(WIN_EX)
    char pram_string[LY_MAXPATH];
    char *escaped = NULL;

    if (strnicmp("file://localhost/", param, 17) == 0) {
	/* decode local path parameter for programs to be
	   able to interpret - TH */
	LYStrNCpy(pram_string, param, sizeof(pram_string) - 1);
	decode_string(pram_string);
	param = pram_string;
    } else {
	/* encode or escape URL parameter - TH */
	escaped = escapeParameter(param);
	param = escaped;
    }

    if (isMAILTO_URL(param)) {
	format(&cmdbuf, command, param + 7);
    } else if (strnicmp("telnet://", param, 9) == 0) {
	char host[sizeof(pram_string)];
	int last_pos;

	LYStrNCpy(host, param + 9, sizeof(host));
	last_pos = strlen(host) - 1;
	if (last_pos > 1 && host[last_pos] == '/')
	    host[last_pos] = '\0';

	format(&cmdbuf, command, host);
    } else if (strnicmp("file://localhost/", param, 17) == 0) {
	char e_buff[LY_MAXPATH], *p;

	p = param + 17;
	delete_danger_characters(p);
	*e_buff = 0;
	if (strchr(p, ':') == NULL) {
	    sprintf(e_buff, "%.3s/", windows_drive);
	}
	strncat(e_buff, p, sizeof(e_buff) - strlen(e_buff) - 1);
	p = strrchr(e_buff, '.');
	if (p) {
	    trimPoundSelector(p);
	}

	/* Less ==> short filename with backslashes,
	 * less ==> long filename with forward slashes, may be quoted
	 */
	if (ISUPPER(command[0])) {
	    char *short_name = HTDOS_short_name(e_buff);

	    p = quote_pathname(short_name);
	    format(&cmdbuf, command, p);
	    FREE(p);
	} else {
	    p = quote_pathname(e_buff);
	    format(&cmdbuf, command, p);
	    FREE(p);
	}
    } else {
	format(&cmdbuf, command, param);
    }
    FREE(escaped);
#else
    format(&cmdbuf, command, param);
#endif
    return cmdbuf;
}

/*
 * Find the EXTERNAL command which matches the given name 'param'.  If there is
 * more than one possibility, make a popup menu of the matching commands and
 * allow the user to select one.  Return the selected command.
 */
static char *lookup_external(char *param,
			     int only_overriders)
{
    int pass, num_disabled, num_matched, num_choices, cur_choice;
    size_t length = 0;
    char *cmdbuf = NULL;
    char **actions = 0;
    char **choices = 0;
    lynx_list_item_type *ptr = 0;

    for (pass = 0; pass < 2; pass++) {
	num_disabled = 0;
	num_matched = 0;
	num_choices = 0;
	for (ptr = externals; ptr != 0; ptr = ptr->next) {

	    if (match_item_by_name(ptr, param, only_overriders)) {
		++num_matched;
		CTRACE((tfp, "EXTERNAL: '%s' <==> '%s'\n", ptr->name, param));
		if (no_externals && !ptr->always_enabled && !only_overriders) {
		    ++num_disabled;
		} else {
		    if (pass == 0) {
			length++;
		    } else if (pass != 0) {
			cmdbuf = format_command(ptr->command, param);
			if (length > 1) {
			    actions[num_choices] = cmdbuf;
			    choices[num_choices] =
				format_command(ptr->menu_name, param);
			}
		    }
		    num_choices++;
		}
	    }
	}
	if (length > 1) {
	    if (pass == 0) {
		actions = typecallocn(char *, length + 1);
		choices = typecallocn(char *, length + 1);
	    } else {
		actions[num_choices] = 0;
		choices[num_choices] = 0;
	    }
	}
    }

    if (num_disabled != 0
	&& num_disabled == num_matched) {
	HTUserMsg(EXTERNALS_DISABLED);
    } else if (num_choices > 1) {
	int old_y, old_x;

	LYGetYX(old_y, old_x);
	cur_choice = LYhandlePopupList(-1,
				       0,
				       old_x,
				       (const char **) choices,
				       -1,
				       -1,
				       FALSE,
				       TRUE);
	wmove(LYwin, old_y, old_x);
	CTRACE((tfp, "selected choice %d of %d\n", cur_choice, num_choices));
	if (cur_choice < 0) {
	    HTInfoMsg(CANCELLED);
	    cmdbuf = 0;
	}
	for (pass = 0; choices[pass] != 0; pass++) {
	    if (pass == cur_choice) {
		cmdbuf = actions[pass];
	    } else {
		FREE(actions[pass]);
	    }
	    FREE(choices[pass]);
	}
	FREE(actions);
	FREE(choices);
    }
    return cmdbuf;
}

BOOL run_external(char *param,
		  int only_overriders)
{
#ifdef WIN_EX
    int status;
#endif
    int redraw_flag = TRUE;
    char *cmdbuf = NULL;
    BOOL found = FALSE;
    int confirmed = TRUE;

    if (externals == NULL)
	return 0;

#ifdef WIN_EX			/* 1998/01/26 (Mon) 09:16:13 */
    if (param == NULL) {
	HTInfoMsg(gettext("External command is null"));
	return 0;
    }
#endif

    cmdbuf = lookup_external(param, only_overriders);
    if (non_empty(cmdbuf)) {
#ifdef WIN_EX			/* 1997/10/17 (Fri) 14:07:50 */
	int len;
	char buff[LY_MAXPATH];

	CTRACE((tfp, "Lynx EXTERNAL: '%s'\n", cmdbuf));
#ifdef WIN_GUI			/* 1997/11/06 (Thu) 14:17:15 */
	confirmed = MessageBox(GetForegroundWindow(), cmdbuf,
			       "Lynx (EXTERNAL COMMAND EXEC)",
			       MB_ICONQUESTION | MB_SETFOREGROUND | MB_OKCANCEL)
	    != IDCANCEL;
#else
	confirmed = HTConfirm(LYElideString(cmdbuf, 40)) != NO;
#endif
	if (confirmed) {
	    len = strlen(cmdbuf);
	    if (len > 255) {
		sprintf(buff, "Lynx: command line too long (%d > 255)", len);
#ifdef WIN_GUI			/* 1997/11/06 (Thu) 14:17:02 */
		MessageBox(GetForegroundWindow(), buff,
			   "Lynx (EXTERNAL COMMAND EXEC)",
			   MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_OK);
		SetConsoleTitle("Lynx for Win32");
#else
		HTConfirm(LYElideString(buff, 40));
#endif
		confirmed = FALSE;
	    } else {
		SetConsoleTitle(cmdbuf);
	    }
	}

	if (strnicmp(cmdbuf, "start ", 6) == 0)
	    redraw_flag = FALSE;
	else
	    redraw_flag = TRUE;
#else
	HTUserMsg(cmdbuf);
#endif
	found = TRUE;
	if (confirmed) {
	    if (redraw_flag) {
		stop_curses();
		fflush(stdout);
	    }

	    /* command running. */
#ifdef WIN_EX			/* 1997/10/17 (Fri) 14:07:50 */
#if defined(__CYGWIN__) || defined(__MINGW32__)
	    status = system(cmdbuf);
#else
	    status = xsystem(cmdbuf);
#endif
	    if (status != 0) {
		sprintf(buff,
			"EXEC code = %04x (%2d, %2d)\r\n"
			"'%s'",
			status, (status / 256), (status & 0xff),
			cmdbuf);
#ifdef SH_EX			/* WIN_GUI for ERROR only */
		MessageBox(GetForegroundWindow(), buff,
			   "Lynx (EXTERNAL COMMAND EXEC)",
			   MB_ICONSTOP | MB_SETFOREGROUND | MB_OK);
#else
		HTConfirm(LYElideString(buff, 40));
#endif /* 1 */
	    }
#else /* Not WIN_EX */
	    LYSystem(cmdbuf);
#endif /* WIN_EX */

#if defined(WIN_EX)
	    SetConsoleTitle("Lynx for Win32");
#endif
	    if (redraw_flag) {
		fflush(stdout);
		start_curses();
	    }
	}
    }

    FREE(cmdbuf);
    return found;
}
#endif /* USE_EXTERNALS */