home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lynx2.8.1dev.10.tar.gz / lynx2.8.1dev.10.tar / lynx2-8 / src / LYGetFile.c < prev    next >
C/C++ Source or Header  |  1998-04-23  |  36KB  |  1,373 lines

  1. #include <HTUtils.h>
  2. #include <tcp.h>
  3. #include <HTTP.h>
  4. #include <HTAnchor.h>        /* Anchor class */
  5. #include <HTAccess.h>
  6. #include <HTParse.h>
  7. #include <LYCurses.h>
  8. #include <GridText.h>
  9. #include <LYGlobalDefs.h>
  10. #include <LYUtils.h>
  11. #include <LYCharSets.h>
  12. #include <LYCharUtils.h>
  13. #include <HTAlert.h>
  14. #include <LYSignal.h>
  15. #include <LYGetFile.h>
  16. #include <LYPrint.h>
  17. #include <LYHistory.h>
  18. #include <LYStrings.h>
  19. #include <LYClean.h>
  20. #include <LYDownload.h>
  21. #include <LYNews.h>
  22. #include <LYMail.h>
  23. #include <LYSystem.h>
  24. #include <LYKeymap.h>
  25. #include <LYBookmark.h>
  26. #include <LYMap.h>
  27. #include <LYList.h>
  28. #ifdef VMS
  29. #include <HTVMSUtils.h>
  30. #endif /* VMS */
  31. #ifdef DOSPATH
  32. #include <HTDOS.h>
  33. #endif
  34. #ifdef DIRED_SUPPORT
  35. #include <LYLocal.h>
  36. #endif /* DIRED_SUPPORT */
  37.  
  38. #include <LYexit.h>
  39. #include <LYLeaks.h>
  40.  
  41. #ifndef VMS
  42. #ifdef SYSLOG_REQUESTED_URLS
  43. #include <syslog.h>
  44. #endif /* SYSLOG_REQUESTED_URLS */
  45. #endif /* !VMS */
  46.  
  47. #define FREE(x) if (x) {free(x); x = NULL;}
  48.  
  49. PRIVATE int fix_http_urls PARAMS((document *doc));
  50. extern char * WWW_Download_File;
  51. #ifdef VMS
  52. extern BOOLEAN LYDidRename;
  53. #endif /* VMS */
  54.  
  55. #if 0 /* UNUSED */
  56. #ifdef DIRED_SUPPORT
  57. PRIVATE char * LYSanctify ARGS1(
  58.     char *,     href)
  59. {
  60.     int i;
  61.     char *p, *cp, *tp;
  62.     char address_buffer[1024];
  63.  
  64.     i = (strlen(href) - 1);
  65.     while (i && href[i] == '/') href[i--] = '\0';
  66.  
  67.     if ((cp = (char *)strchr(href,'~')) != NULL) {
  68.        if (!strncmp(href, "file://localhost/", 17))
  69.      tp = (href + 17);
  70.        else
  71.      tp = (href + 5);
  72.        if ((cp - tp) && *(cp-1) != '/')
  73.      return href;
  74.        LYstrncpy(address_buffer, href, (cp - href));
  75.        if (address_buffer[(strlen(address_buffer) - 1)] == '/')
  76.      address_buffer[(strlen(address_buffer) - 1)] = '\0';
  77.        p = (char *)Home_Dir();
  78.        strcat(address_buffer, p);
  79.        if (strlen(++cp))
  80.      strcat(address_buffer, cp);
  81.        if (strcmp(href, address_buffer))
  82.      StrAllocCopy(href, address_buffer);
  83.     }
  84.     return href;
  85. }
  86. #endif /* DIRED_SUPPORT */
  87. #endif
  88.  
  89.  
  90. PUBLIC BOOLEAN getfile ARGS1(
  91.     document *,    doc)
  92. {
  93.     int url_type = 0;
  94.     char *cp = NULL;
  95.     char *temp = NULL;
  96.     DocAddress WWWDoc;  /* a WWW absolute doc address struct */
  97.  
  98.     /*
  99.      *  Reset LYCancelDownload to prevent unwanted delayed effect. - KW
  100.      */
  101.     if (LYCancelDownload) {
  102.         CTRACE(tfp, "getfile:    resetting LYCancelDownload to FALSE\n");
  103.         LYCancelDownload = FALSE;
  104.     }
  105.  
  106.     /*
  107.      *  Reset fake 'Z' to prevent unwanted delayed effect. - kw
  108.      */
  109.     LYFakeZap(NO);
  110.  
  111. Try_Redirected_URL:
  112.     /*
  113.      *  Load the WWWDoc struct in case we need to use it.
  114.      */
  115.     WWWDoc.address = doc->address;
  116.     WWWDoc.post_data = doc->post_data;
  117.     WWWDoc.post_content_type = doc->post_content_type;
  118.     WWWDoc.bookmark = doc->bookmark;
  119.     WWWDoc.isHEAD = doc->isHEAD;
  120.     WWWDoc.safe = doc->safe;
  121.  
  122.     /*
  123.      *  Reset WWW_Download_File just in case.
  124.      */
  125.     FREE(WWW_Download_File);
  126.  
  127.     /*
  128.      *  Reset redirect_post_content just in case.
  129.      */
  130.     redirect_post_content = FALSE;
  131.  
  132.     CTRACE(tfp,"getfile: getting %s\n\n",doc->address);
  133.  
  134.     /*
  135.      *  Protect against denial of service attacks
  136.      *  via the port 19 CHARGEN service, and block
  137.      *  connections to the port 25 ESMTP service.
  138.      *  Also reject any likely spoof attempts via
  139.      *  wrap arounds at 65536. - FM
  140.      */
  141.     if ((temp = HTParse(doc->address, "", PARSE_HOST)) != NULL &&
  142.         strlen(temp) > 3) {
  143.         char *cp1;
  144.  
  145.         if ((cp1 = strchr(temp, '@')) == NULL)
  146.         cp1 = temp;
  147.         if ((cp = strrchr(cp1, ':')) != NULL) {
  148.         long int value;
  149.  
  150.         cp++;
  151.         if (sscanf(cp, "%ld", &value) == 1) {
  152.             if (value == 19 || value == 65555) {
  153.             HTAlert(PORT_NINETEEN_INVALID);
  154.             FREE(temp);
  155.             return(NULLFILE);
  156.             }
  157.             if (value == 25 || value == 65561) {
  158.             HTAlert(PORT_TWENTYFIVE_INVALID);
  159.             FREE(temp);
  160.             return(NULLFILE);
  161.             }
  162.             if (value > 65535 || value < 0) {
  163.             char msg[265];
  164.             sprintf(msg, PORT_INVALID, (unsigned long)value);
  165.             HTAlert(msg);
  166.             FREE(temp);
  167.             return(NULLFILE);
  168.             }
  169.         } else if (isdigit((unsigned char)*cp)) {
  170.             HTAlert(URL_PORT_BAD);
  171.             FREE(temp);
  172.             return(NULLFILE);
  173.         }
  174.         }
  175.     }
  176.     cp = NULL;
  177.     FREE(temp);
  178.  
  179.     /*
  180.      *  Check to see if this is a universal document ID
  181.      *  that lib WWW wants to handle.
  182.      *
  183.      *  Some special URL's we handle ourselves. :)
  184.      */
  185.     if ((url_type = is_url(doc->address)) != 0) {
  186.         if (LYValidate && !LYPermitURL) {
  187.             if (!(url_type == HTTP_URL_TYPE ||
  188.               url_type == HTTPS_URL_TYPE ||
  189.               url_type == LYNXHIST_URL_TYPE ||
  190.               url_type == LYNXKEYMAP_URL_TYPE ||
  191.               url_type == LYNXIMGMAP_URL_TYPE ||
  192.               url_type == LYNXCOOKIE_URL_TYPE ||
  193.               0==strncasecomp(WWWDoc.address, helpfilepath,
  194.                       strlen(helpfilepath)) ||
  195.               (lynxlistfile != NULL &&
  196.                0==strncasecomp(WWWDoc.address, lynxlistfile,
  197.                       strlen(lynxlistfile))) ||
  198.               (lynxlinksfile != NULL &&
  199.                0==strncasecomp(WWWDoc.address, lynxlinksfile,
  200.                       strlen(lynxlinksfile))) ||
  201.               (lynxjumpfile != NULL &&
  202.                0==strncasecomp(WWWDoc.address, lynxjumpfile,
  203.                       strlen(lynxjumpfile))))) {
  204.             _statusline(NOT_HTTP_URL_OR_ACTION);
  205.             sleep(MessageSecs);
  206.             return(NULLFILE);
  207.             }
  208.         }
  209.         if (traversal) {
  210.             /*
  211.              *    Only traverse http URLs.
  212.              */
  213.             if (url_type != HTTP_URL_TYPE &&
  214.             url_type != LYNXIMGMAP_URL_TYPE)
  215.             return(NULLFILE);
  216.         } else if (check_realm && !LYPermitURL && !LYJumpFileURL) {
  217.             if (!(0==strncmp(startrealm, WWWDoc.address,
  218.                      strlen(startrealm)) ||
  219.               url_type == LYNXHIST_URL_TYPE ||
  220.               url_type == LYNXKEYMAP_URL_TYPE ||
  221.               url_type == LYNXIMGMAP_URL_TYPE ||
  222.               url_type == LYNXCOOKIE_URL_TYPE ||
  223.               url_type == LYNXPRINT_URL_TYPE ||
  224.               url_type == LYNXDOWNLOAD_URL_TYPE ||
  225.               url_type == MAILTO_URL_TYPE ||
  226.               url_type == NEWSPOST_URL_TYPE ||
  227.               url_type == NEWSREPLY_URL_TYPE ||
  228.               url_type == SNEWSPOST_URL_TYPE ||
  229.               url_type == SNEWSREPLY_URL_TYPE ||
  230.               (!LYUserSpecifiedURL &&
  231.                (url_type == LYNXEXEC_URL_TYPE ||
  232.                 url_type == LYNXPROG_URL_TYPE ||
  233.                 url_type == LYNXCGI_URL_TYPE)) ||
  234.               (WWWDoc.bookmark != NULL &&
  235.                *WWWDoc.bookmark != '\0') ||
  236.               0==strncasecomp(WWWDoc.address, helpfilepath,
  237.                       strlen(helpfilepath)) ||
  238.               (lynxlistfile != NULL &&
  239.                0==strncasecomp(WWWDoc.address, lynxlistfile,
  240.                       strlen(lynxlistfile))) ||
  241.               (lynxjumpfile != NULL &&
  242.                0==strncasecomp(WWWDoc.address, lynxjumpfile,
  243.                       strlen(lynxjumpfile))))) {
  244.             _statusline(NOT_IN_STARTING_REALM);
  245.             sleep(MessageSecs);
  246.             return(NULLFILE);
  247.             }
  248.         }
  249.         if (WWWDoc.post_data &&
  250.             url_type != HTTP_URL_TYPE &&
  251.             url_type != HTTPS_URL_TYPE &&
  252.             url_type != LYNXCGI_URL_TYPE &&
  253.             url_type != LYNXIMGMAP_URL_TYPE &&
  254.             url_type != GOPHER_URL_TYPE &&
  255.             url_type != CSO_URL_TYPE &&
  256.             url_type != PROXY_URL_TYPE &&
  257.             !(url_type == FILE_URL_TYPE &&
  258.               *(LYlist_temp_url()) &&
  259.               !strncmp(WWWDoc.address, LYlist_temp_url(),
  260.                    strlen(LYlist_temp_url())))) {
  261.             CTRACE(tfp, "getfile: dropping post_data!\n");
  262.             HTAlert("POST not supported for this URL - ignoring POST data!");
  263.             FREE(doc->post_data);
  264.             FREE(doc->post_content_type);
  265.             WWWDoc.post_data = NULL;
  266.             WWWDoc.post_content_type = NULL;
  267.         }
  268. #ifndef VMS
  269. #ifdef SYSLOG_REQUESTED_URLS
  270.         syslog(LOG_INFO|LOG_LOCAL5, "%s", doc->address);
  271. #endif /* SYSLOG_REQUESTED_URLS */
  272. #endif /* !VMS */
  273.         if (url_type == UNKNOWN_URL_TYPE ||
  274.             url_type == AFS_URL_TYPE ||
  275.             url_type == PROSPERO_URL_TYPE) {
  276.             HTAlert(UNSUPPORTED_URL_SCHEME);
  277.             return(NULLFILE);
  278.  
  279.         } else if (url_type == DATA_URL_TYPE) {
  280.             HTAlert(UNSUPPORTED_DATA_URL);
  281.             return(NULLFILE);
  282.  
  283.         } else if (url_type == LYNXPRINT_URL_TYPE) {
  284.             return(printfile(doc));
  285.  
  286.         } else if (url_type == NEWSPOST_URL_TYPE ||
  287.                url_type == NEWSREPLY_URL_TYPE ||
  288.                url_type == SNEWSPOST_URL_TYPE ||
  289.                url_type == SNEWSREPLY_URL_TYPE) {
  290.  
  291.             if (no_newspost) {
  292.             _statusline(NEWSPOSTING_DISABLED);
  293.             sleep(MessageSecs);
  294.             return(NULLFILE);
  295.             } else {
  296.             HTLoadAbsolute(&WWWDoc);
  297.             return(NULLFILE);
  298.             }
  299.  
  300.         } else if (url_type == LYNXDOWNLOAD_URL_TYPE) {
  301.             LYDownload(doc->address);
  302. #ifdef VMS
  303.             if (LYDidRename) {
  304.             /*
  305.              *  The temporary file was saved to disk via a
  306.              *  rename(), so we can't access the temporary
  307.              *  file again via the download menu.  Clear the
  308.              *  flag, and return NULLFILE to pop. - FM
  309.              */
  310.             LYDidRename = FALSE;
  311.             return(NULLFILE);
  312.             } else {
  313.             return(NORMAL);
  314.             }
  315. #else
  316.             return(NORMAL);
  317. #endif /* VMS */
  318.         } else if (url_type == LYNXDIRED_URL_TYPE) {
  319. #ifdef DIRED_SUPPORT
  320.             if (no_dired_support) {
  321.                _statusline(DIRED_DISABLED);
  322.                sleep(MessageSecs);
  323.                return(NULLFILE);
  324.             } else {
  325.                local_dired(doc);
  326.                WWWDoc.address = doc->address;
  327.                WWWDoc.post_data = doc->post_data;
  328.                WWWDoc.post_content_type = doc->post_content_type;
  329.                WWWDoc.bookmark = doc->bookmark;
  330.                WWWDoc.isHEAD = doc->isHEAD;
  331.                WWWDoc.safe = doc->safe;
  332.  
  333.                if (!HTLoadAbsolute(&WWWDoc))
  334.                return(NOT_FOUND);
  335.                return(NORMAL);
  336.             }
  337. #else
  338.             _statusline(DIRED_DISABLED);
  339.             sleep(MessageSecs);
  340.             return(NULLFILE);
  341. #endif /* DIRED_SUPPORT */
  342.  
  343.         } else if (url_type == LYNXHIST_URL_TYPE) {
  344.             /*
  345.              *    'doc' will change to the new file
  346.              *    if we had a successful LYpop_num(),
  347.              *    and the return value will be FALSE
  348.              *    if we had a cancel. - FM
  349.              */
  350.             if ((historytarget(doc) == FALSE) ||
  351.             !doc || !doc->address) {
  352.             HTMLSetCharacterHandling(current_char_set);
  353.             return(NOT_FOUND);
  354.             }
  355.  
  356.             /*
  357.              *    We changed it so reload.
  358.              */
  359.             WWWDoc.address = doc->address;
  360.             WWWDoc.post_data = doc->post_data;
  361.             WWWDoc.post_content_type = doc->post_content_type;
  362.             WWWDoc.bookmark = doc->bookmark;
  363.             WWWDoc.isHEAD = doc->isHEAD;
  364.             WWWDoc.safe = doc->safe;
  365. #ifndef DONT_TRACK_INTERNAL_LINKS
  366.             if (doc->internal_link && !reloading) {
  367.             LYinternal_flag = TRUE;
  368.             }
  369. #endif
  370.  
  371.             if (!HTLoadAbsolute(&WWWDoc)) {
  372.             HTMLSetCharacterHandling(current_char_set);
  373.             return(NOT_FOUND);
  374.             }
  375.             HTMLSetCharacterHandling(current_char_set);
  376.             return(NORMAL);
  377.  
  378.         } else if (url_type == LYNXEXEC_URL_TYPE ||
  379.                url_type == LYNXPROG_URL_TYPE) {
  380. #ifdef EXEC_LINKS
  381.             if (no_exec &&
  382.             !exec_ok(HTLoadedDocumentURL(),
  383.                  doc->address+9, ALWAYS_EXEC_PATH)) {
  384.             statusline(EXECUTION_DISABLED);
  385.             sleep(MessageSecs);
  386.             } else if (no_bookmark_exec &&
  387.                    HTLoadedDocumentBookmark()) {
  388.             statusline(BOOKMARK_EXEC_DISABLED);
  389.             sleep(MessageSecs);
  390.             } else if (local_exec || (local_exec_on_local_files &&
  391.                    exec_ok(HTLoadedDocumentURL(),
  392.                        doc->address+9, EXEC_PATH))) {
  393.  
  394.             char *p, addressbuf[1024];
  395.  
  396.             /*
  397.              *  Bug puts slash on end if none is in the string.
  398.              */
  399.             char *last_slash = strrchr(doc->address,'/');
  400.             if (last_slash-doc->address==strlen(doc->address)-1)
  401.                 doc->address[strlen(doc->address)-1] = '\0';
  402.  
  403.             p = doc->address;
  404.             /*
  405.              *  Convert '~' to $HOME.
  406.              */
  407.             if ((cp = strchr(doc->address, '~'))) {
  408.                 strncpy(addressbuf, doc->address, cp-doc->address);
  409.                 addressbuf[cp - doc->address] = '\0';
  410. #ifdef DOSPATH
  411.                 p = HTDOS_wwwName((char *)Home_Dir());
  412. #else
  413. #ifdef VMS
  414.                 p = HTVMS_wwwName((char *)Home_Dir());
  415. #else
  416.                 p = (char *)Home_Dir();
  417. #endif /* VMS */
  418. #endif /* DOSPATH */
  419.                 strcat(addressbuf, p);
  420.                 strcat(addressbuf, cp+1);
  421.                 p = addressbuf;
  422.             }
  423.             /*
  424.              *  Show URL before executing it.
  425.              */
  426.             statusline(doc->address);
  427.             sleep(InfoSecs);
  428.             stop_curses();
  429.             /*
  430.              *  Run the command.
  431.              */
  432.             if (strstr(p,"//") == p+9)
  433.                 system(p+11);
  434.             else
  435.                 system(p+9);
  436.             if (url_type != LYNXPROG_URL_TYPE) {
  437.                 /*
  438.                  *    Make sure user gets to see screen output.
  439.                  */
  440. #ifndef VMS
  441.                 signal(SIGINT, SIG_IGN);
  442. #endif /* !VMS */
  443.                 printf("\n%s", RETURN_TO_LYNX);
  444.                 fflush(stdout);
  445.                 LYgetch();
  446. #ifdef VMS
  447.                 {
  448.                   extern BOOLEAN HadVMSInterrupt;
  449.                   HadVMSInterrupt = FALSE;
  450.                 }
  451. #endif /* VMS */
  452.             }
  453.             start_curses();
  454.             LYAddVisitedLink(doc);
  455.  
  456.              } else {
  457.             char buf[512];
  458.  
  459.             sprintf(buf,
  460.                 EXECUTION_DISABLED_FOR_FILE,
  461.                 key_for_func(LYK_OPTIONS));
  462.             _statusline(buf);
  463.             sleep(AlertSecs);
  464.              }
  465. #else /* no exec_links */
  466.              _statusline(EXECUTION_NOT_COMPILED);
  467.              sleep(MessageSecs);
  468. #endif /* EXEC_LINKS */
  469.              return(NULLFILE);
  470.  
  471.         } else if (url_type == MAILTO_URL_TYPE) {
  472.             if (no_mail) {
  473.             _statusline(MAIL_DISABLED);
  474.             sleep(MessageSecs);
  475.             } else {
  476.             HTParentAnchor *tmpanchor;
  477.             CONST char *title;
  478.  
  479.             title = "";
  480.             if ((tmpanchor = HTAnchor_parent(
  481.                         HTAnchor_findAddress(&WWWDoc)
  482.                             )) != NULL) {
  483.                 if (HTAnchor_title(tmpanchor)) {
  484.                 title = HTAnchor_title(tmpanchor);
  485.                 }
  486.             }
  487.             cp = (char *)strchr(doc->address,':')+1;
  488.             reply_by_mail(cp,
  489.                       ((HTMainAnchor && !LYUserSpecifiedURL) ?
  490.                        (char *)HTMainAnchor->address :
  491.                        (char *)doc->address),
  492.                       title);
  493.             }
  494.             return(NULLFILE);
  495.  
  496.         /*
  497.          *  From here on we could have a remote host,
  498.          *  so check if that's allowed.
  499.          */
  500.         } else if (local_host_only &&
  501.                url_type != NEWS_URL_TYPE &&
  502.                url_type != LYNXKEYMAP_URL_TYPE &&
  503.                url_type != LYNXIMGMAP_URL_TYPE &&
  504.                url_type != LYNXCOOKIE_URL_TYPE &&
  505.                url_type != LYNXCGI_URL_TYPE &&
  506.                !(LYisLocalHost(doc->address) ||
  507.                  LYisLocalAlias(doc->address))) {
  508.             statusline(ACCESS_ONLY_LOCALHOST);
  509.             sleep(MessageSecs);
  510.             return(NULLFILE);
  511.  
  512.         /*
  513.          *  Disable www telnet access if not telnet_ok.
  514.          */
  515.         } else if (url_type == TELNET_URL_TYPE ||
  516.                url_type == TN3270_URL_TYPE ||
  517.                url_type == TELNET_GOPHER_URL_TYPE) {
  518.             if (!telnet_ok) {
  519.             _statusline(TELNET_DISABLED);
  520.             sleep(MessageSecs);
  521.             } else if (no_telnet_port && strchr(doc->address+7, ':')) {
  522.             statusline(TELNET_PORT_SPECS_DISABLED);
  523.             sleep(MessageSecs);
  524.             } else {
  525.             stop_curses();
  526.             HTLoadAbsolute(&WWWDoc);
  527.             start_curses();
  528.             fflush(stdout);
  529.             LYAddVisitedLink(doc);
  530.             }
  531.             return(NULLFILE);
  532.  
  533.         /*
  534.          *  Disable www news access if not news_ok.
  535.          */
  536.         } else if (url_type == NEWS_URL_TYPE && !news_ok) {
  537.             _statusline(NEWS_DISABLED);
  538.             sleep(MessageSecs);
  539.             return(NULLFILE);
  540.  
  541.         } else if (url_type == RLOGIN_URL_TYPE) {
  542.             if (!rlogin_ok) {
  543.             statusline(RLOGIN_DISABLED);
  544.             sleep(MessageSecs);
  545.             } else {
  546.             stop_curses();
  547.             HTLoadAbsolute(&WWWDoc);
  548.             fflush(stdout);
  549.             start_curses();
  550.             LYAddVisitedLink(doc);
  551.             }
  552.             return(NULLFILE);
  553.  
  554.         /*
  555.          *  If its a gopher index type and there isn't a search
  556.          *  term already attached then do this.  Otherwise
  557.          *  just load it!
  558.          */
  559.         } else if (url_type == INDEX_GOPHER_URL_TYPE &&
  560.                     strchr(doc->address,'?') == NULL) {
  561.             int status;
  562.             /*
  563.              *    Make sure we don't have a gopher+ escaped tab
  564.              *    instead of a gopher0 question mark delimiting
  565.              *    the search term. - FM
  566.              */
  567.             if ((cp = strstr(doc->address, "%09")) != NULL) {
  568.             *cp = '\0';
  569.             StrAllocCopy(temp, doc->address);
  570.             cp += 3;
  571.             if (*cp && strncmp(cp, "%09", 3)) {
  572.                 StrAllocCat(temp, "?");
  573.                 StrAllocCat(temp, cp);
  574.                 if ((cp = strstr(temp, "%09")) != NULL) {
  575.                 *cp = '\0';
  576.                 }
  577.             }
  578.             StrAllocCopy(doc->address, temp);
  579.             FREE(temp);
  580.             goto Try_Redirected_URL;
  581.             }
  582.             /*
  583.              *    Load it because the do_www_search routine
  584.              *    uses the base url of the currently loaded
  585.              *    document :(
  586.              */
  587.             if (!HTLoadAbsolute(&WWWDoc))
  588.             return(NOT_FOUND);
  589.             status = do_www_search(doc);
  590.             if (status == NULLFILE) {
  591.             LYpop(doc);
  592.             WWWDoc.address = doc->address;
  593.             WWWDoc.post_data = doc->post_data;
  594.             WWWDoc.post_content_type = doc->post_content_type;
  595.             WWWDoc.bookmark = doc->bookmark;
  596.             WWWDoc.isHEAD = doc->isHEAD;
  597.             WWWDoc.safe = doc->safe;
  598.             status = HTLoadAbsolute(&WWWDoc);
  599.             }
  600.             return(status);
  601.  
  602.         } else {
  603.  
  604.             if (url_type == FTP_URL_TYPE && !ftp_ok) {
  605.             statusline(FTP_DISABLED);
  606.             sleep(MessageSecs);
  607.             return(NULLFILE);
  608.             }
  609.  
  610.             if (url_type == HTML_GOPHER_URL_TYPE) {
  611.             char *tmp=NULL;
  612.                /*
  613.             *  If tuple's Path=GET%20/... convert to an http URL.
  614.             */
  615.             if ((cp=strchr(doc->address+9, '/')) != NULL &&
  616.                0==strncmp(++cp, "hGET%20/", 8)) {
  617.                 StrAllocCopy(tmp, "http://");
  618.                 CTRACE(tfp, "getfile: URL '%s'\n",
  619.                     doc->address);
  620.                 *cp = '\0';
  621.                 StrAllocCat(tmp, doc->address+9);
  622.                /*
  623.                 *  If the port is defaulted, it should stay 70.
  624.                 */
  625.                 if (strchr(tmp+6, ':') == NULL) {
  626.                 StrAllocCat(tmp, "70/");
  627.                 tmp[strlen(tmp)-4] = ':';
  628.                 }
  629.                 if (strlen(cp+7) > 1)
  630.                 StrAllocCat(tmp, cp+8);
  631.                 StrAllocCopy(doc->address, tmp);
  632.                 CTRACE(tfp, "  changed to '%s'\n",
  633.                     doc->address);
  634.                 FREE(tmp);
  635.                 url_type = HTTP_URL_TYPE;
  636.             }
  637.             }
  638.             if (url_type == HTTP_URL_TYPE ||
  639.             url_type == HTTPS_URL_TYPE ||
  640.             url_type == FTP_URL_TYPE ||
  641.             url_type == CSO_URL_TYPE)
  642.             fix_http_urls(doc);
  643.             WWWDoc.address = doc->address;  /* possible reload */
  644. #ifdef DIRED_SUPPORT
  645.             lynx_edit_mode = FALSE;
  646. #endif /* DIRED_SUPPORT */
  647.  
  648.             if (url_type == FILE_URL_TYPE) {
  649.             /*
  650.              *  If a file URL has a '~' as the lead character
  651.              *  of its first symbolic element, convert the '~'
  652.              *  to Home_Dir(), then append the rest of of path,
  653.              *  if present, skipping "user" if "~user" was
  654.              *  entered, simplifying, and eliminating any
  655.              *  residual relative elements. - FM
  656.              */
  657.             if (((cp = HTParse(doc->address, "",
  658.                    PARSE_PATH+PARSE_ANCHOR+PARSE_PUNCTUATION))
  659.                   != NULL) &&
  660.                 !strncmp(cp, "/~", 2)) {
  661.                 char *cp1 = strstr(doc->address, "/~");
  662.                 char *cp2;
  663.  
  664.                 CTRACE(tfp, "getfile: URL '%s'\n",
  665.                     doc->address);
  666.                 *cp1 = '\0';
  667.                 cp1 += 2;
  668.                 StrAllocCopy(temp, doc->address);
  669. #ifdef DOSPATH
  670.                 StrAllocCat(temp, "/");
  671.                 StrAllocCat(temp, HTDOS_wwwName((char *)Home_Dir()));
  672. #else
  673. #ifdef VMS
  674.                 StrAllocCat(temp,
  675.                     HTVMS_wwwName((char *)Home_Dir()));
  676. #else
  677.                 StrAllocCat(temp, Home_Dir());
  678. #endif /* VMS */
  679. #endif /* DOSPATH */
  680.                 if ((cp2 = strchr(cp1, '/')) != NULL) {
  681.                 LYTrimRelFromAbsPath(cp2);
  682.                 StrAllocCat(temp, cp2);
  683.                 }
  684.                 StrAllocCopy(doc->address, temp);
  685.                 FREE(temp);
  686.                 CTRACE(tfp, "  changed to '%s'\n",
  687.                     doc->address);
  688.                 WWWDoc.address = doc->address;
  689.             }
  690.             FREE(cp);
  691.             }
  692.             if (TRACE && LYTraceLogFP == NULL)
  693.             sleep(MessageSecs);
  694.             user_message(WWW_WAIT_MESSAGE, doc->address);
  695. #ifdef NOTDEFINED
  696.             sleep(InfoSecs);
  697. #endif /* NOTDEFINED */
  698.             if (TRACE) {
  699. #ifdef USE_SLANG
  700.             if (LYCursesON) {
  701.                 addstr("*\n");
  702.                 refresh();
  703.             }
  704. #endif /* USE_SLANG */
  705.             fprintf(tfp,"\n");
  706.             }
  707.             if ((LYNoRefererHeader == FALSE &&
  708.              LYNoRefererForThis == FALSE) &&
  709.             (url_type == HTTP_URL_TYPE ||
  710.              url_type == HTTPS_URL_TYPE) &&
  711.             (cp = strchr(HTLoadedDocumentURL(), '?')) != NULL &&
  712.             strchr(cp, '=') != NULL) {
  713.             /*
  714.              *  Don't send a Referer header if the URL is
  715.              *  the reply from a form with method GET, in
  716.              *  case the content has personal data (e.g.,
  717.              *  a password or credit card number) which
  718.              *  would become visible in logs. - FM
  719.              */
  720.             LYNoRefererForThis = TRUE;
  721.             }
  722.             cp = NULL;
  723.             if (!HTLoadAbsolute(&WWWDoc)) {
  724.             /*
  725.              *  Check for redirection.
  726.              */
  727.             if (use_this_url_instead != NULL) {
  728.                 char *pound;
  729.  
  730.                 if (!is_url(use_this_url_instead)) {
  731.                 /*
  732.                  *  The server did not return a complete
  733.                  *  URL in its Location: header, probably
  734.                  *  due to a FORM or other CGI script written
  735.                  *  by someone who doesn't know that the http
  736.                  *  protocol requires that it be a complete
  737.                  *  URL, or using a server which does not treat
  738.                  *  such a redirect string from the script as
  739.                  *  an instruction to resolve it versus the
  740.                  *  initial request, check authentication with
  741.                  *  that URL, and then act on it without
  742.                  *  returning redirection to us.  We'll
  743.                  *  violate the http protocol and resolve it
  744.                  *  ourselves using the URL of the original
  745.                  *  request as the BASE, rather than doing
  746.                  *  the RIGHT thing and returning an invalid
  747.                  *  address message. - FM
  748.                  */
  749.                 HTAlert(LOCATION_NOT_ABSOLUTE);
  750.                 temp = HTParse(use_this_url_instead,
  751.                            WWWDoc.address,
  752.                            PARSE_ALL);
  753.                 if (temp && *temp) {
  754.                     StrAllocCopy(use_this_url_instead, temp);
  755.                 }
  756.                 FREE(temp);
  757.                 }
  758.                 HTMLSetCharacterHandling(current_char_set);
  759.                 url_type = is_url(use_this_url_instead);
  760.                 if (url_type == LYNXDOWNLOAD_URL_TYPE ||
  761.                 url_type == LYNXEXEC_URL_TYPE ||
  762.                 url_type == LYNXPROG_URL_TYPE ||
  763. #ifdef DIRED_SUPPORT
  764.                 url_type == LYNXDIRED_URL_TYPE ||
  765. #endif /* DIRED_SUPPORT */
  766.                 url_type == LYNXPRINT_URL_TYPE ||
  767.                 url_type == LYNXHIST_URL_TYPE ||
  768.                 url_type == LYNXCOOKIE_URL_TYPE ||
  769.                 (LYValidate &&
  770.                  url_type != HTTP_URL_TYPE &&
  771.                  url_type != HTTPS_URL_TYPE) ||
  772.                 ((no_file_url || no_goto_file) &&
  773.                  url_type == FILE_URL_TYPE) ||
  774.                 (no_goto_lynxcgi &&
  775.                  url_type == LYNXCGI_URL_TYPE) ||
  776.                 (no_goto_cso &&
  777.                  url_type == CSO_URL_TYPE) ||
  778.                 (no_goto_finger &&
  779.                  url_type == FINGER_URL_TYPE) ||
  780.                 (no_goto_ftp &&
  781.                  url_type == FTP_URL_TYPE) ||
  782.                 (no_goto_gopher &&
  783.                  url_type == GOPHER_URL_TYPE) ||
  784.                 (no_goto_http &&
  785.                  url_type == HTTP_URL_TYPE) ||
  786.                 (no_goto_https &&
  787.                  url_type == HTTPS_URL_TYPE) ||
  788.                 (no_goto_mailto &&
  789.                  url_type == MAILTO_URL_TYPE) ||
  790.                 (no_goto_news &&
  791.                  url_type == NEWS_URL_TYPE) ||
  792.                 (no_goto_nntp &&
  793.                  url_type == NNTP_URL_TYPE) ||
  794.                 (no_goto_rlogin &&
  795.                  url_type == RLOGIN_URL_TYPE) ||
  796.                 (no_goto_snews &&
  797.                  url_type == SNEWS_URL_TYPE) ||
  798.                 (no_goto_telnet &&
  799.                  url_type == TELNET_URL_TYPE) ||
  800.                 (no_goto_tn3270 &&
  801.                  url_type == TN3270_URL_TYPE) ||
  802.                 (no_goto_wais &&
  803.                  url_type == WAIS_URL_TYPE)) {
  804.                 /*
  805.                  *  Some schemes are not acceptable from
  806.                  *  server redirections. - KW & FM
  807.                  */
  808.                 HTAlert(ILLEGAL_REDIRECTION_URL);
  809.                 if (LYCursesON) {
  810.                     _user_message(WWW_ILLEGAL_URL_MESSAGE,
  811.                           use_this_url_instead);
  812.                     sleep(AlertSecs);
  813.                 } else {
  814.                     fprintf(stderr,
  815.                         "Illegal Redirection URL: %s",
  816.                         use_this_url_instead);
  817.                 }
  818.                 FREE(use_this_url_instead);
  819.                 return(NULLFILE);
  820.                 }
  821.                 if ((pound = strchr(doc->address, '#')) != NULL &&
  822.                 strchr(use_this_url_instead, '#') == NULL) {
  823.                 /*
  824.                  *  Our requested URL had a fragment
  825.                  *  associated with it, and the redirection
  826.                  *  URL doesn't, so we'll append the fragment
  827.                  *  associated with the original request.  If
  828.                  *  it's bogus for the redirection URL, we'll
  829.                  *  be positioned at the top of that document,
  830.                  *  so there's no harm done. - FM
  831.                  */
  832.                 CTRACE(tfp,
  833.             "getfile: Adding fragment '%s' to redirection URL.\n",
  834.                     pound);
  835.                 StrAllocCat(use_this_url_instead, pound);
  836.                 }
  837.                 if (TRACE && LYTraceLogFP == NULL)
  838.                 sleep(MessageSecs);
  839.                 _user_message(WWW_USING_MESSAGE,
  840.                       use_this_url_instead);
  841.                 sleep(InfoSecs);
  842.                 CTRACE(tfp, "\n");
  843.                 StrAllocCopy(doc->address,
  844.                     use_this_url_instead);
  845.                 FREE(use_this_url_instead);
  846.                 if (redirect_post_content == FALSE) {
  847.                 /*
  848.                  *  Freeing the content also yields
  849.                  *  a GET request. - FM
  850.                  */
  851.                 FREE(doc->post_data);
  852.                 FREE(doc->post_content_type);
  853.                 }
  854.                 /*
  855.                  *    Go to top to check for URL's which get
  856.                  *    special handling and/or security checks
  857.                  *    in Lynx. - FM
  858.                  */
  859.                 goto Try_Redirected_URL;
  860.             }
  861.             HTMLSetCharacterHandling(current_char_set);
  862.             return(NOT_FOUND);
  863.             }
  864.  
  865.             lynx_mode = NORMAL_LYNX_MODE;
  866.  
  867.             /*
  868.              *    Some URL's don't actually return a document
  869.              *    compare doc->address with the document that is
  870.              *    actually loaded and return NULL if not
  871.              *    loaded.  If www_search_result is not -1
  872.              *    then this is a reference to a named anchor
  873.              *    within the same document.  Do NOT return
  874.              *    NULL.
  875.              */
  876.             {
  877.             char *pound;
  878.             /*
  879.              *  Check for a #fragment selector.
  880.              */
  881.             pound = (char *)strchr(doc->address, '#');
  882.  
  883.             /*
  884.              *  Check to see if there is a temp
  885.              *  file waiting for us to download.
  886.              */
  887.             if (WWW_Download_File) {
  888.                 HTParentAnchor *tmpanchor;
  889.                 char *fname = NULL;
  890.  
  891.                 HTMLSetCharacterHandling(current_char_set);
  892.                 /*
  893.                  *    Check for a suggested filename from
  894.                  *    the Content-Dispostion header. - FM
  895.                  */
  896.                 if (((tmpanchor = HTAnchor_parent(
  897.                         HTAnchor_findAddress(&WWWDoc)
  898.                                  )) != NULL) &&
  899.                 HTAnchor_SugFname(tmpanchor) != NULL) {
  900.                 StrAllocCopy(fname,
  901.                          HTAnchor_SugFname(tmpanchor));
  902.                 } else {
  903.                 StrAllocCopy(fname, doc->address);
  904.                 }
  905.                 /*
  906.                  *    Check whether this is a compressed file,
  907.                  *    which we don't uncompress for downloads,
  908.                  *    and adjust any suffix appropriately. - FM
  909.                  */
  910.                 if (tmpanchor != NULL) {
  911.                 HTCheckFnameForCompression(&fname, tmpanchor,
  912.                                FALSE);
  913.                 }
  914.                 if (LYdownload_options(&fname,
  915.                            WWW_Download_File) < 0) {
  916.                 FREE(fname);
  917.                 return(NOT_FOUND);
  918.                 }
  919.                 LYAddVisitedLink(doc);
  920.                 StrAllocCopy(doc->address, fname);
  921.                 FREE(fname);
  922.                 doc->internal_link = FALSE;
  923.                 WWWDoc.address = doc->address;
  924.                 FREE(doc->post_data);
  925.                 WWWDoc.post_data = NULL;
  926.                 FREE(doc->post_content_type);
  927.                 WWWDoc.post_content_type = NULL;
  928.                 WWWDoc.bookmark = doc->bookmark = FALSE;
  929.                 WWWDoc.isHEAD = doc->isHEAD = FALSE;
  930.                 WWWDoc.safe = doc->safe = FALSE;
  931.                 HTOutputFormat = WWW_PRESENT;
  932.                 if (!HTLoadAbsolute(&WWWDoc))
  933.                 return(NOT_FOUND);
  934.                 else
  935.                 return(NORMAL);
  936.  
  937.             } else if (pound == NULL &&
  938.                    /*
  939.                     *  HTAnchor hash-table searches are now
  940.                     *  case-sensitive (hopefully, without
  941.                     *  anchor deletion problems), so this
  942.                     *  is too. - FM
  943.                     */
  944.                    (strcmp(doc->address,
  945.                        HTLoadedDocumentURL()) ||
  946.                    /*
  947.                     *  Also check the post_data elements. - FM
  948.                     */
  949.                    strcmp((doc->post_data ?
  950.                        doc->post_data : ""),
  951.                       HTLoadedDocumentPost_data()) ||
  952.                    /*
  953.                     *  Also check the isHEAD element. - FM
  954.                     */
  955.                    doc->isHEAD != HTLoadedDocumentIsHEAD())) {
  956.                 HTMLSetCharacterHandling(current_char_set);
  957.                 /*
  958.                  *    Nothing needed to be shown.
  959.                  */
  960.                 LYAddVisitedLink(doc);
  961.                 return(NULLFILE);
  962.  
  963.             } else {
  964.             /*
  965.              *  May set www_search_result.
  966.              */
  967.                 if (pound != NULL)
  968.                 HTFindPoundSelector(pound+1);
  969.                 HTMLSetCharacterHandling(current_char_set);
  970.                 return(NORMAL);
  971.             }
  972.             }
  973.         }
  974.       } else {
  975.           if (TRACE && LYTraceLogFP == NULL)
  976.           sleep(MessageSecs);
  977.           _user_message(WWW_BAD_ADDR_MESSAGE, doc->address);
  978.           CTRACE(tfp,"\n");
  979.           sleep(MessageSecs);
  980.           return(NULLFILE);
  981.       }
  982. }
  983.  
  984. /*
  985.  *  The user wants to select a link or page by number.
  986.  *  If follow_link_number returns DO_LINK_STUFF do_link
  987.  *   will be run immediately following its execution.
  988.  *  If follow_link_number returns DO_GOTOLINK_STUFF
  989.  *   it has updated the passed in doc for positioning on a link.
  990.  *  If follow_link_number returns DO_GOTOPAGE_STUFF
  991.  *   it has set doc->line to the top line of the desired page
  992.  *   for displaying that page.
  993.  *  If follow_link_number returns PRINT_ERROR an error message
  994.  *   will be given to the user.
  995.  *  If follow_link_number returns DO_FORMS_STUFF some forms stuff
  996.  *   will be done. (Not yet implemented.)
  997.  *  If follow_link_number returns DO_NOTHING nothing special
  998.  *   will run after it.
  999.  */
  1000. PUBLIC int follow_link_number ARGS4(
  1001.     int,        c,
  1002.     int,        cur,
  1003.     document *,    doc,
  1004.     int *,        num)
  1005. {
  1006.     char temp[120];
  1007.     int new_top, new_link;
  1008.     BOOL want_go;
  1009.  
  1010.     temp[0] = c;
  1011.     temp[1] = '\0';
  1012.     *num = -1;
  1013.     _statusline(FOLLOW_LINK_NUMBER);
  1014.     /*
  1015.      *    Get the number, possibly with a letter suffix, from the user.
  1016.      */
  1017.     if (LYgetstr(temp, VISIBLE, sizeof(temp), NORECALL) < 0 || *temp == 0) {
  1018.     _statusline(CANCELLED);
  1019.     sleep(InfoSecs);
  1020.     return(DO_NOTHING);
  1021.     }
  1022.     *num = atoi(temp);
  1023.  
  1024.     /*
  1025.      *    Check if we had a 'p' or 'P' following the number as
  1026.      *    a flag for displaying the page with that number. - FM
  1027.      */
  1028.     if (strchr(temp, 'p') != NULL || strchr(temp, 'P') != NULL) {
  1029.     int nlines = HText_getNumOfLines();
  1030.     int npages = ((nlines + 1) > display_lines) ?
  1031.         (((nlines + 1) + (display_lines - 1))/(display_lines))
  1032.                             : 1;
  1033.     if (*num < 1)
  1034.         *num = 1;
  1035.     doc->line = (npages <= 1) ?
  1036.                 1 :
  1037.         ((*num <= npages) ? (((*num - 1) * display_lines) + 1)
  1038.                   : (((npages - 1) * display_lines) + 1));
  1039.     return(DO_GOTOPAGE_STUFF);
  1040.     }
  1041.  
  1042.     /*
  1043.      *    Check if we want to make the link corresponding to the
  1044.      *    number the current link, rather than ACTIVATE-ing it.
  1045.      */
  1046.     want_go = (strchr(temp, 'g') != NULL || strchr(temp, 'G') != NULL);
  1047.  
  1048.    /*
  1049.     *  If we have a valid number, act on it.
  1050.     */
  1051.    if (*num > 0) {
  1052.     int info;
  1053.     /*
  1054.      *  Get the lname, and hightext, directly from www
  1055.      *  structures and add it to the cur link so that
  1056.      *  we can pass it transparently on to getfile(),
  1057.      *  and load new_top and new_link if we instead want
  1058.      *  to make the link number current.  These things
  1059.      *  are done so that a link can be selected anywhere
  1060.      *  in the current document, whether it is displayed
  1061.      *  on the screen or not!
  1062.      */
  1063.     if ((info = HTGetLinkInfo(*num,
  1064.                   want_go,
  1065.                   &new_top,
  1066.                   &new_link,
  1067.                   &links[cur].hightext,
  1068.               &links[cur].lname)) == WWW_INTERN_LINK_TYPE) {
  1069.         links[cur].type = WWW_INTERN_LINK_TYPE;
  1070.         return(DO_LINK_STUFF);
  1071.     } else if (info == LINK_LINE_FOUND) {
  1072.         doc->line = new_top + 1;
  1073.         doc->link = new_link;
  1074.         return(DO_GOTOLINK_STUFF);
  1075.     } else if (info) {
  1076.         links[cur].type = WWW_LINK_TYPE;
  1077.         return(DO_LINK_STUFF);
  1078.     } else {
  1079.         return(PRINT_ERROR);
  1080.     }
  1081.     } else {
  1082.     return(PRINT_ERROR);
  1083.     }
  1084. }
  1085.  
  1086. #if defined(EXEC_LINKS) || defined(LYNXCGI_LINKS)
  1087.  
  1088. struct trust {
  1089.     char *src;
  1090.     char *path;
  1091.     int type;
  1092.     struct trust *next;
  1093. };
  1094.  
  1095. static struct trust trusted_exec_default = {
  1096.   "file://localhost/",    "",    EXEC_PATH,        NULL
  1097. };
  1098. static struct trust always_trusted_exec_default = {
  1099.   "none",        "",    ALWAYS_EXEC_PATH,    NULL
  1100. };
  1101. static struct trust trusted_cgi_default = {
  1102.   "",            "",    CGI_PATH,        NULL
  1103. };
  1104.  
  1105. static struct trust *trusted_exec = &trusted_exec_default;
  1106. static struct trust *always_trusted_exec = &always_trusted_exec_default;
  1107. static struct trust *trusted_cgi = &trusted_cgi_default;
  1108.  
  1109. PRIVATE void LYTrusted_free NOARGS
  1110. {
  1111.     struct trust *cur;
  1112.     struct trust *next;
  1113.  
  1114.     if (trusted_exec != &trusted_exec_default) {
  1115.     cur = trusted_exec;
  1116.     while (cur) {
  1117.         FREE(cur->src);
  1118.         FREE(cur->path);
  1119.         next = cur->next;
  1120.         FREE(cur);
  1121.         cur = next;
  1122.     }
  1123.     }
  1124.  
  1125.     if (always_trusted_exec != &always_trusted_exec_default) {
  1126.     cur = always_trusted_exec;
  1127.     while (cur) {
  1128.         FREE(cur->src);
  1129.         FREE(cur->path);
  1130.         next = cur->next;
  1131.         FREE(cur);
  1132.         cur = next;
  1133.     }
  1134.     }
  1135.  
  1136.     if (trusted_cgi != &trusted_cgi_default) {
  1137.     cur = trusted_cgi;
  1138.     while (cur) {
  1139.         FREE(cur->src);
  1140.         FREE(cur->path);
  1141.         next = cur->next;
  1142.         FREE(cur);
  1143.         cur = next;
  1144.     }
  1145.     }
  1146.  
  1147.     return;
  1148. }
  1149.  
  1150. PUBLIC void add_trusted ARGS2(
  1151.     char *,     str,
  1152.     int,        type)
  1153. {
  1154.     struct trust *tp;
  1155.     char *path;
  1156.     char *src = str;
  1157.     int Type = type;
  1158.     static BOOLEAN first = TRUE;
  1159.  
  1160.     if (!src)
  1161.     return;
  1162.     if (first) {
  1163.     atexit(LYTrusted_free);
  1164.     first = FALSE;
  1165.     }
  1166.  
  1167.     path = strchr(src, '\t');
  1168.     if (path)
  1169.     *path++ = '\0';
  1170.     else
  1171.     path = "";
  1172.  
  1173.     tp = (struct trust *)malloc(sizeof(*tp));
  1174.     if (tp == NULL)
  1175.     outofmem(__FILE__, "add_trusted");
  1176.     tp->src = NULL;
  1177.     tp->path = NULL;
  1178.     tp->type = Type;
  1179.     StrAllocCopy(tp->src, src);
  1180.     StrAllocCopy(tp->path, path);
  1181.     if (Type == EXEC_PATH) {
  1182.     if (trusted_exec == &trusted_exec_default)
  1183.         tp->next = NULL;
  1184.     else
  1185.         tp->next = trusted_exec;
  1186.     trusted_exec = tp;
  1187.     } else if (Type == ALWAYS_EXEC_PATH) {
  1188.     if (always_trusted_exec == &always_trusted_exec_default)
  1189.         tp->next = NULL;
  1190.     else
  1191.         tp->next = always_trusted_exec;
  1192.     always_trusted_exec = tp;
  1193.     } else if (Type == CGI_PATH) {
  1194.     if (trusted_cgi == &trusted_cgi_default)
  1195.         tp->next = NULL;
  1196.     else
  1197.         tp->next = trusted_cgi;
  1198.     trusted_cgi = tp;
  1199.     }
  1200. }
  1201.  
  1202. /*
  1203.  *  Check to see if the supplied paths is allowed to be executed.
  1204.  */
  1205. PUBLIC BOOLEAN exec_ok ARGS3(
  1206.     CONST char *,    source,
  1207.     CONST char *,    link,
  1208.     int,        type)
  1209. {
  1210.     struct trust *tp;
  1211.     CONST char *cp;
  1212.     int Type = type;
  1213.  
  1214.     /*
  1215.      *    Always OK if it is a jump file shortcut.
  1216.      */
  1217.     if (LYJumpFileURL)
  1218.     return TRUE;
  1219.  
  1220.     /*
  1221.      *    Choose the trust structure based on the type.
  1222.      */
  1223.     if (Type == EXEC_PATH) {
  1224.     tp = trusted_exec;
  1225.     } else if (Type == ALWAYS_EXEC_PATH) {
  1226.     tp = always_trusted_exec;
  1227.     } else if (Type == CGI_PATH) {
  1228.     tp = trusted_cgi;
  1229.     } else {
  1230.     HTAlert(MALFORMED_EXEC_REQUEST);
  1231.     return FALSE;
  1232.     }
  1233.  
  1234. #ifdef VMS
  1235.     /*
  1236.      *    Security: reject on relative path.
  1237.      */
  1238.     if ((cp = strchr(link, '[')) != NULL) {
  1239.     char *cp1;
  1240.     if (((cp1 = strchr(cp, '-')) != NULL) &&
  1241.         strchr(cp1, ']') != NULL) {
  1242.         while (cp1[1] == '-')
  1243.         cp1++;
  1244.         if (cp1[1] == ']' ||
  1245.         cp1[1] == '.') {
  1246.         HTAlert(RELPATH_IN_EXEC_LINK);
  1247.         return FALSE;
  1248.         }
  1249.     }
  1250.     }
  1251. #else
  1252.     /*
  1253.      *    Security: reject on relative path.
  1254.      */
  1255.     if (strstr(link, "../") != NULL) {
  1256.     HTAlert(RELPATH_IN_EXEC_LINK);
  1257.     return FALSE;
  1258.     }
  1259.  
  1260.     /*
  1261.      *    Security: reject on strange character.
  1262.      */
  1263.     for (cp = link; *cp != '\0'; cp++) {
  1264.     if (!isalnum(*cp) &&
  1265.         *cp != '_' && *cp != '-' && *cp != ' ' &&
  1266.         *cp != ':' && *cp != '.' && *cp != '/' &&
  1267.         *cp != '@' && *cp != '~' && *cp != '$' &&
  1268.         *cp != '&' && *cp != '+' && *cp != '=' &&
  1269.         *cp != '\t') {
  1270.         char buf[128];
  1271.  
  1272.         sprintf(buf,
  1273.             BADCHAR_IN_EXEC_LINK,
  1274.             *cp);
  1275.         HTAlert(buf);
  1276.         return FALSE;
  1277.     }
  1278.     }
  1279. #endif /* VMS */
  1280.  
  1281. check_tp_for_entry:
  1282.     while (tp) {
  1283.     if (tp->type == Type) {
  1284.         char CONST *command = link;
  1285.  
  1286.         if (strstr(command,"//") == link) {
  1287.         command += 2;
  1288.         }
  1289. #ifdef VMS
  1290.         if (strncasecomp(source, tp->src, strlen(tp->src)) == 0 &&
  1291.         strncasecomp(command, tp->path, strlen(tp->path)) == 0)
  1292. #else
  1293.         if (strncmp(source, tp->src, strlen(tp->src)) == 0 &&
  1294.         strncmp(command, tp->path, strlen(tp->path)) == 0)
  1295. #endif /* VMS */
  1296.         return TRUE;
  1297.     }
  1298.     tp = tp->next;
  1299.     }
  1300.     if (Type == EXEC_PATH &&
  1301.     always_trusted_exec != &always_trusted_exec_default) {
  1302.     Type = ALWAYS_EXEC_PATH;
  1303.     tp = always_trusted_exec;
  1304.     goto check_tp_for_entry;
  1305.     }
  1306.     if (!(no_exec && type == ALWAYS_EXEC_PATH))
  1307.     HTAlert(BADLOCPATH_IN_EXEC_LINK);
  1308.     return FALSE;
  1309. }
  1310. #endif /* EXEC_LINKS || LYNXCGI_LINKS */
  1311.  
  1312. PRIVATE int fix_http_urls ARGS1(
  1313.     document *,    doc)
  1314. {
  1315.     char *slash;
  1316.  
  1317.     /*
  1318.      *    If it's an ftp URL with a trailing slash, trim it off.
  1319.      */
  1320.     if (!strncmp(doc->address, "ftp", 3) &&
  1321.     doc->address[strlen(doc->address)-1] == '/') {
  1322.     char * proxy;
  1323.     char *path = HTParse(doc->address, "", PARSE_PATH|PARSE_PUNCTUATION);
  1324.  
  1325.     /*
  1326.      *  If the path is a lone slash, we're done. - FM
  1327.      */
  1328.     if (path) {
  1329.         if (path[0] == '/' && path[1] == '\0') {
  1330.         FREE(path);
  1331.         return 0;
  1332.         }
  1333.         FREE(path);
  1334.     }
  1335.  
  1336.     /*
  1337.      *  If we're proxying ftp, don't trim anything. - KW
  1338.      */
  1339.     if (((proxy = (char *)getenv("ftp_proxy")) != NULL) &&
  1340.         *proxy != '\0' && !override_proxy(doc->address))
  1341.         return 0;
  1342.  
  1343.     /*
  1344.      *  If we get to here, trim the trailing slash. - FM
  1345.      */
  1346.     CTRACE(tfp, "fix_http_urls: URL '%s'\n", doc->address);
  1347.     doc->address[strlen(doc->address)-1] = '\0';
  1348.     if (TRACE) {
  1349.         fprintf(tfp, "        changed to '%s'\n", doc->address);
  1350.         if (!LYTraceLogFP)
  1351.         sleep(MessageSecs);
  1352.     }
  1353.     }
  1354.  
  1355.     /*
  1356.      *    If there isn't a slash besides the two at the beginning, append one.
  1357.      */
  1358.     if ((slash = strrchr(doc->address, '/')) != NULL) {
  1359.     if (*(slash-1) != '/' || *(slash-2) != ':') {
  1360.         return(0);
  1361.     }
  1362.     }
  1363.     CTRACE(tfp, "fix_http_urls: URL '%s'\n", doc->address);
  1364.     StrAllocCat(doc->address, "/");
  1365.     if (TRACE) {
  1366.     fprintf(tfp, "        changed to '%s'\n",doc->address);
  1367.     if (!LYTraceLogFP)
  1368.         sleep(MessageSecs);
  1369.     }
  1370.  
  1371.     return(1);
  1372. }
  1373.