Exemple #1
0
/*
**	Localize a user profile by filling in all the information that we
**	can figure out automatically, for example the email address, news
**	server etc.
*/
PUBLIC BOOL HTUserProfile_localize (HTUserProfile * up)
{
    if (up) {
	HTTRACE(CORE_TRACE, "User Profile Localizing %p\n" _ up);

	/* Find the FQDN */
	up->fqdn = HTGetHostName();

	/* Find the user email address */
	up->email = HTGetMailAddress();

	/* Find the news server */
	up->news = HTGetNewsServer();

	/* Find the timezone offset */
	up->timezone = HTGetTimeZoneOffset();

	/* Find the default location for temporary files */
	StrAllocCopy(up->tmp, HT_TMP_ROOT);
	if (*(up->tmp+strlen(up->tmp)-1) != DIR_SEPARATOR_CHAR)
	    StrAllocCat(up->tmp, DIR_SEPARATOR_STR);

	return YES;
    }
    return NO;
}
Exemple #2
0
/*
**   This function tries really hard to find a non-existent filename relative
**   to the path given. Returns a string that must be freed by the caller or
**   NULL on error.
*/
PRIVATE char * get_filename (char * base, const char * uri,
			     const char * suffix, BOOL use_last_segment)
{
    char * path = NULL;
    if (use_last_segment) {
	char * uri_path = NULL;
	if (uri && (uri_path = HTParse(uri, "", PARSE_PATH|PARSE_PUNCTUATION))) {
	    char * last_segment = strrchr(uri_path, '/');
	    BOOL slash = (base && *(base+strlen(base)-1)==DIR_SEPARATOR_CHAR); 
	    if (last_segment && *(last_segment+1)) {
		StrAllocMCopy(&path, base ? base : "",
			      slash ? "" : DIR_SEPARATOR_STR, ++last_segment, NULL);
	    } else {
		StrAllocMCopy(&path, base ? base : "",
			      slash ? "" : DIR_SEPARATOR_STR, DEFAULT_LAST_SEGMENT,
			      suffix ? suffix : "", NULL);
	    }
	}
    } else {
	path = HTGetTmpFileName(base);
        if (path && suffix) StrAllocCat(path, suffix);
    }

    HTTRACE(STREAM_TRACE, "Save file... Temporaray file `%s\'\n" _ path ? path : "<null>");
    return path;
}
Exemple #3
0
/*
**	Proxy and Gateway BEFORE filter
**	-------------------------------
**	Checks for registerd proxy servers or gateways and sees whether this
**	request should be redirected to a proxy or a gateway. Proxies have
**	higher priority than gateways so we look for them first!
**	For HTTP/1.0 and HTTP/1.1 we may only send a full URL (including the
**	host portion) to proxy servers. Therefore, we tell the Library whether
**	to use the full URL or the traditional HTTP one without the host part.
*/
PUBLIC int HTProxyFilter (HTRequest * request, void * param, int mode)
{
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * addr = HTAnchor_physical(anchor);
    char * physical = NULL;
    if ((physical = HTProxy_find(addr))) {
	HTRequest_setFullURI(request, YES);			  /* For now */
	HTRequest_setProxy(request, physical);
	HT_FREE(physical);
#if 0
	/* Don't paste the URLs together anymore */
	StrAllocCat(physical, addr);
	HTAnchor_setPhysical(anchor, physical);	
#endif
    } else if ((physical = HTGateway_find(addr))) {
	/* 
	** A gateway URL is crated by chopping off any leading "/" to make the
	** host into part of path
	*/
	char * path =
	    HTParse(addr, "", PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
	char * gatewayed = HTParse((*path=='/') ? path+1 : path, physical, PARSE_ALL);
	HTAnchor_setPhysical(anchor, gatewayed);
	HT_FREE(path);
	HT_FREE(gatewayed);
	HTRequest_setFullURI(request, NO);
	HTRequest_deleteProxy(request);
    } else {
	HTRequest_setFullURI(request, NO);			  /* For now */
	HTRequest_deleteProxy(request);
    }
    return HT_OK;
}
Exemple #4
0
/*
**  Escape a filename and add a '/' if it's a directory
*/
PRIVATE char * expand_name (char * name, HTFileMode mode)
{
    char * escaped = HTEscape(name, URL_XPALPHAS);
    if (mode == HT_IS_DIR)
	if (*(name+strlen(name)-1) != '/') StrAllocCat(escaped, "/");
    return escaped;
}
Exemple #5
0
static char *showRanges(int *state)
{
    char *result = 0;
    int range[2];
    int i;

    range[0] = range[1] = -1;
    for (i = 0; i < KEYMAP_SIZE; ++i) {
	if (!state[i]) {
	    int code = CurrentLineEditor()[i];

	    if (code == LYE_CHAR) {
		if (range[0] < 0)
		    range[0] = i;
		range[1] = i;
		state[i] = 3;
	    } else if (range[0] >= 0) {
		if (non_empty(result))
		    StrAllocCat(result, ", ");
		HTSprintf(&result, "%d-%d", range[0], range[1]);
		range[0] = range[1] = -1;
	    }
	}
    }
    return result;
}
Exemple #6
0
/*							    HTErrorSetPrefix
**
**	Sets the prefix for error URLs in the error message
*/
PUBLIC void HTErrorSetPrefix ARGS1(char *, path)
{
    if (path && *path) {
	StrAllocCopy(HTErrorPrefix, path);
	if (*(HTErrorPrefix+strlen(HTErrorPrefix)-1) != '/')
	    StrAllocCat(HTErrorPrefix, "/");
    }
}
Exemple #7
0
PRIVATE void comma_append ARGS2(
    char **,	dst,
    char *,	src)
{
    if (*src) {
	while (*src == ',' || isspace(UCH(*src)))
	    src++;
	if (*src) {
	    if (isEmpty(*dst)) {
		StrAllocCopy(*dst, src);
	    } else {
		StrAllocCat(*dst, ",");
		StrAllocCat(*dst, src);
	    }
	}
    }
}
Exemple #8
0
/*
**	Existing entries are replaced with new ones
*/
PRIVATE BOOL add_object (HTList * list, const char * access, const char * url,
			 BOOL regex, int regex_flags)
{
    HTProxy *me;
    if (!list || !access || !url || !*url)
	return NO;
    if ((me = (HTProxy *) HT_CALLOC(1, sizeof(HTProxy))) == NULL)
	HT_OUTOFMEM("add_object");
    StrAllocCopy(me->access, access);		     	    /* Access method */

#ifdef HT_POSIX_REGEX
    /* 
    **  If we support regular expressions then compile one up for
    **  this regular expression. Otherwise use is as a normal
    **  access scheme.
    */
    if (regex) {
	me->regex = get_regex_t(access,
				regex_flags < 0 ?
				W3C_DEFAULT_REGEX_FLAGS : regex_flags);
    } else
#endif
    {
	char *ptr = me->access;
	while ((*ptr = TOLOWER(*ptr))) ptr++;
    }

    me->url = HTParse(url, "", PARSE_ACCESS+PARSE_HOST+PARSE_PUNCTUATION);
    if (*(me->url+strlen(me->url)-1) != '/')
	StrAllocCat(me->url, "/");
    me->url = HTSimplify(&me->url);

    /* See if we already have this one */
    {
	HTList *cur = list;
	HTProxy *pres;
	while ((pres = (HTProxy *) HTList_nextObject(cur)) != NULL) {
	    if (!strcmp(pres->access, me->access))
		break;				       /* We already have it */
	}
	if (pres) {
	    HTTRACE(PROT_TRACE, "HTProxy..... replacing for `%s\' access %s\n" _ 
			me->url _ me->access);
	    HT_FREE(pres->access);
	    HT_FREE(pres->url);
#ifdef HT_POSIX_REGEX
	    if (pres->regex) regfree(pres->regex);
#endif
	    HTList_removeObject(list, (void *) pres);
	    HT_FREE(pres);
	}
	HTTRACE(PROT_TRACE, "HTProxy..... adding for `%s\' access %s\n" _ 
		    me->url _ me->access);
	HTList_addObject(list, (void *) me);
    }
    return YES;
}
Exemple #9
0
PUBLIC BOOL HTUserProfile_setTmp (HTUserProfile * up, const char * tmp)
{
    if (up && tmp) {
	StrAllocCopy(up->tmp, tmp);
	if (*(up->tmp+strlen(up->tmp)-1) != DIR_SEPARATOR_CHAR)
	    StrAllocCat(up->tmp, DIR_SEPARATOR_STR);
	return YES;
    }
    return NO;
}
Exemple #10
0
PRIVATE char *net_EndColorHTMLTag (DataObject *obj)
{
	char *new_markup = 0;

	if(obj->in_broken_html)
	  {
       	StrAllocCopy(new_markup, END_BROKEN_ATTRIBUTE_MARKUP);
		obj->in_broken_html = FALSE;
	  }
	StrAllocCat(new_markup, "&gt;");
	StrAllocCat(new_markup, END_TAG_MARKUP);
	if (obj->tag_type == P_SCRIPT)
	  {
		StrAllocCat(new_markup, "</PRE><XMP>");
		obj->state = IN_SCRIPT;
	  }
	else
	  {
		obj->state = IN_CONTENT;
	  }
	return new_markup;
}
Exemple #11
0
/*
 * Remove all older versions of the given file.  We may fail to remove some
 * version due to permissions -- the loop stops either at that point, or when
 * we run out of older versions to remove.
 */
void HTVMS_purge(char *filename)
{
    char *older_file = 0;
    char *oldest_file = 0;
    struct stat sb;

    StrAllocCopy(older_file, filename);
    StrAllocCat(older_file, ";-1");

    while (remove(older_file) == 0) ;
    /*
     * If we do not have any more older versions, it is safe to rename the
     * current file to version #1.
     */
    if (stat(older_file, &sb) != 0) {
	StrAllocCopy(oldest_file, filename);
	StrAllocCat(oldest_file, ";1");
	rename(older_file, oldest_file);
	FREE(oldest_file);
    }

    FREE(older_file);
}
static void set_environ(int name,
			const char *value,
			const char *no_value)
{
    static const char *names[MAX_PUTENV] =
    {
	"LYNX_PRINT_TITLE",
	"LYNX_PRINT_URL",
	"LYNX_PRINT_DATE",
	"LYNX_PRINT_LASTMOD",
    };
    static char *pointers[MAX_PUTENV];
    char *envbuffer = 0;

#ifdef VMS
#define SET_ENVIRON(name, value, no_value) set_environ(name, value, no_value)
    char temp[80];

    StrAllocCopy(envbuffer, value);
    if (isEmpty(envbuffer))
	StrAllocCopy(envbuffer, no_value);
    Define_VMSLogical(strcpy(temp, names[name]), envbuffer);
    FREE(envbuffer);
#else
#define SET_ENVIRON(name, value, no_value) set_environ(name, value, "")
    /*
     * Once we've given a string to 'putenv()', we must not free it until we
     * give it a string to replace it.
     */
    StrAllocCopy(envbuffer, names[name]);
    StrAllocCat(envbuffer, "=");
    StrAllocCat(envbuffer, value ? value : no_value);
    putenv(envbuffer);
    FREE(pointers[name]);
    pointers[name] = envbuffer;
#endif
}
Exemple #13
0
PUBLIC void HTAnchor_appendTitle ARGS2(
	HTParentAnchor *,	me,
	CONST char *,		title)
{
    int i;

    if (me) {
	StrAllocCat(me->title, title);
	for (i = 0; me->title[i]; i++) {
	    if (UCH(me->title[i]) == 1 ||
		UCH(me->title[i]) == 2) {
		me->title[i] = ' ';
	    }
	}
    }
}
/* PUBLIC					HTAA_makeProtectionTemplate()
 *		CREATE A PROTECTION TEMPLATE FOR THE FILES
 *		IN THE SAME DIRECTORY AS THE GIVEN FILE
 *		(Used by server if there is no fancier way for
 *		it to tell the client, and by browser if server
 *		didn't send WWW-ProtectionTemplate: field)
 * ON ENTRY:
 *	docname is the document pathname (from URL).
 *
 * ON EXIT:
 *	returns a template matching docname, and other files
 *		files in that directory.
 *
 *		E.g.  /foo/bar/x.html  =>  /foo/bar/ *
 *						    ^
 *				Space only to prevent it from
 *				being a comment marker here,
 *				there really isn't any space.
 */
char *HTAA_makeProtectionTemplate(const char *docname)
{
    char *ctemplate = NULL;
    char *slash = NULL;

    if (docname) {
	StrAllocCopy(ctemplate, docname);
	slash = strrchr(ctemplate, '/');
	if (slash)
	    slash++;
	else
	    slash = ctemplate;
	*slash = '\0';
	StrAllocCat(ctemplate, "*");
    } else
	StrAllocCopy(ctemplate, "*");

    CTRACE((tfp, "make_template: made template `%s' for file `%s'\n",
	    ctemplate, docname));

    return ctemplate;
}
Exemple #15
0
PRIVATE void
net_get_default_help_URL(char **pHelpBase)
{
	int		success;
	int32	helpType;
	
	if ((success = PREF_GetIntPref(PREF_DEFAULT_HELP_LOC_ID, &helpType))
		== PREF_NOERROR) {

		switch (helpType) {

			case 0:		/* Netscape's help site: */
				StrAllocCopy(*pHelpBase, PREF_NSCP_HELP_URL);
				break;
			case 1:		/* Internal installed location. */
				*pHelpBase = FE_GetNetHelpDir();
				break;
			case 2:
				success = PREF_CopyCharPref(PREF_DEFAULT_HELP_URL_ID, pHelpBase);
				break;
			default:
				success = PREF_ERROR;
		}
		/* ...any of the above might accidentally _not_ end with a '/'*/
		if ((*pHelpBase) && ((*pHelpBase)[XP_STRLEN(*pHelpBase)-1]) != '/') {
			StrAllocCat(*pHelpBase, "/");
		}
	}

	/* Fall back on the Netscape help site */

	if (success != PREF_NOERROR) {
		StrAllocCopy(*pHelpBase, PREF_NSCP_HELP_URL);
	}

	return;
}
/*
 * LYShowInfo prints a page of info about the current file and the link that
 * the cursor is on.
 */
int LYShowInfo(DocInfo *doc,
	       DocInfo *newdoc,
	       char *owner_address)
{
    static char tempfile[LY_MAXPATH] = "\0";

    int url_type;
    FILE *fp0;
    char *Title = NULL;
    const char *cp;
    char *temp = NULL;
    char *buffer = NULL;

    BOOLEAN LYInfoAdvanced = (BOOL) (user_mode == ADVANCED_MODE);

#ifdef DIRED_SUPPORT
    struct stat dir_info;
    const char *name;
#endif /* DIRED_SUPPORT */

    if (LYReuseTempfiles) {
	fp0 = LYOpenTempRewrite(tempfile, HTML_SUFFIX, "w");
    } else {
	(void) LYRemoveTemp(tempfile);
	fp0 = LYOpenTemp(tempfile, HTML_SUFFIX, "w");
    }
    if (fp0 == NULL) {
	HTAlert(CANNOT_OPEN_TEMP);
	return (-1);
    }

    /*
     * Point the address pointer at this Url
     */
    LYLocalFileToURL(&newdoc->address, tempfile);

    if (nlinks > 0 && links[doc->link].lname != NULL &&
	(url_type = is_url(links[doc->link].lname)) != 0 &&
	(url_type == LYNXEXEC_URL_TYPE ||
	 url_type == LYNXPROG_URL_TYPE)) {
	char *last_slash = strrchr(links[doc->link].lname, '/');
	int next_to_last = (int) strlen(links[doc->link].lname) - 1;

	if ((last_slash - links[doc->link].lname) == next_to_last) {
	    links[doc->link].lname[next_to_last] = '\0';
	}
    }

    label_columns = 9;

    WriteInternalTitle(fp0, SHOWINFO_TITLE);

    fprintf(fp0, "<h1>%s %s (%s) (<a href=\"%s\">%s</a>)",
	    LYNX_NAME, LYNX_VERSION,
	    LYVersionDate(),
	    (LYVersionIsRelease()? LYNX_WWW_HOME : LYNX_WWW_DIST),
	    LYVersionStatus());

    fprintf(fp0, "</h1>\n");	/* don't forget to close <h1> */

#ifdef DIRED_SUPPORT
    if (lynx_edit_mode && nlinks > 0) {

	BEGIN_DL(gettext("Directory that you are currently viewing"));

	temp = HTfullURL_toFile(doc->address);
	ADD_SS(gettext("Name:"), temp);
	FREE(temp);

	dt_URL(fp0, doc->address);

	END_DL();

	temp = HTfullURL_toFile(links[doc->link].lname);

	if (lstat(temp, &dir_info) == -1) {
	    CTRACE((tfp, "lstat(%s) failed, errno=%d\n", temp, errno));
	    HTAlert(CURRENT_LINK_STATUS_FAILED);
	} else {
	    char modes[80];

	    label_columns = 16;
	    if (S_ISDIR(dir_info.st_mode)) {
		BEGIN_DL(gettext("Directory that you have currently selected"));
	    } else if (S_ISREG(dir_info.st_mode)) {
		BEGIN_DL(gettext("File that you have currently selected"));
#ifdef S_IFLNK
	    } else if (S_ISLNK(dir_info.st_mode)) {
		BEGIN_DL(gettext("Symbolic link that you have currently selected"));
#endif
	    } else {
		BEGIN_DL(gettext("Item that you have currently selected"));
	    }
	    ADD_SS(gettext("Full name:"), temp);
#ifdef S_IFLNK
	    if (S_ISLNK(dir_info.st_mode)) {
		char buf[MAX_LINE];
		int buf_size;
		size_t limit = sizeof(buf) - 1;

		if ((buf_size = (int) readlink(temp, buf, limit)) != -1) {
		    if (buf_size > (int) limit)
			buf_size = (int) limit;
		    buf[buf_size] = '\0';
		} else {
		    sprintf(buf, "%.*s", (int) limit,
			    gettext("Unable to follow link"));
		}
		ADD_SS(gettext("Points to file:"), buf);
	    }
#endif
	    name = HTAA_UidToName((int) dir_info.st_uid);
	    if (*name)
		ADD_SS(gettext("Name of owner:"), name);
	    name = HTAA_GidToName((int) dir_info.st_gid);
	    if (*name)
		ADD_SS(gettext("Group name:"), name);
	    if (S_ISREG(dir_info.st_mode)) {
		ADD_NN(gettext("File size:"),
		       (long) dir_info.st_size,
		       gettext("(bytes)"));
	    }
	    /*
	     * Include date and time information.
	     */
	    ADD_SS(gettext("Creation date:"),
		   ctime(&dir_info.st_ctime));

	    ADD_SS(gettext("Last modified:"),
		   ctime(&dir_info.st_mtime));

	    ADD_SS(gettext("Last accessed:"),
		   ctime(&dir_info.st_atime));

	    END_DL();

	    label_columns = 9;
	    BEGIN_DL(gettext("Access Permissions"));
	    modes[0] = '\0';
	    modes[1] = '\0';	/* In case there are no permissions */
	    modes[2] = '\0';
	    if ((dir_info.st_mode & S_IRUSR))
		strcat(modes, ", read");
	    if ((dir_info.st_mode & S_IWUSR))
		strcat(modes, ", write");
	    if ((dir_info.st_mode & S_IXUSR)) {
		if (S_ISDIR(dir_info.st_mode))
		    strcat(modes, ", search");
		else {
		    strcat(modes, ", execute");
		    if ((dir_info.st_mode & S_ISUID))
			strcat(modes, ", setuid");
		}
	    }
	    ADD_SS(gettext("Owner:"), &modes[2]);

	    modes[0] = '\0';
	    modes[1] = '\0';	/* In case there are no permissions */
	    modes[2] = '\0';
	    if ((dir_info.st_mode & S_IRGRP))
		strcat(modes, ", read");
	    if ((dir_info.st_mode & S_IWGRP))
		strcat(modes, ", write");
	    if ((dir_info.st_mode & S_IXGRP)) {
		if (S_ISDIR(dir_info.st_mode))
		    strcat(modes, ", search");
		else {
		    strcat(modes, ", execute");
		    if ((dir_info.st_mode & S_ISGID))
			strcat(modes, ", setgid");
		}
	    }
	    ADD_SS(gettext("Group:"), &modes[2]);

	    modes[0] = '\0';
	    modes[1] = '\0';	/* In case there are no permissions */
	    modes[2] = '\0';
	    if ((dir_info.st_mode & S_IROTH))
		strcat(modes, ", read");
	    if ((dir_info.st_mode & S_IWOTH))
		strcat(modes, ", write");
	    if ((dir_info.st_mode & S_IXOTH)) {
		if (S_ISDIR(dir_info.st_mode))
		    strcat(modes, ", search");
		else {
		    strcat(modes, ", execute");
#ifdef S_ISVTX
		    if ((dir_info.st_mode & S_ISVTX))
			strcat(modes, ", sticky");
#endif
		}
	    }
	    ADD_SS(gettext("World:"), &modes[2]);
	    END_DL();
	}
	FREE(temp);
    } else {
#endif /* DIRED_SUPPORT */

	BEGIN_DL(gettext("File that you are currently viewing"));

	LYformTitle(&Title, doc->title);
	HTSprintf(&temp, "%s%s",
		  LYEntifyTitle(&buffer, Title),
		  ((doc->isHEAD &&
		    !strstr(Title, " (HEAD)") &&
		    !strstr(Title, " - HEAD")) ? " (HEAD)" : ""));
	ADD_SS(gettext("Linkname:"), temp);
	FREE(temp);

	dt_URL(fp0, doc->address);

	if (HTLoadedDocumentCharset()) {
	    ADD_SS(gettext("Charset:"),
		   HTLoadedDocumentCharset());
	} else {
	    LYUCcharset *p_in = HTAnchor_getUCInfoStage(HTMainAnchor,
							UCT_STAGE_PARSER);

	    if (!p_in || isEmpty(p_in->MIMEname) ||
		HTAnchor_getUCLYhndl(HTMainAnchor, UCT_STAGE_PARSER) < 0) {
		p_in = HTAnchor_getUCInfoStage(HTMainAnchor, UCT_STAGE_MIME);
	    }
	    if (p_in && non_empty(p_in->MIMEname) &&
		HTAnchor_getUCLYhndl(HTMainAnchor, UCT_STAGE_MIME) >= 0) {
		HTSprintf(&temp, "%s %s",
			  LYEntifyTitle(&buffer, p_in->MIMEname),
			  gettext("(assumed)"));
		ADD_SS(gettext("Charset:"), p_in->MIMEname);
		FREE(temp);
	    }
	}

	if ((cp = HText_getServer()) != NULL && *cp != '\0')
	    ADD_SS(gettext("Server:"), cp);

	if ((cp = HText_getDate()) != NULL && *cp != '\0')
	    ADD_SS(gettext("Date:"), cp);

	if ((cp = HText_getLastModified()) != NULL && *cp != '\0')
	    ADD_SS(gettext("Last Mod:"), cp);

	if (LYInfoAdvanced) {
	    if (HTMainAnchor && HTMainAnchor->expires) {
		ADD_SS(gettext("Expires:"), HTMainAnchor->expires);
	    }
	    if (HTMainAnchor && HTMainAnchor->cache_control) {
		ADD_SS(gettext("Cache-Control:"), HTMainAnchor->cache_control);
	    }
	    if (HTMainAnchor && HTMainAnchor->content_length > 0) {
		ADD_NN(gettext("Content-Length:"),
		       HTMainAnchor->content_length,
		       gettext("bytes"));
	    } else {
		ADD_NN(gettext("Length:"),
		       HText_getNumOfBytes(),
		       gettext("bytes"));
	    }
	    if (HTMainAnchor && HTMainAnchor->content_language) {
		ADD_SS(gettext("Language:"), HTMainAnchor->content_language);
	    }
	}

	if (doc->post_data) {
	    fprintf(fp0, "<dt><em>%s</em> <xmp>%.*s</xmp>\n",
		    LYEntifyTitle(&buffer, gettext("Post Data:")),
		    BStrLen(doc->post_data),
		    BStrData(doc->post_data));
	    ADD_SS(gettext("Post Content Type:"), doc->post_content_type);
	}

	ADD_SS(gettext("Owner(s):"),
	       (owner_address
		? owner_address
		: NO_NOTHING));

	ADD_NN(gettext("size:"),
	       HText_getNumOfLines(),
	       gettext("lines"));

	StrAllocCopy(temp,
		     ((lynx_mode == FORMS_LYNX_MODE)
		      ? gettext("forms mode")
		      : (HTisDocumentSource()
			 ? gettext("source")
			 : gettext("normal"))));
	if (doc->safe)
	    StrAllocCat(temp, gettext(", safe"));
	if (doc->internal_link)
	    StrAllocCat(temp, gettext(", via internal link"));

	if (LYInfoAdvanced) {
	    if (HText_hasNoCacheSet(HTMainText))
		StrAllocCat(temp, gettext(", no-cache"));
	    if (HTAnchor_isISMAPScript((HTAnchor *) HTMainAnchor))
		StrAllocCat(temp, gettext(", ISMAP script"));
	    if (doc->bookmark)
		StrAllocCat(temp, gettext(", bookmark file"));
	}

	ADD_SS(gettext("mode:"), temp);
	FREE(temp);

	END_DL();

	if (nlinks > 0) {
	    BEGIN_DL(gettext("Link that you currently have selected"));
	    ADD_SS(gettext("Linkname:"),
		   LYGetHiliteStr(doc->link, 0));
	    if (lynx_mode == FORMS_LYNX_MODE &&
		links[doc->link].type == WWW_FORM_LINK_TYPE) {
		if (links[doc->link].l_form->submit_method) {
		    int method = links[doc->link].l_form->submit_method;
		    char *enctype = links[doc->link].l_form->submit_enctype;

		    ADD_SS(gettext("Method:"),
			   ((method == URL_POST_METHOD) ? "POST" :
			    ((method == URL_MAIL_METHOD) ? "(email)" :
			     "GET")));
		    ADD_SS(gettext("Enctype:"),
			   (non_empty(enctype)
			    ? enctype
			    : "application/x-www-form-urlencoded"));
		}
		if (links[doc->link].l_form->submit_action) {
		    ADD_SS(gettext("Action:"),
			   links[doc->link].l_form->submit_action);
		}
		if (!(links[doc->link].l_form->submit_method &&
		      links[doc->link].l_form->submit_action)) {
		    fprintf(fp0, "<dt>&nbsp;%s\n",
			    LYEntifyTitle(&buffer, gettext("(Form field)")));
		}
	    } else {
		dt_URL(fp0, NonNull(links[doc->link].lname));
	    }
	    END_DL();

	} else {
	    fprintf(fp0, "<h2>%s</h2>",
		    LYEntifyTitle(&buffer,
				  gettext("No Links on the current page")));
	}

	if ((cp = HText_getHttpHeaders()) != 0) {
	    fprintf(fp0, "<h2>%s</h2>",
		    LYEntifyTitle(&buffer, gettext("Server Headers:")));
	    fprintf(fp0, "<pre>%s</pre>",
		    LYEntifyTitle(&buffer, cp));
	}
#ifdef DIRED_SUPPORT
    }
#endif /* DIRED_SUPPORT */
    EndInternalPage(fp0);

    LYrefresh();

    LYCloseTemp(tempfile);
    FREE(Title);
    FREE(buffer);

    return (0);
}
Exemple #17
0
PRIVATE int FileEvent (SOCKET soc, void * pVoid, HTEventType type)
{
    file_info *file = pVoid;			      /* Specific access information */
    int status = HT_ERROR;
    HTNet * net = file->net;
    HTRequest * request = HTNet_request(net);
    HTParentAnchor * anchor = HTRequest_anchor(request);

    /*
    ** Initiate a new file structure and bind to request structure
    ** This is actually state FILE_BEGIN, but it can't be in the state
    ** machine as we need the structure first.
    */
    if (type == HTEvent_CLOSE) {				      /* Interrupted */
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
			   NULL, 0, "HTLoadFile");
	FileCleanup(request, HT_INTERRUPTED);
	return HT_OK;
    }


    /* Now jump into the machine. We know the state from the previous run */
    while (1) {
	switch (file->state) {
	case FS_BEGIN:

	    /* We only support safe (GET, HEAD, etc) methods for the moment */
	    if (!HTMethod_isSafe(HTRequest_method(request))) {
		HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;
		break;
	    }

	    /* Check whether we have access to local disk at all */
	    if (HTLib_secure()) {
		HTTRACE(PROT_TRACE, "LoadFile.... No access to local file system\n");
		file->state = FS_TRY_FTP;
		break;
	    }
	    file->local = HTWWWToLocal(HTAnchor_physical(anchor), "",
				       HTRequest_userProfile(request));
	    if (!file->local) {
		file->state = FS_TRY_FTP;
		break;
	    }

	    /* Create a new host object and link it to the net object */
	    {
		HTHost * host = NULL;
		if ((host = HTHost_new("localhost", 0)) == NULL) return HT_ERROR;
		HTNet_setHost(net, host);
		if (HTHost_addNet(host, net) == HT_PENDING) {
		    HTTRACE(PROT_TRACE, "HTLoadFile.. Pending...\n");
		    /* move to the hack state */
		    file->state = FS_PENDING;
		    return HT_OK;
		}
	    }
	    file->state = FS_DO_CN;
	    break;

	case FS_PENDING:
	    /*
	    ** 2000/08/10 JK : This is a funny state. Because of the
	    ** internal libwww stacks, when doing multiple local
	    ** requests (e.g., while using the Robot), we need to ask
	    ** again for the host object. If we had jumped directly to
	    ** the FS_DO_CN state, libwww would have blocked because
	    ** of socket starvation.
	    ** This state is similar to FS_BEGINNING, but just requests 
	    ** the host object. 
	    ** YES. THIS IS AN UGLY HACK!!
	    */
	    {
		HTHost * host = NULL;
		if ((host = HTHost_new("localhost", 0)) == NULL) return HT_ERROR;
		HTNet_setHost(net, host);
		if (HTHost_addNet(host, net) == HT_PENDING) {
		    HTTRACE(PROT_TRACE, "HTLoadFile.. Pending...\n");
		    file->state = FS_PENDING;
		    return HT_OK;
		}
	    }
	    file->state = FS_DO_CN;
	    break;

	case FS_DO_CN:
	    /*
	    ** If we have to do content negotiation then find the object that
	    ** fits best into either what the client has indicated in the
	    ** accept headers or what the client has registered on its own.
	    ** The object chosen can in fact be a directory! However, content
	    ** negotiation only makes sense if we can read the directory!
	    ** We stat the file in order to find the size and to see it if
	    ** exists.
	    */
	    if (HTRequest_negotiation(request) &&
		HTMethod_isSafe(HTRequest_method(request))) {
 		char * conneg = HTMulti(request, file->local,&file->stat_info);
		if (conneg) {
		    HT_FREE(file->local);
		    file->local = conneg;
		    HTAnchor_setPhysical(anchor, conneg);
		    HTTRACE(PROT_TRACE, "Load File... Found `%s\'\n" _ conneg);
		} else {
		    HTTRACE(PROT_TRACE, "Load File... Not found - even tried content negotiation\n");
		    HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_ERROR;
		    break;
		}
	    } else {
		if (HT_STAT(file->local, &file->stat_info) == -1) {
		    HTTRACE(PROT_TRACE, "Load File... Not found `%s\'\n" _ file->local);
		    HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_FOUND,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_ERROR;
		    break;
		}
	    }

	    /*
	    ** Check to see if the 'localname' is in fact a directory.
	    ** Note that we can't do a HEAD on a directory
	    */
	    if (((file->stat_info.st_mode) & S_IFMT) == S_IFDIR) {
		if (HTRequest_method(request) == METHOD_GET)
		    file->state = FS_PARSE_DIR;
		else {
		    HTRequest_addError(request, ERR_INFO, NO, HTERR_NO_CONTENT,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_NO_DATA;
		}
		break;
	    }

	    /*
	    ** If empty file then only serve it if it is editable. We also get
	    ** the bindings for the file suffixes in lack of better bindings
	    */
	    {
		BOOL editable = HTEditable(file->local, &file->stat_info);
		if (file_suffix_binding) HTBind_getAnchorBindings(anchor);
		if (editable) HTAnchor_appendAllow(anchor, METHOD_PUT);

		/* Set the file size */
		if (file->stat_info.st_size)
		    HTAnchor_setLength(anchor, file->stat_info.st_size);

		/* Set the file last modified time stamp */
		if (file->stat_info.st_mtime > 0)
		    HTAnchor_setLastModified(anchor, file->stat_info.st_mtime);

		/* Check to see if we can edit it */
		if (!editable && !file->stat_info.st_size) {
		    HTRequest_addError(request, ERR_INFO, NO, HTERR_NO_CONTENT,
				       NULL, 0, "HTLoadFile");
		    file->state = FS_NO_DATA;
		} else {
		    file->state = (HTRequest_method(request)==METHOD_GET) ? 
			FS_NEED_OPEN_FILE : FS_GOT_DATA;
		}
	    }
	    break;

	  case FS_NEED_OPEN_FILE:
	    status = HTFileOpen(net, file->local, HT_FB_RDONLY);
	    if (status == HT_OK) {
		/* 
		** Create the stream pipe FROM the channel to the application.
		** The target for the input stream pipe is set up using the
		** stream stack.
		*/
		{
		    HTStream * rstream = HTStreamStack(HTAnchor_format(anchor),
						       HTRequest_outputFormat(request),
						       HTRequest_outputStream(request),
						       request, YES);
		    HTNet_setReadStream(net, rstream);
		    HTRequest_setOutputConnected(request, YES);
		}

		/*
		** Create the stream pipe TO the channel from the application
		** and hook it up to the request object
		*/
		{
		    HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
		    HTRequest_setInputStream(request, (HTStream *) output);
		}

		/*
		** Set up concurrent read/write if this request isn't the
		** source for a PUT or POST. As source we don't start reading
		** before all destinations are ready. If destination then
		** register the input stream and get ready for read
		*/
		if (HTRequest_isSource(request) && !HTRequest_destinationsReady(request))
		    return HT_OK;
		HTRequest_addError(request, ERR_INFO, NO, HTERR_OK, NULL, 0,
				   "HTLoadFile");
		file->state = FS_NEED_BODY;

		/* If we are _not_ using preemptive mode and we are Unix fd's
		** then return here to get the same effect as when we are
		** connecting to a socket. That way, HTFile acts just like any
		** other protocol module even though we are in fact doing
		** blocking connect
		*/
		if (HTEvent_isCallbacksRegistered()) {
		    if (!HTRequest_preemptive(request)) {
			if (!HTNet_preemptive(net)) {
			    HTTRACE(PROT_TRACE, "HTLoadFile.. Returning\n");
			    HTHost_register(HTNet_host(net), net, HTEvent_READ);
			} else if (!file->timer) {
			    HTTRACE(PROT_TRACE, "HTLoadFile.. Returning\n");
			    file->timer =
				HTTimer_new(NULL, ReturnEvent, file, 1, YES, NO);
			}
			return HT_OK;
		    }
		}
	    } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
		return HT_OK;
	    else {
		HTRequest_addError(request, ERR_INFO, NO, HTERR_INTERNAL,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;		       /* Error or interrupt */
	    }
	    break;

	  case FS_NEED_BODY:
	    status = HTHost_read(HTNet_host(net), net);
	    if (status == HT_WOULD_BLOCK)
		return HT_OK;
	    else if (status == HT_LOADED || status == HT_CLOSED) {
		file->state = FS_GOT_DATA;
	    } else {
		HTRequest_addError(request, ERR_INFO, NO, HTERR_FORBIDDEN,
				   NULL, 0, "HTLoadFile");
		file->state = FS_ERROR;
	    }
	    break;

	  case FS_PARSE_DIR:
	    status = HTFile_readDir(request, file);
	    if (status == HT_LOADED)
		file->state = FS_GOT_DATA;
	    else
		file->state = FS_ERROR;
	    break;

	  case FS_TRY_FTP:
	    {
		char *url = HTAnchor_physical(anchor);
		HTAnchor *anchor;
		char *newname = NULL;
		StrAllocCopy(newname, "ftp:");
		if (!strncmp(url, "file:", 5))
		    StrAllocCat(newname, url+5);
		else
		    StrAllocCat(newname, url);
		anchor = HTAnchor_findAddress(newname);
		HTRequest_setAnchor(request, anchor);
		HT_FREE(newname);
		FileCleanup(request, HT_IGNORE);
		return HTLoad(request, YES);
	    }
	    break;

	  case FS_GOT_DATA:
	    FileCleanup(request, HT_LOADED);
	    return HT_OK;
	    break;

	  case FS_NO_DATA:
	    FileCleanup(request, HT_NO_DATA);
	    return HT_OK;
	    break;

	  case FS_RETRY:
	    FileCleanup(request, HT_RETRY);
	    return HT_OK;
	    break;

	  case FS_ERROR:
	    FileCleanup(request, HT_ERROR);
	    return HT_OK;
	    break;
	}
    } /* End of while(1) */
}
Exemple #18
0
/* evaluate the buffer encompassed by the style attribute on any tag.
 * this will be JSS or CSS 
 *
 * Returns TRUE if it needs to block layout
 * Returns FALSE if not.
 */
XP_Bool
lo_ProcessStyleAttribute(MWContext *context, lo_DocState *state, PA_Tag *tag, char *script_buff)
{
    lo_TopState *top_state;
    char *scope_to = NULL;
    int32 script_buff_len;
    char *new_id;
    XP_Bool in_double_quote=FALSE, in_single_quote=FALSE;
    char *ptr, *end;
    ETEvalStuff * stuff;

    if (!state)
  	{
       XP_FREEIF(script_buff);
	   return FALSE;
	}


    if (!script_buff)
        return FALSE;

    /* @@@ A bit of a hack.
     * Get rid of the style attribute in the tag->data so that we don't
     * go circular
     *
     * get rid of STYLE by rewriting it as SYTLE so that the parser 
     * ignores it :)
     */
    for (ptr=(char*)tag->data, end = ptr+tag->data_len; ptr < end; ptr++) {
        if (*ptr == '"') {
            in_double_quote = !in_double_quote;
        }
        else if (*ptr == '\'') {
            in_single_quote = !in_single_quote;
        }
        else if (!in_single_quote &&
                 !in_double_quote &&
                 !strncasecomp(ptr, PARAM_STYLE, sizeof(PARAM_STYLE)-1)) {
            *ptr = 'T';    /* ttyle NOT style */
            break;
        }
    }

    script_buff_len = XP_STRLEN(script_buff);

    top_state = state->top_state;

    /* get the tag ID if it has one */
    new_id = (char *)lo_FetchParamValue(context, tag, PARAM_ID);

    if (!new_id)
        new_id = PR_smprintf(NSIMPLICITID"%ld", top_state->tag_count);

    if (!new_id)
        return FALSE;

    if (top_state->default_style_script_type == SCRIPT_TYPE_JSSS ||
	top_state->default_style_script_type == SCRIPT_TYPE_MOCHA) {

    	StrAllocCopy(scope_to, "document.ids.");
    	StrAllocCat(scope_to, new_id);

    	if (!scope_to) {
    	    XP_FREE(new_id);
	    return(FALSE);
	}
    }
    else if (top_state->default_style_script_type == SCRIPT_TYPE_CSS) {
        char *new_jss_buff;
        int32 new_jss_buff_len;
        char *new_css_buff;
        int32 new_css_buff_len;

        /* scope the css to the ns implicit ID */
        new_css_buff = PR_smprintf("#%s { %s }", new_id, script_buff);

        XP_FREE(script_buff);

        if (!new_css_buff) {
	    XP_FREE(new_id);
	    return FALSE;
	}

        new_css_buff_len = XP_STRLEN(new_css_buff);
        
        /* convert to JSS */
        CSS_ConvertToJS(new_css_buff,
                        new_css_buff_len,
                        &new_jss_buff,
                        &new_jss_buff_len);

        XP_FREE(new_css_buff);

        if (!new_jss_buff) {
	    XP_FREE(new_id);
	    return FALSE;
	}

        script_buff = new_jss_buff;
        script_buff_len = new_jss_buff_len;
    }
    else {
        /* unknown script type, punt */
        XP_FREE(script_buff);
	XP_FREE(new_id);
        return FALSE;
    }

    /* not needed anymore */
    XP_FREE(new_id);

    stuff = (ETEvalStuff *) XP_NEW_ZAP(ETEvalStuff);
    if (!stuff) {
	/* what do we free here? */
	XP_FREE(new_id);
        return FALSE;
    }

    if (lo_CloneTagAndBlockLayout(context, state, tag)) {
        tag->type = P_UNKNOWN;
	stuff->len = XP_STRLEN(script_buff);
	stuff->line_no = top_state->script_lineno;
	stuff->scope_to = scope_to;
	stuff->want_result = JS_FALSE;
	stuff->data = context;
	stuff->version = top_state->version;
	stuff->principals = NULL;

        ET_EvaluateScript(context, script_buff, stuff, lo_StyleEvalExitFn);

	/* don't free scope_to, ET_EvaluateScript has taken possession */
        XP_FREE(script_buff);

        return TRUE;
    }

    XP_FREEIF(scope_to);
    XP_FREE(script_buff);
    
    return FALSE;
}
Exemple #19
0
/*	HTFile_readDir
**	--------------
**	Reads the directory "path"
**	Returns:
**		HT_ERROR	Error
**		HT_FORBIDDEN	Directory reading not allowed
**		HT_LOADED	Successfully read the directory
*/
PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
{
#ifdef HAVE_READDIR
    DIR * dp;
    struct stat file_info;
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char *url = HTAnchor_physical(anchor);
    char fullname[HT_MAX_PATH+1];
    char *name;
    HTTRACE(PROT_TRACE, "Reading..... directory\n");
    if (dir_access == HT_DIR_FORBID) {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
		   NULL, 0, "HTFile_readDir");
	return HT_FORBIDDEN;
    }
    
    /* Initialize path name for stat() */
    if (*(name = (url+strlen(url)-1)) != '/') {
	char *newurl = NULL;
	StrAllocCopy(newurl, url);
	StrAllocCat(newurl, "/");
	HT_FREE(file->local);
	file->local = HTWWWToLocal(newurl, "", HTRequest_userProfile(request));
	HT_FREE(newurl);
    }
    strcpy(fullname, file->local);
    name = fullname+strlen(fullname);		 /* Point to end of fullname */

    /* Check if access is enabled */
    if (dir_access == HT_DIR_SELECTIVE) {
	strcpy(name, DEFAULT_DIR_FILE);
	if (HT_STAT(fullname, &file_info)) {
	    HTTRACE(PROT_TRACE, "Read dir.... `%s\' not found\n" _ DEFAULT_DIR_FILE);
	    HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
		       NULL, 0, "HTFile_readDir");
	    return HT_FORBIDDEN;
	}
    }

    if ((dp = opendir(file->local))) {
	struct dirent * dirbuf;
	HTDir *dir = HTDir_new(request, dir_show, dir_key);
	char datestr[20];
	char sizestr[10];
	HTFileMode mode;
#ifdef HT_REENTRANT
	struct dirent result;				    /* For readdir_r */
#endif

#ifdef HAVE_READDIR_R_2
        while ((dirbuf = (struct dirent *) readdir_r(dp, &result)))
#elif defined(HAVE_READDIR_R_3)
        while (readdir_r(dp, &result, &dirbuf) == 0)
#else
	while ((dirbuf = readdir(dp)))
#endif /* HAVE_READDIR_R_2 */
	{
	    /* Current and parent directories are never shown in list */
#ifdef HAVE_DIRENT_INO
	    if (!dirbuf->d_ino ||
		!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
#else
	    if (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
#endif
		continue;

	    /* Make a lstat on the file */
	    strcpy(name, dirbuf->d_name);
	    if (HT_LSTAT(fullname, &file_info)) {
		HTTRACE(PROT_TRACE, "Read dir.... lstat failed: %s\n" _ fullname);
		continue;
	    }

	    /* Convert stat info to fit our setup */
	    if (((mode_t) file_info.st_mode & S_IFMT) == S_IFDIR) {
#ifdef VMS
		char *dot = strstr(name, ".DIR");      /* strip .DIR part... */
		if (dot) *dot = '\0';
#endif /* VMS */
		mode = HT_IS_DIR;
		if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
	    } else {
		mode = HT_IS_FILE;
		if (dir_show & HT_DS_SIZE)
		    HTNumToStr(file_info.st_size, sizestr, 10);
	    }
	    if (dir_show & HT_DS_DATE)
		HTDateDirStr(&file_info.st_mtime, datestr, 20);

	    /* Add to the list */
	    if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
		break;
	}
	closedir(dp);
	HTDir_free(dir);
	return HT_LOADED;
    } else {
	HTRequest_addSystemError(request,  ERR_FATAL, errno, NO, "opendir");
	return HT_ERROR;
    }
#else
    return HT_ERROR;	/* needed for WWW_MSWINDOWS */
#endif /* HAVE_READDIR */
}
Exemple #20
0
/*
**  mailform() sends form content to the mailto address(es). - FM
*/
PUBLIC void mailform ARGS4(
    CONST char *,	mailto_address,
    CONST char *,	mailto_subject,
    CONST char *,	mailto_content,
    CONST char *,	mailto_type)
{
    FILE *fd;
    char *address = NULL;
    char *ccaddr = NULL;
    char *keywords = NULL;
    char *cp = NULL;
    char self[MAX_SUBJECT + 10];
    char subject[MAX_SUBJECT + 10];
    char *searchpart = NULL;
    char buf[512];
    int ch, len, i;
#if USE_VMS_MAILER
    static char *cmd;
    char *command = NULL;
    BOOLEAN isPMDF = LYMailPMDF();
    char hdrfile[LY_MAXPATH];
#endif
#if !CAN_PIPE_TO_MAILER
    char my_tmpfile[LY_MAXPATH];
#endif

    CTRACE((tfp, "mailto_address: \"%s\"\n", NONNULL(mailto_address)));
    CTRACE((tfp, "mailto_subject: \"%s\"\n", NONNULL(mailto_subject)));
    CTRACE((tfp, "mailto_content: \"%s\"\n", NONNULL(mailto_content)));
    CTRACE((tfp, "mailto_type:    \"%s\"\n", NONNULL(mailto_type)));

    if (!LYSystemMail())
	return;

    if (!mailto_address || !mailto_content) {
	HTAlert(BAD_FORM_MAILTO);
	return;
    }
    subject[0] = '\0';
    self[0] = '\0';

    if ((cp = (char *)strchr(mailto_address,'\n')) != NULL)
	*cp = '\0';
    StrAllocCopy(address, mailto_address);

    /*
     *	Check for a ?searchpart. - FM
     */
    if ((cp = strchr(address, '?')) != NULL) {
	StrAllocCopy(searchpart, cp);
	*cp = '\0';
	cp = (searchpart + 1);
	if (*cp != '\0') {
	    /*
	     *	Seek and handle a subject=foo. - FM
	     */
	    extract_subject(subject, searchpart);

	    /*
	     *	Seek and handle to=address(es) fields.
	     *	Appends to address. - FM
	     */
	    extract_field(&address, searchpart, "to=");

	    /*
	     *	Seek and handle cc=address(es) fields.	Excludes
	     *	Bcc=address(es) as unsafe.  We may append our own
	     *	cc (below) as a list for the actual mailing. - FM
	     */
	    extract_field(&ccaddr, searchpart, "cc=");

	    /*
	     *	Seek and handle keywords=term(s) fields. - FM
	     */
	    extract_field(&keywords, searchpart, "keywords=");

	    if (keywords != NULL) {
		if (*keywords != '\0') {
		    SafeHTUnEscape(keywords);
		} else {
		    FREE(keywords);
		}
	    }

	    FREE(searchpart);
	}
    }

    if (convert_explorer(address)) {
	HTAlert(BAD_FORM_MAILTO);
	goto cleanup;
    }
    if (ccaddr != NULL) {
	if (convert_explorer(ccaddr)) {
	    FREE(ccaddr);
	}
    }

    /*
     *	Unescape the address and ccaddr fields. - FM
     */
    SafeHTUnEscape(address);
    if (ccaddr != NULL) {
	SafeHTUnEscape(ccaddr);
    }

    /*
     *	Allow user to edit the default Subject - FM
     */
    if (isEmpty(subject)) {
	if (!isEmpty(mailto_subject)) {
	    LYstrncpy(subject, mailto_subject, MAX_SUBJECT);
	} else {
	    sprintf(subject, "mailto:%.63s", address);
	}
    }
    _statusline(SUBJECT_PROMPT);
    if ((ch = LYgetstr(subject, VISIBLE, MAX_SUBJECT, NORECALL)) < 0) {
	/*
	 * User cancelled via ^G. - FM
	 */
	HTInfoMsg(FORM_MAILTO_CANCELLED);
	goto cleanup;
    }

    /*
     *	Allow user to specify a self copy via a CC:
     *	entry, if permitted. - FM
     */
    if (!LYNoCc) {
	sprintf(self, "%.*s", MAX_SUBJECT,
		isEmpty(personal_mail_address) ? "" : personal_mail_address);
	_statusline("Cc: ");
	if ((ch = LYgetstr(self, VISIBLE, MAX_SUBJECT, NORECALL)) < 0) {
	    /*
	     * User cancelled via ^G. - FM
	     */
	    HTInfoMsg(FORM_MAILTO_CANCELLED);
	    goto cleanup;
	}
	remove_tildes(self);
	if (ccaddr == NULL) {
	    StrAllocCopy(ccaddr, self);
	} else {
	    StrAllocCat(ccaddr, ",");
	    StrAllocCat(ccaddr, self);
	}
    }

#if CAN_PIPE_TO_MAILER
    if ((fd = LYPipeToMailer()) == 0) {
	HTAlert(FORM_MAILTO_FAILED);
	goto cleanup;
    }

    if (!isEmpty(mailto_type)) {
	fprintf(fd, "Mime-Version: 1.0\n");
	fprintf(fd, "Content-Type: %s\n", mailto_type);
    }
    fprintf(fd, "To: %s\n", address);
    if (!isEmpty(personal_mail_address))
	fprintf(fd, "From: %s\n", personal_mail_address);
    if (!isEmpty(ccaddr))
	fprintf(fd, "Cc: %s\n", ccaddr);
    fprintf(fd, "Subject: %s\n\n", subject);
    if (!isEmpty(keywords))
	fprintf(fd, "Keywords: %s\n", keywords);
    _statusline(SENDING_FORM_CONTENT);
#else	/* e.g., VMS, DOS */
    if ((fd = LYOpenTemp(my_tmpfile, ".txt", "w")) == NULL) {
	HTAlert(FORM_MAILTO_FAILED);
	goto cleanup;
    }
#if USE_VMS_MAILER
    if (isPMDF) {
	FILE *hfd;
	if ((hfd = LYOpenTemp(hdrfile, ".txt", "w")) == NULL) {
	    HTAlert(FORM_MAILTO_FAILED);
	    LYCloseTempFP(fd);
	    goto cleanup;
	}
	if (!isEmpty(mailto_type)) {
	    fprintf(hfd, "Mime-Version: 1.0\n");
	    fprintf(hfd, "Content-Type: %s\n", mailto_type);
	    if (!isEmpty(personal_mail_address))
		fprintf(hfd, "From: %s\n", personal_mail_address);
	}
	/*
	 *  For PMDF, put any keywords and the subject
	 *  in the header file and close it. - FM
	 */
	if (!isEmpty(keywords)) {
	    fprintf(hfd, "Keywords: %s\n", keywords);
	}
	fprintf(hfd, "Subject: %s\n\n", subject);
	LYCloseTempFP(hfd);
    } else if (mailto_type &&
	       !strncasecomp(mailto_type, "multipart/form-data", 19)) {
	/*
	 *  Ugh!  There's no good way to include headers while
	 *  we're still using "generic" VMS MAIL, so we'll put
	 *  this in the body of the message. - FM
	 */
	fprintf(fd, "X-Content-Type: %s\n\n", mailto_type);
    }
#else	/* !VMS (DOS) */
#if USE_BLAT_MAILER
    if (mail_is_blat) {
	if (strlen(subject) > MAX_SUBJECT)
	    subject[MAX_SUBJECT] = '\0';
    } else
#endif
    {
	if (!isEmpty(mailto_type)) {
	    fprintf(fd, "Mime-Version: 1.0\n");
	    fprintf(fd, "Content-Type: %s\n", mailto_type);
	}
	fprintf(fd,"To: %s\n", address);
	if (!isEmpty(personal_mail_address))
	    fprintf(fd,"From: %s\n", personal_mail_address);
	fprintf(fd,"Subject: %.70s\n\n", subject);
    }
#endif /* VMS */
#endif /* CAN_PIPE_TO_MAILER */

    /*
     *	Break up the content into lines with a maximum length of 78.
     *	If the ENCTYPE was text/plain, we have physical newlines and
     *	should take them into account.	Otherwise, the actual newline
     *	characters in the content are hex escaped. - FM
     */
    while((cp = strchr(mailto_content, '\n')) != NULL) {
	*cp = '\0';
	i = 0;
	len = strlen(mailto_content);
	while (len > 78) {
	    strncpy(buf, &mailto_content[i], 78);
	    buf[78] = '\0';
	    fprintf(fd, "%s\n", buf);
	    i += 78;
	    len = strlen(&mailto_content[i]);
	}
	fprintf(fd, "%s\n", &mailto_content[i]);
	mailto_content = (cp+1);
    }
    i = 0;
    len = strlen(mailto_content);
    while (len > 78) {
	strncpy(buf, &mailto_content[i], 78);
	buf[78] = '\0';
	fprintf(fd, "%s\n", buf);
	i += 78;
	len = strlen(&mailto_content[i]);
    }
    if (len)
	fprintf(fd, "%s\n", &mailto_content[i]);

#if CAN_PIPE_TO_MAILER
    pclose(fd);
    LYSleepMsg();
#else
    LYCloseTempFP(fd);
#if USE_VMS_MAILER
    /*
     *	Set the mail command. - FM
     */
    if (isPMDF) {
	/*
	 *  Now set up the command. - FM
	 */
	HTSprintf0(&cmd,
		"%s %s %s,%s ",
		system_mail,
		system_mail_flags,
		hdrfile,
		my_tmpfile);
    } else {
	/*
	 *  For "generic" VMS MAIL, include the subject in the
	 *  command, and ignore any keywords to minimize risk
	 *  of them making the line too long or having problem
	 *  characters. - FM
	 */
	HTSprintf0(&cmd,
		"%s %s%s/subject=\"%s\" %s ",
		system_mail,
		system_mail_flags,
		(strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
		subject,
		my_tmpfile);
    }
    StrAllocCopy(command, cmd);

    vms_append_addrs(&command, address, "");
    if (!isEmpty(ccaddr)) {
	vms_append_addrs(&command, ccaddr, "/CC");
    }

    stop_curses();
    printf("%s\n\n$ %s\n\n%s", SENDING_FORM_CONTENT, command, PLEASE_WAIT);
    LYSystem(command);	/* Mail (VMS) */
    FREE(command);
    LYSleepAlert();
    start_curses();
    LYRemoveTemp(my_tmpfile);
    if (isPMDF)
	LYRemoveTemp(hdrfile);
#else /* DOS */
    LYSendMailFile (
	address,
	my_tmpfile,
	subject,
	ccaddr,
	SENDING_FORM_CONTENT);
    LYRemoveTemp(my_tmpfile);
#endif /* USE_VMS_MAILER */
#endif /* CAN_PIPE_TO_MAILER */

cleanup:
    FREE(address);
    FREE(ccaddr);
    FREE(keywords);
    return;
}
Exemple #21
0
PRIVATE int NewsEvent (SOCKET soc, void * pVoid, HTEventType type)
{
    news_info *news = (news_info *)pVoid;
    int status = HT_ERROR;
    HTNet * net = news->net;
    HTRequest * request = HTNet_request(net);
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char * url = HTAnchor_physical(anchor);
    HTHost * host = HTNet_host(net);
    
    /*
    ** Initiate a new nntp structure and bind to request structure
    ** This is actually state NNTP_BEGIN, but it can't be in the state
    ** machine as we need the structure first.
    */
    if (type == HTEvent_CLOSE) {			      /* Interrupted */
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
			   NULL, 0, "HTLoadHTTP");
	HTNewsCleanup(request, HT_INTERRUPTED);
	return HT_OK;
    } else
	news = (news_info *) HTNet_context(net);		/* Get existing copy */

    /* Now jump into the machine. We know the state from the previous run */
    while (1) {
        switch (news->state) {
          case NEWS_BEGIN:
	    news->state = (!strchr(url, '@') && strchr(url, '*')) ?
		NEWS_SEEK_CACHE : NEWS_NEED_CONNECTION;
	    break;

	case NEWS_SEEK_CACHE:
	    if (HTNewsCache_before(request, NULL, 0) == HT_LOADED)
		news->state = NEWS_SUCCESS;
	    else
		news->state = NEWS_NEED_CONNECTION;
	    break;

	  case NEWS_NEED_CONNECTION: 		/* Let's set up a connection */
	    if (!strncasecomp(url, "news:", 5)) {
		HTUserProfile * up = HTRequest_userProfile(request);
		char * newshost = HTUserProfile_news(up);
		StrAllocCopy(news->name, url+5);
		if (newshost) {
		    char *newshack = NULL;    /* Then we can use HTParse :-) */
		    StrAllocCopy(newshack, "news://");
		    StrAllocCat(newshack, newshost);
		    status = HTHost_connect(host, net, (char *) newshack);
		    host = HTNet_host(net);
		    HT_FREE(newshack);
		} else
		    news->state = NEWS_ERROR;
	    } else if (!strncasecomp(url, "nntp:", 5)) {
		news->name = HTParse(url, "", PARSE_PATH);
		status = HTHost_connect(host, net, url);
		host = HTNet_host(net);
	    } else {
		HTTRACE(PROT_TRACE, "News........ Huh?");
		news->state = NEWS_ERROR;
            }
            if (status == HT_OK) {
		BOOL greeting = NO;

		/* Set up the persistent connection */
		if (!HTNet_persistent(net)) {
		    HTNet_setPersistent(net, YES, HT_TP_SINGLE);
		    greeting = YES;
		}

		/*
		** Check the protocol class to see if we have connected to a
		** the right class of server, in this case HTTP.
		*/
		{
		    HTHost * host = HTNet_host(net);
		    char * s_class = HTHost_class(host);
		    if (s_class && strcasecomp(s_class, "nntp")) {
			HTRequest_addError(request, ERR_FATAL, NO, HTERR_CLASS,
					   NULL, 0, "HTLoadNews");
			news->state = NEWS_ERROR;
			break;
		    }
		    HTHost_setClass(host, "nntp");
		}

		/* 
		** Create the stream pipe FROM the channel to the application.
		** The target for the input stream pipe is set up using the
		** stream stack.
		*/
		{
		    HTStream * rstream = HTNewsStatus_new(request, news, host);
		    HTNet_setReadStream(net, rstream);
		    HTRequest_setOutputConnected(request, YES);
		}

		/*
		** Create the stream pipe TO the channel from the application
		** and hook it up to the request object
		*/
		{
		    HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
		    HTRequest_setInputStream(request, (HTStream *) output);
		}

		news->state = greeting ? NEWS_NEED_GREETING : NEWS_NEED_SWITCH;

	    } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
		return HT_OK;
	    else
		news->state = NEWS_ERROR;
	    break;

	  case NEWS_NEED_GREETING:
	    status = HTHost_read(HTNet_host(net), net);
	    if (status == HT_WOULD_BLOCK)
		return HT_OK;
	    else if (status == HT_LOADED) {
		if (news->repcode/100 == 2)
		    news->state = NEWS_NEED_SWITCH;
		else
		    news->state = NEWS_ERROR;
	    } else
		news->state = NEWS_ERROR;
	    break;

	  case NEWS_NEED_SWITCH:
	  {
	      HTMethod method = HTRequest_method(request);
	      /*
	      ** Find out what to ask the news server. Syntax of address is
	      **	xxx@yyy		Article
	      **	<xxx@yyy>	Same article
	      **	xxxxx		News group (no "@")
	      */
	      if (method == METHOD_GET) {
		  if (strchr(url, '@')) {				  /* ARTICLE */
		      if (*(news->name) != '<') {		  /* Add '<' and '>' */
			  char *newart;
			  if ((newart = (char  *) HT_MALLOC(strlen(news->name)+3)) == NULL)
			      HT_OUTOFMEM("HTLoadNews");
			  sprintf(newart, "<%s>", news->name);
			  HT_FREE(news->name);
			  news->name = newart;
		      }
		      news->state = NEWS_NEED_ARTICLE;
		  } else if (strchr(url, '*'))
		      news->state = NEWS_NEED_LIST;
		  else
		      news->state = NEWS_NEED_GROUP;
	      } else if (method == METHOD_POST)
		  news->state = NEWS_NEED_POST;
	      else {
		  HTRequest_addError(request, ERR_FATAL, NO,
				     HTERR_NOT_IMPLEMENTED,NULL, 0,"HTLoadNews");
		  news->state = NEWS_ERROR;
	      }
	      HTUnEscape(news->name);
	      HTCleanTelnetString(news->name);
	  }
	  break;

	  case NEWS_NEED_ARTICLE:
	    if (!news->sent) {
		status = SendCommand(request, news, "ARTICLE", news->name);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_MIME;

		/*
		** Set the default content type to plain text as news servers
		** almost never send any useful information about the length
		** of the body or the type - the success of MIME!
		*/
		HTAnchor_setFormat(anchor, WWW_PLAINTEXT);
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

#if HT_LISTGROUP
	  case NEWS_NEED_LGRP:
	    if (!news->sent) {
		status = SendCommand(request, news, "LIST", "NEWSGROUPS");
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
 		news->format = WWW_NNTP_LIST;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_NEED_LIST;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;
#endif /* HT_LISTGROUP */

	  case NEWS_NEED_LIST:
	    if (!news->sent) {
		status = SendCommand(request, news, "LIST", NULL);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_NNTP_LIST;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    news->state = (news->repcode/100 == 2) ?
			NEWS_SUCCESS : NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_GROUP:
	    if (!news->sent) {
		status = SendCommand(request, news, "GROUP", news->name);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2) {
			if (sscanf(news->reply, "%d%d%d", &news->total,
				   &news->first, &news->last) == 3) {
			    if (MaxArt && news->total>MaxArt)
				news->last = news->first-MaxArt;
			    news->current = news->first;

			    /* If no content in this group */
			    if (news->first == news->last) {
				HTRequest_addError(request, ERR_FATAL, NO,
						   HTERR_NO_CONTENT,
						   NULL, 0, "HTLoadNews");
				news->state = NEWS_NO_DATA;
				break;
			    }
			    news->state = NEWS_NEED_XOVER;
			} else
			    news->state = NEWS_ERROR;
		    } else
			news->state = NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_XOVER:
	    if (!news->sent) {
		char buf[20];
		sprintf(buf, "%d-%d", news->first, news->last);
		status = SendCommand(request, news, "XOVER", buf);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->format = WWW_NNTP_OVER;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_OK)
		    news->state = NEWS_NEED_BODY;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2)
			news->state = NEWS_SUCCESS;
		    else {
			news->format = WWW_NNTP_HEAD;
			news->state = NEWS_NEED_HEAD;
		    }
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_HEAD:
	    if (!news->sent) {
		char buf[10];
		sprintf(buf, "%d", news->current++);
		status = SendCommand(request, news, "HEAD", buf);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_ERROR)
		    news->state = NEWS_ERROR;
		news->sent = YES;
	    } else {
		status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
		else if (status == HT_LOADED) {
		    if (news->repcode/100 == 2) {
			if (news->current > news->last)
			    news->state = NEWS_SUCCESS;
		    } else
			news->state = NEWS_ERROR;
		} else
		    news->state = NEWS_ERROR;
		news->sent = NO;
	    }
	    break;

	  case NEWS_NEED_POST:
	  {
	      HTStream * oldinput = HTRequest_inputStream(request);
	      HTStream * newinput =
		  HTNewsPost_new(request, HTBuffer_new(oldinput, request,512));
	      HTRequest_setInputStream(request, newinput);
	      
	      /* Remember to convert to CRLF */

	  }
	  news->state = NEWS_NEED_BODY;
	  break;

          case NEWS_NEED_BODY:
            if (type == HTEvent_WRITE || type == HTEvent_BEGIN) {
		if (HTRequest_isDestination(request)) {
		    HTRequest * source = HTRequest_source(request);
		    HTNet * srcnet = HTRequest_net(source);
		    if (srcnet) {
			HTHost_register(HTNet_host(srcnet), srcnet, HTEvent_READ);
			HTHost_unregister(HTNet_host(srcnet), srcnet, HTEvent_WRITE);
		    }
		    return HT_OK;
		}

		/*
		**  Should we use the input stream directly or call the post
		**  callback function to send data down to the network?
		*/
		{
		    HTStream * input = HTRequest_inputStream(request);
		    HTPostCallback * pcbf = HTRequest_postCallback(request);
		    if (pcbf) {
			status = pcbf(request, input);
			if (status == HT_PAUSE || status == HT_LOADED)
			    type = HTEvent_READ;
		    } else {
			status = (*input->isa->flush)(input);
			type = HTEvent_READ;
		    }
		    if (status == HT_WOULD_BLOCK) return HT_OK;
		}
		status = request->PostCallback ?
                    request->PostCallback(request, request->input_stream) :
			(*request->input_stream->isa->flush)(request->input_stream);
 		if (status == HT_WOULD_BLOCK)
                    return HT_OK;
                else 	
                    type = HTEvent_READ;	  /* Trick to ensure that we do READ */
	    } else if (type == HTEvent_READ) {
                status = HTHost_read(HTNet_host(net), net);
		if (status == HT_WOULD_BLOCK)
		    return HT_OK;
                else if (status == HT_LOADED)
		    news->state = NEWS_SUCCESS;
		else
		    news->state = NEWS_ERROR;
	    } else {
		news->state = NEWS_ERROR;
	    }
	    break;
		
	  case NEWS_SUCCESS:
	    HTNewsCleanup(request, HT_LOADED);
	    return HT_OK;
	    break;

	case NEWS_NO_DATA:
	    HTNewsCleanup(request, HT_NO_DATA);
	    return HT_OK;
	    break;

	  case NEWS_ERROR:
	    HTNewsCleanup(request, HT_NOT_FOUND);
	    return HT_OK;
	    break;
	}
    } /* End of while(1) */
}
/*
 * This procedure outputs the Visited Links list into a temporary file.  - FM
 * Returns links's number to make active (1-based), or 0 if not required.
 */
int LYShowVisitedLinks(char **newfile)
{
    static char tempfile[LY_MAXPATH] = "\0";
    char *Title = NULL;
    char *Address = NULL;
    int x, tot;
    FILE *fp0;
    VisitedLink *vl;
    HTList *cur = Visited_Links;
    int offset;
    int ret = 0;
    const char *arrow, *post_arrow;

    if (!cur)
	return (-1);

    if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0)
	return (-1);

    LYLocalFileToURL(newfile, tempfile);
    LYRegisterUIPage(*newfile, UIP_VLINKS);

    LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
    LYforce_no_cache = TRUE;	/* force this file to be new */

    BeginInternalPage(fp0, VISITED_LINKS_TITLE, VISITED_LINKS_HELP);

#ifndef NO_OPTION_FORMS
    fprintf(fp0, "<form action=\"%s\" method=\"post\">\n", STR_LYNXOPTIONS);
    LYMenuVisitedLinks(fp0, FALSE);
    fprintf(fp0, "<input type=\"submit\" value=\"Accept Changes\">\n");
    fprintf(fp0, "</form>\n");
    fprintf(fp0, "<P>\n");
#endif

    fprintf(fp0, "<pre>\n");
    fprintf(fp0, "<em>%s</em>\n",
	    gettext("You visited (POSTs, bookmark, menu and list files excluded):"));
    if (Visited_Links_As & VISITED_LINKS_REVERSE)
	tot = x = HTList_count(Visited_Links);
    else
	tot = x = -1;

    if (Visited_Links_As & VISITED_LINKS_AS_TREE) {
	vl = First_tree;
    } else if (Visited_Links_As & VISITED_LINKS_AS_LATEST) {
	if (Visited_Links_As & VISITED_LINKS_REVERSE)
	    vl = Latest_last.prev_latest;
	else
	    vl = Latest_first.next_latest;
	if (vl == &Latest_last || vl == &Latest_first)
	    vl = NULL;
    } else {
	if (Visited_Links_As & VISITED_LINKS_REVERSE)
	    vl = Last_by_first;
	else
	    vl = (VisitedLink *) HTList_nextObject(cur);
    }
    while (NULL != vl) {
	/*
	 * The number of the document (most recent highest), its title in a
	 * link, and its address.  - FM
	 */
	post_arrow = arrow = "";
	if (Visited_Links_As & VISITED_LINKS_REVERSE)
	    x--;
	else
	    x++;
	if (vl == PrevActiveVisitedLink) {
	    if (Visited_Links_As & VISITED_LINKS_REVERSE)
		ret = tot - x + 2;
	    else
		ret = x + 3;
	}
	if (vl == PrevActiveVisitedLink) {
	    post_arrow = "<A NAME=current></A>";
	    /* Otherwise levels 0 and 1 look the same when with arrow: */
	    arrow = (vl->level && (Visited_Links_As & VISITED_LINKS_AS_TREE))
		? "==>" : "=>";
	    StrAllocCat(*newfile, "#current");
	}
	if (Visited_Links_As & VISITED_LINKS_AS_TREE) {
	    offset = 2 * vl->level;
	    if (offset > 24)
		offset = (offset + 24) / 2;
	    if (offset > LYcols * 3 / 4)
		offset = LYcols * 3 / 4;
	} else
	    offset = (x > 99 ? 0 : x < 10 ? 2 : 1);
	if (non_empty(vl->title)) {
	    StrAllocCopy(Title, vl->title);
	    LYEntify(&Title, TRUE);
	    LYTrimLeading(Title);
	    LYTrimTrailing(Title);
	    if (*Title == '\0')
		StrAllocCopy(Title, NO_TITLE);
	} else {
	    StrAllocCopy(Title, NO_TITLE);
	}
	if (non_empty(vl->address)) {
	    StrAllocCopy(Address, vl->address);
	    LYEntify(&Address, FALSE);
	    fprintf(fp0,
		    "%-*s%s<em>%d</em>. <tab id=t%d><a href=\"%s\">%s</a>\n",
		    offset, arrow, post_arrow,
		    x, x, Address, Title);
	} else {
	    fprintf(fp0,
		    "%-*s%s<em>%d</em>. <tab id=t%d><em>%s</em>\n",
		    offset, arrow, post_arrow,
		    x, x, Title);
	}
	if (Address != NULL) {
	    StrAllocCopy(Address, vl->address);
	    LYEntify(&Address, TRUE);
	}
	fprintf(fp0, "<tab to=t%d>%s\n", x,
		((Address != NULL) ? Address : gettext("(no address)")));
	if (Visited_Links_As & VISITED_LINKS_AS_TREE)
	    vl = vl->next_tree;
	else if (Visited_Links_As & VISITED_LINKS_AS_LATEST) {
	    if (Visited_Links_As & VISITED_LINKS_REVERSE)
		vl = vl->prev_latest;
	    else
		vl = vl->next_latest;
	    if (vl == &Latest_last || vl == &Latest_first)
		vl = NULL;
	} else {
	    if (Visited_Links_As & VISITED_LINKS_REVERSE)
		vl = vl->prev_first;
	    else
		vl = (VisitedLink *) HTList_nextObject(cur);
	}
    }
    fprintf(fp0, "</pre>\n");
    EndInternalPage(fp0);

    LYCloseTempFP(fp0);
    FREE(Title);
    FREE(Address);
    return (ret);
}
Exemple #23
0
/*
**  reply_by_mail() invokes sendmail on Unix or mail on VMS to send
**  a comment from the users to the owner
*/
PUBLIC void reply_by_mail ARGS4(
	char *,		mail_address,
	char *,		filename,
	CONST char *,	title,
	CONST char *,	refid)
{
#ifndef NO_ANONYMOUS_EMAIL
    static char *personal_name = NULL;
#endif
    char user_input[LINESIZE];
    FILE *fd, *fp;
    char *label = NULL;
    char *from_address = NULL;
    char *cc_address = NULL;
    char *to_address = NULL;
    char *the_subject = NULL;
    char *ccaddr = NULL;
    char *keywords = NULL;
    char *searchpart = NULL;
    char *body = NULL;
    char *cp = NULL, *cp1 = NULL;
    int i;
    int c = 0;	/* user input */
    char my_tmpfile[LY_MAXPATH];
    char default_subject[MAX_SUBJECT + 10];
#if USE_VMS_MAILER
    char *command = NULL;
    BOOLEAN isPMDF = LYMailPMDF();
    char hdrfile[LY_MAXPATH];
    FILE *hfd = 0;
#else
#if !CAN_PIPE_TO_MAILER
    char tmpfile2[LY_MAXPATH];
#endif
    char buf[4096];	/* 512 */
    char *header = NULL;
    int n;
#endif /* USE_VMS_MAILER */

    CTRACE((tfp, "reply_by_mail(\"%s\", \"%s\", \"%s\", \"%s\")\n",
	NONNULL(mail_address),
	NONNULL(filename),
	NONNULL(title),
	NONNULL(refid)));

    term_letter = FALSE;

    if (!LYSystemMail())
	return;

    if (isEmpty(mail_address)) {
	HTAlert(NO_ADDRESS_IN_MAILTO_URL);
	return;
    }
    StrAllocCopy(to_address, mail_address);

    if ((fd = LYOpenTemp(my_tmpfile, ".txt", "w")) == NULL) {
	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
	return;
    }
#if USE_VMS_MAILER
    if (isPMDF) {
	if ((hfd = LYOpenTemp(hdrfile, ".txt", "w")) == NULL) {
	    HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
	    return;
	}
    }
#endif /* VMS */
    default_subject[0] = '\0';

    /*
     *	Check for a ?searchpart. - FM
     */
    if ((cp = strchr(to_address, '?')) != NULL) {
	StrAllocCopy(searchpart, cp);
	*cp = '\0';
	cp = (searchpart + 1);
	if (*cp != '\0') {
	    /*
	     *	Seek and handle a subject=foo. - FM
	     */
	    extract_subject(default_subject, searchpart);

	    /*
	     *	Seek and handle to=address(es) fields.
	     *	Appends to address. - FM
	     */
	    extract_field(&to_address, searchpart, "to=");

	    /*
	     *	Seek and handle cc=address(es) fields.	Excludes
	     *	Bcc=address(es) as unsafe.  We may append our own
	     *	cc (below) as a list for the actual mailing. - FM
	     */
	    extract_field(&ccaddr, searchpart, "cc=");

	    /*
	     *	Seek and handle keywords=term(s) fields. - FM
	     */
	    extract_field(&keywords, searchpart, "keywords=");

	    if (keywords != NULL) {
		if (*keywords != '\0') {
		    SafeHTUnEscape(keywords);
		} else {
		    FREE(keywords);
		}
	    }

	    /*
	     *	Seek and handle body=foo fields. - FM
	     */
	    extract_body(&body, searchpart);

	    FREE(searchpart);
	}
    }

    if (convert_explorer(to_address)) {
	HTAlert(NO_ADDRESS_IN_MAILTO_URL);
	goto cancelled;
    }
    if (ccaddr != NULL) {
	if (convert_explorer(ccaddr)) {
	    FREE(ccaddr);
	}
    }

    /*
     *	Unescape the address and ccaddr fields. - FM
     */
    SafeHTUnEscape(to_address);
    if (ccaddr != NULL) {
	SafeHTUnEscape(ccaddr);
    }

    /*
     *	Set the default subject. - FM
     */
    if (isEmpty(default_subject) && !isEmpty(title)) {
	strncpy(default_subject, title, MAX_SUBJECT);
	default_subject[MAX_SUBJECT] = '\0';
    }

    /*
     *	Use ^G to cancel mailing of comment
     *	and don't let SIGINTs exit lynx.
     */
    signal(SIGINT, terminate_letter);

#if USE_VMS_MAILER
    if (isPMDF || !body) {
	/*
	 *  Put the X-URL and X-Mailer lines in the hdrfile
	 *  for PMDF or my_tmpfile for VMS MAIL. - FM
	 */
	fprintf((isPMDF ? hfd : fd),
		"X-URL: %s%s\n",
		isEmpty(filename) ? STR_MAILTO_URL : filename,
		isEmpty(filename) ? to_address : "");
	fprintf((isPMDF ? hfd : fd),
		"X-Mailer: %s, Version %s\n", LYNX_NAME, LYNX_VERSION);
#ifdef NO_ANONYMOUS_EMAIL
	if (!isPMDF) {
	    fprintf(fd, "\n");
	}
#endif /* NO_ANONYMOUS_EMAIL */
    }
#else /* Unix/DOS/Windows */
    /*
     *	Put the To: line in the header.
     */
#ifndef DOSPATH
    asprintf(&header, "To: %s\n", to_address);
    if (!header) {
	fprintf(stderr, "Out of memory, you lose!\n");
	exit(1);
    }
#endif

    /*
     *	Put the Mime-Version, Content-Type and
     *	Content-Transfer-Encoding in the header.
     *	This assumes that the same character set is used
     *	for composing the mail which is currently selected
     *	as display character set...
     *	Don't send a charset if we have a CJK character set
     *	selected, since it may not be appropriate for mail...
     *	Also don't use an unofficial "x-" charset.
     *	Also if the charset would be "us-ascii" (7-bit replacements
     *	selected, don't send any MIME headers. - kw
     */
    if (strncasecomp(LYCharSet_UC[current_char_set].MIMEname,
		     "us-ascii", 8) != 0) {
	StrAllocCat(header, "Mime-Version: 1.0\n");
	if (!LYHaveCJKCharacterSet &&
	    strncasecomp(LYCharSet_UC[current_char_set].MIMEname, "x-", 2)
	    != 0) {
	    HTSprintf(&header, "Content-Type: text/plain; charset=%s\n",
		    LYCharSet_UC[current_char_set].MIMEname);
	}
	StrAllocCat(header, "Content-Transfer-Encoding: 8bit\n");
    }
    /*
     *	Put the X-URL and X-Mailer lines in the header.
     */
    if (!isEmpty(filename)) {
	HTSprintf(&header, "X-URL: %s\n", filename);
    } else {
	HTSprintf(&header, "X-URL: mailto:%s\n", to_address);
    }
    HTSprintf(&header, "X-Mailer: %s, Version %s\n", LYNX_NAME, LYNX_VERSION);

    if (!isEmpty(refid)) {
	HTSprintf(&header, "In-Reply-To: <%s>\n", refid);
    }
#endif /* VMS */

    /*
     *	Clear the screen and inform the user.
     */
    LYclear();
    LYmove(2,0);
    scrollok(LYwin, TRUE);	/* Enable scrolling. */
    if (body)
	LYaddstr(SENDING_MESSAGE_WITH_BODY_TO);
    else
	LYaddstr(SENDING_COMMENT_TO);
    show_addresses(to_address);
    if (
#if USE_VMS_MAILER
	(isPMDF == TRUE) &&
#endif /* VMS */
	(cp = ccaddr) != NULL)
    {
	if (strchr(cp, ',') != NULL) {
	    LYaddstr(WITH_COPIES_TO);
	} else {
	    LYaddstr(WITH_COPY_TO);
	}
	show_addresses(ccaddr);
    }
    LYaddstr(CTRL_G_TO_CANCEL_SEND);

#if USE_VMS_MAILER
    if (isPMDF || !body) {
#endif /* USE_VMS_MAILER */
#ifndef NO_ANONYMOUS_EMAIL
    /*
     *	Get the user's personal name.
     */
    LYaddstr(ENTER_NAME_OR_BLANK);
#if USE_VMS_MAILER
    if (isPMDF) {
	label = "Personal_name: ";
    } else {
	label = "X-Personal_name: ";
    }
#else
    label = "X-Personal_Name: ";
#endif /* USE_VMS_MAILER */
    if (!header_prompt(label, &personal_name, LINESIZE)) {
	goto cancelled;
    }
    if (*personal_name) {
#if USE_VMS_MAILER
	fprintf((isPMDF ? hfd : fd), "%s: %s\n", label, personal_name);
#else
	HTSprintf(&header, "%s: %s\n", label, personal_name);
#endif /* VMS */
    }

    /*
     *	Get the user's return address.
     */
    LYaddstr(ENTER_MAIL_ADDRESS_OR_OTHER);
    LYaddstr(MEANS_TO_CONTACT_FOR_RESPONSE);
#if USE_VMS_MAILER
    if (isPMDF) {
	label = "From";
    } else {
	label = "X-From";
    }
#else
    label = "From";
#endif /* VMS */
    /* Add the personal mail address if there is one. */
    if (personal_mail_address)
	StrAllocCopy(from_address, personal_mail_address);
    if (!header_prompt(label, &from_address, LINESIZE)) {
	goto cancelled;
    }
#if USE_VMS_MAILER
    if (*from_address) {
	fprintf(isPMDF ? hfd : fd, "%s: %s\n", label, from_address);
    }
    if (!isPMDF) {
	fprintf(fd, "\n");
    }
#else
    HTSprintf(&header, "%s: %s\n", label, from_address);
#endif /* USE_VMS_MAILER */
#endif /* !NO_ANONYMOUS_EMAIL */
#if USE_VMS_MAILER
    }
#endif /* USE_VMS_MAILER */

    /*
     *	Get the subject line.
     */
    LYaddstr(ENTER_SUBJECT_LINE);
    label = "Subject";
    if (*default_subject) {
	StrAllocCopy(the_subject, default_subject);
    } else if (!isEmpty(filename)) {
	HTSprintf(&the_subject, "%s", filename);
    } else {
	HTSprintf(&the_subject, "mailto:%s", to_address);
    }
    if (!header_prompt(label, &the_subject, MAX_SUBJECT)) {
	goto cancelled;
    }

    /*
     *	Offer a CC line, if permitted. - FM
     */
    if (!LYNoCc) {
	LYaddstr(ENTER_ADDRESS_FOR_CC);
	LYaddstr(BLANK_FOR_NO_COPY);
	if (personal_mail_address)
	    StrAllocCopy(cc_address, personal_mail_address);
	if (!header_prompt("Cc", &cc_address, LINESIZE)) {
	    goto cancelled;
	}
	comma_append(&ccaddr, cc_address);
    }

#if !USE_VMS_MAILER
    HTSprintf(&header, "%s: %s\n", label, the_subject);
#if !CAN_PIPE_TO_MAILER
    if (*to_address) {
	HTSprintf(&header, "To: %s\n", to_address);
    }
#endif

    /*
    **	Add the Cc: header. - FM
    */
    if (!isEmpty(ccaddr)) {
	HTSprintf(&header, "Cc: %s\n", ccaddr);
    }

    /*
    **	Add the Keywords: header. - FM
    */
    if (!isEmpty(keywords)) {
	HTSprintf(&header, "Keywords: %s\n", keywords);
    }

    /*
     *	Terminate the header.
     */
    StrAllocCat(header, "\n");
    CTRACE((tfp,"**header==\n%s",header));
#endif /* !VMS */

    if (!no_editor && !isEmpty(editor)) {

	if (body) {
	    cp1 = body;
	    while((cp = strchr(cp1, '\n')) != NULL) {
		*cp++ = '\0';
		fprintf(fd, "%s\n", cp1);
		cp1 = cp;
	    }
	} else if (strcmp(HTLoadedDocumentURL(), "")) {
	    /*
	     *	Ask if the user wants to include the original message.
	     */
	    BOOLEAN is_preparsed = (BOOL) (LYPreparsedSource &&
				    HTisDocumentSource());
	    if (HTConfirm(is_preparsed
		? INC_PREPARSED_MSG_PROMPT
		: INC_ORIG_MSG_PROMPT) == YES) {
		print_wwwfile_to_fd(fd, (BOOL) !is_preparsed);
	    }
	}
	LYCloseTempFP(fd);	/* Close the tmpfile. */
	scrollok(LYwin,FALSE);	/* Stop scrolling.    */

	if (term_letter || LYCharIsINTERRUPT(c))
	    goto cleanup;

	/*
	 *  Spawn the users editor on the mail file
	 */
	edit_temporary_file(my_tmpfile, "", SPAWNING_EDITOR_FOR_MAIL);

    } else if (body) {
	/*
	 *  Let user review the body. - FM
	 */
	LYclear();
	LYmove(0,0);
	LYaddstr(REVIEW_MESSAGE_BODY);
	LYrefresh();
	cp1 = body;
	i = (LYlines - 5);
	while((cp = strchr(cp1, '\n')) != NULL) {
	    if (i <= 0) {
		LYaddstr(RETURN_TO_CONTINUE);
		LYrefresh();
		c = LYgetch();
		LYaddstr("\n");
		if (term_letter || LYCharIsINTERRUPT(c)) {
		    goto cancelled;
		}
		i = (LYlines - 2);
	    }
	    *cp++ = '\0';
	    fprintf(fd, "%s\n", cp1);
	    LYaddstr(cp1);
	    LYaddstr("\n");
	    cp1 = cp;
	    i--;
	}
	while (i >= 0) {
	    LYaddstr("\n");
	    i--;
	}
	LYrefresh();
	LYCloseTempFP(fd);	/* Close the tmpfile.	  */
	scrollok(LYwin,FALSE);	/* Stop scrolling.	  */

    } else {
	/*
	 *  Use the internal line editor for the message.
	 */
	LYaddstr(ENTER_MESSAGE_BELOW);
	LYaddstr(ENTER_PERIOD_WHEN_DONE_A);
	LYaddstr(ENTER_PERIOD_WHEN_DONE_B);
	LYaddstr("\n\n");
	LYrefresh();
	*user_input = '\0';
	if (LYgetstr(user_input, VISIBLE, sizeof(user_input), NORECALL) < 0 ||
	    term_letter || STREQ(user_input, ".")) {
	    goto cancelled;
	}

	while (!STREQ(user_input, ".") && !term_letter) {
	    LYaddstr("\n");
	    remove_tildes(user_input);
	    fprintf(fd, "%s\n", user_input);
	    *user_input = '\0';
	    if (LYgetstr(user_input, VISIBLE,
			 sizeof(user_input), NORECALL) < 0) {
		goto cancelled;
	    }
	}

	fprintf(fd, "\n");	/* Terminate the message. */
	LYCloseTempFP(fd);	/* Close the tmpfile.	  */
	scrollok(LYwin,FALSE);	/* Stop scrolling.	  */
    }

#if !USE_VMS_MAILER
    /*
     *	Ignore CTRL-C on this last question.
     */
    signal(SIGINT, SIG_IGN);
#endif /* !VMS */
    LYStatusLine = (LYlines - 1);
    c = HTConfirm (body ? SEND_MESSAGE_PROMPT : SEND_COMMENT_PROMPT);
    LYStatusLine = -1;
    if (c != YES) {
	LYclear();  /* clear the screen */
	goto cleanup;
    }
    if ((body == NULL && LynxSigFile != NULL) &&
	(fp = fopen(LynxSigFile, TXT_R)) != NULL) {
	LYStatusLine = (LYlines - 1);
	if (term_letter) {
	    _user_message(APPEND_SIG_FILE, LynxSigFile);
	    c = 0;
	} else {
	    char *msg = NULL;
	    HTSprintf0(&msg, APPEND_SIG_FILE, LynxSigFile);
	    c = HTConfirm(msg);
	    FREE(msg);
	}
	LYStatusLine = -1;
	if (c == YES) {
	    if ((fd = fopen(my_tmpfile, TXT_A)) != NULL) {
		char *buffer = NULL;
		fputs("-- \n", fd);
		while (LYSafeGets(&buffer, fp) != NULL) {
		    fputs(buffer, fd);
		}
		LYCloseOutput(fd);
		FREE(buffer);
	    }
	}
	LYCloseInput(fp);
    }
    LYclear();  /* Clear the screen. */

    /*
     *	Send the message.
     */
#if USE_VMS_MAILER
    /*
     *	Set the mail command. - FM
     */
    if (isPMDF) {
	/*
	 *  For PMDF, put any keywords and the subject
	 *  in the header file and close it. - FM
	 */
	if (!isEmpty(keywords)) {
	    fprintf(hfd, "Keywords: %s\n", keywords);
	}
	fprintf(hfd, "Subject: %s\n\n", the_subject);
	LYCloseTempFP(hfd);
	/*
	 *  Now set up the command. - FM
	 */
	HTSprintf0(&command, "%s %s %s,%s ",
		system_mail,
		system_mail_flags,
		hdrfile,
		my_tmpfile);
    } else {
	/*
	 *  For "generic" VMS MAIL, include the subject in the
	 *  command, and ignore any keywords to minimize risk
	 *  of them making the line too long or having problem
	 *  characters. - FM
	 */
	HTSprintf0(&command, "%s %s%s/subject=\"%s\" %s ",
		system_mail,
		system_mail_flags,
		(strncasecomp(system_mail, "MAIL", 4) ? "" : "/noself"),
		the_subject,
		my_tmpfile);
    }

    vms_append_addrs(&command, to_address, "");
    if (!isEmpty(ccaddr)) {
	vms_append_addrs(&command, ccaddr, "/CC");
    }

    stop_curses();
    printf("%s\n\n$ %s\n\n%s", SENDING_COMMENT, command, PLEASE_WAIT);
    LYSystem(command);	/* SENDING COMMENT (VMS) */
    FREE(command);
    LYSleepAlert();
    start_curses();
#else /* Unix/DOS/Windows */
    /*
     *	Send the tmpfile into sendmail.
     */
    _statusline(SENDING_YOUR_MSG);
#if CAN_PIPE_TO_MAILER
    signal(SIGINT, SIG_IGN);
    if ((fp = LYPipeToMailer()) == 0) {
	HTInfoMsg(CANCELLED);
    }
#else
    if ((fp = LYOpenTemp(tmpfile2, ".txt", "w")) == NULL) {
	HTAlert(MAILTO_URL_TEMPOPEN_FAILED);
    }
#endif /* CAN_PIPE_TO_MAILER */
    if (fp != 0) {
	fd = fopen(my_tmpfile, TXT_R);
	if (fd == NULL) {
	    HTInfoMsg(CANCELLED);
#if CAN_PIPE_TO_MAILER
	    pclose(fp);
#else
	    LYCloseTempFP(fp);
#endif /* CAN_PIPE_TO_MAILER */
	} else {
#if USE_BLAT_MAILER
	    if (!mail_is_blat)
		fputs(header, fp);
#else
	    fputs(header, fp);
#endif
	    while ((n = fread(buf, 1, sizeof(buf), fd)) != 0) {
		fwrite(buf, 1, n, fp);
	    }
#if CAN_PIPE_TO_MAILER
	    pclose(fp);
#else
	    LYCloseTempFP(fp);	/* Close the tmpfile. */
	    LYSendMailFile (
		to_address,
		tmpfile2,
		the_subject,
		ccaddr,
		SENDING_COMMENT);
	    LYRemoveTemp(tmpfile2);	/* Delete the tmpfile. */
#endif /* CAN_PIPE_TO_MAILER */
	    LYCloseInput(fd); /* Close the tmpfile. */
	}
    }
#endif /* USE_VMS_MAILER */
    goto cleanup;

    /*
     *	Come here to cleanup and exit.
     */
cancelled:
    HTInfoMsg(CANCELLED);
    LYCloseTempFP(fd);		/* Close the tmpfile.	*/
    scrollok(LYwin,FALSE);	/* Stop scrolling.	*/
cleanup:
    signal(SIGINT, cleanup_sig);
    term_letter = FALSE;

#if USE_VMS_MAILER
    while (LYRemoveTemp(my_tmpfile) == 0)
	;		 /* Delete the tmpfile(s). */
    if (isPMDF) {
	LYRemoveTemp(hdrfile); /* Delete the hdrfile. */
    }
#else
    FREE(header);
    LYRemoveTemp(my_tmpfile);  /* Delete the tmpfile. */
#endif /* VMS */

    FREE(from_address);
    FREE(the_subject);
    FREE(cc_address);
    FREE(to_address);
    FREE(ccaddr);
    FREE(keywords);
    FREE(body);
    return;
}
/*
 * This function makes the history page seem like any other type of file since
 * more info is needed than can be provided by the normal link structure.  We
 * saved out the history number to a special URL.
 *
 * The info looks like:  LYNXHIST:#
 */
BOOLEAN historytarget(DocInfo *newdoc)
{
    int number;
    DocAddress WWWDoc;
    HTParentAnchor *tmpanchor;
    HText *text;
    BOOLEAN treat_as_intern = FALSE;

    if ((!newdoc || !newdoc->address) ||
	strlen(newdoc->address) < 10 || !isdigit(UCH(*(newdoc->address + 9))))
	return (FALSE);

    if ((number = atoi(newdoc->address + 9)) > nhist + nhist_extra || number < 0)
	return (FALSE);

    /*
     * Optimization: assume we came from the History Page,
     * so never return back - always a new version next time.
     * But check first whether HTMainText is really the History
     * Page document - in some obscure situations this may not be
     * the case.  If HTMainText seems to be a History Page document,
     * also check that it really hasn't been pushed. - LP, kw
     */
    if (HTMainText && nhist > 0 &&
	!strcmp(HTLoadedDocumentTitle(), HISTORY_PAGE_TITLE) &&
	LYIsUIPage3(HTLoadedDocumentURL(), UIP_HISTORY, 0) &&
	strcmp(HTLoadedDocumentURL(), HDOC(nhist - 1).address)) {
	HTuncache_current_document();	/* don't waste the cache */
    }

    LYpop_num(number, newdoc);
    if (((newdoc->internal_link &&
	  history[number].intern_seq_start == history[nhist - 1].intern_seq_start)
	 || (number < nhist - 1 &&
	     HDOC(nhist - 1).internal_link &&
	     number == history[nhist - 1].intern_seq_start))
	&& !(LYforce_no_cache == TRUE && LYoverride_no_cache == FALSE)) {
	if (track_internal_links) {
	    LYforce_no_cache = FALSE;
	    LYinternal_flag = TRUE;
	    newdoc->internal_link = TRUE;
	    treat_as_intern = TRUE;
	}
    } else {
	newdoc->internal_link = FALSE;
    }
    /*
     * If we have POST content, and have LYresubmit_posts set or have no_cache
     * set or do not still have the text cached, ask the user whether to
     * resubmit the form.  - FM
     */
    if (newdoc->post_data != NULL) {
	WWWDoc.address = newdoc->address;
	WWWDoc.post_data = newdoc->post_data;
	WWWDoc.post_content_type = newdoc->post_content_type;
	WWWDoc.bookmark = newdoc->bookmark;
	WWWDoc.isHEAD = newdoc->isHEAD;
	WWWDoc.safe = newdoc->safe;
	tmpanchor = HTAnchor_findAddress(&WWWDoc);
	text = (HText *) HTAnchor_document(tmpanchor);
	if (((((LYresubmit_posts == TRUE) ||
	       (LYforce_no_cache == TRUE &&
		LYoverride_no_cache == FALSE)) &&
	      !(treat_as_intern && !reloading)) ||
	     text == NULL) &&
	    (isLYNXIMGMAP(newdoc->address) ||
	     HTConfirm(CONFIRM_POST_RESUBMISSION) == TRUE)) {
	    LYforce_no_cache = TRUE;
	    LYoverride_no_cache = FALSE;
	} else if (text != NULL) {
	    LYforce_no_cache = FALSE;
	    LYoverride_no_cache = TRUE;
	} else {
	    HTInfoMsg(CANCELLED);
	    return (FALSE);
	}
    }

    if (number != 0)
	StrAllocCat(newdoc->title, gettext(" (From History)"));
    return (TRUE);
}
/*
 * This procedure outputs the history buffer into a temporary file.
 */
int showhistory(char **newfile)
{
    static char tempfile[LY_MAXPATH] = "\0";
    char *Title = NULL;
    int x = 0;
    FILE *fp0;

    if ((fp0 = InternalPageFP(tempfile, TRUE)) == 0)
	return (-1);

    LYLocalFileToURL(newfile, tempfile);

    LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
    LYforce_no_cache = TRUE;	/* force this file to be new */

    BeginInternalPage(fp0, HISTORY_PAGE_TITLE, HISTORY_PAGE_HELP);

    fprintf(fp0, "<p align=right> <a href=\"%s\">[%s]</a>\n",
	    STR_LYNXMESSAGES, STATUSLINES_TITLE);

    fprintf(fp0, "<pre>\n");

    fprintf(fp0, "<em>%s</em>\n", gettext("You selected:"));
    for (x = nhist + nhist_extra - 1; x >= 0; x--) {
	/*
	 * The number of the document in the hist stack, its title in a link,
	 * and its address.  - FM
	 */
	if (HDOC(x).title != NULL) {
	    StrAllocCopy(Title, HDOC(x).title);
	    LYEntify(&Title, TRUE);
	    LYTrimLeading(Title);
	    LYTrimTrailing(Title);
	    if (*Title == '\0')
		StrAllocCopy(Title, NO_TITLE);
	} else {
	    StrAllocCopy(Title, NO_TITLE);
	}
	fprintf(fp0,
		"%s<em>%d</em>. <tab id=t%d><a href=\"%s%d\">%s</a>\n",
		(x > 99 ? "" : x < 10 ? "  " : " "),
		x, x, STR_LYNXHIST, x, Title);
	if (HDOC(x).address != NULL) {
	    StrAllocCopy(Title, HDOC(x).address);
	    LYEntify(&Title, TRUE);
	} else {
	    StrAllocCopy(Title, gettext("(no address)"));
	}
	if (HDOC(x).internal_link) {
	    if (history[x].intern_seq_start == history[nhist - 1].intern_seq_start)
		StrAllocCat(Title, gettext(" (internal)"));
	    else
		StrAllocCat(Title, gettext(" (was internal)"));
	}
	fprintf(fp0, "<tab to=t%d>%s\n", x, Title);
    }
    fprintf(fp0, "</pre>\n");
    EndInternalPage(fp0);

    LYCloseTempFP(fp0);
    FREE(Title);
    return (0);
}
/*
 * Push the current filename, link and line number onto the history list.
 */
int LYpush(DocInfo *doc, int force_push)
{
    /*
     * Don't push NULL file names.
     */
    if (*doc->address == '\0')
	return 0;

    /*
     * Check whether this is a document we don't push unless forced.  - FM
     */
    if (!force_push) {
	/*
	 * Don't push the history, printer, or download lists.
	 */
	if (!LYwouldPush(doc->title, doc->address)) {
	    if (!LYforce_no_cache)
		LYoverride_no_cache = TRUE;
	    return 0;
	}
    }

    /*
     * If file is identical to one before it, don't push it.
     * But do not duplicate it if there is only one on the stack,
     * note that HDOC() starts from 0, so nhist should be > 0.
     */
    if (nhist >= 1 && are_identical(&(history[nhist - 1]), doc)) {
	if (HDOC(nhist - 1).internal_link == doc->internal_link) {
	    /* But it is nice to have the last position remembered!
	       - kw */
	    HDOC(nhist - 1).link = doc->link;
	    HDOC(nhist - 1).line = doc->line;
	    return 0;
	}
    }

    /*
     * If file is identical to the current document, just move the pointer.
     */
    if (nhist_extra >= 1 && are_identical(&(history[nhist]), doc)) {
	HDOC(nhist).link = doc->link;
	HDOC(nhist).line = doc->line;
	nhist_extra--;
	LYAllocHistory(nhist);
	nhist++;
	trace_history("LYpush: just move the cursor");
	return 1;
    }

    clean_extra_history();
#ifdef LY_FIND_LEAKS
    if (!already_registered_clean_all_history) {
	already_registered_clean_all_history = 1;
	atexit(clean_all_history);
    }
#endif

    /*
     * OK, push it...
     */
    LYAllocHistory(nhist);
    HDOC(nhist).link = doc->link;
    HDOC(nhist).line = doc->line;

    HDOC(nhist).title = NULL;
    LYformTitle(&(HDOC(nhist).title), doc->title);

    HDOC(nhist).address = NULL;
    StrAllocCopy(HDOC(nhist).address, doc->address);

    HDOC(nhist).post_data = NULL;
    BStrCopy(HDOC(nhist).post_data, doc->post_data);

    HDOC(nhist).post_content_type = NULL;
    StrAllocCopy(HDOC(nhist).post_content_type, doc->post_content_type);

    HDOC(nhist).bookmark = NULL;
    StrAllocCopy(HDOC(nhist).bookmark, doc->bookmark);

    HDOC(nhist).isHEAD = doc->isHEAD;
    HDOC(nhist).safe = doc->safe;

    HDOC(nhist).internal_link = FALSE;	/* by default */
    history[nhist].intern_seq_start = -1;	/* by default */
    if (doc->internal_link) {
	/* Now some tricky stuff: if the caller thinks that the doc
	   to push was the result of following an internal
	   (fragment) link, we check whether we believe it.
	   It is only accepted as valid if the immediately preceding
	   item on the history stack is actually the same document
	   except for fragment and location info.  I.e. the Parent
	   Anchors are the same.
	   Also of course this requires that this is not the first
	   history item. - kw */
	if (nhist > 0) {
	    DocAddress WWWDoc;
	    HTParentAnchor *thisparent, *thatparent = NULL;

	    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;
	    thisparent =
		HTAnchor_findAddress(&WWWDoc);
	    /* Now find the ParentAnchor for the previous history
	     * item - kw
	     */
	    if (thisparent) {
		/* If the last-pushed item is a LYNXIMGMAP but THIS one
		 * isn't, compare the physical URLs instead. - kw
		 */
		if (isLYNXIMGMAP(HDOC(nhist - 1).address) &&
		    !isLYNXIMGMAP(doc->address)) {
		    WWWDoc.address = HDOC(nhist - 1).address + LEN_LYNXIMGMAP;
		    /*
		     * If THIS item is a LYNXIMGMAP but the last-pushed one
		     * isn't, fake it by using THIS item's address for
		     * thatparent... - kw
		     */
		} else if (isLYNXIMGMAP(doc->address) &&
			   !isLYNXIMGMAP(HDOC(nhist - 1).address)) {
		    char *temp = NULL;

		    StrAllocCopy(temp, STR_LYNXIMGMAP);
		    StrAllocCat(temp, doc->address + LEN_LYNXIMGMAP);
		    WWWDoc.address = temp;
		    WWWDoc.post_content_type = HDOC(nhist - 1).post_content_type;
		    WWWDoc.bookmark = HDOC(nhist - 1).bookmark;
		    WWWDoc.isHEAD = HDOC(nhist - 1).isHEAD;
		    WWWDoc.safe = HDOC(nhist - 1).safe;
		    thatparent =
			HTAnchor_findAddress(&WWWDoc);
		    FREE(temp);
		} else {
		    WWWDoc.address = HDOC(nhist - 1).address;
		}
		if (!thatparent) {	/* if not yet done */
		    WWWDoc.post_data = HDOC(nhist - 1).post_data;
		    WWWDoc.post_content_type = HDOC(nhist - 1).post_content_type;
		    WWWDoc.bookmark = HDOC(nhist - 1).bookmark;
		    WWWDoc.isHEAD = HDOC(nhist - 1).isHEAD;
		    WWWDoc.safe = HDOC(nhist - 1).safe;
		    thatparent =
			HTAnchor_findAddress(&WWWDoc);
		}
		/* In addition to equality of the ParentAnchors, require
		 * that IF we have a HTMainText (i.e., it wasn't just
		 * HTuncache'd by mainloop), THEN it has to be consistent
		 * with what we are trying to push.
		 *
		 * This may be overkill...  - kw
		 */
		if (thatparent == thisparent &&
		    (!HTMainText || HTMainAnchor == thisparent)
		    ) {
		    HDOC(nhist).internal_link = TRUE;
		    history[nhist].intern_seq_start =
			history[nhist - 1].intern_seq_start >= 0 ?
			history[nhist - 1].intern_seq_start : nhist - 1;
		    CTRACE((tfp, "\nLYpush: pushed as internal link, OK\n"));
		}
	    }
	}
	if (!HDOC(nhist).internal_link) {
	    CTRACE((tfp, "\nLYpush: push as internal link requested, %s\n",
		    "but didn't check out!"));
	}
    }
    CTRACE((tfp, "\nLYpush[%d]: address:%s\n        title:%s\n",
	    nhist, doc->address, doc->title));
    nhist++;
    return 1;
}
Exemple #27
0
PUBLIC void HTAnchor_appendTitle (HTParentAnchor * me, const char * title)
{
    if (me && title) StrAllocCat(me->title, title);
}
Exemple #28
0
/*	Translate by rules					HTTranslate()
 *	------------------
 *
 *	The most recently defined rules are applied first.
 *
 * On entry,
 *	required	points to a string whose equivalent value is needed
 * On exit,
 *	returns		the address of the equivalent string allocated from
 *			the heap which the CALLER MUST FREE. If no translation
 *			occurred, then it is a copy of the original.
 * NEW FEATURES:
 *			When a "protect" or "defprot" rule is matched,
 *			a call to HTAA_setCurrentProtection() or
 *			HTAA_setDefaultProtection() is made to notify
 *			the Access Authorization module that the file is
 *			protected, and so it knows how to handle it.
 *								-- AL
 */
char *HTTranslate(const char *required)
{
    rule *r;
    char *current = NULL;
    char *msgtmp = NULL;
    const char *pMsg;
    int proxy_none_flag = 0;
    int permitredir_flag = 0;

    StrAllocCopy(current, required);

    HTAA_clearProtections();	/* Reset from previous call -- AL */

    for (r = rules; r; r = r->next) {
	char *p = r->pattern;
	int m = 0;		/* Number of characters matched against wildcard */
	const char *q = current;

	for (; *p && *q; p++, q++) {	/* Find first mismatch */
	    if (*p != *q)
		break;
	}

	if (*p == '*') {	/* Match up to wildcard */
	    m = strlen(q) - strlen(p + 1);	/* Amount to match to wildcard */
	    if (m < 0)
		continue;	/* tail is too short to match */
	    if (0 != strcmp(q + m, p + 1))
		continue;	/* Tail mismatch */
	} else
	    /* Not wildcard */ if (*p != *q)
	    continue;		/* plain mismatch: go to next rule */

	if (!rule_cond_ok(r))	/* check condition, next rule if false - kw */
	    continue;

	switch (r->op) {	/* Perform operation */

#ifdef ACCESS_AUTH
	case HT_DefProt:
	case HT_Protect:
	    {
		char *local_copy = NULL;
		char *p2;
		char *eff_ids = NULL;
		char *prot_file = NULL;

		CTRACE((tfp, "HTRule: `%s' matched %s %s: `%s'\n",
			current,
			(r->op == HT_Protect ? "Protect" : "DefProt"),
			"rule, setup",
			(r->equiv ? r->equiv :
			 (r->op == HT_Protect ? "DEFAULT" : "NULL!!"))));

		if (r->equiv) {
		    StrAllocCopy(local_copy, r->equiv);
		    p2 = local_copy;
		    prot_file = HTNextField(&p2);
		    eff_ids = HTNextField(&p2);
		}

		if (r->op == HT_Protect)
		    HTAA_setCurrentProtection(current, prot_file, eff_ids);
		else
		    HTAA_setDefaultProtection(current, prot_file, eff_ids);

		FREE(local_copy);

		/* continue translating rules */
	    }
	    break;
#endif /* ACCESS_AUTH */

	case HT_UserMsg:	/* Produce message immediately */
	    LYFixCursesOn("show rule message:");
	    HTUserMsg2((r->equiv ? r->equiv : "Rule: %s"), current);
	    break;
	case HT_InfoMsg:	/* Produce messages immediately */
	case HT_Progress:
	case HT_Alert:
	    LYFixCursesOn("show rule message:");	/* and fall through */
	case HT_AlwaysAlert:
	    pMsg = r->equiv ? r->equiv :
		(r->op == HT_AlwaysAlert) ? "%s" : "Rule: %s";
	    if (strchr(pMsg, '%')) {
		HTSprintf0(&msgtmp, pMsg, current);
		pMsg = msgtmp;
	    }
	    switch (r->op) {	/* Actually produce message */
	    case HT_InfoMsg:
		HTInfoMsg(pMsg);
		break;
	    case HT_Progress:
		HTProgress(pMsg);
		break;
	    case HT_Alert:
		HTAlert(pMsg);
		break;
	    case HT_AlwaysAlert:
		HTAlwaysAlert("Rule alert:", pMsg);
		break;
	    default:
		break;
	    }
	    FREE(msgtmp);
	    break;

	case HT_PermitRedir:	/* Set special flag */
	    permitredir_flag = 1;
	    CTRACE((tfp, "HTRule: Mark for redirection permitted\n"));
	    break;

	case HT_Pass:		/* Authorised */
	    if (!r->equiv) {
		if (proxy_none_flag) {
		    char *temp = NULL;

		    StrAllocCopy(temp, "NoProxy=");
		    StrAllocCat(temp, current);
		    FREE(current);
		    current = temp;
		}
		CTRACE((tfp, "HTRule: Pass `%s'\n", current));
		return current;
	    }
	    /* Else fall through ...to map and pass */

	case HT_Map:
	case HT_Redirect:
	case HT_RedirectPerm:
	    if (*p == *q) {	/* End of both strings, no wildcard */
		CTRACE((tfp, "For `%s' using `%s'\n", current, r->equiv));
		StrAllocCopy(current, r->equiv);	/* use entire translation */
	    } else {
		char *ins = strchr(r->equiv, '*');	/* Insertion point */

		if (ins) {	/* Consistent rule!!! */
		    char *temp = NULL;

		    HTSprintf0(&temp, "%.*s%.*s%s",
			       (int) (ins - r->equiv),
			       r->equiv,
			       m,
			       q,
			       ins + 1);
		    CTRACE((tfp, "For `%s' using `%s'\n",
			    current, temp));
		    FREE(current);
		    current = temp;	/* Use this */

		} else {	/* No insertion point */
		    char *temp = NULL;

		    StrAllocCopy(temp, r->equiv);
		    CTRACE((tfp, "For `%s' using `%s'\n",
			    current, temp));
		    FREE(current);
		    current = temp;	/* Use this */
		}		/* If no insertion point exists */
	    }
	    if (r->op == HT_Pass) {
		if (proxy_none_flag) {
		    char *temp = NULL;

		    StrAllocCopy(temp, "NoProxy=");
		    StrAllocCat(temp, current);
		    FREE(current);
		    current = temp;
		}
		CTRACE((tfp, "HTRule: ...and pass `%s'\n",
			current));
		return current;
	    } else if (r->op == HT_Redirect) {
		CTRACE((tfp, "HTRule: ...and redirect to `%s'\n",
			current));
		redirecting_url = current;
		HTPermitRedir = (BOOL) (permitredir_flag == 1);
		return (char *) 0;
	    } else if (r->op == HT_RedirectPerm) {
		CTRACE((tfp, "HTRule: ...and redirect like 301 to `%s'\n",
			current));
		redirecting_url = current;
		permanent_redirection = TRUE;
		HTPermitRedir = (BOOL) (permitredir_flag == 1);
		return (char *) 0;
	    }
	    break;

	case HT_UseProxy:
	    if (r->equiv && 0 == strcasecomp(r->equiv, "none")) {
		CTRACE((tfp, "For `%s' will not use proxy\n", current));
		proxy_none_flag = 1;
	    } else if (proxy_none_flag) {
		CTRACE((tfp, "For `%s' proxy server ignored: %s\n",
			current,
			NONNULL(r->equiv)));
	    } else {
		char *temp = NULL;

		StrAllocCopy(temp, "Proxied=");
		StrAllocCat(temp, r->equiv);
		StrAllocCat(temp, current);
		CTRACE((tfp, "HTRule: proxy server found: %s\n",
			NONNULL(r->equiv)));
		FREE(current);
		return temp;
	    }
	    break;

	case HT_Invalid:
	case HT_Fail:		/* Unauthorised */
	    CTRACE((tfp, "HTRule: *** FAIL `%s'\n", current));
	    FREE(current);
	    return (char *) 0;
	}			/* if tail matches ... switch operation */

    }				/* loop over rules */

    if (proxy_none_flag) {
	char *temp = NULL;

	StrAllocCopy(temp, "NoProxy=");
	StrAllocCat(temp, current);
	FREE(current);
	return temp;
    }

    return current;
}
Exemple #29
0
/* -------------------------------------------------------------------------
   This function tries really hard to find a non-existent filename relative
   to the path given.
       path:	path of directory in which to put temp file
       url:	used for a similar name or generating a hash within 'limit'
       suffix:	if != 0, this suffix is used, else no suffix
       limit:	if 0 => use last part of url
		if >0 generate hash. Max value
		      of limit is max(unsigned int).
   Returns NULL if no filename could be found.
   Henrik 10/03-94
   ------------------------------------------------------------------------- */
PUBLIC char *HTFWriter_filename ARGS4(char *, path, char *, url,
				      CONST char *, suffix,
				      unsigned int, limit)
{
#define HASHTRY 20			   /* Keep this less than 10, please */
    static int primes[HASHTRY] = {31, 37, 41, 43, 47};	      /* Some primes */
    char *urlfile = strrchr(url, '/');
    char *filename = NULL;
    StrAllocCopy(filename, path);
    if (filename /*&& urlfile++*/) {		   /* We don't want two '/'s */
	int digits = 1;
	unsigned hash;
	char *hashstr = NULL;
	char *replace = 0;
	char *ptr;				/* Dummy used several places */
	char format[10];
	if (*(filename+strlen(filename)-1) != '/')  /* But one is OK, though */
	    StrAllocCat(filename, "/");
	if (limit) {					  /* Use hash method */
	    unsigned int residue = limit;
	    while (residue /= 10)		    /* Find number of digits */
		digits++;
	    if ((hashstr = malloc(digits+1)) == NULL)
		outofmem(__FILE__, "HTFWriter_filename");
	    for(ptr=urlfile, hash=0; *ptr; ptr++)          /* Calculate hash */
		hash = *ptr + *primes * hash;
	    hash %= limit;
	    sprintf(format, "%%0%du", digits);     /* Convert hash to string */
	    sprintf(hashstr, format, hash);
	    *(hashstr+digits) = '\0';
	    StrAllocCat(filename, hashstr);
#ifndef NO_GETPID
/* RISK: Race conditions may occur if this is not added to the filename */
	    {
		char pidstr[10];
		sprintf(pidstr, "-%d", (int) getpid());
		StrAllocCat(filename, pidstr);
	    }
#endif
	    if (suffix) {				       /* Add suffix */
		if (*suffix != '.')
		    StrAllocCat(filename, ".");
		StrAllocCat(filename, suffix);
	    }
	    replace = strrchr(filename, '/')+1;	   /* Remember place */
	} else {      					     /* Use url name */
	    char *urlptr = 0;			     /* Strip off any suffix */
	    StrAllocCopy(urlptr, urlfile);
	    ptr = strrchr(urlptr, '.');
	    if (ptr)
		*ptr = '\0';
	    StrAllocCat(filename, urlptr);
	    free(urlptr);
	    if (suffix) {			    /* Add new suffix if any */
		if (*suffix != '.')
		    StrAllocCat(filename, ".");
		StrAllocCat(filename, suffix);
	    }
	}
	{					       /* Try if file exists */
	    int cnt;
	    FILE *fp;
	    for (cnt=1; cnt<HASHTRY; cnt++) {
		if ((fp = fopen(filename, "r")) != NULL) {
		    fclose(fp);
		    if (limit) {          /* recalculate hash with new prime */
			for(ptr=urlfile, hash=0; *ptr; ptr++)
			    hash = *ptr + *(primes+cnt) * hash;
			hash %= limit;
			sprintf(hashstr, format, hash);
			*(hashstr+digits) = '\0';
			memcpy(replace, hashstr, digits);
		    } else { 		/* Add .n to the urlfile. n is a int */
			if (cnt == 1) {
			    StrAllocCat(filename, ".1");
			    replace = filename+strlen(filename)-1;
			} else
			    *replace = (char) cnt+0x30;   /* Works if cnt<10 */
		    }
		} else
		    break;		       /* File does not exist, so OK */
	    }
	    if (cnt >= HASHTRY) {      	   /* If no file name could be found */
		free(filename);
		filename = NULL;
	    }
	}
	FREE(hashstr);
    }
    return filename;
}
/* PUBLIC						HTAA_getUnfoldedLine()
 *		READ AN UNFOLDED HEADER LINE FROM SOCKET
 * ON ENTRY:
 *	HTAA_setupReader must absolutely be called before
 *	this function to set up internal buffer.
 *
 * ON EXIT:
 *	returns a newly-allocated character string representing
 *		the read line.	The line is unfolded, i.e.
 *		lines that begin with whitespace are appended
 *		to current line.  E.g.
 *
 *			Field-Name: Blaa-Blaa
 *			 This-Is-A-Continuation-Line
 *			 Here-Is_Another
 *
 *		is seen by the caller as:
 *
 *	Field-Name: Blaa-Blaa This-Is-A-Continuation-Line Here-Is_Another
 *
 */
char *HTAA_getUnfoldedLine(void)
{
    char *line = NULL;
    char *cur;
    int count;
    BOOL peek_for_folding = NO;

    if (in_soc < 0) {
	CTRACE((tfp, "%s %s\n",
		"HTAA_getUnfoldedLine: buffer not initialized",
		"with function HTAA_setupReader()"));
	return NULL;
    }

    for (;;) {

	/* Reading from socket */

	if (start_pointer >= end_pointer) {	/*Read the next block and continue */
#ifdef USE_SSL
	    if (SSL_handle)
		count = SSL_read(SSL_handle, buffer, BUFFER_SIZE);
	    else
		count = NETREAD(in_soc, buffer, BUFFER_SIZE);
#else
	    count = NETREAD(in_soc, buffer, BUFFER_SIZE);
#endif /* USE_SSL */
	    if (count <= 0) {
		in_soc = -1;
		return line;
	    }
	    if (count > (int) buffer_length)
		count = (int) buffer_length;
	    start_pointer = buffer;
	    end_pointer = buffer + count;
	    *end_pointer = '\0';
#ifdef NOT_ASCII
	    cur = start_pointer;
	    while (cur < end_pointer) {
		*cur = TOASCII(*cur);
		cur++;
	    }
#endif /*NOT_ASCII */
	}
	cur = start_pointer;

	/* Unfolding */

	if (peek_for_folding) {
	    if (*cur != ' ' && *cur != '\t')
		return line;	/* Ok, no continuation line */
	    else		/* So this is a continuation line, continue */
		peek_for_folding = NO;
	}

	/* Finding end-of-line */

	while (cur < end_pointer && *cur != '\n')	/* Find the end-of-line */
	    cur++;		/* (or end-of-buffer).  */

	/* Terminating line */

	if (cur < end_pointer) {	/* So *cur==LF, terminate line */
	    *cur = '\0';	/* Overwrite LF */
	    if (*(cur - 1) == '\r')
		*(cur - 1) = '\0';	/* Overwrite CR */
	    peek_for_folding = YES;	/* Check for a continuation line */
	}

	/* Copying the result */

	if (line)
	    StrAllocCat(line, start_pointer);	/* Append */
	else
	    StrAllocCopy(line, start_pointer);	/* A new line */

	start_pointer = cur + 1;	/* Skip the read line */

    }				/* forever */
}