#include "HTUtils.h"
#include "tcp.h"
#include "HTAnchor.h" /* Anchor class */
#include "HTAccess.h"
#include "HTParse.h"
#include "LYCurses.h"
#include "GridText.h"
#include "LYGlobalDefs.h"
#include "LYUtils.h"
#include "LYCharSets.h"
#include "LYCharUtils.h"
#include "HTAlert.h"
#include "LYSignal.h"
#include "LYGetFile.h"
#include "LYPrint.h"
#include "LYHistory.h"
#include "LYStrings.h"
#include "LYClean.h"
#include "LYDownload.h"
#include "LYNews.h"
#include "LYMail.h"
#include "LYSystem.h"
#include "LYKeymap.h"
#include "LYBookmark.h"
#include "LYMap.h"
#ifdef VMS
#include "HTVMSUtils.h"
#endif /* VMS */
#ifdef DIRED_SUPPORT
#include "LYLocal.h"
#endif /* DIRED_SUPPORT */
#include "LYexit.h"
#include "LYLeaks.h"
#ifndef VMS
#ifdef SYSLOG_REQUESTED_URLS
#include <syslog.h>
#endif /* SYSLOG_REQUESTED_URLS */
#endif /* !VMS */
#define FREE(x) if (x) {free(x); x = NULL;}
PRIVATE int fix_http_urls PARAMS((document *doc));
extern char * WWW_Download_File;
extern BOOL redirect_post_content;
#ifdef VMS
extern BOOLEAN LYDidRename;
#endif /* VMS */
#ifdef DIRED_SUPPORT
PRIVATE char * LYSanctify ARGS1(
char *, href)
{
int i;
char *p, *cp, *tp;
char address_buffer[1024];
i = (strlen(href) - 1);
while (i && href[i] == '/') href[i--] = '\0';
if ((cp = (char *)strchr(href,'~')) != NULL) {
if (!strncmp(href, "file://localhost/", 17))
tp = (href + 17);
else
tp = (href + 5);
if ((cp - tp) && *(cp-1) != '/')
return href;
LYstrncpy(address_buffer, href, (cp - href));
if (address_buffer[(strlen(address_buffer) - 1)] == '/')
address_buffer[(strlen(address_buffer) - 1)] = '\0';
p = (char *)Home_Dir();
strcat(address_buffer, p);
if (strlen(++cp))
strcat(address_buffer, cp);
if (strcmp(href, address_buffer))
StrAllocCopy(href, address_buffer);
}
return href;
}
#endif /* DIRED_SUPPORT */
PUBLIC BOOLEAN getfile ARGS1(
document *, doc)
{
int url_type = 0;
char *cp = NULL;
char *temp = NULL;
DocAddress WWWDoc; /* a WWW absolute doc address struct */
Try_Redirected_URL:
/*
* Load the WWWDoc struct in case we need to use it.
*/
WWWDoc.address = doc->address;
WWWDoc.post_data = doc->post_data;
WWWDoc.post_content_type = doc->post_content_type;
WWWDoc.bookmark = doc->bookmark;
WWWDoc.isHEAD = doc->isHEAD;
WWWDoc.safe = doc->safe;
/*
* Reset WWW_Download_File just in case.
*/
FREE(WWW_Download_File);
/*
* Reset redirect_post_content just in case.
*/
redirect_post_content = FALSE;
if (TRACE) {
fprintf(stderr,"LYGetFile: getting %s\n\n",doc->address);
}
/*
* Protect against denial of service attacks
* via the port 19 CHARGEN service, and block
* connections to the port 25 ESMTP service. - FM
*/
if ((temp = HTParse(doc->address, "", PARSE_HOST)) != NULL &&
strlen(temp) > 3) {
char *cp1;
if ((cp1 = strchr(temp, '@')) == NULL)
cp1 = temp;
if ((cp = strrchr(cp1, ':')) != NULL) {
int value;
cp++;
if (sscanf(cp, "%d", &value) == 1) {
if (value == 19) {
HTAlert(PORT_NINETEEN_INVALID);
FREE(temp);
return(NULLFILE);
}
if (value == 25) {
HTAlert(PORT_TWENTYFIVE_INVALID);
FREE(temp);
return(NULLFILE);
}
}
}
}
cp = NULL;
FREE(temp);
/*
* Check to see if this is a universal document ID
* that lib WWW wants to handle.
*
* Some special URL's we handle ourselves. :)
*/
if ((url_type = is_url(doc->address)) != 0) {
if (LYValidate && !LYPermitURL) {
if (!(url_type == HTTP_URL_TYPE ||
url_type == HTTPS_URL_TYPE ||
url_type == LYNXHIST_URL_TYPE ||
url_type == LYNXKEYMAP_URL_TYPE ||
url_type == LYNXIMGMAP_URL_TYPE ||
url_type == LYNXCOOKIE_URL_TYPE ||
0==strncasecomp(WWWDoc.address, helpfilepath,
strlen(helpfilepath)) ||
0==strncasecomp(WWWDoc.address, aboutfilepath,
strlen(aboutfilepath)) ||
(lynxlistfile != NULL &&
0==strncasecomp(WWWDoc.address, lynxlistfile,
strlen(lynxlistfile))) ||
(lynxlinksfile != NULL &&
0==strncasecomp(WWWDoc.address, lynxlinksfile,
strlen(lynxlinksfile))) ||
(lynxjumpfile != NULL &&
0==strncasecomp(WWWDoc.address, lynxjumpfile,
strlen(lynxjumpfile))))) {
_statusline(NOT_HTTP_URL_OR_ACTION);
sleep(MessageSecs);
return(NULLFILE);
}
}
if (traversal) {
/*
* Only traverse http URLs.
*/
if (url_type != HTTP_URL_TYPE &&
url_type != LYNXIMGMAP_URL_TYPE)
return(NULLFILE);
} else if (check_realm && !LYPermitURL && !LYJumpFileURL) {
if (!(0==strncmp(startrealm, WWWDoc.address,
strlen(startrealm)) ||
url_type == LYNXHIST_URL_TYPE ||
url_type == LYNXKEYMAP_URL_TYPE ||
url_type == LYNXIMGMAP_URL_TYPE ||
url_type == LYNXCOOKIE_URL_TYPE ||
url_type == LYNXPRINT_URL_TYPE ||
url_type == LYNXDOWNLOAD_URL_TYPE ||
url_type == MAILTO_URL_TYPE ||
url_type == NEWSPOST_URL_TYPE ||
url_type == NEWSREPLY_URL_TYPE ||
url_type == SNEWSPOST_URL_TYPE ||
url_type == SNEWSREPLY_URL_TYPE ||
(!LYUserSpecifiedURL &&
(url_type == LYNXEXEC_URL_TYPE ||
url_type == LYNXPROG_URL_TYPE ||
url_type == LYNXCGI_URL_TYPE)) ||
(WWWDoc.bookmark != NULL &&
*WWWDoc.bookmark != '\0') ||
0==strncasecomp(WWWDoc.address, helpfilepath,
strlen(helpfilepath)) ||
0==strncasecomp(WWWDoc.address, aboutfilepath,
strlen(aboutfilepath)) ||
(lynxlistfile != NULL &&
0==strncasecomp(WWWDoc.address, lynxlistfile,
strlen(lynxlistfile))) ||
(lynxjumpfile != NULL &&
0==strncasecomp(WWWDoc.address, lynxjumpfile,
strlen(lynxjumpfile))))) {
_statusline(NOT_IN_STARTING_REALM);
sleep(MessageSecs);
return(NULLFILE);
}
}
#ifndef VMS
#ifdef SYSLOG_REQUESTED_URLS
syslog(LOG_INFO|LOG_LOCAL5, "%s", doc->address);
#endif /* SYSLOG_REQUESTED_URLS */
#endif /* !VMS */
if (url_type == UNKNOWN_URL_TYPE ||
url_type == AFS_URL_TYPE ||
url_type == PROSPERO_URL_TYPE) {
HTAlert(UNSUPPORTED_URL_SCHEME);
return(NULLFILE);
} else if (url_type == DATA_URL_TYPE) {
HTAlert(UNSUPPORTED_DATA_URL);
return(NULLFILE);
} else if (url_type == LYNXPRINT_URL_TYPE) {
return(printfile(doc));
} else if (url_type == NEWSPOST_URL_TYPE ||
url_type == NEWSREPLY_URL_TYPE ||
url_type == SNEWSPOST_URL_TYPE ||
url_type == SNEWSREPLY_URL_TYPE) {
if (no_newspost) {
_statusline(NEWSPOSTING_DISABLED);
sleep(MessageSecs);
return(NULLFILE);
} else {
HTLoadAbsolute(&WWWDoc);
return(NULLFILE);
}
} else if (url_type == LYNXDOWNLOAD_URL_TYPE) {
LYDownload(doc->address);
#ifdef VMS
if (LYDidRename) {
/*
* The temporary file was saved to disk via a
* rename(), so we can't access the temporary
* file again via the download menu. Clear the
* flag, and return NULLFILE to pop. - FM
*/
LYDidRename = FALSE;
return(NULLFILE);
} else {
return(NORMAL);
}
#else
return(NORMAL);
#endif /* VMS */
} else if (url_type == LYNXDIRED_URL_TYPE) {
#ifdef DIRED_SUPPORT
if (no_dired_support) {
_statusline(DIRED_DISABLED);
sleep(MessageSecs);
return(NULLFILE);
} else {
local_dired(doc);
WWWDoc.address = doc->address;
WWWDoc.post_data = doc->post_data;
WWWDoc.post_content_type = doc->post_content_type;
WWWDoc.bookmark = doc->bookmark;
WWWDoc.isHEAD = doc->isHEAD;
WWWDoc.safe = doc->safe;
if (!HTLoadAbsolute(&WWWDoc))
return(NOT_FOUND);
return(NORMAL);
}
#else
_statusline(DIRED_DISABLED);
sleep(MessageSecs);
return(NULLFILE);
#endif /* DIRED_SUPPORT */
} else if (url_type == LYNXHIST_URL_TYPE) {
/*
* 'doc' will change to the new file
* if we had a successful LYpop_num(),
* and the return value will be FALSE
* if we had a cancel. - FM
*/
if ((historytarget(doc) == FALSE) ||
!doc || !doc->address) {
HTMLSetCharacterHandling(current_char_set);
return(NOT_FOUND);
}
/*
* We changed it so reload.
*/
WWWDoc.address = doc->address;
WWWDoc.post_data = doc->post_data;
WWWDoc.post_content_type = doc->post_content_type;
WWWDoc.bookmark = doc->bookmark;
WWWDoc.isHEAD = doc->isHEAD;
WWWDoc.safe = doc->safe;
if (!HTLoadAbsolute(&WWWDoc)) {
HTMLSetCharacterHandling(current_char_set);
return(NOT_FOUND);
}
HTMLSetCharacterHandling(current_char_set);
return(NORMAL);
} else if (url_type == LYNXEXEC_URL_TYPE ||
url_type == LYNXPROG_URL_TYPE) {
#ifdef EXEC_LINKS
if (no_exec &&
!exec_ok(HTLoadedDocumentURL(),
doc->address+9, ALWAYS_EXEC_PATH)) {
statusline(EXECUTION_DISABLED);
sleep(MessageSecs);
} else if (no_bookmark_exec &&
HTLoadedDocumentBookmark()) {
statusline(BOOKMARK_EXEC_DISABLED);
sleep(MessageSecs);
} else if (local_exec || (local_exec_on_local_files &&
exec_ok(HTLoadedDocumentURL(),
doc->address+9, EXEC_PATH))) {
char *p, addressbuf[1024];
/*
* Bug puts slash on end if none is in the string.
*/
char *last_slash = strrchr(doc->address,'/');
if (last_slash-doc->address==strlen(doc->address)-1)
doc->address[strlen(doc->address)-1] = '\0';
p = doc->address;
/*
* Convert '~' to $HOME.
*/
if ((cp = strchr(doc->address, '~'))) {
strncpy(addressbuf, doc->address, cp-doc->address);
addressbuf[cp - doc->address] = '\0';
#ifdef VMS
p = HTVMS_wwwName((char *)Home_Dir());
#else
p = (char *)Home_Dir();
#endif /* VMS */
strcat(addressbuf, p);
strcat(addressbuf, cp+1);
p = addressbuf;
}
/*
* Show URL before executing it.
*/
statusline(doc->address);
sleep(InfoSecs);
stop_curses();
/*
* Run the command.
*/
if (strstr(p,"//") == p+9)
system(p+11);
else
system(p+9);
if (url_type != LYNXPROG_URL_TYPE) {
/*
* Make sure user gets to see screen output.
*/
#ifndef VMS
signal(SIGINT, SIG_IGN);
#endif /* !VMS */
printf("\n%s", RETURN_TO_LYNX);
fflush(stdout);
LYgetch();
#ifdef VMS
{
extern BOOLEAN HadVMSInterrupt;
HadVMSInterrupt = FALSE;
}
#endif /* VMS */
}
start_curses();
LYAddVisitedLink(doc);
} else {
char buf[512];
sprintf(buf,
EXECUTION_DISABLED_FOR_FILE,
key_for_func(LYK_OPTIONS));
_statusline(buf);
sleep(AlertSecs);
}
#else /* no exec_links */
_statusline(EXECUTION_NOT_COMPILED);
sleep(MessageSecs);
#endif /* EXEC_LINKS */
return(NULLFILE);
} else if (url_type == MAILTO_URL_TYPE) {
if (no_mail) {
_statusline(MAIL_DISABLED);
sleep(MessageSecs);
} else {
HTParentAnchor *tmpanchor;
CONST char *title;
title = "";
if ((tmpanchor = HTAnchor_parent(
HTAnchor_findAddress(&WWWDoc)
)) != NULL) {
if (HTAnchor_title(tmpanchor)) {
title = HTAnchor_title(tmpanchor);
}
}
cp = (char *)strchr(doc->address,':')+1;
reply_by_mail(cp,
((HTMainAnchor && !LYUserSpecifiedURL) ?
(char *)HTMainAnchor->address :
(char *)doc->address),
(char *)title);
}
return(NULLFILE);
/*
* From here on we could have a remote host,
* so check if that's allowed.
*/
} else if (local_host_only &&
url_type != NEWS_URL_TYPE &&
url_type != LYNXKEYMAP_URL_TYPE &&
url_type != LYNXIMGMAP_URL_TYPE &&
url_type != LYNXCOOKIE_URL_TYPE &&
url_type != LYNXCGI_URL_TYPE &&
!(LYisLocalHost(doc->address) ||
LYisLocalAlias(doc->address))) {
statusline(ACCESS_ONLY_LOCALHOST);
sleep(MessageSecs);
return(NULLFILE);
/*
* Disable www telnet access if not telnet_ok.
*/
} else if (url_type == TELNET_URL_TYPE ||
url_type == TN3270_URL_TYPE ||
url_type == TELNET_GOPHER_URL_TYPE) {
if (!telnet_ok) {
_statusline(TELNET_DISABLED);
sleep(MessageSecs);
} else if (no_telnet_port && strchr(doc->address+7, ':')) {
statusline(TELNET_PORT_SPECS_DISABLED);
sleep(MessageSecs);
} else {
stop_curses();
HTLoadAbsolute(&WWWDoc);
start_curses();
fflush(stdout);
LYAddVisitedLink(doc);
}
return(NULLFILE);
/*
* Disable www news access if not news_ok.
*/
} else if (url_type == NEWS_URL_TYPE && !news_ok) {
_statusline(NEWS_DISABLED);
sleep(MessageSecs);
return(NULLFILE);
} else if (url_type == RLOGIN_URL_TYPE) {
if (!rlogin_ok) {
statusline(RLOGIN_DISABLED);
sleep(MessageSecs);
} else {
stop_curses();
HTLoadAbsolute(&WWWDoc);
fflush(stdout);
start_curses();
LYAddVisitedLink(doc);
}
return(NULLFILE);
/*
* If its a gopher index type and there isn't a search
* term already attached then do this. Otherwise
* just load it!
*/
} else if (url_type == INDEX_GOPHER_URL_TYPE &&
strchr(doc->address,'?') == NULL) {
int status;
/*
* Make sure we don't have a gopher+ escaped tab
* instead of a gopher0 question mark delimiting
* the search term. - FM
*/
if ((cp = strstr(doc->address, "%09")) != NULL) {
*cp = '\0';
StrAllocCopy(temp, doc->address);
cp += 3;
if (*cp && strncmp(cp, "%09", 3)) {
StrAllocCat(temp, "?");
StrAllocCat(temp, cp);
if ((cp = strstr(temp, "%09")) != NULL) {
*cp = '\0';
}
}
StrAllocCopy(doc->address, temp);
FREE(temp);
goto Try_Redirected_URL;
}
/*
* Load it because the do_www_search routine
* uses the base url of the currently loaded
* document :(
*/
if (!HTLoadAbsolute(&WWWDoc))
return(NOT_FOUND);
status = do_www_search(doc);
if (status == NULLFILE) {
LYpop(doc);
WWWDoc.address = doc->address;
WWWDoc.post_data = doc->post_data;
WWWDoc.post_content_type = doc->post_content_type;
WWWDoc.bookmark = doc->bookmark;
WWWDoc.isHEAD = doc->isHEAD;
WWWDoc.safe = doc->safe;
status = HTLoadAbsolute(&WWWDoc);
}
return(status);
} else {
if (url_type == FTP_URL_TYPE && !ftp_ok) {
statusline(FTP_DISABLED);
sleep(MessageSecs);
return(NULLFILE);
}
if (url_type == HTML_GOPHER_URL_TYPE) {
char *tmp=NULL;
/*
* If tuple's Path=GET%20/... convert to an http URL.
*/
if ((cp=strchr(doc->address+9, '/')) != NULL &&
0==strncmp(++cp, "hGET%20/", 8)) {
StrAllocCopy(tmp, "http://");
if (TRACE)
fprintf(stderr,
"LYGetFile: URL %s\nchanged to ",
doc->address);
*cp = '\0';
StrAllocCat(tmp, doc->address+9);
/*
* If the port is defaulted, it should stay 70.
*/
if (strchr(tmp+6, ':') == NULL) {
StrAllocCat(tmp, "70/");
tmp[strlen(tmp)-4] = ':';
}
if (strlen(cp+7) > 1)
StrAllocCat(tmp, cp+8);
StrAllocCopy(doc->address, tmp);
if (TRACE)
fprintf(stderr, "%s\n",doc->address);
FREE(tmp);
url_type = HTTP_URL_TYPE;
}
}
if (url_type == HTTP_URL_TYPE ||
url_type == HTTPS_URL_TYPE ||
url_type == FTP_URL_TYPE ||
url_type == CSO_URL_TYPE)
fix_http_urls(doc);
WWWDoc.address = doc->address; /* possible reload */
#ifdef DIRED_SUPPORT
lynx_edit_mode = FALSE;
if (url_type == FILE_URL_TYPE) {
doc->address = LYSanctify(doc->address);
WWWDoc.address = doc->address;
}
#else
if (url_type == FILE_URL_TYPE &&
(cp=strstr(doc->address, "/~")) != NULL) {
*cp = '\0';
cp += 2;
StrAllocCopy(temp, doc->address);
#ifdef VMS
StrAllocCat(temp, HTVMS_wwwName((char *)Home_Dir()));
#else
StrAllocCat(temp, Home_Dir());
#endif /* VMS */
if (*cp)
StrAllocCat(temp, cp);
StrAllocCopy(doc->address, temp);
FREE(temp);
WWWDoc.address = doc->address;
}
#endif /* DIRED_SUPPORT */
if (TRACE)
sleep(MessageSecs);
user_message(WWW_WAIT_MESSAGE, doc->address);
#ifdef NOTDEFINED
sleep(InfoSecs);
#endif /* NOTDEFINED */
if (TRACE) {
#ifdef USE_SLANG
if (LYCursesON) {
addstr("*\n");
refresh();
}
#endif /* USE_SLANG */
fprintf(stderr,"\n");
}
if (!HTLoadAbsolute(&WWWDoc)) {
/*
* Check for redirection.
*/
if (use_this_url_instead != NULL) {
if (!is_url(use_this_url_instead)) {
/*
* The server did not return a complete
* URL in its Location: header, probably
* due to a FORM or other CGI script written
* by someone who doesn't know that the http
* protocol requires that it be a complete
* URL, or using a server which does not treat
* such a redirect string from the script as
* an instruction to resolve it versus the
* initial request, check authentication with
* that URL, and then act on it without
* returning redirection to us. We'll
* violate the http protocol and resolve it
* ourselves using the URL of the original
* request as the BASE, rather than doing
* the RIGHT thing and returning an invalid
* address message. - FM
*/
HTAlert(LOCATION_NOT_ABSOLUTE);
temp = HTParse(use_this_url_instead,
WWWDoc.address,
PARSE_ALL);
if (temp && *temp) {
StrAllocCopy(use_this_url_instead, temp);
}
FREE(temp);
}
HTMLSetCharacterHandling(current_char_set);
if (TRACE)
sleep(MessageSecs);
_user_message("Using %s", use_this_url_instead);
sleep(InfoSecs);
if (TRACE)
fprintf(stderr, "\n");
StrAllocCopy(doc->address,
use_this_url_instead);
FREE(use_this_url_instead);
if (redirect_post_content == FALSE) {
/*
* Freeing the content also yields
* a GET request. - FM
*/
FREE(doc->post_data);
FREE(doc->post_content_type);
}
/*
* Go to top to check for URL's which get
* special handling and/or security checks
* in Lynx. - FM
*/
goto Try_Redirected_URL;
}
HTMLSetCharacterHandling(current_char_set);
return(NOT_FOUND);
}
lynx_mode = NORMAL_LYNX_MODE;
/*
* Some URL's don't actually return a document
* compare doc->address with the document that is
* actually loaded and return NULL if not
* loaded. If www_search_result is not -1
* then this is a reference to a named anchor
* within the same document. Do NOT return
* NULL.
*/
{
char *pound;
/*
* Check for #selector.
*/
pound = (char *)strchr(doc->address, '#');
/*
* Check to see if there is a temp
* file waiting for us to download.
*/
if (WWW_Download_File) {
HTParentAnchor *tmpanchor;
char *fname = NULL;
HTMLSetCharacterHandling(current_char_set);
/*
* Check for a suggested filename from
* the Content-Dispostion header. - FM
*/
if (((tmpanchor = HTAnchor_parent(
HTAnchor_findAddress(&WWWDoc)
)) != NULL) &&
HTAnchor_SugFname(tmpanchor) != NULL) {
StrAllocCopy(fname,
HTAnchor_SugFname(tmpanchor));
} else {
StrAllocCopy(fname, doc->address);
}
if (LYdownload_options(&fname,
WWW_Download_File) < 0) {
FREE(fname);
return(NOT_FOUND);
}
LYAddVisitedLink(doc);
StrAllocCopy(doc->address, fname);
FREE(fname);
WWWDoc.address = doc->address;
FREE(doc->post_data);
WWWDoc.post_data = NULL;
FREE(doc->post_content_type);
WWWDoc.post_content_type = NULL;
WWWDoc.bookmark = doc->bookmark = FALSE;
WWWDoc.isHEAD = doc->isHEAD = FALSE;
WWWDoc.safe = doc->safe = FALSE;
HTOutputFormat = WWW_PRESENT;
if (!HTLoadAbsolute(&WWWDoc))
return(NOT_FOUND);
else
return(NORMAL);
} else if (pound == NULL &&
/*
* HTAnchor hash-table searches are now
* case-sensitive (hopefully, without
* anchor deletion problems), so this
* is too. - FM
*/
(strcmp(doc->address,
HTLoadedDocumentURL()) ||
/*
* Also check the post_data elements. - FM
*/
strcmp((doc->post_data ?
doc->post_data : ""),
HTLoadedDocumentPost_data()) ||
/*
* Also check the isHEAD element. - FM
*/
doc->isHEAD != HTLoadedDocumentIsHEAD())) {
HTMLSetCharacterHandling(current_char_set);
/*
* Nothing needed to be shown.
*/
LYAddVisitedLink(doc);
return(NULLFILE);
} else {
/*
* May set www_search_result.
*/
if (pound != NULL)
HTFindPoundSelector(pound+1);
HTMLSetCharacterHandling(current_char_set);
return(NORMAL);
}
}
}
} else {
if (TRACE)
sleep(MessageSecs);
_user_message("Badly formed address %s",doc->address);
if (TRACE)
fprintf(stderr,"\n");
sleep(MessageSecs);
return(NULLFILE);
}
}
/*
* The user wants to select a link by number.
* If follow_link_number returns DO_LINK_STUFF do_link
* will be run immeditely following its execution.
* If follow_link_number returns PRINT_ERROR an error message
* will be given to the user.
* If follow_link_number returns DO_FORMS_STUFF some forms stuff
* will be done.
* If follow_link_number returns DO_NOTHING nothing special
* will run after it.
*/
PUBLIC int follow_link_number ARGS2(
int, c,
int, cur)
{
char temp[120];
int link_number;
temp[0] = c;
temp[1] = '\0';
_statusline(FOLLOW_LINK_NUMBER);
/*
* Get the number from the user.
*/
if (LYgetstr(temp, VISIBLE, sizeof(temp), NORECALL) < 0 || *temp == 0) {
_statusline(CANCELLED);
sleep(InfoSecs);
return(DO_NOTHING);
}
link_number = atoi(temp);
if (link_number > 0) {
/*
* Get the lname, and hightext, direct from
* www structures and add it to the cur link
* so that we can pass it transparently on to
* get_file(). This is done so that you may select a link
* anywhere in the document, whether it is displayed
* on the screen or not!
*/
if (HTGetLinkInfo(link_number,
&links[cur].hightext,
&links[cur].lname)) {
links[cur].type = WWW_LINK_TYPE;
return(DO_LINK_STUFF);
} else {
return(PRINT_ERROR);
}
} else {
return(PRINT_ERROR);
}
}
#if defined(EXEC_LINKS) || defined(LYNXCGI_LINKS)
struct trust {
char *src;
char *path;
int type;
struct trust *next;
};
static struct trust trusted_exec_default = {
"file://localhost/", "", EXEC_PATH, NULL
};
static struct trust always_trusted_exec_default = {
"none", "", ALWAYS_EXEC_PATH, NULL
};
static struct trust trusted_cgi_default = {
"", "", CGI_PATH, NULL
};
static struct trust *trusted_exec = &trusted_exec_default;
static struct trust *always_trusted_exec = &always_trusted_exec_default;
static struct trust *trusted_cgi = &trusted_cgi_default;
PRIVATE void LYTrusted_free NOARGS
{
struct trust *cur;
struct trust *next;
if (trusted_exec != &trusted_exec_default) {
cur = trusted_exec;
while (cur) {
FREE(cur->src);
FREE(cur->path);
next = cur->next;
FREE(cur);
cur = next;
}
}
if (always_trusted_exec != &always_trusted_exec_default) {
cur = always_trusted_exec;
while (cur) {
FREE(cur->src);
FREE(cur->path);
next = cur->next;
FREE(cur);
cur = next;
}
}
if (trusted_cgi != &trusted_cgi_default) {
cur = trusted_cgi;
while (cur) {
FREE(cur->src);
FREE(cur->path);
next = cur->next;
FREE(cur);
cur = next;
}
}
return;
}
PUBLIC void add_trusted ARGS2(
char *, str,
int, type)
{
struct trust *tp;
char *path;
char *src = str;
int Type = type;
static BOOLEAN first = TRUE;
if (!src)
return;
if (first) {
atexit(LYTrusted_free);
first = FALSE;
}
path = strchr(src, '\t');
if (path)
*path++ = '\0';
else
path = "";
tp = (struct trust *)malloc(sizeof(*tp));
if (tp == NULL)
outofmem(__FILE__, "add_trusted");
tp->src = NULL;
tp->path = NULL;
tp->type = Type;
StrAllocCopy(tp->src, src);
StrAllocCopy(tp->path, path);
if (Type == EXEC_PATH) {
if (trusted_exec == &trusted_exec_default)
tp->next = NULL;
else
tp->next = trusted_exec;
trusted_exec = tp;
} else if (Type == ALWAYS_EXEC_PATH) {
if (always_trusted_exec == &always_trusted_exec_default)
tp->next = NULL;
else
tp->next = always_trusted_exec;
always_trusted_exec = tp;
} else if (Type == CGI_PATH) {
if (trusted_cgi == &trusted_cgi_default)
tp->next = NULL;
else
tp->next = trusted_cgi;
trusted_cgi = tp;
}
}
/*
* Check to see if the supplied paths is allowed to be executed.
*/
PUBLIC BOOLEAN exec_ok ARGS3(
CONST char *, source,
CONST char *, link,
int, type)
{
struct trust *tp;
CONST char *cp;
int Type = type;
/*
* Always OK if it is a jump file shortcut.
*/
if (LYJumpFileURL)
return TRUE;
/*
* Choose the trust structure based on the type.
*/
if (Type == EXEC_PATH) {
tp = trusted_exec;
} else if (Type == ALWAYS_EXEC_PATH) {
tp = always_trusted_exec;
} else if (Type == CGI_PATH) {
tp = trusted_cgi;
} else {
HTAlert(MALFORMED_EXEC_REQUEST);
return FALSE;
}
#ifdef VMS
/*
* Security: reject on relative path.
*/
if ((cp = strchr(link, '[')) != NULL) {
char *cp1;
if (((cp1 = strchr(cp, '-')) != NULL) &&
strchr(cp1, ']') != NULL) {
while (cp1[1] == '-')
cp1++;
if (cp1[1] == ']' ||
cp1[1] == '.') {
HTAlert(RELPATH_IN_EXEC_LINK);
return FALSE;
}
}
}
#else
/*
* Security: reject on relative path.
*/
if (strstr(link, "../") != NULL) {
HTAlert(RELPATH_IN_EXEC_LINK);
return FALSE;
}
/*
* Security: reject on strange character.
*/
for (cp = link; *cp != '\0'; cp++) {
if (!isalnum(*cp) && *cp != '_' && *cp != '-' &&
*cp != ' ' && *cp != ':' && *cp != '.' &&
*cp != '/' && *cp != '@' && *cp != '~' &&
*cp != '$' && *cp != '\t') {
char buf[128];
sprintf(buf,
BADCHAR_IN_EXEC_LINK,
*cp);
HTAlert(buf);
return FALSE;
}
}
#endif /* VMS */
check_tp_for_entry:
while (tp) {
if (tp->type == Type) {
char CONST *command = link;
if (strstr(command,"//") == link) {
command += 2;
}
#ifdef VMS
if (strncasecomp(source, tp->src, strlen(tp->src)) == 0 &&
strncasecomp(command, tp->path, strlen(tp->path)) == 0)
#else
if (strncmp(source, tp->src, strlen(tp->src)) == 0 &&
strncmp(command, tp->path, strlen(tp->path)) == 0)
#endif /* VMS */
return TRUE;
}
tp = tp->next;
}
if (Type == EXEC_PATH &&
always_trusted_exec != &always_trusted_exec_default) {
Type = ALWAYS_EXEC_PATH;
tp = always_trusted_exec;
goto check_tp_for_entry;
}
if (!(no_exec && type == ALWAYS_EXEC_PATH))
HTAlert(BADLOCPATH_IN_EXEC_LINK);
return FALSE;
}
#endif /* EXEC_LINKS || LYNXCGI_LINKS */
PRIVATE int fix_http_urls ARGS1(
document *, doc)
{
char *slash;
/*
* If it's an ftp URL with a trailing slash, trim it off.
*/
if (!strncmp(doc->address, "ftp", 3) &&
doc->address[strlen(doc->address)-1] == '/') {
char * proxy;
char *path = HTParse(doc->address, "", PARSE_PATH|PARSE_PUNCTUATION);
/*
* If the path is a lone slash, we're done. - FM
*/
if (path) {
if (path[0] == '/' && path[1] == '\0') {
FREE(path);
return 0;
}
FREE(path);
}
/*
* If we're proxying ftp, don't trim anything. - KW
*/
if (((proxy = (char *)getenv("ftp_proxy")) != NULL) &&
*proxy != '\0' && !override_proxy(doc->address))
return 0;
/*
* If we get to here, trim the trailing slash. - FM
*/
if (TRACE)
fprintf(stderr,"LYGetFile: URL %s\n", doc->address);
doc->address[strlen(doc->address)-1] = '\0';
if (TRACE) {
fprintf(stderr," changed to %s\n", doc->address);
sleep(MessageSecs);
}
}
/*
* If there isn't a slash besides the two at the beginning, append one.
*/
if ((slash = strrchr(doc->address, '/')) != NULL) {
if (*(slash-1) != '/' || *(slash-2) != ':') {
return(0);
}
}
if (TRACE)
fprintf(stderr,"LYGetFile: URL %s\n", doc->address);
StrAllocCat(doc->address, "/");
if (TRACE) {
fprintf(stderr," changed to %s\n",doc->address);
sleep(MessageSecs);
}
return(1);
}