diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/DefaultStyle.c | 13 | ||||
-rw-r--r-- | src/GridText.c | 604 | ||||
-rw-r--r-- | src/GridText.h | 9 | ||||
-rw-r--r-- | src/HTAlert.c | 109 | ||||
-rw-r--r-- | src/HTAlert.h | 14 | ||||
-rw-r--r-- | src/HTFWriter.c | 44 | ||||
-rw-r--r-- | src/HTInit.c | 6 | ||||
-rw-r--r-- | src/HTML.c | 294 | ||||
-rw-r--r-- | src/LYBookmark.c | 486 | ||||
-rw-r--r-- | src/LYBookmark.h | 14 | ||||
-rw-r--r-- | src/LYCgi.c | 6 | ||||
-rw-r--r-- | src/LYCharUtils.c | 2 | ||||
-rw-r--r-- | src/LYCurses.h | 23 | ||||
-rw-r--r-- | src/LYForms.c | 597 | ||||
-rw-r--r-- | src/LYGetFile.c | 140 | ||||
-rw-r--r-- | src/LYGlobalDefs.h | 14 | ||||
-rw-r--r-- | src/LYHistory.c | 14 | ||||
-rw-r--r-- | src/LYKeymap.c | 16 | ||||
-rw-r--r-- | src/LYKeymap.h | 1 | ||||
-rw-r--r-- | src/LYLocal.c | 424 | ||||
-rw-r--r-- | src/LYLocal.h | 7 | ||||
-rw-r--r-- | src/LYMail.c | 157 | ||||
-rw-r--r-- | src/LYMail.h | 23 | ||||
-rw-r--r-- | src/LYMain.c | 139 | ||||
-rw-r--r-- | src/LYMainLoop.c | 525 | ||||
-rw-r--r-- | src/LYMap.c | 2 | ||||
-rw-r--r-- | src/LYNews.c | 1 | ||||
-rw-r--r-- | src/LYOptions.c | 668 | ||||
-rw-r--r-- | src/LYOptions.h | 27 | ||||
-rw-r--r-- | src/LYPrint.c | 123 | ||||
-rw-r--r-- | src/LYReadCFG.c | 18 | ||||
-rw-r--r-- | src/LYShowInfo.c | 88 | ||||
-rw-r--r-- | src/LYStructs.h | 9 | ||||
-rw-r--r-- | src/LYUtils.c | 133 | ||||
-rw-r--r-- | src/LYUtils.h | 5 | ||||
-rw-r--r-- | src/LYrcFile.c | 180 |
36 files changed, 3724 insertions, 1211 deletions
diff --git a/src/DefaultStyle.c b/src/DefaultStyle.c index 1cbe4252..b4ee349a 100644 --- a/src/DefaultStyle.c +++ b/src/DefaultStyle.c @@ -277,18 +277,11 @@ PRIVATE HTStyle HTStyleExample = { &HTStyleGlossaryCompact6, "Example", "XMP", HT_FONT, 1.0, HT_BLACK, 0, 0, 0, 0, 0, HT_LEFT, 1, 0, tabs_8, - NO, NO, 1, 1, 0 -}; - -PRIVATE HTStyle HTStyleStyle = { /* HTML 3.0 STYLE - FM */ - &HTStyleExample, "Style", "STYLE", - HT_FONT, 1.0, HT_BLACK, 0, 0, - 0, 0, 0, HT_LEFT, 1, 0, tabs_8, - NO, NO, 1, 1, 0 + NO, NO, 0, 0, 0 }; PRIVATE HTStyle HTStylePreformatted = { - &HTStyleStyle, "Preformatted", "PRE", + &HTStyleExample, "Preformatted", "PRE", HT_FONT, 1.0, HT_BLACK, 0, 0, 0, 0, 0, HT_LEFT, 1, 0, tabs_8, NO, YES, 0, 0, 0 @@ -298,7 +291,7 @@ PRIVATE HTStyle HTStyleListing = { &HTStylePreformatted, "Listing", "LISTING", HT_FONT, 1.0, HT_BLACK, 0, 0, 0, 0, 0, HT_LEFT, 1, 0, tabs_8, - NO, NO, 1, 1, 0 }; + NO, NO, 0, 0, 0 }; PRIVATE HTStyle HTStyleAddress = { &HTStyleListing, "Address", "ADDRESS", diff --git a/src/GridText.c b/src/GridText.c index 2c35304d..e988c7ba 100644 --- a/src/GridText.c +++ b/src/GridText.c @@ -68,10 +68,10 @@ PUBLIC char * HTAppVersion = LYNX_VERSION; /* Application version */ PUBLIC int HTFormNumber = 0; PUBLIC int HTFormFields = 0; -PUBLIC char * HTCurSelectGroup = NULL; /* form select group name */ -PUBLIC int HTCurSelectGroupType = F_RADIO_TYPE; /* group type */ -PUBLIC char * HTCurSelectGroupSize = NULL; /* length of select */ -PRIVATE char * HTCurSelectedOptionValue = NULL; /* select choice */ +PUBLIC char * HTCurSelectGroup = NULL; /* Form select group name */ +PUBLIC int HTCurSelectGroupType = F_RADIO_TYPE; /* Group type */ +PUBLIC char * HTCurSelectGroupSize = NULL; /* Length of select */ +PRIVATE char * HTCurSelectedOptionValue = NULL; /* Select choice */ PUBLIC char * checked_box = "[X]"; PUBLIC char * unchecked_box = "[ ]"; @@ -157,7 +157,8 @@ struct _HText { /* * Boring static variable used for moving cursor across */ -#define UNDERSCORES(n) (&underscore_string[(MAX_LINE-1) - (n)]) +#define UNDERSCORES(n) \ + ((n) >= MAX_LINE ? underscore_string : &underscore_string[(MAX_LINE-1)] - (n)) /* * Memory leak fixed. @@ -192,7 +193,7 @@ PUBLIC HText * HText_new ARGS1(HTParentAnchor *,anchor) int status, VMType=3, VMTotal; #endif /* VMS && VAXC && !__DECC */ HTLine * line = NULL; - HText * self = (HText *) calloc(sizeof(*self),1); + HText * self = (HText *) calloc(1, sizeof(*self)); if (!self) return self; #if defined(VMS) && defined (VAXC) && !defined(__DECC) @@ -239,7 +240,7 @@ PUBLIC HText * HText_new ARGS1(HTParentAnchor *,anchor) #endif /* VMS && VAXC && !__DECC */ } - line = self->last_line = (HTLine *)calloc(sizeof(char),LINE_SIZE(MAX_LINE)); + line = self->last_line = (HTLine *)calloc(1, LINE_SIZE(MAX_LINE)); if (line == NULL) outofmem(__FILE__, "HText_New"); line->next = line->prev = line; @@ -281,14 +282,20 @@ PUBLIC HText * HText_new ARGS1(HTParentAnchor *,anchor) * Check to see if our underline and star_string need initialization * if the underline is not filled with dots. */ - if (underscore_string[0] != '.') { /* Make a line */ + if (underscore_string[0] != '.') { char *p; - for (p=underscore_string; p<underscore_string+(MAX_LINE-1); p++) - *p = '.'; /* Used for printfs later */ + /* + * Create and array of dots for the UNDERSCORES macro. - FM + */ + memset(underscore_string, '.', (MAX_LINE-1)); underscore_string[(MAX_LINE-1)] = '\0'; - for (p=star_string; p<star_string+(LINESIZE-1); p++) - *p = '_'; /* Used for printfs later */ - star_string[(LINESIZE-1)] = '\0'; + underscore_string[MAX_LINE] = '\0'; + /* + * Create and array of underscores for the STARS macro. - FM + */ + memset(star_string, '_', (MAX_LINE-1)); + star_string[(MAX_LINE-1)] = '\0'; + star_string[MAX_LINE] = '\0'; } underline_on = FALSE; /* reset */ @@ -594,7 +601,8 @@ PRIVATE void display_title ARGS1(HText *,text) if (cp == NULL) outofmem(__FILE__, "display_title"); if (HTCJK != NOCJK) { - if (*title && (tmp = (unsigned char *)calloc(1, strlen(title) + 1))) { + if (*title && + (tmp = (unsigned char *)calloc(1, (strlen(title) + 1)))) { if (kanji_code == EUC) { TO_EUC((unsigned char *)title, tmp); } else if (kanji_code == SJIS) { @@ -878,7 +886,7 @@ PRIVATE void display_page ARGS3(HText *,text, int,line_number, char *, target) } } - if (Anchor_ptr == text->last_anchor) + if (Anchor_ptr == text->last_anchor || nlinks == MAXLINKS) break; } @@ -953,7 +961,7 @@ PRIVATE void split_line ARGS2(HText *,text, int,split) HTLine * previous = text->last_line; int ctrl_chars_on_previous_line = 0; char * cp; - HTLine * line = (HTLine *)calloc(sizeof(char), LINE_SIZE(MAX_LINE)); + HTLine * line = (HTLine *)calloc(1, LINE_SIZE(MAX_LINE)); ctrl_chars_on_this_line = 0; /*reset since we are going to a new line*/ HTML_Last_Char = ' '; @@ -1126,7 +1134,7 @@ PRIVATE void split_line ARGS2(HText *,text, int,split) * problem with Ultrix (4.2) : realloc() is not declared properly. * So we'll use a substitute for realloc. */ - temp = (HTLine *)calloc(sizeof(char), LINE_SIZE(previous->size)); + temp = (HTLine *)calloc(1, LINE_SIZE(previous->size)); if (temp == NULL) outofmem(__FILE__, "split_line"); memcpy(temp, previous, LINE_SIZE(previous->size)); @@ -1639,7 +1647,7 @@ PUBLIC void HText_beginAnchor ARGS2(HText *,text, HTChildAnchor *,anc) { char marker[16]; - TextAnchor * a = (TextAnchor *) calloc(sizeof(*a),1); + TextAnchor * a = (TextAnchor *) calloc(1, sizeof(*a)); if (a == NULL) outofmem(__FILE__, "HText_beginAnchor"); @@ -1938,7 +1946,8 @@ PUBLIC HTChildAnchor * HText_childNumber ARGS1(int,number) return (HTChildAnchor *)0; /* Fail */ } -/* HTGetLinkInfo returns some link info based on the number +/* + * HTGetLinkInfo returns some link info based on the number. */ PUBLIC int HTGetLinkInfo ARGS3(int, number, char **, hightext, char **, lname) { @@ -1969,16 +1978,18 @@ PUBLIC int HTGetLinkInfo ARGS3(int, number, char **, hightext, char **, lname) return(NO); } -/* HText_getNumOfLines returns the number of lines in the - * current document +/* + * HText_getNumOfLines returns the number of lines in the + * current document. */ PUBLIC int HText_getNumOfLines NOARGS { return(HTMainText->lines); } -/* HText_getTitle returns the title of the - * current document +/* + * HText_getTitle returns the title of the + * current document. */ PUBLIC char * HText_getTitle NOARGS { @@ -1986,12 +1997,47 @@ PUBLIC char * HText_getTitle NOARGS } /* - * HText_pageDisplay displays a screen of text - * starting from the line 'line_num'-1 - * this is the primary call for lynx + * HText_getSugFname returns the suggested filename of the current + * document (normally derived from a Content-Disposition header with + * file; filename=name.suffix). - FM + */ +PUBLIC char * HText_getSugFname NOARGS +{ + return((char *) HTAnchor_SugFname(HTMainText->node_anchor)); +} + +/* + * HText_getLastModified returns the Last-Modified header + * if available, for the current document. - FM */ -extern char is_www_index; +PUBLIC char * HText_getLastModified NOARGS +{ + return((char *) HTAnchor_last_modified(HTMainText->node_anchor)); +} +/* + * HText_getDate returns the Date header + * if available, for the current document. - FM + */ +PUBLIC char * HText_getDate NOARGS +{ + return((char *) HTAnchor_date(HTMainText->node_anchor)); +} + +/* + * HText_getServer returns the Server header + * if available, for the current document. - FM + */ +PUBLIC char * HText_getServer NOARGS +{ + return((char *) HTAnchor_server(HTMainText->node_anchor)); +} + +/* + * HText_pageDisplay displays a screen of text + * starting from the line 'line_num'-1 + * this is the primary call for lynx + */ PUBLIC void HText_pageDisplay ARGS2(int,line_num, char *, target) { display_page(HTMainText, line_num-1, target); @@ -2000,8 +2046,8 @@ PUBLIC void HText_pageDisplay ARGS2(int,line_num, char *, target) } /* - * HText_LinksInLines returns the number of links in the - * 'lines' number of lines beginning with 'line_num'-1. - FM + * HText_LinksInLines returns the number of links in the + * 'lines' number of lines beginning with 'line_num'-1. - FM */ PUBLIC int HText_LinksInLines ARGS3(HText *,text, int,line_num, int,lines) { @@ -2034,7 +2080,8 @@ PUBLIC void HText_setStale ARGS1(HText *,text) PUBLIC void HText_refresh ARGS1(HText *,text) { - if (text->stale) display_page(text, text->top_of_screen, ""); + if (text->stale) + display_page(text, text->top_of_screen, ""); } PUBLIC int HText_sourceAnchors ARGS1(HText *,text) @@ -2679,8 +2726,7 @@ PUBLIC void www_user_search ARGS2(int,start_line, char *,target) www_search_result=count; return; } else if (count > start_line) { /* next line */ - _user_message("\"%s\" could not be found in this document", - target); + _user_message(STRING_NOT_FOUND, target); sleep(MessageSecs); return; /* end */ } else { @@ -2721,7 +2767,18 @@ PUBLIC void user_message ARGS2(char *,message, char *,argument) */ PUBLIC char * HText_getOwner NOARGS { - return((char *)HTAnchor_owner(HTMainText->node_anchor)); + return((char *)HTAnchor_owner(HTMainText->node_anchor)); +} + +/* HText_setMainTextOwner sets the owner for the + * current document + */ +PUBLIC void HText_setMainTextOwner ARGS1(CONST char *, owner) +{ + if (!HTMainText) + return; + + HTAnchor_setOwner(HTMainText->node_anchor, owner); } /* HText_getRevTitle returns the RevTitle element of the @@ -2730,7 +2787,7 @@ PUBLIC char * HText_getOwner NOARGS */ PUBLIC char * HText_getRevTitle NOARGS { - return((char *)HTAnchor_RevTitle(HTMainText->node_anchor)); + return((char *)HTAnchor_RevTitle(HTMainText->node_anchor)); } PUBLIC void HTuncache_current_document NOARGS @@ -2743,53 +2800,85 @@ PUBLIC void HTuncache_current_document NOARGS PUBLIC int HTisDocumentSource NOARGS { - return(HTMainText->source); + return(HTMainText->source); } PUBLIC char * HTLoadedDocumentURL NOARGS { - if (!HTMainText) + if (!HTMainText) return (""); - if (HTMainText->node_anchor && HTMainText->node_anchor->address) + if (HTMainText->node_anchor && HTMainText->node_anchor->address) return(HTMainText->node_anchor->address); - else + else return (""); } PUBLIC char * HTLoadedDocumentPost_data NOARGS { - if (!HTMainText) + if (!HTMainText) return (""); - if (HTMainText->node_anchor && HTMainText->node_anchor->post_data) + if (HTMainText->node_anchor && HTMainText->node_anchor->post_data) return(HTMainText->node_anchor->post_data); - else + else return (""); } PUBLIC char * HTLoadedDocumentTitle NOARGS { - if (!HTMainText) + if (!HTMainText) return (""); - if (HTMainText->node_anchor && HTMainText->node_anchor->title) + if (HTMainText->node_anchor && HTMainText->node_anchor->title) return(HTMainText->node_anchor->title); - else + else return (""); } PUBLIC BOOLEAN HTLoadedDocumentIsHEAD NOARGS { - if (!HTMainText) + if (!HTMainText) return (FALSE); - if (HTMainText->node_anchor && HTMainText->node_anchor->isHEAD) + if (HTMainText->node_anchor && HTMainText->node_anchor->isHEAD) return(HTMainText->node_anchor->isHEAD); - else + else return (FALSE); } +PUBLIC char * HTLoadedDocumentCharset NOARGS +{ + if (!HTMainText) + return (NULL); + + if (HTMainText->node_anchor && HTMainText->node_anchor->charset) + return(HTMainText->node_anchor->charset); + else + return (NULL); +} + +PUBLIC void HText_setNodeAnchorBookmark ARGS1( + CONST char *, bookmark) +{ + if (!HTMainText) + return; + + if (HTMainText->node_anchor) + HTAnchor_setBookmark(HTMainText->node_anchor, bookmark); +} + +PUBLIC char * HTLoadedDocumentBookmark NOARGS +{ + if (!HTMainText) + return (NULL); + + if (HTMainText->node_anchor && HTMainText->node_anchor->bookmark) + return(HTMainText->node_anchor->bookmark); + else + return (NULL); +} + PUBLIC int HText_LastLineSize ARGS1(HText *,text) { if (!text || !text->last_line || !text->last_line->size) @@ -2921,6 +3010,7 @@ PRIVATE int HTFormMethod; PRIVATE char * HTFormAction = NULL; PRIVATE char * HTFormEnctype = NULL; PRIVATE char * HTFormTitle = NULL; +PRIVATE BOOLEAN HTFormDisabled = FALSE; PUBLIC void HText_beginForm ARGS4( char *, action, @@ -2931,7 +3021,11 @@ PUBLIC void HText_beginForm ARGS4( HTFormMethod = URL_GET_METHOD; HTFormNumber++; HTFormFields = 0; + HTFormDisabled = FALSE; + /* + * Check the ACTION. - FM + */ if (action != NULL) { if (!strncmp(action, "mailto:", 7)) { HTFormMethod = URL_MAIL_METHOD; @@ -2941,15 +3035,28 @@ PUBLIC void HText_beginForm ARGS4( else StrAllocCopy(HTFormAction, HTLoadedDocumentURL()); - if (method != NULL) - if (!strcasecomp(method,"post") && HTFormMethod != URL_MAIL_METHOD) - HTFormMethod = URL_POST_METHOD; + /* + * Check the METHOD. - FM + */ + if (method != NULL && HTFormMethod != URL_MAIL_METHOD) + if (!strcasecomp(method,"post") || !strcasecomp(method,"pget")) + HTFormMethod = URL_POST_METHOD; - if ((enctype != NULL) && *enctype) + /* + * Check the ENCTYPE. - FM + */ + if ((enctype != NULL) && *enctype) { StrAllocCopy(HTFormEnctype, enctype); - else + if (HTFormMethod != URL_MAIL_METHOD && + !strncasecomp(enctype, "multipart/form-data", 19)) + HTFormMethod = URL_POST_METHOD; + } else { FREE(HTFormEnctype); + } + /* + * Check the TITLE. - FM + */ if ((title != NULL) && *title) StrAllocCopy(HTFormTitle, title); else @@ -2992,6 +3099,8 @@ PUBLIC void HText_endForm ARGS1(HText *,text) StrAllocCopy(a->input_field->submit_title, HTFormTitle); a->input_field->submit_method = HTFormMethod; a->input_field->type = F_TEXT_SUBMIT_TYPE; + if (HTFormDisabled) + a->input_field->disabled = TRUE; break; } if (a == text->last_anchor) @@ -3006,6 +3115,7 @@ PUBLIC void HText_endForm ARGS1(HText *,text) FREE(HTFormEnctype); FREE(HTFormTitle); HTFormFields = 0; + HTFormDisabled = FALSE; } PUBLIC void HText_beginSelect ARGS3(char *,name, BOOLEAN,multiple, char *, size) @@ -3087,7 +3197,15 @@ PUBLIC char * HText_setLastOptionValue ARGS5(HText *, text, char *, value, * Put the text on the screen as well. */ HText_appendText(text, cp); - + + } else if (LYSelectPopups == FALSE) { + StrAllocCopy(text->last_anchor->input_field->value, + (submit_value ? submit_value : cp)); + /* + * Put the text on the screen as well. + */ + HText_appendText(text, cp); + } else { /* * Create a linked list of option values. @@ -3106,7 +3224,7 @@ PUBLIC char * HText_setLastOptionValue ARGS5(HText *, text, char *, value, * No option items yet. */ new_ptr = text->last_anchor->input_field->select_list = - (OptionType *) calloc(1,sizeof(OptionType)); + (OptionType *) calloc(1, sizeof(OptionType)); if (new_ptr == NULL) outofmem(__FILE__, "HText_setLastOptionValue"); @@ -3119,7 +3237,7 @@ PUBLIC char * HText_setLastOptionValue ARGS5(HText *, text, char *, value, number++; /* add one more */ op_ptr->next = new_ptr = - (OptionType *) calloc(1,sizeof(OptionType)); + (OptionType *) calloc(1, sizeof(OptionType)); if (new_ptr == NULL) outofmem(__FILE__, "HText_setLastOptionValue"); } @@ -3248,11 +3366,17 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I) /* - * If this is a radio button, and it's the first with this name, - * make sure it's checked by default. Otherwise, if it's checked, - * uncheck the default or any preceding radio button with this name - * that was checked. - FM + * If this is a radio button, or an OPTION we're converting + * to a radio button, and it's the first with this name, make + * sure it's checked by default. Otherwise, if it's checked, + * uncheck the default or any preceding radio button with this + * name that was checked. - FM */ + if (I->type != NULL && !strcmp(I->type,"OPTION") && + HTCurSelectGroupType == F_RADIO_TYPE && LYSelectPopups == FALSE) { + I->type = "RADIO"; + I->name = HTCurSelectGroup; + } if (I->name && I->type && !strcasecomp(I->type, "radio")) { if (!text->last_anchor) { I->checked = TRUE; @@ -3299,7 +3423,7 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I) f->select_list = 0; f->number = HTFormNumber; - f->disabled = I->disabled; + f->disabled = (HTFormDisabled ? TRUE : I->disabled); f->no_cache = NO; HTFormFields++; @@ -3312,22 +3436,12 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I) f->no_cache = TRUE; /* - * Disable if the ENCTYPE is multipart/form-data - * until we add code to handle it. - FM - */ - if (HTFormEnctype) { - if (!strcmp(HTFormEnctype, "multipart/form-data")) { - f->disabled = YES; - } - } - - /* * Set up VALUE. */ if (I->value) StrAllocCopy(IValue, I->value); if (IValue && HTCJK != NOCJK) { - if ((tmp = (unsigned char *)calloc(1, strlen(IValue)+1))) { + if ((tmp = (unsigned char *)calloc(1, (strlen(IValue) + 1)))) { if (kanji_code == EUC) { TO_EUC((unsigned char *)IValue, tmp); } else if (kanji_code == SJIS) { @@ -3346,6 +3460,7 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I) /* * Special case of OPTION. + * Is handled above if radio type and LYSelectPopups is FALSE. */ /* set the values and let the parsing below do the work */ if (I->type != NULL && !strcmp(I->type,"OPTION")) { @@ -3365,7 +3480,6 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I) if (HTCurSelectGroupSize != NULL) { f->size_l = atoi(HTCurSelectGroupSize); FREE(HTCurSelectGroupSize); - HTCurSelectGroupSize = NULL; } } @@ -3518,10 +3632,10 @@ PUBLIC int HText_beginInput ARGS2(HText *,text, InputFieldData *,I) StrAllocCopy(f->submit_title, HTFormTitle); f->submit_method = HTFormMethod; - } else if (f->type == F_RADIO_TYPE || f->type == F_CHECKBOX_TYPE ) { + } else if (f->type == F_RADIO_TYPE || f->type == F_CHECKBOX_TYPE) { f->size=3; if (IValue == NULL) - StrAllocCopy(f->value, "on"); + StrAllocCopy(f->value, (f->type == F_CHECKBOX_TYPE ? "on" : "")); } FREE(IValue); @@ -3578,9 +3692,20 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, char *previous_blanks = NULL; BOOLEAN PlainText = FALSE; BOOLEAN SemiColon = FALSE; + char *Boundary = NULL; + char *MultipartContentType = NULL; if (submit_item->submit_action) { /* + * If we're mailing, make sure it's a mailto ACTION. - FM + */ + if ((submit_item->submit_method == URL_MAIL_METHOD) && + strncmp(submit_item->submit_action, "mailto:", 7)) { + HTAlert(BAD_FORM_MAILTO); + return; + } + + /* * Set length plus breathing room. */ len = strlen(submit_item->submit_action) + 2048; @@ -3589,6 +3714,36 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, } /* + * Check the ENCTYPE and set up the appropriate variables. - FM + */ + if (submit_item->submit_enctype && + !strncasecomp(submit_item->submit_enctype, "text/plain", 10)) { + /* + * Do not hex escape, and use physical newlines + * to separate name=value pairs. - FM + */ + PlainText = TRUE; + } else if (submit_item->submit_enctype && + !strncasecomp(submit_item->submit_enctype, + "application/sgml-form-urlencoded", 32)) { + /* + * Use semicolons instead of ampersands as the + * separators for name=value pairs. - FM + */ + SemiColon = TRUE; + } else if (submit_item->submit_enctype && + !strncasecomp(submit_item->submit_enctype, + "multipart/form-data", 19)) { + /* + * Use the multipart MIME format. We should generate + * a boundary string which we are sure doesn't occur + * in the content, but for now we'll just assume that + * this string doesn't. - FM + */ + Boundary = "xnyLAaB03X"; + } + + /* * Go through list of anchors and get size first. */ while (1) { @@ -3597,15 +3752,14 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, form_ptr = anchor_ptr->input_field; - len += strlen(form_ptr->name)+10; + len += (strlen(form_ptr->name) + (Boundary ? 100 : 10)); /* * Calculate by the option submit value if present. */ - if (form_ptr->cp_submit_value != NULL) { - len += strlen(form_ptr->cp_submit_value) + 10; - } - else { - len += strlen(form_ptr->value)+10; + if (form_ptr->cp_submit_value != NULL) { + len += (strlen(form_ptr->cp_submit_value) + 10); + } else { + len += (strlen(form_ptr->value) + 10); } len += 32; /* plus and ampersand + safty net */ @@ -3623,28 +3777,11 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, /* * Get query ready. */ - query = (char *)calloc (sizeof(char), len); + query = (char *)calloc(1, len); if (query == NULL) outofmem(__FILE__, "HText_SubmitForm"); - if (submit_item->submit_enctype && - !strncasecomp(submit_item->submit_enctype, "text/plain", 10)) { - /* - * Do not hex escape, and use physical newlines - * to separate name=value pairs. - FM - */ - PlainText = TRUE; - } else if (submit_item->submit_enctype && - !strncasecomp(submit_item->submit_enctype, - "application/sgml-form-urlencoded", 32)) { - /* - * Use semicolons instead of ampersands as the - * separators for name=value pairs. - FM - */ - SemiColon = TRUE; - } - - if (submit_item->submit_method == URL_GET_METHOD) { + if (submit_item->submit_method == URL_GET_METHOD && Boundary == NULL) { strcpy (query, submit_item->submit_action); /* * Method is GET. Clip out any anchor in the current URL. @@ -3660,44 +3797,59 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, strcat(query,"?"); } else { query[0] = '\0'; - if (submit_item->submit_method != URL_MAIL_METHOD) { - /* - * We are submitting POST content to a server, - * so load the post_content_type element. - FM - */ - if (SemiColon == TRUE) { - StrAllocCopy(doc->post_content_type, - "application/sgml-form-urlencoded"); - } else if (PlainText == TRUE) { - StrAllocCopy(doc->post_content_type, - "text/plain"); - } else { - StrAllocCopy(doc->post_content_type, - "application/x-www-form-urlencoded"); - } + /* + * We are submitting POST content to a server, + * so load the post_content_type element. - FM + */ + if (SemiColon == TRUE) { + StrAllocCopy(doc->post_content_type, + "application/sgml-form-urlencoded"); + } else if (PlainText == TRUE) { + StrAllocCopy(doc->post_content_type, + "text/plain"); + } else if (Boundary != NULL) { + StrAllocCopy(doc->post_content_type, + "multipart/form-data; boundary="); + StrAllocCat(doc->post_content_type, Boundary); + } else { + StrAllocCopy(doc->post_content_type, + "application/x-www-form-urlencoded"); + } - /* - * Append the exended charset info if known, and it is - * not ISO-8859-1 or US-ASCII. We'll assume the user - * has the matching character set selected, or a - * download offer would have been forced and we would - * not be processing the form here. We don't yet want - * to do this unless the server indicated the charset - * in the original transmission, because otherwise it - * might be an old server and CGI script which will - * not parse out the extended charset info, and reject - * the POST Content-Type as invalid. - FM - */ - if (HTMainText->node_anchor->charset != NULL && - *HTMainText->node_anchor->charset != '\0') { - if (strcasecomp(HTMainText->node_anchor->charset, - "iso-8859-1") && - strcasecomp(HTMainText->node_anchor->charset, - "us-ascii")) { - StrAllocCat(doc->post_content_type, ";charset="); - StrAllocCat(doc->post_content_type, - HTMainText->node_anchor->charset); - } + /* + * Append the exended charset info if known, and it is not + * ISO-8859-1 or US-ASCII. We'll assume the user has the + * matching character set selected, or a download offer would + * have been forced and we would not be processing the form + * here. We don't yet want to do this unless the server + * indicated the charset in the original transmission, because + * otherwise it might be an old server and CGI script which + * will not parse out the extended charset info, and reject + * the POST Content-Type as invalid. If the ENCTYPE is + * multipart/form-data and the charset is known, set up a + * Content-Type string for the text fields and append the + * charset even if it is ISO-8859-1 or US-ASCII, but don't + * append it to the post_content_type header. Note that we do + * not yet have a way to vary the charset among multipart form + * fields, so this code assumes it is the same for all of the + * text fields. - FM + */ + if (HTMainText->node_anchor->charset != NULL && + *HTMainText->node_anchor->charset != '\0') { + if (Boundary == NULL && + strcasecomp(HTMainText->node_anchor->charset, "iso-8859-1") && + strcasecomp(HTMainText->node_anchor->charset, "us-ascii")) { + StrAllocCat(doc->post_content_type, "; charset="); + StrAllocCat(doc->post_content_type, + HTMainText->node_anchor->charset); + } else if (Boundary != NULL) { + MultipartContentType = (char *)calloc(1, + (40 + strlen(HTMainText->node_anchor->charset))); + if (query == NULL) + outofmem(__FILE__, "HText_SubmitForm"); + sprintf(MultipartContentType, + "\r\nContent-Type: text/plain; charset=%s", + HTMainText->node_anchor->charset); } } } @@ -3735,12 +3887,19 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, (form_ptr->value && *form_ptr->value != '\0' && !strcmp(form_ptr->value, link_value)))) { if (first_one) { + if (Boundary) { + sprintf(&query[strlen(query)], + "--%s\r\n", Boundary); + } first_one=FALSE; } else { if (PlainText) { strcat(query, "\n"); } else if (SemiColon) { strcat(query, ";"); + } else if (Boundary) { + sprintf(&query[strlen(query)], + "\r\n--%s\r\n", Boundary); } else { strcat(query, "&"); } @@ -3749,6 +3908,14 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, if (PlainText) { StrAllocCopy(escaped1, (form_ptr->name ? form_ptr->name : "")); + } else if (Boundary) { + StrAllocCopy(escaped1, + "Content-Disposition: form-data; name="); + StrAllocCat(escaped1, (form_ptr->name ? + form_ptr->name : "")); + if (MultipartContentType) + StrAllocCat(escaped1, MultipartContentType); + StrAllocCat(escaped1, "\r\n\r\n"); } else { escaped1 = HTEscape(form_ptr->name,URL_XALPHAS); } @@ -3772,7 +3939,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, form_ptr->cp_submit_value[i] = 173; } } - if (PlainText) { + if (PlainText || Boundary) { StrAllocCopy(escaped2, (form_ptr->cp_submit_value ? form_ptr->cp_submit_value : "")); @@ -3796,7 +3963,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, form_ptr->value[i] = 173; } } - if (PlainText) { + if (PlainText || Boundary) { StrAllocCopy(escaped2, (form_ptr->value ? form_ptr->value : "")); } else { @@ -3805,34 +3972,46 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, } } - if (!strcmp(form_ptr->value, "[IMAGE]-Submit")) + if (!strcmp(form_ptr->value, "[IMAGE]-Submit")) { /* * It's a clickable image submit button. * Fake a 0,0 coordinate pair, which * typically returns the image's default. - FM */ - sprintf(&query[strlen(query)], - "%s.x=0%s%s.y=0%s", - escaped1, - (PlainText ? - "\n" : (SemiColon ? - ";" : "&")), - escaped1, - ((PlainText && *escaped1) ? - "\n" : "")); - else + if (Boundary) { + escaped1[(strlen(escaped1) - 4)] = '\0'; + sprintf(&query[strlen(query)], + "%s.x\r\n\r\n0\r\n--%s\r\n%s.y\r\n\r\n0", + escaped1, + Boundary, + escaped1); + } else { + sprintf(&query[strlen(query)], + "%s.x=0%s%s.y=0%s", + escaped1, + (PlainText ? + "\n" : (SemiColon ? + ";" : "&")), + escaped1, + ((PlainText && *escaped1) ? + "\n" : "")); + } + } else { /* * It's a standard submit button. * Use the name=value pair. = FM */ sprintf(&query[strlen(query)], - "%s=%s%s%s", + "%s%s%s%s%s", escaped1, + (Boundary ? + "" : "="), (PlainText ? "\n" : ""), escaped2, ((PlainText && *escaped2) ? "\n" : "")); + } FREE(escaped1); FREE(escaped2); } @@ -3843,12 +4022,19 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, /* only add if selected */ if (form_ptr->num_value) { if (first_one) { + if (Boundary) { + sprintf(&query[strlen(query)], + "--%s\r\n", Boundary); + } first_one=FALSE; } else { if (PlainText) { strcat(query, "\n"); } else if (SemiColon) { strcat(query, ";"); + } else if (Boundary) { + sprintf(&query[strlen(query)], + "\r\n--%s\r\n", Boundary); } else { strcat(query, "&"); } @@ -3857,6 +4043,15 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, if (PlainText) { StrAllocCopy(escaped1, (form_ptr->name ? form_ptr->name : "")); + } else if (Boundary) { + StrAllocCopy(escaped1, + "Content-Disposition: form-data; name="); + StrAllocCat(escaped1, + (form_ptr->name ? + form_ptr->name : "")); + if (MultipartContentType) + StrAllocCat(escaped1, MultipartContentType); + StrAllocCat(escaped1, "\r\n\r\n"); } else { escaped1 = HTEscape(form_ptr->name, URL_XALPHAS); } @@ -3879,7 +4074,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, form_ptr->cp_submit_value[i] = 173; } } - if (PlainText) { + if (PlainText || Boundary) { StrAllocCopy(escaped2, (form_ptr->cp_submit_value ? form_ptr->cp_submit_value : "")); @@ -3904,7 +4099,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, } } - if (PlainText) { + if (PlainText || Boundary) { StrAllocCopy(escaped2, (form_ptr->value ? form_ptr->value : "")); } else { @@ -3914,8 +4109,10 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, } sprintf(&query[strlen(query)], - "%s=%s%s%s", + "%s%s%s%s%s", escaped1, + (Boundary ? + "" : "="), (PlainText ? "\n" : ""), escaped2, @@ -3939,7 +4136,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, form_ptr->value[i] = 173; } } - if (PlainText) { + if (PlainText || Boundary) { StrAllocCopy(escaped2, (form_ptr->value ? form_ptr->value : "")); } else { @@ -3955,12 +4152,19 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, */ FREE(previous_blanks); if (first_one) { + if (Boundary) { + sprintf(&query[strlen(query)], + "--%s\r\n", Boundary); + } first_one=FALSE; } else { if (PlainText) { strcat(query, "\n"); } else if (SemiColon) { strcat(query, ";"); + } else if (Boundary) { + sprintf(&query[strlen(query)], + "\r\n--%s\r\n", Boundary); } else { strcat(query, "&"); } @@ -3968,12 +4172,22 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, if (PlainText) { StrAllocCopy(escaped1, (form_ptr->name ? form_ptr->name : "")); + } else if (Boundary) { + StrAllocCopy(escaped1, + "Content-Disposition: form-data; name="); + StrAllocCat(escaped1, (form_ptr->name ? + form_ptr->name : "")); + if (MultipartContentType) + StrAllocCat(escaped1, MultipartContentType); + StrAllocCat(escaped1, "\r\n\r\n"); } else { escaped1 = HTEscape(form_ptr->name, URL_XALPHAS); } sprintf(&query[strlen(query)], - "%s=%s%s%s", + "%s%s%s%s%s", escaped1, + (Boundary ? + "" : "="), (PlainText ? "\n" : ""), escaped2, @@ -3994,6 +4208,9 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, if (PlainText) { sprintf(&query[strlen(query)], "%s\n", escaped2); + } else if (Boundary) { + sprintf(&query[strlen(query)], "%s\r\n", + escaped2); } else { sprintf(&query[strlen(query)], "%%0a%s", escaped2); @@ -4001,6 +4218,8 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, } else { if (PlainText) { StrAllocCat(previous_blanks, "\n"); + } else if (Boundary) { + StrAllocCat(previous_blanks, "\r\n"); } else { StrAllocCat(previous_blanks, "%0a"); } @@ -4014,12 +4233,19 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, case F_OPTION_LIST_TYPE: case F_HIDDEN_TYPE: if (first_one) { + if (Boundary) { + sprintf(&query[strlen(query)], + "--%s\r\n", Boundary); + } first_one=FALSE; } else { if (PlainText) { strcat(query, "\n"); } else if (SemiColon) { strcat(query, ";"); + } else if (Boundary) { + sprintf(&query[strlen(query)], + "\r\n--%s\r\n", Boundary); } else { strcat(query, "&"); } @@ -4028,6 +4254,14 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, if (PlainText) { StrAllocCopy(escaped1, (form_ptr->name ? form_ptr->name : "")); + } else if (Boundary) { + StrAllocCopy(escaped1, + "Content-Disposition: form-data; name="); + StrAllocCat(escaped1, (form_ptr->name ? + form_ptr->name : "")); + if (MultipartContentType) + StrAllocCat(escaped1, MultipartContentType); + StrAllocCat(escaped1, "\r\n\r\n"); } else { escaped1 = HTEscape(form_ptr->name, URL_XALPHAS); } @@ -4051,7 +4285,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, form_ptr->cp_submit_value[i] = 173; } } - if (PlainText) { + if (PlainText || Boundary) { StrAllocCopy(escaped2, (form_ptr->cp_submit_value ? form_ptr->cp_submit_value : "")); @@ -4075,7 +4309,7 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, form_ptr->value[i] = 173; } } - if (PlainText) { + if (PlainText || Boundary) { StrAllocCopy(escaped2, (form_ptr->value ? form_ptr->value : "")); } else { @@ -4085,8 +4319,10 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, } sprintf(&query[strlen(query)], - "%s=%s%s%s", + "%s%s%s%s%s", escaped1, + (Boundary ? + "" : "="), (PlainText ? "\n" : ""), escaped2, @@ -4106,15 +4342,13 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, anchor_ptr = anchor_ptr->next; } + if (Boundary) { + sprintf(&query[strlen(query)], "\r\n--%s--\r\n", Boundary); + } FREE(previous_blanks); if (submit_item->submit_method == URL_MAIL_METHOD) { - if (strncmp(submit_item->submit_action, "mailto:", 7)) { - HTAlert(BAD_FORM_MAILTO); - FREE(query); - return; - } - _user_message("submitting %s", submit_item->submit_action); + _user_message("Submitting %s", submit_item->submit_action); if (TRACE) { fprintf(stderr, "\nGridText - mailto_address: %s\n", (submit_item->submit_action+7)); @@ -4133,14 +4367,16 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, (submit_item->submit_title) : (HText_getTitle() ? HText_getTitle() : "")), - query); + query, + doc->post_content_type); FREE(query); + FREE(doc->post_content_type); return; } else { _statusline(SUBMITTING_FORM); } - if (submit_item->submit_method == URL_POST_METHOD) { + if (submit_item->submit_method == URL_POST_METHOD || Boundary) { StrAllocCopy(doc->post_data, query); if (TRACE) fprintf(stderr,"GridText - post_data: %s\n",doc->post_data); @@ -4156,14 +4392,42 @@ PUBLIC void HText_SubmitForm ARGS4(FormInfo *,submit_item, document *,doc, } } +PUBLIC void HText_DisableCurrentForm NOARGS +{ + TextAnchor * anchor_ptr = HTMainText->first_anchor; + + HTFormDisabled = TRUE; + + /* + * Go through list of anchors and set the disabled flag. + */ + while (1) { + if (anchor_ptr->link_type == INPUT_ANCHOR && + anchor_ptr->input_field->number == HTFormNumber) { + + anchor_ptr->input_field->disabled = TRUE; + } + + if (anchor_ptr == HTMainText->last_anchor) + break; + + + anchor_ptr = anchor_ptr->next; + } + + return; +} + PUBLIC void HText_ResetForm ARGS1(FormInfo *,form) { TextAnchor * anchor_ptr = HTMainText->first_anchor; _statusline(RESETTING_FORM); - /* go through list of anchors and reset values */ - while (1) { + /* + * Go through list of anchors and reset values. + */ + while (1) { if (anchor_ptr->link_type == INPUT_ANCHOR) { if (anchor_ptr->input_field->number == form->number) { @@ -4198,9 +4462,7 @@ PUBLIC void HText_ResetForm ARGS1(FormInfo *,form) anchor_ptr = anchor_ptr->next; - } - - + } } PUBLIC void HText_activateRadioButton ARGS1(FormInfo *,form) diff --git a/src/GridText.h b/src/GridText.h index c20ae2ec..0ed5cad0 100644 --- a/src/GridText.h +++ b/src/GridText.h @@ -64,7 +64,12 @@ extern int HText_sourceAnchors PARAMS((HText * text)); extern void HText_setStale PARAMS((HText * text)); extern void HText_refresh PARAMS((HText * text)); extern char * HText_getTitle NOPARAMS; +extern char * HText_getSugFname NOPARAMS; +extern char * HText_getLastModified NOPARAMS; +extern char * HText_getDate NOPARAMS; +extern char * HText_getServer NOPARAMS; extern char * HText_getOwner NOPARAMS; +extern void HText_setMainTextOwner PARAMS((CONST char * owner)); extern char * HText_getRevTitle NOPARAMS; extern void print_wwwfile_to_fd PARAMS((FILE * fp, int is_reply)); extern BOOLEAN HTFindPoundSelector PARAMS((char *selector)); @@ -78,6 +83,9 @@ extern char * HTLoadedDocumentURL NOPARAMS; extern char * HTLoadedDocumentPost_data NOPARAMS; extern char * HTLoadedDocumentTitle NOPARAMS; extern BOOLEAN HTLoadedDocumentIsHEAD NOPARAMS; +extern char * HTLoadedDocumentCharset NOPARAMS; +extern void HText_setNodeAnchorBookmark PARAMS((CONST char *bookmark)); +extern char * HTLoadedDocumentBookmark NOPARAMS; extern int HText_LastLineSize PARAMS((HText *me)); extern int HText_PreviousLineSize PARAMS((HText *me)); extern void HText_NegateLineOne PARAMS((HText *text)); @@ -99,6 +107,7 @@ extern char * HText_setLastOptionValue PARAMS((HText *text, char *value, extern int HText_beginInput PARAMS((HText *text, InputFieldData *I)); extern void HText_SubmitForm PARAMS((FormInfo *submit_item, document *doc, char *link_name, char *link_value)); +extern void HText_DisableCurrentForm NOPARAMS; extern void HText_ResetForm PARAMS((FormInfo *form)); extern void HText_activateRadioButton PARAMS((FormInfo *form)); diff --git a/src/HTAlert.c b/src/HTAlert.c index 79a4a7b0..5a3ddc1c 100644 --- a/src/HTAlert.c +++ b/src/HTAlert.c @@ -13,11 +13,12 @@ #include "HTUtils.h" #include "tcp.h" #include "HTAlert.h" +#include "LYGlobalDefs.h" +#include "LYCurses.h" #include "LYStrings.h" #include "LYUtils.h" #include "LYSignal.h" #include "GridText.h" -#include "LYGlobalDefs.h" #include "LYLeaks.h" @@ -214,3 +215,109 @@ PUBLIC void HTPromptUsernameAndPassword ARGS3(CONST char *, Msg, } } + +#define SERVER_ASKED_FOR_REDIRECTION \ + "Server asked for redirection of POST content to" +#define PROCEED_GET_CANCEL "P)roceed, use G)ET or C)ancel " +#define ADVANCED_POST_REDIRECT \ + "Redirection of POST content. P)roceed, see U)RL, use G)ET or C)ancel" +#define LOCATION_HEADER "Location: " + +/* Confirm redirection of POST HTConfirmPostRedirect() +** +** On entry, +** redirecting_url is the Location. +** +** On exit, +** Returns 0 on cancel, +** 1 for redirect of POST with content, +** 303 for redirect as GET without content +*/ +PUBLIC int HTConfirmPostRedirect ARGS1( + CONST char *, redirecting_url) +{ + char *show_POST_url = NULL; + char url[256]; + int on_screen = 0; /* 0 - show menu + * 1 - show url + * 2 - menu is already on screen */ + + if (dump_output_immediately) + /* + * Treat as 303 (GET without content) if not interactive. + */ + return 303; + + if (user_mode == NOVICE_MODE) { + on_screen = 2; + move(LYlines-2, 0); + addstr(SERVER_ASKED_FOR_REDIRECTION); + clrtoeol(); + move(LYlines-1, 0); + sprintf(url, "URL: %.*s", + (LYcols < 250 ? LYcols-6 : 250), redirecting_url); + addstr(url); + clrtoeol(); + _statusline(PROCEED_GET_CANCEL); + } else { + StrAllocCopy(show_POST_url, LOCATION_HEADER); + StrAllocCat(show_POST_url, redirecting_url); + } + while (1) { + int c; + + switch (on_screen) { + case 0: + _statusline(ADVANCED_POST_REDIRECT); + break; + case 1: + _statusline(show_POST_url); + } + c = LYgetch(); + switch (TOUPPER(c)) { + case 'P': + /* + * Proceed with 301 or 302 redirect of POST + * (we check only for 0 and 303 in HTTP.c). + */ + FREE(show_POST_url); + return 1; + + case 7: + case 'C': + /* + * Cancel request. + */ + FREE(show_POST_url); + return 0; + + case 'G': + /* + * Treat as 303 (GET without content). + */ + FREE(show_POST_url); + return 303; + + case 'U': + /* + * Show URL for intermediate or advanced mode. + */ + if (user_mode != NOVICE_MODE) + if (on_screen == 1) + on_screen = 0; + else + on_screen = 1; + break; + + default: + /* + * Get another character. + */ + if (on_screen == 1) + on_screen = 0; + else + on_screen = 2; + } + } +} + diff --git a/src/HTAlert.h b/src/HTAlert.h index 8ce0be53..dc470cfd 100644 --- a/src/HTAlert.h +++ b/src/HTAlert.h @@ -81,6 +81,20 @@ extern void HTPromptUsernameAndPassword PARAMS(( char ** username, char ** password)); + +/* Confirm redirection of POST HTConfirmPostRedirect() +** +** On entry, +** redirecting_url is the Location. +** +** On exit, +** Returns 0 on cancel, +** 1 for redirect of POST with content, +** 303 for redirect as GET without content +*/ +extern int HTConfirmPostRedirect PARAMS(( + CONST char * redirecting_url)); + /* */ diff --git a/src/HTFWriter.c b/src/HTFWriter.c index a3b46f0c..e9f7d1ee 100644 --- a/src/HTFWriter.c +++ b/src/HTFWriter.c @@ -50,6 +50,11 @@ PUBLIC unsigned long LYVMS_FixedLengthRecords PARAMS((char *filename)); #endif /* USE_COMMAND_FILE */ #endif /* VMS */ +PUBLIC HTStream* HTSaveToFile PARAMS(( + HTPresentation * pres, + HTParentAnchor * anchor, + HTStream * sink)); + #define FREE(x) if (x) {free(x); x = NULL;} @@ -201,13 +206,23 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me) StrAllocCat(addr, path); #endif /* VMS */ StrAllocCopy(me->anchor->FileCache, path); + FREE(path); FREE(me->anchor->content_encoding); status = HTLoadFile(addr, me->anchor, me->pres->rep_out, me->sink); + if (dump_output_immediately && + me->pres->rep_out == HTAtom_for("www/present")) { + FREE(addr); + remove(me->anchor->FileCache); + FREE(me->anchor->FileCache); + FREE(me->remove_command); + FREE(me->end_command); + FREE(me); + return; + } } - FREE(path); FREE(addr); } @@ -251,9 +266,10 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me) FREE(me->end_command); } - FREE(me); - if (dump_output_immediately) { + if (me->anchor->FileCache) + remove(me->anchor->FileCache); + FREE(me); (void) signal(SIGHUP, SIG_DFL); (void) signal(SIGTERM, SIG_DFL); #ifndef VMS @@ -265,6 +281,9 @@ PRIVATE void HTFWriter_free ARGS1(HTStream *, me) #endif /* SIGTSTP */ exit(0); } + + FREE(me); + return; } /* Abort writing @@ -368,6 +387,10 @@ PUBLIC HTStream* HTSaveAndExecute ARGS3( #if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) if (pres->quality == 999.0) { /* exec link */ + if (dump_output_immediately) { + LYCancelledFetch = TRUE; + return(NULL); + } if (no_exec) { _statusline(EXECUTION_DISABLED); sleep(AlertSecs); @@ -390,6 +413,10 @@ PUBLIC HTStream* HTSaveAndExecute ARGS3( } #endif /* EXEC_LINKS || EXEC_SCRIPTS */ + if (dump_output_immediately) { + return(HTSaveToFile(pres, anchor, sink)); + } + me = (HTStream*)calloc(sizeof(*me),1); if (me == NULL) outofmem(__FILE__, "HTSaveAndExecute"); @@ -681,6 +708,17 @@ PUBLIC HTStream* HTSaveToFile ARGS3( _statusline(RETRIEVING_FILE); StrAllocCopy(anchor->FileCache, fnam); + if (!strncasecomp(pres->rep->name, "text/html", 9)) { + /* + * Add the document's URL as a BASE tag at the top of the file, + * so that any partial or relative URLs within it will be resolved + * relative to that if no BASE tag is present and replaces it. + * Note that the markup will be technically invalid if a DOCTYPE + * declaration, or HTML or HEAD tags, are present, and thus the + * file may need editing for perfection. - FM + */ + fprintf(ret_obj->fp, "<BASE HREF=\"%s\">\n\n", anchor->address); + } return ret_obj; } diff --git a/src/HTInit.c b/src/HTInit.c index 0038e605..63933236 100644 --- a/src/HTInit.c +++ b/src/HTInit.c @@ -141,6 +141,12 @@ PUBLIC void HTFormatInit NOARGS /* * Now add our basic conversions. */ + HTSetConversion("text/x-sgml", + "www/source", HTPlainPresent, 1.0, 0.0, 0.0, 0); + HTSetConversion("text/x-sgml", + "www/present", HTMLPresent, 1.0, 0.0, 0.0, 0); + HTSetConversion("text/sgml", "www/source", HTPlainPresent, 1.0, 0.0, 0.0, 0); + HTSetConversion("text/sgml", "www/present", HTMLPresent, 1.0, 0.0, 0.0, 0); HTSetConversion("text/plain","www/present", HTPlainPresent, 1.0, 0.0, 0.0, 0); HTSetConversion("text/html", "www/source", HTPlainPresent, 1.0, 0.0, 0.0, 0); HTSetConversion("text/html", "text/x-c", HTMLToC, 0.5, 0.0, 0.0, 0); diff --git a/src/HTML.c b/src/HTML.c index 885a5596..e96ab89d 100644 --- a/src/HTML.c +++ b/src/HTML.c @@ -1,10 +1,10 @@ /* Structured stream to Rich hypertext converter ** ============================================ ** -** This generates of a hypertext object. It converts from the -** structured stream interface fro HTMl events into the style- -** oriented iunterface of the HText.h interface. This module is -** only used in clients and shouldnot be linked into servers. +** This generates a hypertext object. It converts from the +** structured stream interface of HTML events into the style- +** oriented interface of the HText.h interface. This module is +** only used in clients and should not be linked into servers. ** ** Override this module if making a new GUI browser. ** @@ -13,43 +13,31 @@ */ #include "HTUtils.h" #include "tcp.h" - #include "HTML.h" - -/* #define CAREFUL Check nesting here not really necessary */ - -/*#include <ctype.h> included by HTUtils.h -- FM */ -/*#include <stdio.h> included by HTUtils.h -- FM */ - #include "HTCJK.h" #include "HTAtom.h" #include "HTChunk.h" #include "HText.h" #include "HTStyle.h" - #include "HTAlert.h" #include "HTMLGen.h" #include "HTParse.h" - #include "HTNestedList.h" #include "HTForms.h" - #include "GridText.h" - #include "HTFont.h" - -#ifdef VMS -#include "LYCurses.h" -#include "HTVMSUtils.h" -#endif /* VMS */ - - #include "LYGlobalDefs.h" #include "LYSignal.h" #include "LYUtils.h" #include "LYCharSets.h" #include "LYCharUtils.h" #include "LYMap.h" +#include "LYBookmark.h" + +#ifdef VMS +#include "LYCurses.h" +#include "HTVMSUtils.h" +#endif /* VMS */ #include "LYexit.h" #include "LYLeaks.h" @@ -305,7 +293,7 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c) /* * Ignore all non-MAP content when just * scanning a document for MAPs. - FM - * + */ if (LYMapsOnly) return; @@ -414,8 +402,7 @@ PRIVATE void HTML_put_character ARGS2(HTStructured *, me, char, c) B_inPRE = TRUE; } else if (!strcmp(me->sp->style->name,"Listing") || - !strcmp(me->sp->style->name,"Example") || - !strcmp(me->sp->style->name,"Style")) { + !strcmp(me->sp->style->name,"Example")) { if (c != '\r') { B_inP = TRUE; B_inLABEL = FALSE; @@ -637,8 +624,6 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR); B_inUnderline = FALSE; } - FREE(base_href); - B_inBASE = FALSE; break; case HTML_HEAD: @@ -652,8 +637,6 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR); B_inUnderline = FALSE; } - FREE(base_href); - B_inBASE = FALSE; break; case HTML_BASE: @@ -1023,9 +1006,9 @@ PRIVATE void HTML_start_element ARGS5( } B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - (id_string ? id_string : 0), /* Tag */ + id_string, /* Tag */ href, /* Addresss */ - 0); /* Type */ + (void *)0); /* Type */ if (id_string) *cp = '#'; FREE(id_string); @@ -1225,9 +1208,9 @@ PRIVATE void HTML_start_element ARGS5( */ B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ - href ? href : 0, /* Addresss */ - 0); /* Type */ + NULL, /* Tag */ + href, /* Addresss */ + (void *)0); /* Type */ { if (dest = HTAnchor_parent( HTAnchor_followMainLink((HTAnchor*)B_CurrentA) @@ -1240,8 +1223,8 @@ PRIVATE void HTML_start_element ARGS5( (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ LYToolbarName, /* Tag */ - 0, /* Addresss */ - 0))) { /* Type */ + NULL, /* Addresss */ + (void *)0))) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); HText_setToolbar(me->text); @@ -1439,9 +1422,9 @@ PRIVATE void HTML_start_element ARGS5( B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ href, /* Addresss */ - 0); /* Type */ + (void *)0); /* Type */ HTML_EnsureSingleSpace(me); if (B_inUnderline == FALSE) HText_appendCharacter(me->text,LY_UNDERLINE_START_CHAR); @@ -1478,8 +1461,8 @@ PRIVATE void HTML_start_element ARGS5( (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ LYToolbarName, /* Tag */ - 0, /* Addresss */ - 0))) { /* Type */ + NULL, /* Addresss */ + (void *)0))) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); HText_setToolbar(me->text); @@ -1938,7 +1921,7 @@ PRIVATE void HTML_start_element ARGS5( * use chevrons, but for now we'll always use double- * or single-quotes. - FM */ - if (Quote_Level == ((Quote_Level/2)*2)) + if (!(Quote_Level & 1)) HText_appendCharacter(me->text, '"'); else HText_appendCharacter(me->text, '`'); @@ -2517,13 +2500,13 @@ PRIVATE void HTML_start_element ARGS5( } B_CurrentA = HTAnchor_findChildAndLink( - me->node_anchor, /* Parent */ - (id_string ? id_string : 0), /* Tag */ - (href ? href : 0), /* Address */ + me->node_anchor, /* Parent */ + id_string, /* Tag */ + href, /* Address */ (present && present[HTML_A_TYPE] && value[HTML_A_TYPE]) ? - (HTLinkType*)HTAtom_for(value[HTML_A_TYPE]) : 0); /* Type */ + (HTLinkType*)HTAtom_for(value[HTML_A_TYPE]) : (void *)0); /* Type */ /* * Get rid of href since no longer needed. @@ -2821,17 +2804,17 @@ PRIVATE void HTML_start_element ARGS5( if (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id_string, /* Tag */ - 0, /* Addresss */ - 0)) { /* Type */ + NULL, /* Addresss */ + (void *)0)) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); } } B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ map_href, /* Addresss */ - 0); /* Type */ + (void *)0); /* Type */ if (B_CurrentA && title) { if (dest = HTAnchor_parent( HTAnchor_followMainLink((HTAnchor*)B_CurrentA) @@ -2862,8 +2845,8 @@ PRIVATE void HTML_start_element ARGS5( if (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id_string, /* Tag */ - 0, /* Addresss */ - 0)) { /* Type */ + NULL, /* Addresss */ + (void *)0)) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); } @@ -2875,17 +2858,17 @@ PRIVATE void HTML_start_element ARGS5( if (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id_string, /* Tag */ - 0, /* Addresss */ - 0)) { /* Type */ + NULL, /* Addresss */ + (void *)0)) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); } } B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ map_href, /* Addresss */ - 0); /* Type */ + (void *)0); /* Type */ if (B_CurrentA && title) { if (dest = HTAnchor_parent( HTAnchor_followMainLink((HTAnchor*)B_CurrentA) @@ -2916,8 +2899,8 @@ PRIVATE void HTML_start_element ARGS5( if (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id_string, /* Tag */ - 0, /* Addresss */ - 0)) { /* Type */ + NULL, /* Addresss */ + (void *)0)) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); } @@ -2929,9 +2912,9 @@ PRIVATE void HTML_start_element ARGS5( */ B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ - href ? href : 0, /* Addresss */ - 0); /* Type */ + NULL, /* Tag */ + href, /* Addresss */ + (void *)0); /* Type */ FREE(href); HText_beginAnchor(me->text, B_CurrentA); if (B_inBoldH == FALSE) @@ -2969,9 +2952,9 @@ PRIVATE void HTML_start_element ARGS5( } B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ map_href, /* Addresss */ - 0); /* Type */ + (void *)0); /* Type */ if (B_CurrentA && title) { if (dest = HTAnchor_parent( HTAnchor_followMainLink((HTAnchor*)B_CurrentA) @@ -3007,8 +2990,8 @@ PRIVATE void HTML_start_element ARGS5( if (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id_string, /* Tag */ - 0, /* Addresss */ - 0)) { /* Type */ + NULL, /* Addresss */ + (void *)0)) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); } @@ -3238,9 +3221,9 @@ PRIVATE void HTML_start_element ARGS5( if ((B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ href, /* Addresss */ - 0))) { /* Type */ + (void *)0))) { /* Type */ HText_beginAnchor(me->text, B_CurrentA); if (B_inBoldH == FALSE) HText_appendCharacter(me->text,LY_BOLD_START_CHAR); @@ -3415,9 +3398,9 @@ PRIVATE void HTML_start_element ARGS5( if ((B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ href, /* Addresss */ - 0))) { /* Type */ + (void *)0))) { /* Type */ if (!me->text) { UPDATE_STYLE; } else { @@ -3566,9 +3549,9 @@ PRIVATE void HTML_start_element ARGS5( if ((href && *href) && (B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ href, /* Addresss */ - 0))) { /* Type */ + (void *)0))) { /* Type */ HText_beginAnchor(me->text, B_CurrentA); if (B_inBoldH == FALSE) HText_appendCharacter(me->text,LY_BOLD_START_CHAR); @@ -3632,9 +3615,9 @@ PRIVATE void HTML_start_element ARGS5( UPDATE_STYLE; if ((B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ href, /* Addresss */ - 0))) { /* Type */ + (void *)0))) { /* Type */ HTML_put_character(me, ' '); /* space char may be ignored */ me->in_word = NO; HText_beginAnchor(me->text, B_CurrentA); @@ -3741,9 +3724,9 @@ PRIVATE void HTML_start_element ARGS5( if ((B_CurrentA = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ - 0, /* Tag */ + NULL, /* Tag */ href, /* Addresss */ - 0))) { /* Type */ + (void *)0))) { /* Type */ HText_beginAnchor(me->text, B_CurrentA); if (B_inBoldH == FALSE) HText_appendCharacter(me->text,LY_BOLD_START_CHAR); @@ -3885,9 +3868,9 @@ PRIVATE void HTML_start_element ARGS5( } if (action) { source = HTAnchor_findChildAndLink(me->node_anchor, - 0, + NULL, action, - 0); + (void *)0); if (link_dest = HTAnchor_followMainLink((HTAnchor *)source)) { /* * Memory leak fixed. @@ -4033,6 +4016,7 @@ PRIVATE void HTML_start_element ARGS5( * Not yet implemented. */ HTML_put_string(me,"[RANGE Input] (Not yet implemented.)"); + HText_DisableCurrentForm(); if (TRACE) fprintf(stderr, "HTML: Ignoring TYPE=\"range\"\n"); break; @@ -4052,6 +4036,7 @@ PRIVATE void HTML_start_element ARGS5( HText_appendCharacter(me->text, LY_UNDERLINE_END_CHAR); } + HText_DisableCurrentForm(); if (TRACE) fprintf(stderr, "HTML: Ignoring TYPE=\"file\"\n"); break; @@ -4232,8 +4217,8 @@ PRIVATE void HTML_start_element ARGS5( (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id_string, /* Tag */ - 0, /* Addresss */ - 0))) { /* Type */ + NULL, /* Addresss */ + (void *)0))) { /* Type */ if (!me->text) UPDATE_STYLE; HText_beginAnchor(me->text, B_ID_A); @@ -4309,15 +4294,27 @@ PRIVATE void HTML_start_element ARGS5( select_disabled=YES; if (present && present[HTML_SELECT_SIZE] && value[HTML_SELECT_SIZE] && *value[HTML_SELECT_SIZE]) { +#ifdef NOTDEFINED StrAllocCopy(size, value[HTML_SELECT_SIZE]); +#else + /* + * Let the size be determined by the number of OPTIONs. - FM + */ + if (TRACE) + fprintf(stderr, + "HTML: Ignoring SIZE=\"%s\" for SELECT.\n", + (char *)value[HTML_SELECT_SIZE]); +#endif /* NOTDEFINED */ } - if (B_inBoldH == TRUE && multiple == NO) { + if (B_inBoldH == TRUE && + (multiple == NO || LYSelectPopups == FALSE)) { HText_appendCharacter(me->text,LY_BOLD_END_CHAR); B_inBoldH = FALSE; B_needBoldH = TRUE; } - if (B_inUnderline == TRUE && multiple == NO) { + if (B_inUnderline == TRUE && + (multiple == NO || LYSelectPopups == FALSE)) { HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR); B_inUnderline = FALSE; } @@ -4376,12 +4373,15 @@ PRIVATE void HTML_start_element ARGS5( } /* - * If its not a multiple option list then don't - * use the checkbox method, and don't put - * anything on the screen yet. + * If its not a multiple option list and select popups + * are enabled, then don't use the checkbox/button method, + * and don't put anything on the screen yet. */ - if (first_option || HTCurSelectGroupType == F_CHECKBOX_TYPE) { - if (HTCurSelectGroupType == F_CHECKBOX_TYPE) { + if (first_option || + HTCurSelectGroupType == F_CHECKBOX_TYPE || + LYSelectPopups == FALSE) { + if (HTCurSelectGroupType == F_CHECKBOX_TYPE || + LYSelectPopups == FALSE) { /* * Start a newline before each option. */ @@ -4405,7 +4405,9 @@ PRIVATE void HTML_start_element ARGS5( I.type = "OPTION"; - if (present && present[HTML_OPTION_SELECTED]) + if ((present && present[HTML_OPTION_SELECTED]) || + (first_option && LYSelectPopups == FALSE && + HTCurSelectGroupType == F_RADIO_TYPE)) I.checked=YES; if (present && present[HTML_OPTION_VALUE] && @@ -4445,8 +4447,8 @@ PRIVATE void HTML_start_element ARGS5( if (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ value[HTML_OPTION_ID], /* Tag */ - 0, /* Addresss */ - 0)) { /* Type */ + NULL, /* Addresss */ + (void *)0)) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); I.id = (char *)value[HTML_OPTION_ID]; @@ -4455,9 +4457,8 @@ PRIVATE void HTML_start_element ARGS5( HText_beginInput(me->text, &I); - first_option = FALSE; - - if (HTCurSelectGroupType == F_CHECKBOX_TYPE) { + if (HTCurSelectGroupType == F_CHECKBOX_TYPE || + LYSelectPopups == FALSE) { /* * Put 3 underscores and one space before each option. */ @@ -4472,10 +4473,14 @@ PRIVATE void HTML_start_element ARGS5( * Get ready for the next value. */ HTChunkClear(&me->option); - if (present && present[HTML_OPTION_SELECTED]) - LastOptionChecked=YES; + if ((present && present[HTML_OPTION_SELECTED]) || + (first_option && LYSelectPopups == FALSE && + HTCurSelectGroupType == F_RADIO_TYPE)) + LastOptionChecked = TRUE; else - LastOptionChecked=NO; + LastOptionChecked = FALSE; + first_option = FALSE; + if (present && present[HTML_OPTION_VALUE] && value[HTML_OPTION_VALUE]) @@ -4596,6 +4601,9 @@ PRIVATE void HTML_end_element ARGS3( int, element_number, char **, include) { + int i; + char *temp = NULL; + #ifdef CAREFUL /* parser assumed to produce good nesting */ if (element_number != me->sp[0].tag_number) { fprintf(stderr, @@ -4604,15 +4612,23 @@ PRIVATE void HTML_end_element ARGS3( HTML_dtd.tags[me->sp->tag_number].name); /* panic */ } -#endif +#endif /* CAREFUL */ + + /* + * If we're seeking MAPs, skip everything that's + * not a MAP or AREA tag. - FM + */ if (LYMapsOnly) { if (!(element_number == HTML_MAP || element_number == HTML_AREA)) { return; } } - + + /* + * Pop state off stack. + */ if (me->sp < me->stack + MAX_NESTING+1) { - (me->sp)++; /* Pop state off stack */ + (me->sp)++; if (TRACE) fprintf(stderr, "HTML:end_element: Popped style off stack - %s\n", @@ -4623,7 +4639,9 @@ PRIVATE void HTML_end_element ARGS3( "Stack underflow error! Tried to pop off more styles than exist in stack\n"); } - /* Check for unclosed TEXTAREA */ + /* + * Check for unclosed TEXTAREA. - FM + */ if (B_inTEXTAREA && element_number != HTML_TEXTAREA) if (TRACE) { fprintf(stderr, "HTML: Missing TEXTAREA end tag\n"); @@ -4633,6 +4651,9 @@ PRIVATE void HTML_end_element ARGS3( sleep(MessageSecs); } + /* + * Handle the end tag. - FM + */ switch(element_number) { case HTML_HTML: @@ -4647,8 +4668,6 @@ PRIVATE void HTML_end_element ARGS3( HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR); B_inUnderline = FALSE; } - FREE(base_href); - B_inBASE = FALSE; if (B_inA || B_inFORM || B_inSELECT || B_inTEXTAREA) if (TRACE) fprintf(stderr, @@ -4683,6 +4702,36 @@ PRIVATE void HTML_end_element ARGS3( HTChunkTerminate(&me->title); HTAnchor_setTitle(me->node_anchor, me->title.data); HTChunkClear(&me->title); + /* + * Check if it's a bookmark file, and if so, insert the + * current description string and filepath for it. - FM + */ + if (me->node_anchor->bookmark && *me->node_anchor->bookmark) { + for (i = 0; i <= MBM_V_MAXFILES; i++) { + if (MBM_A_subbookmark[i] && + !strcmp(MBM_A_subbookmark[i], + me->node_anchor->bookmark)) { + StrAllocCat(*include, "<H2><EM>Description:</EM> "); + StrAllocCopy(temp, + ((MBM_A_subdescript[i] && + *MBM_A_subdescript[i]) ? + MBM_A_subdescript[i] : "(none)")); + LYEntify((char **)&temp, TRUE); + StrAllocCat(*include, temp); + StrAllocCat(*include, + "<BR><EM> Filepath:</EM> "); + StrAllocCopy(temp, + ((MBM_A_subbookmark[i] && + *MBM_A_subbookmark[i]) ? + MBM_A_subbookmark[i] : "(unknown)")); + LYEntify((char **)&temp, TRUE); + StrAllocCat(*include, temp); + FREE(temp); + StrAllocCat(*include, "</H2>"); + break; + } + } + } break; case HTML_STYLE: @@ -4886,7 +4935,7 @@ PRIVATE void HTML_end_element ARGS3( * use chevrons, but for now we'll always use double- * or single-quotes. - FM */ - if (Quote_Level == ((Quote_Level/2)*2)) + if (!(Quote_Level & 1)) HText_appendCharacter(me->text, '"'); else HText_appendCharacter(me->text, '\''); @@ -5508,9 +5557,10 @@ End_Object: LastOptionChecked = FALSE; - if (HTCurSelectGroupType == F_CHECKBOX_TYPE) { + if (HTCurSelectGroupType == F_CHECKBOX_TYPE || + LYSelectPopups == FALSE) { /* - * Start a newline after the last checkbox option. + * Start a newline after the last checkbox/button option. */ HTML_EnsureSingleSpace(me); } else { @@ -5648,11 +5698,22 @@ PUBLIC void HTML_free ARGS1(HTStructured *, me) UPDATE_STYLE; /* Creates empty document here! */ if (me->comment_end) HTML_put_string(me,me->comment_end); - HText_endAppend(me->text); + if (me->text) { + if (B_inUnderline) { + HText_appendCharacter(me->text,LY_UNDERLINE_END_CHAR); + B_inUnderline = FALSE; + } + HText_endAppend(me->text); + } if (me->target) { (*me->targetClass._free)(me->target); } + List_Nesting_Level = -1; + HTML_zero_OL_Counter(); + Division_Level = -1; + Underline_Level = 0; + Quote_Level = 0; if (me->sp && me->sp->style && me->sp->style->name) { if (!strcmp(me->sp->style->name, "DivCenter") || !strcmp(me->sp->style->name, "HeadingCenter")) { @@ -5666,6 +5727,7 @@ PUBLIC void HTML_free ARGS1(HTStructured *, me) styles[HTML_PRE]->alignment = HT_LEFT; } FREE(base_href); + B_inBASE = FALSE; FREE(LYMapName); FREE(me); } @@ -5689,6 +5751,21 @@ PRIVATE void HTML_abort ARGS2(HTStructured *, me, HTError, e) if (me->target) { (*me->targetClass._abort)(me->target, e); } + if (me->sp && me->sp->style && me->sp->style->name) { + if (!strcmp(me->sp->style->name, "DivCenter") || + !strcmp(me->sp->style->name, "HeadingCenter")) { + me->sp->style->alignment = HT_CENTER; + } else if (!strcmp(me->sp->style->name, "DivRight") || + !strcmp(me->sp->style->name, "HeadingRight")) { + me->sp->style->alignment = HT_RIGHT; + } else { + me->sp->style->alignment = HT_LEFT; + } + styles[HTML_PRE]->alignment = HT_LEFT; + } + FREE(base_href); + B_inBASE = FALSE; + FREE(LYMapName); FREE(me); } @@ -5762,7 +5839,6 @@ PRIVATE void get_styles NOARGS styles[HTML_PLAINTEXT] = styles[HTML_XMP] = HTStyleNamed(styleSheet, "Example"); styles[HTML_PRE] = HTStyleNamed(styleSheet, "Preformatted"); - styles[HTML_STYLE] = HTStyleNamed(styleSheet, "Style"); styles[HTML_LISTING] = HTStyleNamed(styleSheet, "Listing"); } /* P U B L I C @@ -6206,8 +6282,8 @@ PRIVATE void HTML_CheckForID ARGS4( (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ temp, /* Tag */ - 0, /* Addresss */ - 0))) { /* Type */ + NULL, /* Addresss */ + (void *)0))) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); } @@ -6238,8 +6314,8 @@ PRIVATE void HTML_HandleID ARGS2( if (B_ID_A = HTAnchor_findChildAndLink( me->node_anchor, /* Parent */ id, /* Tag */ - 0, /* Addresss */ - 0)) { /* Type */ + NULL, /* Addresss */ + (void *)0)) { /* Type */ HText_beginAnchor(me->text, B_ID_A); HText_endAnchor(me->text); } diff --git a/src/LYBookmark.c b/src/LYBookmark.c index 88dca1ef..4ba29d0b 100644 --- a/src/LYBookmark.c +++ b/src/LYBookmark.c @@ -9,10 +9,12 @@ #include "LYSystem.h" #include "LYKeymap.h" #include "LYCharUtils.h" +#include "LYCurses.h" #ifdef VMS #include "HTVMSUtils.h" #include <nam.h> +extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */ #endif /* VMS */ #include "LYLeaks.h" @@ -26,52 +28,70 @@ PRIVATE char * convert_mosaic_bookmark_file PARAMS((char *filename_buffer)); * Tries to open the bookmark file for reading. * if successful the file is closed and the filename * is returned and the URL is given in name. + * + * Returns a zero-length pointer to flag a cancel, + * a space to flag an undefined selection, and + * NULL for a failure (processing error). - FM */ -PUBLIC char * get_bookmark_filename ARGS1(char **,URL) +PUBLIC char * get_bookmark_filename ARGS1( + char **, URL) { char URL_buffer[256]; static char filename_buffer[256]; char string_buffer[256]; FILE *fp; + int MBM_tmp; - if (!bookmark_page) { + /* + * Multi_Bookmarks support. - FMG & FM + * Let user select a bookmark file. + */ + MBM_tmp = select_multi_bookmarks(); + if (MBM_tmp == -2) + /* + * Zero-length pointer flags a cancel. + */ + return(""); + if (MBM_tmp == -1) { sprintf(string_buffer, BOOKMARK_FILE_NOT_DEFINED, key_for_func(LYK_OPTIONS)); _statusline(string_buffer); sleep(AlertSecs); - return(NULL); + /* + * Space flags an undefined selection. + */ + return(" "); + } else { + StrAllocCopy(BookmarkPage, MBM_A_subbookmark[MBM_tmp]); } /* - * See if it is in the home path. + * Seek it in the home path. */ #ifdef VMS - sprintf(filename_buffer,"%s%s", Home_Dir(), bookmark_page); + LYVMS_HomePathAndFilename(filename_buffer, + sizeof(filename_buffer), + BookmarkPage); #else - sprintf(filename_buffer,"%s/%s", Home_Dir(), bookmark_page); + sprintf(filename_buffer,"%s/%s", Home_Dir(), BookmarkPage); #endif /* VMS */ + if (TRACE) + fprintf(stderr, "\nget_bookmark_filename: SEEKING %s\n AS %s\n\n", + BookmarkPage, filename_buffer); if ((fp = fopen(filename_buffer,"r")) != NULL) { goto success; } /* - * See if we can open it raw. - */ - if ((fp = fopen(bookmark_page,"r")) != NULL) { - strcpy(filename_buffer, bookmark_page); - goto success; - } - - /* * Failure. */ return(NULL); success: /* - * We now have the file open. Check if it is a mosaic - * hotlist. + * We now have the file open. + * Check if it is a mosaic hotlist. */ if (fgets(string_buffer, 255, fp) && !strncmp(string_buffer, "ncsa-xmosaic-hotlist-format-1", 29)) { @@ -79,23 +99,23 @@ success: /* * It is a mosaic hotlist file. */ - is_mosaic_hotlist=TRUE; + is_mosaic_hotlist = TRUE; fclose(fp); newname = convert_mosaic_bookmark_file(filename_buffer); #ifdef VMS - sprintf(URL_buffer,"file://localhost%s", HTVMS_wwwName((char *)newname)); + sprintf(URL_buffer,"file://localhost%s", + HTVMS_wwwName((char *)newname)); #else - sprintf(URL_buffer,"file://localhost%s", newname); + sprintf(URL_buffer,"file://localhost%s", newname); #endif /* VMS */ - } else { fclose(fp); - is_mosaic_hotlist=FALSE; + is_mosaic_hotlist = FALSE; #ifdef VMS - sprintf(URL_buffer,"file://localhost%s", - HTVMS_wwwName((char *)filename_buffer)); + sprintf(URL_buffer,"file://localhost%s", + HTVMS_wwwName((char *)filename_buffer)); #else - sprintf(URL_buffer,"file://localhost%s", filename_buffer); + sprintf(URL_buffer,"file://localhost%s", filename_buffer); #endif /* VMS */ } @@ -104,7 +124,8 @@ success: } /* big end */ -PRIVATE char * convert_mosaic_bookmark_file ARGS1(char *,filename_buffer) +PRIVATE char * convert_mosaic_bookmark_file ARGS1( + char *, filename_buffer) { static char newfile[256]; static BOOLEAN first = TRUE; @@ -122,14 +143,13 @@ PRIVATE char * convert_mosaic_bookmark_file ARGS1(char *,filename_buffer) #endif /* VMS */ } - - if((nfp = fopen(newfile, "w")) == NULL) { + if ((nfp = fopen(newfile, "w")) == NULL) { _statusline(NO_TEMP_FOR_HOTLIST); sleep(AlertSecs); return (""); } - if((fp = fopen(filename_buffer, "r")) == NULL) + if ((fp = fopen(filename_buffer, "r")) == NULL) return (""); /* should always open */ fprintf(nfp,"<head>\n<title>%s</title>\n</head>\n",MOSAIC_BOOKMARK_TITLE); @@ -161,7 +181,9 @@ PRIVATE char * convert_mosaic_bookmark_file ARGS1(char *,filename_buffer) return(newfile); } -PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title) +PUBLIC void save_bookmark_link ARGS2( + char *, address, + char *, title) { FILE *fp; BOOLEAN first_time = FALSE; @@ -177,10 +199,27 @@ PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title) } filename = get_bookmark_filename(&bookmark_URL); - FREE(bookmark_URL); /* don't need it */ - if (!bookmark_page) + + /* + * If filename is a space, invalid bookmark + * file was selected. If zero-length, user + * cancelled. Ignore request in both cases! + */ + if (filename) + if (*filename == '\0' || !strcmp(filename," ")) + return; + /* + * If BookmarkPage didn't get loaded, something + * went wrong, so ignore the request. + */ + if (!BookmarkPage) return; + /* + * We don't need the full URL. + */ + FREE(bookmark_URL); + /* * Allow user to change the title. - FM */ @@ -205,32 +244,25 @@ PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title) /* * Open the bookmark file. - FM */ - if (filename == NULL) { + if (filename == NULL) first_time = TRUE; - /* - * Try in the home directory first. - */ + /* + * Try in the home directory. + */ #ifdef VMS - sprintf(filename_buffer, "sys$login:%s", bookmark_page); + LYVMS_HomePathAndFilename(filename_buffer, + sizeof(filename_buffer), + BookmarkPage); #else - sprintf(filename_buffer, "%s/%s", Home_Dir(), bookmark_page); + sprintf(filename_buffer, "%s/%s", Home_Dir(), BookmarkPage); #endif /* VMS */ - if ((fp = fopen(filename_buffer,"w")) == NULL) { - /* - * Try it raw. - */ - if ((fp = fopen(bookmark_page,"r")) == NULL) { - _statusline(BOOKMARK_OPEN_FAILED); - sleep(AlertSecs); - return; - } - } - } else { - if ((fp = fopen(filename,"a+")) == NULL) { - _statusline(BOOKMARK_OPEN_FAILED); - sleep(AlertSecs); - return; - } + if (TRACE) + fprintf(stderr, "\nsave_bookmark_link: SEEKING %s\n AS %s\n\n", + BookmarkPage, filename_buffer); + if ((fp = fopen(filename_buffer, (first_time ? "w" : "a+"))) == NULL) { + _statusline(BOOKMARK_OPEN_FAILED); + sleep(AlertSecs); + return; } /* @@ -245,8 +277,8 @@ PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title) if (first_time) { fprintf(fp,"<head>\n<title>%s</title>\n</head>\n",BOOKMARK_TITLE); fprintf(fp,"\ - You can delete links using the new remove bookmark command.\n\ - it is usually the 'R' key but may have been remapped by you or\n\ + You can delete links using the remove bookmark command. It\n\ + is usually the 'R' key but may have been remapped by you or\n\ your system administrator.<br>\n\ This file may also be edited with a standard text editor.\n\ Outdated or invalid links may be removed by simply deleting\n\ @@ -277,38 +309,47 @@ PUBLIC void save_bookmark_link ARGS2(char *,address, char *,title) sleep(MessageSecs); } -PUBLIC void remove_bookmark_link ARGS1(int,cur) +PUBLIC void remove_bookmark_link ARGS2( + int, cur, + char *, cur_bookmark_page) { FILE *fp, *nfp; char buf[BUFSIZ]; int n; #ifdef VMS + char filename_buffer[NAM$C_MAXRSS+12]; char newfile[NAM$C_MAXRSS+12]; #else - char newfile[128]; + char filename_buffer[256]; + char newfile[256]; struct stat stat_buf; mode_t mode; #endif /* VMS */ - char *filename; - char *URL = 0; if (TRACE) fprintf(stderr, "remove_bookmark_link: deleting link number: %d\n", cur); - filename = get_bookmark_filename(&URL); - FREE(URL); /* don't need it */ - if (!bookmark_page) + if (!cur_bookmark_page) return; - - if ((!filename) || (fp=fopen(filename, "r")) == NULL) { +#ifdef VMS + LYVMS_HomePathAndFilename(filename_buffer, + sizeof(filename_buffer), + cur_bookmark_page); +#else + sprintf(filename_buffer,"%s/%s", Home_Dir(), cur_bookmark_page); +#endif /* VMS */ + if (TRACE) + fprintf(stderr, "\nremove_bookmark_link: SEEKING %s\n AS %s\n\n", + cur_bookmark_page, filename_buffer); + if ((fp = fopen(filename_buffer, "r")) == NULL) { _statusline(BOOKMARK_OPEN_FAILED_FOR_DEL); sleep(AlertSecs); return; } #ifdef VMS - sprintf(newfile, "%s-%d", filename, getpid()); + sprintf(newfile, "%s-%d", filename_buffer, getpid()); #else tempname(newfile, NEW_FILE); #endif /* VMS */ @@ -327,7 +368,7 @@ PUBLIC void remove_bookmark_link ARGS1(int,cur) /* * Explicitly preserve bookmark file mode on Unix. - DSL */ - if (stat(filename,&stat_buf) == 0) { + if (stat(filename_buffer, &stat_buf) == 0) { mode = ((stat_buf.st_mode & 0777) | 0600); (void) fclose(nfp); nfp = NULL; @@ -385,27 +426,27 @@ PUBLIC void remove_bookmark_link ARGS1(int,cur) if (TRACE) fprintf(stderr, "remove_bookmark_link: files: %s %s\n", - newfile, filename); + newfile, filename_buffer); fclose(fp); fp = NULL; fclose(nfp); nfp = NULL; - if (rename(newfile, filename) != -1) { + if (rename(newfile, filename_buffer) != -1) { #ifdef VMS char VMSfilename[256]; /* * Purge lower version of file. */ - sprintf(VMSfilename, "%s;-1", filename); + sprintf(VMSfilename, "%s;-1", filename_buffer); while (remove(VMSfilename) == 0) ; /* * Reset version number. */ - sprintf(VMSfilename, "%s;1", filename); - rename(filename, VMSfilename); + sprintf(VMSfilename, "%s;1", filename_buffer); + rename(filename_buffer, VMSfilename); #endif /* VMS */ return; } else { @@ -417,7 +458,7 @@ PUBLIC void remove_bookmark_link ARGS1(int,cur) */ if (errno == EXDEV) { char buffer[2048]; - sprintf(buffer, "%s %s %s", MV_PATH, newfile, filename); + sprintf(buffer, "%s %s %s", MV_PATH, newfile, filename_buffer); system(buffer); return; } @@ -442,3 +483,304 @@ failure: fclose(fp); remove(newfile); } + +/* + * Allows user to select sub-bookmarks files. - FMG & FM + */ +PUBLIC int select_multi_bookmarks NOARGS +{ + int c; + + /* + * If not enabled, pick the "default" (0). + */ + if (LYMultiBookmarks == FALSE || LYHaveSubBookmarks() == FALSE) { + if (MBM_A_subbookmark[0]) /* If it exists! */ + return(0); + else + return(-1); + } + + /* + * For ADVANCED users, we can just mess with the status line to save + * the 2 redraws of the screen, if LYMBMAdvnced is TRUE. '=' will + * still show the screen and let them do it the "long" way. + */ + if (LYMBMAdvanced && user_mode == ADVANCED_MODE) { + move(LYlines-1, 0); + clrtoeol(); + start_reverse(); + addstr("Select subbookmark, '=' for menu, or ^G to cancel: "); + stop_reverse(); + refresh(); + +get_advanced_choice: + c = LYgetch(); +#ifdef VMS + if (HadVMSInterrupt) { + HadVMSInterrupt = FALSE; + c = 7; + } +#endif /* VMS */ + if (LYisNonAlnumKeyname(c, LYK_PREV_DOC) || + c == 7 || c == 3) { + /* + * Treat left-arrow, ^G, or ^C as cancel. + */ + return(-2); + } + if (LYisNonAlnumKeyname(c, LYK_REFRESH)) { + /* + * Refresh the screen. + */ + clearok(curscr, TRUE); + refresh(); + goto get_advanced_choice; + } + if (LYisNonAlnumKeyname(c, LYK_ACTIVATE)) { + /* + * Assume default bookmark file on ENTER or right-arrow. + */ + return (MBM_A_subbookmark[0] ? 0 : -1); + } + switch (c) { + case '=': + /* + * Get the choice via the menu. + */ + return(select_menu_multi_bookmarks()); + + default: + /* + * Convert to an array index, act on it if valid. + * Otherwise, get another keystroke. + */ + c = TOUPPER(c) - 'A'; + if (c < 0 || c > MBM_V_MAXFILES) { + goto get_advanced_choice; + } + } + /* + * See if we have a bookmark like that. + */ + return (MBM_A_subbookmark[c] ? c : -1); + } else { + /* + * Get the choice via the menu. + */ + return(select_menu_multi_bookmarks()); + } +} + +/* + * Allows user to select sub-bookmarks files. - FMG & FM + */ +PUBLIC int select_menu_multi_bookmarks NOARGS +{ + FILE *fp; + int c, MBM_counter, MBM_tmp_count, MBM_allow; + int MBM_screens, MBM_from, MBM_to, MBM_current; + char string_buffer[256]; + char *cp, *cp1; + + /* + * If not enabled, pick the "default" (0). + */ + if (LYMultiBookmarks == FALSE) + return(0); + + /* + * Filip M. Gieszczykiewicz (filipg@paranoia.com) & FM + * --------------------------------------------------- + * LYMultiBookmarks - TRUE when multi_support enabled. + * + * MBM_A_subbookmark[n] - Hold values of the respective + * "multi_bookmarkn" in the lynxrc file. + * + * MBM_A_subdescript[n] - Hold description entries in the + * lynxrc file. + * + * Note: MBM_A_subbookmark[0] is defined to be same value as + * "bookmark_file" in the lynxrc file and/or the startup + * "bookmark_page". + * + * We make the display of bookmarks depend on rows we have + * available. + * + * We load BookmarkPage with the valid MBM_A_subbookmark[n] + * via get_bookmark_filename(). Otherwise, that function + * returns a zero-length string to indicate a cancel, a + * single space to indicate an invalid choice, or NULL to + * indicate an inaccessible file. + */ + MBM_allow=(LYlines-7); /* We need 7 for header and footer */ + /* + * Screen big enough? + */ + if (MBM_allow <= 0) { + /* + * Too small. + */ + _statusline(MULTIBOOKMARKS_SMALL); + sleep(AlertSecs); + return (-2); + } + /* + * Load the bad choice message. + */ + sprintf(string_buffer, + BOOKMARK_FILE_NOT_DEFINED, + key_for_func(LYK_OPTIONS)); + + MBM_screens = (MBM_V_MAXFILES/MBM_allow)+1; /* int rounds off low. */ + + MBM_current = 1; /* Gotta start somewhere :-) */ + +draw_bookmark_choices: + MBM_from = MBM_allow * MBM_current - MBM_allow; + if (MBM_from < 0) + MBM_from = 0; /* 0 is default bookmark... */ + if (MBM_current != 1) + MBM_from++; + + MBM_to = (MBM_allow * MBM_current); + if (MBM_to > MBM_V_MAXFILES) + MBM_to = MBM_V_MAXFILES; + + /* + * Display menu of bookmarks. + */ + clear(); + move(1, 5); + if (bold_H1 || bold_headers) + start_bold(); + if (MBM_screens > 1) + printw(" Select Bookmark (screen %d of %d)", MBM_current, MBM_screens); + else + printw(" Select Bookmark"); + if (bold_H1 || bold_headers) + stop_bold(); + + MBM_tmp_count = 0; + for (c = MBM_from; c <= MBM_to; c++) { + move(3+MBM_tmp_count, 5); + printw("%c : %s",(c+'A'), + (!MBM_A_subdescript[c] ? "" : MBM_A_subdescript[c])); + + move(3+MBM_tmp_count,36); + printw("(%s)", + (!MBM_A_subbookmark[c] ? "" : MBM_A_subbookmark[c])); + + MBM_tmp_count++; + } + + /* + * Don't need to show it if it all fits on one screen! + */ + if (MBM_screens > 1) { + move(LYlines-2, 0); + addstr(MULTIBOOKMARKS_MOVE); + } + + move(LYlines-1, 0); + clrtoeol(); + start_reverse(); + addstr(MULTIBOOKMARKS_SAVE); + stop_reverse(); + refresh(); + +get_bookmark_choice: + c = LYgetch(); +#ifdef VMS + if (HadVMSInterrupt) { + HadVMSInterrupt = FALSE; + c = 7; + } +#endif /* VMS */ + + if (LYisNonAlnumKeyname(c, LYK_PREV_DOC) || + c == 7 || c == 3) { + /* + * Treat left-arrow, ^G, or ^C as cancel. + */ + return(-2); + } + + if (LYisNonAlnumKeyname(c, LYK_REFRESH)) { + /* + * Refresh the screen. + */ + clearok(curscr, TRUE); + refresh(); + goto get_bookmark_choice; + } + + if (LYisNonAlnumKeyname(c, LYK_ACTIVATE)) { + /* + * Assume default bookmark file on ENTER or right-arrow. + */ + return(MBM_A_subbookmark[0] ? 0 : -1); + } + + /* + * Next range, if available. + */ + if ((c == ']' || LYisNonAlnumKeyname(c, LYK_NEXT_PAGE)) && + MBM_screens > 1) { + if (++MBM_current > MBM_screens) + MBM_current = 1; + goto draw_bookmark_choices; + } + + /* + * Previous range, if available. + */ + if ((c == '[' || LYisNonAlnumKeyname(c, LYK_PREV_PAGE)) && + MBM_screens > 1) { + if (--MBM_current <= 0) + MBM_current = MBM_screens; + goto draw_bookmark_choices; + } + + c = TOUPPER(c) - 'A'; + /* + * See if we have a bookmark like that. + */ + if (c < 0 || c > MBM_V_MAXFILES) { + goto get_bookmark_choice; + } else if (!MBM_A_subbookmark[c]) { + move(LYlines-1, 0); + clrtoeol(); + start_reverse(); + addstr(string_buffer); + stop_reverse(); + refresh(); + sleep(AlertSecs); + move(LYlines-1, 0); + clrtoeol(); + start_reverse(); + addstr(MULTIBOOKMARKS_SAVE); + stop_reverse(); + refresh(); + goto get_bookmark_choice; + } else { + return(c); + } +} + +/* + * This function returns TRUE if we have sub-bookmarks defined. + * Otherwise (i.e., only the default bookmark file is defined), + * it returns FALSE. - FM + */ +PUBLIC BOOLEAN LYHaveSubBookmarks NOARGS +{ + int i; + + for (i = 1; i < MBM_V_MAXFILES; i++) { + if (MBM_A_subbookmark[i] != NULL && *MBM_A_subbookmark[i] != '\0') + return(TRUE); + } + + return(FALSE); +} diff --git a/src/LYBookmark.h b/src/LYBookmark.h index 838c025e..41f54c6b 100644 --- a/src/LYBookmark.h +++ b/src/LYBookmark.h @@ -8,10 +8,22 @@ extern char * get_bookmark_filename PARAMS((char **name)); extern void save_bookmark_link PARAMS((char *address, char *title)); -extern void remove_bookmark_link PARAMS((int cur)); +extern void remove_bookmark_link PARAMS((int cur, char *cur_bookmark_page)); +extern int select_multi_bookmarks NOPARAMS; +extern int select_menu_multi_bookmarks NOPARAMS; +extern BOOLEAN LYHaveSubBookmarks NOPARAMS; + +extern void edit_bookmarks NOPARAMS; /* in LYOptions.c */ #define BOOKMARK_TITLE "Bookmark file" #define MOSAIC_BOOKMARK_TITLE "Converted Mosaic Hotlist" +#define MBM_V_MAXFILES 25 /* Max number of sub-bookmark files */ +/* + * Arrays that holds the names of sub-bookmark files + * and their descriptions. + */ +char *MBM_A_subbookmark[MBM_V_MAXFILES+1]; +char *MBM_A_subdescript[MBM_V_MAXFILES+1]; #endif /* LYBOOKMARK_H */ diff --git a/src/LYCgi.c b/src/LYCgi.c index 77eefb77..9a81fadb 100644 --- a/src/LYCgi.c +++ b/src/LYCgi.c @@ -176,10 +176,8 @@ PUBLIC int LYLoadCGI ARGS4( sleep(MessageSecs); status = HT_NOT_LOADED; - } else if (!reloading && no_bookmark_exec && bookmark_page && - (strstr(HTLoadedDocumentURL(), bookmark_page) || - !strcmp(HTLoadedDocumentTitle(), - MOSAIC_BOOKMARK_TITLE))) { + } else if (!reloading && no_bookmark_exec && + HTLoadedDocumentBookmark()) { _statusline(BOOKMARK_EXEC_DISABLED); sleep(MessageSecs); status = HT_NOT_LOADED; diff --git a/src/LYCharUtils.c b/src/LYCharUtils.c index 75d50f8d..18aa65d0 100644 --- a/src/LYCharUtils.c +++ b/src/LYCharUtils.c @@ -1024,7 +1024,7 @@ PUBLIC char *LYFindEndOfComment ARGS1( */ return NULL; - if (strcmp(str, "<!--")) + if (strncmp(str, "<!--", 4)) /* * We don't have the start of a comment, so * return the beginning of the string. - FM diff --git a/src/LYCurses.h b/src/LYCurses.h index 065fdd1d..d18cd6e3 100644 --- a/src/LYCurses.h +++ b/src/LYCurses.h @@ -12,8 +12,7 @@ #if defined(UNIX) && !defined(unix) #define unix #endif /* UNIX && !unix */ -#include "slang.h" -#include "slcurses.h" +#include <slang.h> #else /* Using curses: */ @@ -125,6 +124,21 @@ extern unsigned int Lynx_Color_Flags; #define NO_TTYTYPE #endif /* !NO_TTYTYPE */ +/* Map some curses functions to slang functions. */ +#define stdscr NULL +#define COLS SLtt_Screen_Cols +#define LINES SLtt_Screen_Rows +#define move SLsmg_gotorc +#define addstr SLsmg_write_string +#define clear SLsmg_cls +#define standout SLsmg_reverse_video +#define standend SLsmg_normal_video +#define clrtoeol SLsmg_erase_eol +#define scrollok(a,b) SLsmg_Newline_Moves = ((b) ? 1 : -1) +#define addch SLsmg_write_char +#define echo() +#define printw SLsmg_printf + extern int curscr; extern BOOLEAN FullRefresh; #ifdef clearok @@ -139,10 +153,9 @@ extern void LY_SLrefresh NOPARAMS; #ifdef VMS extern void VTHome NOPARAMS; -#ifdef endwin -#undef endwin -#endif /*endwin */ #define endwin() clear(),refresh(),SLsmg_reset_smg(),VTHome() +#else +#define endwin SLsmg_reset_smg(),SLang_reset_tty #endif /* VMS */ #else /* Define curses functions: */ diff --git a/src/LYForms.c b/src/LYForms.c index 14132d58..b7cd64ee 100644 --- a/src/LYForms.c +++ b/src/LYForms.c @@ -25,8 +25,8 @@ extern HTCJKlang HTCJK; PRIVATE int form_getstr PARAMS((struct link * form_link)); PRIVATE int popup_options PARAMS((int cur_selection, OptionType *list, - int ly, int lx, int width, - int i_length)); + int ly, int lx, int width, + int i_length, int disabled)); PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, document *,newdoc, BOOLEAN *,refresh_screen, @@ -36,10 +36,11 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, FormInfo *form = form_link->form; int c=DO_NOTHING; - /* If there is no form to perform action on, don't do anything. + /* + * If there is no form to perform action on, don't do anything. */ - if(form == NULL) { - return(c); + if (form == NULL) { + return(c); } /* move to the link position */ @@ -49,7 +50,7 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, case F_CHECKBOX_TYPE: if (form->disabled == YES) break; - if(form->num_value) { + if (form->num_value) { form_link->hightext = unchecked_box; form->num_value = 0; } else { @@ -69,18 +70,18 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, int dummy; dummy = popup_options(form->num_value, form->select_list, form_link->ly, form_link->lx, form->size, - form->size_l); + form->size_l, form->disabled); c = 12; /* CTRL-R for repaint */ break; } form->num_value = popup_options(form->num_value, form->select_list, form_link->ly, form_link->lx, form->size, - form->size_l); + form->size_l, form->disabled); { OptionType * opt_ptr=form->select_list; int i; - for(i=0; i<form->num_value; i++, opt_ptr = opt_ptr->next) + for (i = 0; i < form->num_value; i++, opt_ptr = opt_ptr->next) ; /* null body */ form->value = opt_ptr->name; /* set the name */ form->cp_submit_value = opt_ptr->cp_submit_value; /* set the value */ @@ -94,7 +95,7 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, /* radio buttons must have one and * only one down at a time! */ - if(form->num_value) { + if (form->num_value) { _statusline(NEED_CHECKED_RADIO_BUTTON); sleep(MessageSecs); @@ -104,8 +105,8 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, * unselect any that are selected. :) */ start_bold(); - for(i=0; i < nlinks; i++) - if(links[i].type == WWW_FORM_LINK_TYPE && + for (i = 0; i < nlinks; i++) + if (links[i].type == WWW_FORM_LINK_TYPE && links[i].form->type == F_RADIO_TYPE && links[i].form->number == form->number && /* if it has the same name and its on */ @@ -128,7 +129,7 @@ PUBLIC int change_form_link ARGS6(struct link *, form_link, int, mode, case F_TEXTAREA_TYPE: case F_PASSWORD_TYPE: c = form_getstr(form_link); - if(form->type == F_PASSWORD_TYPE) + if (form->type == F_PASSWORD_TYPE) form_link->hightext = STARS(strlen(form->value)); else form_link->hightext = form->value; @@ -230,7 +231,7 @@ PRIVATE int form_getstr ARGS1(struct link *, form_link) /* get the initial position of the cursor */ GetYX(startline, startcol); - if(startcol + form->size > LYcols-1) + if (startcol + form->size > LYcols-1) far_col = LYcols-1; else far_col = startcol + form->size; @@ -291,11 +292,11 @@ again: case LTARROW: if (MyEdit.pos==0) { int c='Y'; /* Go back immediately if no changes */ - if(strcmp(MyEdit.buffer, form->value)) { + if (strcmp(MyEdit.buffer, form->value)) { _statusline(PREV_DOC_QUERY); c=LYgetch(); } - if(TOUPPER(c) == 'Y') { + if (TOUPPER(c) == 'Y') { #ifdef NOTDEFINED /* * Why not just keep what we have?? @@ -351,97 +352,124 @@ breakfor: } -PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list, - int, ly, int, lx, int,width, - int, i_length) +PRIVATE int popup_options ARGS7( + int, cur_selection, + OptionType *, list, + int, ly, + int, lx, + int, width, + int, i_length, + int, disabled) { /* - * Revamped to handle within-tag VALUE's, if present, - * and to position the popup window appropriately, - * taking the user_mode setting into account. -- FM + * Revamped to handle within-tag VALUE's, if present, + * and to position the popup window appropriately, + * taking the user_mode setting into account. -- FM */ - int c=0, cmd=0, i=0; + int c = 0, cmd = 0, i = 0, j = 0; int orig_selection = cur_selection; #ifndef USE_SLANG WINDOW * form_window; #endif /* !USE_SLANG */ - int num_options=0, top, bottom, length= -1; - OptionType * opt_ptr=list; - int window_offset=0; + int num_options = 0, top, bottom, length = -1; + OptionType * opt_ptr = list; + int window_offset = 0; int display_lines; #ifdef VMS extern BOOLEAN HadVMSInterrupt; /* Flag from cleanup_sig() AST */ -#endif +#endif /* VMS */ + static char prev_target[512]; /* Search string buffer */ + static char prev_target_buffer[512]; /* Next search buffer */ + static BOOL first = TRUE; + char *cp; + int ch = 0, recall; + int QueryTotal; + int QueryNum; + BOOLEAN FirstRecall = TRUE; + OptionType * tmp_ptr; + BOOLEAN ReDraw = FALSE; + + /* + * Initialize the search string buffer. - FM + */ + if (first) { + *prev_target_buffer = '\0'; + first = FALSE; + } + *prev_target = '\0'; + QueryTotal = (search_queries ? HTList_count(search_queries) : 0); + recall = ((QueryTotal >= 1) ? RECALL : NORECALL); + QueryNum = QueryTotal; /* - * Set display_lines based on the user_mode global. + * Set display_lines based on the user_mode global. */ - if(user_mode==NOVICE_MODE) + if (user_mode==NOVICE_MODE) display_lines = LYlines-4; else display_lines = LYlines-2; /* - * Counting the number of options to be displayed. + * Counting the number of options to be displayed. * num_options ranges 0...n */ - for(; opt_ptr->next; num_options++, opt_ptr = opt_ptr->next) + for (; opt_ptr->next; num_options++, opt_ptr = opt_ptr->next) ; /* null body */ /* - * Let's assume for the sake of sanity that ly is the number + * Let's assume for the sake of sanity that ly is the number * corresponding to the line the selection box is on. - * Let's also assume that cur_selection is the number of the + * Let's also assume that cur_selection is the number of the * item that should be initially selected, as 0 beign the * first item. - * So what we have, is the top equal to the current screen line + * So what we have, is the top equal to the current screen line * subtracting the cur_selection + 1 (the one must be for the * top line we will draw in a box). If the top goes under 0, * consider it 0. */ top = ly - (cur_selection + 1); - if(top < 0) + if (top < 0) top = 0; /* - * Check and see if we need to put the i_length parameter up to - * the number of real options. + * Check and see if we need to put the i_length parameter up to + * the number of real options. */ - if(!i_length) { + if (!i_length) { i_length = num_options; } else { /* - * Otherwise, it is really one number too high. + * Otherwise, it is really one number too high. */ i_length--; } /* - * The bottom is the value of the top plus the number of options - * to view plus 3 (one for the top line, one for the bottom line, - * and one to offset the 0 counted in the num_options). + * The bottom is the value of the top plus the number of options + * to view plus 3 (one for the top line, one for the bottom line, + * and one to offset the 0 counted in the num_options). */ bottom = top + i_length + 3; /* - * Hmm... If the bottom goes beyond the number of lines available + * Hmm... If the bottom goes beyond the number of lines available, */ - if(bottom > display_lines) { + if (bottom > display_lines) { /* - * Position the window at the top if we have more options - * than will fit in the window. + * Position the window at the top if we have more + * options than will fit in the window. */ - if(i_length+3 > display_lines) { + if (i_length+3 > display_lines) { top = 0; bottom = top + i_length+3; - if(bottom > display_lines) + if (bottom > display_lines) bottom = display_lines + 1; } else { /* - * Try to position the window so that the selected option will - * appear where the selecton box currently is positioned. - * It could end up too high, at this point, but we'll move it + * Try to position the window so that the selected option will + * appear where the selection box currently is positioned. + * It could end up too high, at this point, but we'll move it * down latter, if that has happened. */ top = (display_lines + 1) - (i_length + 3); @@ -450,12 +478,12 @@ PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list, } /* - * This is really fun, when the length is 4, it means 0-4, or 5. + * This is really fun, when the length is 4, it means 0-4, or 5. */ length = (bottom - top) - 2; /* - * Move the window down if it's too high. + * Move the window down if it's too high. */ if (bottom < ly + 2) { bottom = ly + 2; @@ -465,8 +493,8 @@ PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list, } /* - * Set up the overall window, including the boxing characters ('*'), if - * it all fits. Otherwise, set up the widest window possible. - FM + * Set up the overall window, including the boxing characters ('*'), + * if it all fits. Otherwise, set up the widest window possible. - FM */ #ifndef USE_SLANG if (!(form_window = newwin(bottom - top, width+4, top, lx - 1)) && @@ -480,11 +508,11 @@ PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list, #endif /* !USE_SLANG */ /* - * Set up the window_offset for options. + * Set up the window_offset for options. * cur_selection ranges from 0...n * length ranges from 0...m */ - if(cur_selection >= length) { + if (cur_selection >= length) { window_offset = cur_selection - length + 1; } @@ -495,12 +523,13 @@ PRIVATE int popup_options ARGS6(int,cur_selection, OptionType *,list, * 09-05-94 FM */ redraw: + opt_ptr = list; - opt_ptr=list; - - /* display the boxed options */ - for(i = 0; i <= num_options; i++, opt_ptr = opt_ptr->next) { - if(i >= window_offset && i - window_offset < length) { + /* + * Display the boxed options. + */ + for (i = 0; i <= num_options; i++, opt_ptr = opt_ptr->next) { + if (i >= window_offset && i - window_offset < length) { #ifndef USE_SLANG wmove(form_window,(i+1)-window_offset,2); wclrtoeol(form_window); @@ -521,12 +550,16 @@ redraw: #else SLsmg_draw_box (top, lx - 1, bottom - top, width + 4); #endif /* !USE_SLANG */ - opt_ptr=NULL; + opt_ptr = NULL; - /* loop on user input */ - while(cmd != LYK_ACTIVATE) { + /* + * Loop on user input. + */ + while (cmd != LYK_ACTIVATE) { - /* unreverse cur selection */ + /* + * Unreverse cur selection. + */ if (opt_ptr != NULL) { #ifndef USE_SLANG wmove(form_window,(i+1)-window_offset,2); @@ -537,9 +570,9 @@ redraw: #endif /* !USE_SLANG */ } - opt_ptr=list; + opt_ptr = list; - for(i=0; i<cur_selection; i++, opt_ptr = opt_ptr->next) + for (i = 0; i < cur_selection; i++, opt_ptr = opt_ptr->next) ; /* null body */ #ifndef USE_SLANG @@ -568,85 +601,67 @@ redraw: switch(cmd) { case LYK_PREV_LINK: case LYK_UP_LINK: - - if( cur_selection) - cur_selection--; - /* scroll the window up if neccessary */ - if (cur_selection-window_offset < 0) { + if (cur_selection > 0) + cur_selection--; + + /* + * Scroll the window up if neccessary. + */ + if ((cur_selection - window_offset) < 0) { window_offset--; -#ifdef USE_SLANG goto redraw; -#else - wmove(form_window,1,2); - winsertln(form_window); -#ifdef VMS - VMSbox(form_window, (bottom - top), (width + 4)); -#else - box(form_window, BOXVERT, BOXHORI); -#endif /* VMS */ -#endif /* USE_SLANG */ } break; case LYK_NEXT_LINK: case LYK_DOWN_LINK: - if(cur_selection < num_options) + if (cur_selection < num_options) cur_selection++; - /* scroll the window down if neccessary */ - if(cur_selection-window_offset >= length) { - /* remove the bottom border befor scrolling */ + /* + * Scroll the window down if neccessary + */ + if ((cur_selection - window_offset) >= length) { window_offset++; -#ifdef USE_SLANG goto redraw; -#else - wmove(form_window,length+1,1); - wclrtoeol(form_window); - scroll(form_window); -#ifdef VMS - VMSbox(form_window, (bottom - top), (width + 4)); -#else - box(form_window, BOXVERT, BOXHORI); -#endif /* VMS */ -#endif /* USE_SLANG */ } break; case LYK_NEXT_PAGE: /* - * Okay, are we on the last page of the list? - * if not then, + * Okay, are we on the last page of the list? + * If not then, */ - if(window_offset != num_options - length + 1) { + if (window_offset != (num_options - length + 1)) { /* - * Modify the current selection to not be a - * coordinate in the list, but a coordinate - * on the item selected in the window. + * Modify the current selection to not be a + * coordinate in the list, but a coordinate + * on the item selected in the window. */ cur_selection -= window_offset; /* - * Page down the proper length for the list. - * If simply to far, back up. + * Page down the proper length for the list. + * If simply to far, back up. */ window_offset += length; - if(window_offset > num_options - length) { - window_offset = num_options - length + 1; + if (window_offset > (num_options - length)) { + window_offset = (num_options - length + 1); } /* - * Readjust the current selection to be a list - * coordinate rather than window. - * Redraw this thing. + * Readjust the current selection to be a + * list coordinate rather than window. + * Redraw this thing. */ cur_selection += window_offset; goto redraw; } - else if(cur_selection < num_options) { + else if (cur_selection < num_options) { /* - * Already on last page of the list so just - * redraw it with the last item selected. + * Already on last page of the list so just + * redraw it with the last item selected. */ cur_selection = num_options; } @@ -654,47 +669,372 @@ redraw: case LYK_PREV_PAGE: /* - * Are we on the first page of the list? - * if not then, + * Are we on the first page of the list? + * If not then, */ - if(window_offset != 0) { + if (window_offset != 0) { /* - * Modify the current selection to not be a list - * coordinate, but a window coordinate. + * Modify the current selection to not be a + * list coordinate, but a window coordinate. */ cur_selection -= window_offset; /* - * Page up the proper length. - * If too far, back up. + * Page up the proper length. + * If too far, back up. */ window_offset -= length; - if(window_offset < 0) { + if (window_offset < 0) { window_offset = 0; } /* - * Readjust the current selection. + * Readjust the current selection. */ cur_selection += window_offset; goto redraw; - } - else if(cur_selection > 0) { + } else if (cur_selection > 0) { /* - * Already on the first page so just - * back up to the first item. + * Already on the first page so just + * back up to the first item. */ cur_selection = 0; } break; + case LYK_HOME: + cur_selection = 0; + if (window_offset > 0) { + window_offset = 0; + goto redraw; + } + break; + + case LYK_END: + cur_selection = num_options; + if (window_offset != (num_options - length + 1)) { + window_offset = (num_options - length + 1); + goto redraw; + } + break; + + case LYK_DOWN_TWO: + cur_selection += 2; + if (cur_selection > num_options) + cur_selection = num_options; + + /* + * Scroll the window down if neccessary. + */ + if ((cur_selection - window_offset) >= length) { + window_offset += 2; + if (window_offset > (num_options - length + 1)) + window_offset = (num_options - length + 1); + goto redraw; + } + break; + + case LYK_UP_TWO: + cur_selection -= 2; + if (cur_selection < 0) + cur_selection = 0; + + /* + * Scroll the window up if neccessary. + */ + if ((cur_selection - window_offset) < 0) { + window_offset -= 2; + if (window_offset < 0) + window_offset = 0; + goto redraw; + } + break; + + case LYK_DOWN_HALF: + cur_selection += (length/2); + if (cur_selection > num_options) + cur_selection = num_options; + + /* + * Scroll the window down if neccessary. + */ + if ((cur_selection - window_offset) >= length) { + window_offset += (length/2); + if (window_offset > (num_options - length + 1)) + window_offset = (num_options - length + 1); + goto redraw; + } + break; + + case LYK_UP_HALF: + cur_selection -= (length/2); + if (cur_selection < 0) + cur_selection = 0; + + /* + * Scroll the window up if neccessary. + */ + if ((cur_selection - window_offset) < 0) { + window_offset -= (length/2); + if (window_offset < 0) + window_offset = 0; + goto redraw; + } + break; + + case LYK_REFRESH: + clearok(curscr, TRUE); + refresh(); + break; + + case LYK_NEXT: + strcpy(prev_target, prev_target_buffer); + case LYK_WHEREIS: + if (*prev_target == '\0' ) { + _statusline(ENTER_WHEREIS_QUERY); + if ((ch = LYgetstr(prev_target, VISIBLE, + sizeof(prev_target_buffer), + recall)) < 0) { + /* + * User cancelled the search via ^G. - FM + */ + _statusline(CANCELLED); + sleep(InfoSecs); + goto restore_popup_statusline; + } + } + +check_recall: + if (*prev_target == '\0' && + !(recall && (ch == UPARROW || ch == DNARROW))) { + /* + * No entry. Simply break. - FM + */ + _statusline(CANCELLED); + sleep(InfoSecs); + goto restore_popup_statusline; + } + + if (recall && ch == UPARROW) { + if (FirstRecall) { + /* + * Use the current string or + * last query in the list. - FM + */ + FirstRecall = FALSE; + if (*prev_target_buffer) { + for (QueryNum = (QueryTotal - 1); + QueryNum > 0; QueryNum--) { + if ((cp=(char *)HTList_objectAt(search_queries, + QueryNum)) != NULL && + !strcmp(prev_target_buffer, cp)) { + break; + } + } + } else { + QueryNum = 0; + } + } else { + /* + * Go back to the previous query in the list. - FM + */ + QueryNum++; + } + if (QueryNum >= QueryTotal) + /* + * Roll around to the last query in the list. - FM + */ + QueryNum = 0; + if ((cp=(char *)HTList_objectAt(search_queries, + QueryNum)) != NULL) { + strcpy(prev_target, cp); + if (*prev_target_buffer && + !strcmp(prev_target_buffer, prev_target)) { + _statusline(EDIT_CURRENT_QUERY); + } else if ((*prev_target_buffer && QueryTotal == 2) || + (!(*prev_target_buffer) && + QueryTotal == 1)) { + _statusline(EDIT_THE_PREV_QUERY); + } else { + _statusline(EDIT_A_PREV_QUERY); + } + if ((ch=LYgetstr(prev_target, VISIBLE, + sizeof(prev_target_buffer), recall)) < 0) { + /* + * User cancelled the search via ^G. - FM + */ + _statusline(CANCELLED); + sleep(InfoSecs); + goto restore_popup_statusline; + } + goto check_recall; + } + } else if (recall && ch == DNARROW) { + if (FirstRecall) { + /* + * Use the current string or + * first query in the list. - FM + */ + FirstRecall = FALSE; + if (*prev_target_buffer) { + for (QueryNum = 0; + QueryNum < (QueryTotal - 1); QueryNum++) { + if ((cp=(char *)HTList_objectAt(search_queries, + QueryNum)) != NULL && + !strcmp(prev_target_buffer, cp)) { + break; + } + } + } else { + QueryNum = QueryTotal - 1; + } + } else { + /* + * Advance to the next query in the list. - FM + */ + QueryNum--; + } + if (QueryNum < 0) + /* + * Roll around to the first query in the list. - FM + */ + QueryNum = QueryTotal - 1; + if ((cp=(char *)HTList_objectAt(search_queries, + QueryNum)) != NULL) { + strcpy(prev_target, cp); + if (*prev_target_buffer && + !strcmp(prev_target_buffer, prev_target)) { + _statusline(EDIT_CURRENT_QUERY); + } else if ((*prev_target_buffer && + QueryTotal == 2) || + (!(*prev_target_buffer) && + QueryTotal == 1)) { + _statusline(EDIT_THE_PREV_QUERY); + } else { + _statusline(EDIT_A_PREV_QUERY); + } + if ((ch = LYgetstr(prev_target, VISIBLE, + sizeof(prev_target_buffer), + recall)) < 0) { + /* + * User cancelled the search via ^G. - FM + */ + _statusline(CANCELLED); + sleep(InfoSecs); + goto restore_popup_statusline; + } + goto check_recall; + } + } + /* + * Replace the search string buffer with the new target. - FM + */ + strcpy(prev_target_buffer, prev_target); + HTAddSearchQuery(prev_target_buffer); + + /* + * Start search at the next option. - FM + */ + for (j = 1, tmp_ptr = opt_ptr->next; + tmp_ptr != NULL; tmp_ptr = tmp_ptr->next, j++) { + if (case_sensitive) { + if (strstr(tmp_ptr->name, prev_target_buffer) != NULL) + break; + } else { + if (LYstrstr(tmp_ptr->name, prev_target_buffer) != NULL) + break; + } + } + if (tmp_ptr != NULL) { + /* + * We have a hit, so make that option the current. - FM + */ + cur_selection += j; + /* + * Scroll the window down if neccessary. + */ + if ((cur_selection - window_offset) >= length) { + window_offset += j; + if (window_offset > (num_options - length + 1)) + window_offset = (num_options - length + 1); + ReDraw = TRUE; + } + goto restore_popup_statusline; + } + + /* + * If we started at the beginning, it can't be present. - FM + */ + if (cur_selection == 0) { + _user_message(STRING_NOT_FOUND, prev_target_buffer); + sleep(MessageSecs); + goto restore_popup_statusline; + } + + /* + * Search from the beginning to the current option. - FM + */ + for (j = 0, tmp_ptr = list; + j < cur_selection; tmp_ptr = tmp_ptr->next, j++) { + if (case_sensitive) { + if (strstr(tmp_ptr->name, prev_target_buffer) != NULL) + break; + } else { + if (LYstrstr(tmp_ptr->name, prev_target_buffer) != NULL) + break; + } + } + if (j < cur_selection) { + /* + * We have a hit, so make that option the current. - FM + */ + j = (cur_selection - j); + cur_selection -= j; + /* + * Scroll the window up if neccessary. + */ + if ((cur_selection - window_offset) < 0) { + window_offset -= j; + if (window_offset < 0) + window_offset = 0; + ReDraw = TRUE; + } + goto restore_popup_statusline; + } + + /* + * Didn't find it in the preceding options either. - FM + */ + _user_message(STRING_NOT_FOUND, prev_target_buffer); + sleep(MessageSecs); + +restore_popup_statusline: + /* + * Restore the popup statusline and + * reset the search variables. - FM + */ + if (disabled) + _statusline(FORM_LINK_OPTION_LIST_UNM_MSG); + else + _statusline(FORM_LINK_OPTION_LIST_MESSAGE); + *prev_target = '\0'; + QueryTotal = (search_queries ? HTList_count(search_queries) + : 0); + recall = ((QueryTotal >= 1) ? RECALL : NORECALL); + QueryNum = QueryTotal; + if (ReDraw == TRUE) { + ReDraw = FALSE; + goto redraw; + } + break; + case LYK_QUIT: case LYK_ABORT: case LYK_PREV_DOC: case 7: /* Control-G */ case 3: /* Control-C */ cur_selection = orig_selection; - cmd=LYK_ACTIVATE; /* to exit */ + cmd = LYK_ACTIVATE; /* to exit */ break; } @@ -706,4 +1046,3 @@ redraw: return(cur_selection); } - diff --git a/src/LYGetFile.c b/src/LYGetFile.c index 81d0d945..cd8ef577 100644 --- a/src/LYGetFile.c +++ b/src/LYGetFile.c @@ -53,28 +53,28 @@ extern BOOLEAN LYDidRename; PRIVATE char * LYSanctify ARGS1(char *, href) { int i; - char *p,*cp,*tp; + char *p, *cp, *tp; char address_buffer[1024]; - i = strlen(href) - 1; + i = (strlen(href) - 1); while (i && href[i] == '/') href[i--] = '\0'; - if ((cp = (char *) strchr(href,'~')) != NULL) { - if (!strncmp(href,"file://localhost/",17)) - tp = href + 17; + if ((cp = (char *)strchr(href,'~')) != NULL) { + if (!strncmp(href, "file://localhost/", 17)) + tp = (href + 17); else - tp = href + 5; - if ((cp-tp) && *(cp-1) != '/') + tp = (href + 5); + if ((cp - tp) && *(cp-1) != '/') return href; - LYstrncpy(address_buffer,href,cp-href); - if (address_buffer[strlen(address_buffer)-1] == '/') - address_buffer[strlen(address_buffer)-1] = '\0'; + LYstrncpy(address_buffer, href, (cp - href)); + if (address_buffer[(strlen(address_buffer) - 1)] == '/') + address_buffer[(strlen(address_buffer) - 1)] = '\0'; p = (char *)Home_Dir(); - strcat(address_buffer,p); + strcat(address_buffer, p); if (strlen(++cp)) - strcat(address_buffer,cp); - if (strcmp(href,address_buffer)) - StrAllocCopy(href,address_buffer); + strcat(address_buffer, cp); + if (strcmp(href, address_buffer)) + StrAllocCopy(href, address_buffer); } return href; } @@ -92,6 +92,7 @@ Try_Redirected_URL: 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; /* reset WWW_Download_File just in case */ @@ -133,7 +134,8 @@ Try_Redirected_URL: } if (traversal) { /* only traverse http URLs */ - if (url_type != HTTP_URL_TYPE) + if (url_type != HTTP_URL_TYPE && + url_type != LYNXIMGMAP_URL_TYPE) return(NULLFILE); } else if (check_realm && !LYPermitURL && !LYJumpFileURL) { if (!(0==strncmp(startrealm, WWWDoc.address, @@ -237,6 +239,7 @@ Try_Redirected_URL: 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; if (!HTLoadAbsolute(&WWWDoc)) @@ -266,6 +269,7 @@ Try_Redirected_URL: 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; if (!HTLoadAbsolute(&WWWDoc)) { @@ -283,10 +287,8 @@ Try_Redirected_URL: doc->address+9, ALWAYS_EXEC_PATH)) { statusline(EXECUTION_DISABLED); sleep(MessageSecs); - } else if (no_bookmark_exec && bookmark_page && - (strstr(HTLoadedDocumentURL(), bookmark_page) || - !strcmp(HTLoadedDocumentTitle(), - MOSAIC_BOOKMARK_TITLE))) { + } else if (no_bookmark_exec && + HTLoadedDocumentBookmark()) { statusline(BOOKMARK_EXEC_DISABLED); sleep(MessageSecs); } else if (local_exec || (local_exec_on_local_files && @@ -476,6 +478,7 @@ Try_Redirected_URL: 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; status = HTLoadAbsolute(&WWWDoc); } @@ -639,51 +642,80 @@ Try_Redirected_URL: */ { char *pound; - /* check for #selector */ + /* + * Check for #selector. + */ pound = (char *)strchr(doc->address, '#'); - /* check to see if there is a temp - * file waiting for us to download + /* + * Check to see if there is a temp + * file waiting for us to download. */ if (WWW_Download_File) { - HTMLSetCharacterHandling(current_char_set); - if (LYdownload_options(&doc->address, - WWW_Download_File) < 0) - return(NOT_FOUND); - WWWDoc.address = doc->address; - FREE(WWWDoc.post_data); - FREE(WWWDoc.post_content_type); - WWWDoc.isHEAD = FALSE; - HTOutputFormat = WWW_PRESENT; - if (!HTLoadAbsolute(&WWWDoc)) - return(NOT_FOUND); - else - return(NORMAL); + HTParentAnchor *tmpanchor; + char *fname = NULL; + + HTMLSetCharacterHandling(current_char_set); + /* + * Check for a suggested filename from + * the Content-Dispostion header. - FM + */ + if (((tmpanchor = HTAnchor_parent( + HTAnchor_findAddress(&WWWDoc) + )) != NULL) && + HTAnchor_SugFname(tmpanchor) != NULL) { + StrAllocCopy(fname, + HTAnchor_SugFname(tmpanchor)); + } else { + StrAllocCopy(fname, doc->address); + } + if (LYdownload_options(&fname, + WWW_Download_File) < 0) { + FREE(fname); + return(NOT_FOUND); + } + StrAllocCopy(doc->address, fname); + FREE(fname); + WWWDoc.address = doc->address; + FREE(WWWDoc.post_data); + FREE(WWWDoc.post_content_type); + WWWDoc.bookmark = doc->bookmark; + WWWDoc.isHEAD = FALSE; + HTOutputFormat = WWW_PRESENT; + if (!HTLoadAbsolute(&WWWDoc)) + return(NOT_FOUND); + else + return(NORMAL); } else if (pound == NULL && - /* - * HTAnchor hash-table searches are now - * case-sensitive (hopefully, without - * anchor deletion problems), so this - * is too. - FM - */ - (strcmp(doc->address, - HTLoadedDocumentURL()) || - /* - * Also check the post_data elements. - FM - */ - strcmp(doc->post_data ? doc->post_data : "", - HTLoadedDocumentPost_data()) || - /* - * Also check the isHEAD element. - FM - */ - doc->isHEAD != HTLoadedDocumentIsHEAD())) { + /* + * HTAnchor hash-table searches are now + * case-sensitive (hopefully, without + * anchor deletion problems), so this + * is too. - FM + */ + (strcmp(doc->address, + HTLoadedDocumentURL()) || + /* + * Also check the post_data elements. - FM + */ + strcmp((doc->post_data ? + doc->post_data : ""), + HTLoadedDocumentPost_data()) || + /* + * Also check the isHEAD element. - FM + */ + doc->isHEAD != HTLoadedDocumentIsHEAD())) { HTMLSetCharacterHandling(current_char_set); - /* nothing needed to be shown */ + /* + * Nothing needed to be shown. + */ return(NULLFILE); } else { - /* may set www_search_result */ + /* + * May set www_search_result. + */ if (pound != NULL) HTFindPoundSelector(pound+1); HTMLSetCharacterHandling(current_char_set); diff --git a/src/LYGlobalDefs.h b/src/LYGlobalDefs.h index 88c84b82..5f2577c5 100644 --- a/src/LYGlobalDefs.h +++ b/src/LYGlobalDefs.h @@ -48,7 +48,7 @@ extern char *list_format; extern BOOLEAN lynx_edit_mode; extern BOOLEAN no_dired_support; extern BOOLEAN dir_list_style; -extern taglink *tagged; +extern HTList *tagged; #define FILES_FIRST 1 #define MIXED_STYLE 2 #ifdef OK_OVERRIDE @@ -81,7 +81,8 @@ extern BOOLEAN LYUseNoviceLineTwo; /* True if TOGGLE_HELP is not mapped */ #define MAX_LINE 1024 /* Hope that no window is larger than this */ extern char star_string[MAX_LINE + 1]; /* from GridText.c */ -#define STARS(n) (&star_string[(MAX_LINE-1) - (n)]) +#define STARS(n) \ + ((n) >= MAX_LINE ? star_string : &star_string[(MAX_LINE-1)] - (n)) #define DIRNAMESIZE 256 extern BOOLEAN LYShowCursor; /* show the cursor or hide it */ @@ -153,6 +154,8 @@ extern BOOLEAN no_suspend; extern BOOLEAN no_editor; extern BOOLEAN no_shell; extern BOOLEAN no_bookmark; +extern BOOLEAN no_multibook; +extern BOOLEAN no_bookmark_exec; extern BOOLEAN no_option_save; extern BOOLEAN no_print; extern BOOLEAN no_download; @@ -160,7 +163,6 @@ extern BOOLEAN no_disk_save; extern BOOLEAN no_exec; extern BOOLEAN no_lynxcgi; extern BOOLEAN exec_frozen; -extern BOOLEAN no_bookmark_exec; extern BOOLEAN no_goto; extern BOOLEAN no_goto_cso; extern BOOLEAN no_goto_file; @@ -197,6 +199,7 @@ extern char *editor; /* if non empty it enables edit mode with * the editor that is named */ extern char *jumpfile; extern char *bookmark_page; +extern char *BookmarkPage; extern char *personal_type_map; extern char *global_type_map; extern char *global_extension_map; @@ -248,5 +251,10 @@ extern BOOLEAN LYisConfiguredForX; extern char *URLDomainPrefixes; extern char *URLDomainSuffixes; extern BOOLEAN startfile_ok; +extern BOOLEAN LYSelectPopups; /* Cast popups to radio buttons? */ +extern BOOLEAN LYUseDefSelPop; /* Command line -popup toggle */ +extern int LYMultiBookmarks; /* Multi bookmark support on? */ +extern BOOLEAN LYMBMBlocked; /* Force MBM support off? */ +extern BOOLEAN LYMBMAdvanced; /* MBM statusline for ADVANCED? */ #endif /* LYGLOBALDEFS_H */ diff --git a/src/LYHistory.c b/src/LYHistory.c index d947820d..8ad69cb3 100644 --- a/src/LYHistory.c +++ b/src/LYHistory.c @@ -66,14 +66,16 @@ PUBLIC void LYpush ARGS1(document *,doc) if (nhist<MAXHIST) { history[nhist].link = doc->link; history[nhist].page = doc->line; - history[nhist].title = 0; + history[nhist].title = NULL; StrAllocCopy(history[nhist].title, doc->title); - history[nhist].address = 0; + history[nhist].address = NULL; StrAllocCopy(history[nhist].address, doc->address); - history[nhist].post_data = 0; + history[nhist].post_data = NULL; StrAllocCopy(history[nhist].post_data, doc->post_data); - history[nhist].post_content_type = 0; + history[nhist].post_content_type = NULL; StrAllocCopy(history[nhist].post_content_type, doc->post_content_type); + history[nhist].bookmark = NULL; + StrAllocCopy(history[nhist].bookmark, doc->bookmark); history[nhist].isHEAD = doc->isHEAD; nhist++; @@ -101,6 +103,8 @@ PUBLIC void LYpop ARGS1(document *,doc) doc->post_data = history[nhist].post_data; FREE(doc->post_content_type); doc->post_content_type = history[nhist].post_content_type; + FREE(doc->bookmark); + doc->bookmark = history[nhist].bookmark; doc->isHEAD = history[nhist].isHEAD; if(TRACE) @@ -124,6 +128,7 @@ PUBLIC void LYpop_num ARGS2(int,number, document *,doc) StrAllocCopy(doc->address, history[number].address); StrAllocCopy(doc->post_data, history[number].post_data); StrAllocCopy(doc->post_content_type, history[number].post_content_type); + StrAllocCopy(doc->bookmark, history[number].bookmark); doc->isHEAD = history[number].isHEAD; } } @@ -236,6 +241,7 @@ PUBLIC void historytarget ARGS1(document *,newdoc) 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; if ((HText *)HTAnchor_document( HTAnchor_parent(HTAnchor_findAddress(&WWWDoc)) diff --git a/src/LYKeymap.c b/src/LYKeymap.c index a12a471b..5ba5f6a1 100644 --- a/src/LYKeymap.c +++ b/src/LYKeymap.c @@ -750,3 +750,19 @@ PUBLIC char *key_for_func ARGS1 (int,func) } return buf; } + +/* + * This function returns TRUE if the ch is non-alphanumeric + * and maps to keyname (LYK_foo in the keymap[] array). - FM + */ +PUBLIC BOOL LYisNonAlnumKeyname ARGS2( + int, ch, + int, keyname) +{ + if ((ch >= '0' && ch <= '9') || + (ch >= 'A' && ch <= 'z') || + ch < 0 || ch > 269) + return (FALSE); + + return(keymap[ch+1] == keyname); +} diff --git a/src/LYKeymap.h b/src/LYKeymap.h index af29e432..99c38fd2 100644 --- a/src/LYKeymap.h +++ b/src/LYKeymap.h @@ -12,6 +12,7 @@ extern void set_numbers_as_arrows NOPARAMS; extern void reset_numbers_as_arrows NOPARAMS; extern void print_keymap PARAMS((char **newfile)); extern char *key_for_func PARAMS((int func)); +extern BOOLEAN LYisNonAlnumKeyname PARAMS((int ch, int keyname)); extern char keymap[]; /* main keymap matrix */ diff --git a/src/LYLocal.c b/src/LYLocal.c index 591b7ff4..95a49abc 100644 --- a/src/LYLocal.c +++ b/src/LYLocal.c @@ -5,8 +5,16 @@ Added OK_PERMIT compilation option. Support replacement of compiled-in f)ull menu configuration via DIRED_MENU definitions in lynx.cfg, so that more than one menu - can be driven by the same executable. -*/ + can be driven by the same executable. */ +/* Modified Oct-96 Klaus Weide (kweide@tezcat.com): + Changed to use the library's HTList_* functions and macros for + managing the list of tagged file URLs. + Keep track of proper level of URL escaping, so that unusual filenames + which contain #% etc. are handled properly (some HTUnEscapeSome()'s + left in to be conservative, and to document where superfluous + unescaping took place before). + Dynamic memory instead of fixed length buffers in a few cases. + Other minor changes to make things work as intended. */ #ifdef DIRED_SUPPORT @@ -19,6 +27,8 @@ #include "LYStrings.h" #include "LYStructs.h" #include "LYGetFile.h" +#include "LYHistory.h" +#include "LYUpload.h" #include "LYLocal.h" #include "LYSystem.h" @@ -30,7 +40,6 @@ #define FREE(x) if (x) {free(x); x = NULL;} -PRIVATE void clear_tags NOPARAMS; PRIVATE int my_spawn PARAMS((char *path, char **argv, char *msg)); PRIVATE char *filename PARAMS((char *prompt, char *buf, int bufsize)); @@ -39,7 +48,8 @@ PRIVATE BOOLEAN permit_location PARAMS((char * destpath, char * srcpath, char ** newpath)); #endif /* OK_PERMIT */ -PRIVATE char *render_item PARAMS((char *s, char *path, char *dir, char *buf)); +PRIVATE char *render_item PARAMS((char *s, char *path, char *dir, char *buf, + int bufsize, BOOLEAN url_syntax)); PRIVATE struct dired_menu *menu_head = NULL; struct dired_menu { @@ -129,7 +139,7 @@ struct dired_menu { #ifdef OK_ZIP { DE_DIR, "", "Package and compress", - "(using zip)", "LYNXDIRED://ZIP%f", NULL }, + "(using zip)", "LYNXDIRED://ZIP%p", NULL }, #endif /* OK_ZIP */ { DE_FILE, "", "Compress", @@ -142,11 +152,11 @@ struct dired_menu { #ifdef OK_ZIP { DE_FILE, "", "Compress", - "(using zip)", "LYNXDIRED://ZIP%f", NULL }, + "(using zip)", "LYNXDIRED://ZIP%p", NULL }, #endif /* OK_ZIP */ { DE_TAG, "", "Move all tagged items to another location.", - "", "LYNXDIRED://MOVE_TAGGED", NULL }, + "", "LYNXDIRED://MOVE_TAGGED%d", NULL }, { DE_TAG, "", "Remove all tagged files and directories.", "", "LYNXDIRED://REMOVE_TAGGED", NULL }, @@ -162,13 +172,14 @@ PRIVATE BOOLEAN remove_tagged NOARGS int c, ans; char *cp,*tp; char tmpbuf[1024]; - char testpath[512]; + char *testpath = NULL; struct stat dir_info; int count,i; - taglink *tag; + HTList *tag; char *args[5]; - if (tagged == NULL) return 0; /* should never happen */ + if (HTList_isEmpty(tagged)) /* should never happen */ + return 0; _statusline("Remove all tagged files and directories (y or n): "); c = LYgetch(); @@ -176,15 +187,14 @@ PRIVATE BOOLEAN remove_tagged NOARGS count = 0; tag = tagged; - while(ans == 'Y' && tag != NULL) { - cp = tag->name; + while(ans == 'Y' && (cp = (char *)HTList_nextObject(tag)) != NULL) { if(is_url(cp) == FILE_URL_TYPE) { /* unecessary check */ tp = cp; if(!strncmp(tp,"file://localhost",16)) tp += 16; else if(!strncmp(tp,"file:",5)) tp += 5; - strcpy(testpath,tp); + StrAllocCopy(testpath,tp); HTUnEscape(testpath); if((i = strlen(testpath)) && testpath[i-1] == '/') testpath[i-1] = '\0'; @@ -202,19 +212,25 @@ PRIVATE BOOLEAN remove_tagged NOARGS args[2] = testpath; args[3] = (char *) 0; sprintf(tmpbuf, "remove %s", testpath); - if (my_spawn(RM_PATH, args, tmpbuf) <= 0) + if (my_spawn(RM_PATH, args, tmpbuf) <= 0) { + FREE(testpath); return count; + } ++count; } } - tag = tag->next; } + FREE(testpath); clear_tags(); return count; } /* Move all tagged files and directories to a new location. */ /* Input is current directory. */ +/* The tests in this function can, at best, prevent some user mistakes - + anybody who relies on them for security is seriously misguided. + If a user has enough permissions to move a file somewhere, the same + uid with Lynx & dired can do the same thing. */ PRIVATE BOOLEAN modify_tagged ARGS1( char *, testpath) @@ -224,13 +240,15 @@ PRIVATE BOOLEAN modify_tagged ARGS1( ino_t inode; uid_t owner; char tmpbuf[1024]; - char savepath[512]; + char *savepath = NULL; + char *srcpath = NULL; struct stat dir_info; char *args[5]; - int count; - taglink *tag; + int count = 0; + HTList *tag; - if (tagged == NULL) return 0; /* should never happen */ + if (HTList_isEmpty(tagged)) /* should never happen */ + return 0; _statusline("Enter new location for tagged items: "); @@ -240,17 +258,46 @@ PRIVATE BOOLEAN modify_tagged ARGS1( /* determine the ownership of the current location */ - cp = testpath; + + /* + * This test used to always fail from the dired menu... + * changed to something that hopefully makes more sense - KW + */ + if (testpath && *testpath && 0!=strcmp(testpath,"/")) { + /* + * testpath passed in and is not empty and not + * a single "/" (which would probably be bogus) - use it + */ + cp = testpath; + } else { + /* + * Prepare to get directory path from one of the tagged files. + */ + cp = HTList_lastObject(tagged); + testpath = NULL; /* won't be needed any more in this function, + set to NULL as a flag */ + if (!cp) /* last resort, should never happen */ + cp = "/"; + } if (!strncmp(cp,"file://localhost",16)) cp += 16; else if (!strncmp(cp,"file:",5)) cp += 5; - strcpy(savepath,cp); + if (testpath==NULL) { + /* + * Get the directory containing the file or subdir. + */ + cp = strip_trailing_slash(cp); + savepath = HTParse(".", cp, PARSE_PATH+PARSE_PUNCTUATION); + } else { + StrAllocCopy(savepath, cp); + } HTUnEscape(savepath); if (stat(savepath,&dir_info) == -1) { sprintf(tmpbuf,"Unable to get status of %s ",savepath); _statusline(tmpbuf); sleep(AlertSecs); + FREE(savepath); return 0; } @@ -264,20 +311,29 @@ PRIVATE BOOLEAN modify_tagged ARGS1( /* replace ~/ references to the home directory */ if (!strncmp(tmpbuf,"~/",2)) { - cp = (char *)Home_Dir(); - strcpy(testpath,cp); - strcat(testpath,tmpbuf+1); - strcpy(tmpbuf,testpath); + char *cp1 = NULL; + StrAllocCopy(cp1, (char *)Home_Dir()); + StrAllocCat(cp1, (tmpbuf+1)); + if (strlen(cp1) > (sizeof(tmpbuf)-1)) { + sprintf(tmpbuf, "%s ", "Path too long"); + _statusline(tmpbuf); + sleep(AlertSecs); + FREE(savepath); + FREE(cp1); + return 0; + } + strcpy(tmpbuf, cp1); + FREE(cp1); } /* if path is relative prefix it with current location */ if (tmpbuf[0] != '/') { if (savepath[strlen(savepath)-1] != '/') - strcat(savepath,"/"); - strcat(savepath,tmpbuf); + StrAllocCat(savepath,"/"); + StrAllocCat(savepath,tmpbuf); } else { - strcpy(savepath,tmpbuf); + StrAllocCopy(savepath,tmpbuf); } /* stat the target location to determine type and ownership */ @@ -286,6 +342,7 @@ PRIVATE BOOLEAN modify_tagged ARGS1( sprintf(tmpbuf,"Unable to get status of %s ",savepath); _statusline(tmpbuf); sleep(AlertSecs); + FREE(savepath); return 0; } @@ -295,6 +352,7 @@ PRIVATE BOOLEAN modify_tagged ARGS1( _statusline( "Source and destination are the same location - request ignored!"); sleep(AlertSecs); + FREE(savepath); return 0; } @@ -308,35 +366,38 @@ PRIVATE BOOLEAN modify_tagged ARGS1( /* move all tagged items to the target location */ - while (tag != NULL) { - cp = tag->name; + while((cp = (char *)HTList_nextObject(tag)) != NULL) { if(!strncmp(cp,"file://localhost",16)) cp += 16; else if(!strncmp(cp,"file:",5)) cp += 5; - strcpy(testpath,cp); - HTUnEscape(testpath); + StrAllocCopy(srcpath, cp); + HTUnEscape(srcpath); - sprintf(tmpbuf,"move %s to %s",testpath,savepath); + sprintf(tmpbuf, "move %s to %s", srcpath, savepath); args[0] = "mv"; - args[1] = testpath; + args[1] = srcpath; args[2] = savepath; args[3] = (char *) 0; if (my_spawn(MV_PATH, args, tmpbuf) <= 0) break; - tag = tag->next; ++count; } + FREE(srcpath); + FREE(savepath); clear_tags(); return count; } else { _statusline("Destination has different owner! Request denied. "); sleep(AlertSecs); + FREE(srcpath); + FREE(savepath); return 0; } } else { _statusline("Destination is not a valid directory! Request denied. "); sleep(AlertSecs); + FREE(savepath); return 0; } } @@ -548,14 +609,14 @@ PUBLIC BOOLEAN local_modify ARGS2( char testpath[512]; /* a bit ridiculous */ int count; - if (tagged != NULL) { + if (!HTList_isEmpty(tagged)) { cp = doc->address; if (!strncmp(cp,"file://localhost",16)) cp += 16; else if (!strncmp(cp,"file:",5)) cp += 5; strcpy(testpath,cp); - HTUnEscape(testpath); + HTUnEscapeSome(testpath,"/"); count = modify_tagged(testpath); if (doc->link > (nlinks-count-1)) doc->link = nlinks-count-1; @@ -842,7 +903,7 @@ PUBLIC BOOLEAN local_remove ARGS1( char testpath[512]; int count,i; - if (tagged != NULL) { + if (!HTList_isEmpty(tagged)) { count = remove_tagged(); @@ -972,8 +1033,12 @@ PRIVATE BOOLEAN permit_location ARGS3( fprintf(fp0, "<Html><Head>\n<Title>%s</Title>\n</Head>\n<Body>\n", PERMIT_OPTIONS_TITLE); fprintf(fp0,"<H1>Permissions for %s</H1>\n", user_filename); - fprintf(fp0, "<Form Action=\"LYNXDIRED://PERMIT_LOCATION%s\">\n", - srcpath); + { /* prevent filenames which include '#' or '?' from messing it up */ + char * srcpath_url = HTEscape(srcpath, URL_PATH); + fprintf(fp0, "<Form Action=\"LYNXDIRED://PERMIT_LOCATION%s\">\n", + srcpath_url); + FREE(srcpath_url); + } fprintf(fp0, "<Ol><Li>Specify permissions below:<Br><Br>\n"); fprintf(fp0, "Owner:<Br>\n"); @@ -1038,7 +1103,6 @@ PRIVATE BOOLEAN permit_location ARGS3( char *args[5]; char amode[10]; - HTUnEscape(destpath); cp = destpath; while (*cp != '\0' && *cp != '?') { /* Find filename */ cp++; @@ -1048,6 +1112,8 @@ PRIVATE BOOLEAN permit_location ARGS3( } *cp++ = '\0'; /* Null terminate file name and start working on the masks */ + + HTUnEscape(destpath); /* will now operate only on filename part */ /* A couple of sanity tests */ destpath = strip_trailing_slash(destpath); @@ -1121,6 +1187,7 @@ PRIVATE BOOLEAN permit_location ARGS3( } #endif /* OK_PERMIT */ +#ifdef NOTDEFINED PUBLIC BOOLEAN is_a_file ARGS1( char *, testname) { @@ -1143,6 +1210,7 @@ PUBLIC BOOLEAN is_a_file ARGS1( else return 0; } +#endif /* NOTDEFINED */ /* display or remove a tag from a given link */ @@ -1174,19 +1242,19 @@ PUBLIC void tagflag ARGS2( } PUBLIC void showtags ARGS1( - taglink *, t) + HTList *, t) { int i; - taglink *s; - + HTList *s; + char * name; + for(i=0;i<nlinks;i++) { s = t; - while(s != NULL) { - if(!strcmp(links[i].lname,s->name)) { + while((name = HTList_nextObject(s)) != NULL) { + if(!strcmp(links[i].lname,name)) { tagflag(ON,i); break; - } else - s = s->next; + } } } } @@ -1201,18 +1269,31 @@ PUBLIC char * strip_trailing_slash ARGS1( return dirname; } -/* Perform file management operations for LYNXDIRED URL's */ - +/* +** Perform file management operations for LYNXDIRED URL's. +** Attempt to be consistent. These are (pseudo) URLs - i.e. they should +** be in URL syntax: some bytes will be URL-escaped with '%'. This is +** necessary because these (pseudo) URLs will go through some of the same +** kinds of interpretations and mutilations as real ones: HTParse, stripping +** off #fragments etc. (Some access schemes currently have special rules +** about not escaping parsing '#' "the URL way" built into HTParse, but that +** doesn't look like a clean way.) +*/ PUBLIC int local_dired ARGS1( document *, doc) { - char *line; - char *cp,*tp; + char *line_url; /* will point to doc's address, which is a URL */ + char *line = NULL; /* same as line_url, but HTUnEscaped, will be alloced */ + char *cp, *tp, *bp; char tmpbuf[256]; char buffer[512]; - line = doc->address; - HTUnEscape(line); + line_url = doc->address; + HTUnEscapeSome(line_url,"/"); /* don't mess too much with *doc */ + + StrAllocCopy(line, line_url); + HTUnEscape(line); /* _file_ (not URL) syntax, for those functions + that need it. DOn't forget to FREE it. */ /* This causes a SIGSEGV later when StrAllocCopy tries to free tp * let's make it point to NULL @@ -1226,6 +1307,7 @@ PUBLIC int local_dired ARGS1( } else if (!strncmp(line,"LYNXDIRED://INSTALL_SRC",23)) { local_install(NULL, &line[23], &tp); StrAllocCopy(doc->address, tp); + FREE(line); return 0; } else if (!strncmp(line,"LYNXDIRED://INSTALL_DEST",24)) { local_install(&line[24], NULL, &tp); @@ -1235,26 +1317,36 @@ PUBLIC int local_dired ARGS1( } else if (!strncmp(line,"LYNXDIRED://MODIFY_LOCATION",27)) { if (modify_location(&line[27])) ++LYforce_no_cache; } else if (!strncmp(line,"LYNXDIRED://MOVE_TAGGED",23)) { - if (modify_tagged(&line[23])) ++LYforce_no_cache; + if (modify_tagged(&line_url[23])) ++LYforce_no_cache; #ifdef OK_PERMIT } else if (!strncmp(line,"LYNXDIRED://PERMIT_SRC",22)) { permit_location(NULL, &line[22], &tp); - StrAllocCopy(doc->address, tp); + if (tp) /* one of the checks may have failed */ + StrAllocCopy(doc->address, tp); + FREE(line); return 0; } else if (!strncmp(line,"LYNXDIRED://PERMIT_LOCATION",27)) { - permit_location(&line[27], NULL, &tp); + permit_location(&line_url[27], NULL, &tp); #endif /* OK_PERMIT */ } else if (!strncmp(line,"LYNXDIRED://REMOVE_SINGLE",25)) { if (remove_single(&line[25])) ++LYforce_no_cache; } else if (!strncmp(line,"LYNXDIRED://REMOVE_TAGGED",25)) { if (remove_tagged()) ++LYforce_no_cache; } else if (!strncmp(line,"LYNXDIRED://UPLOAD",18)) { - if (LYUpload(line)) ++LYforce_no_cache; + /* + * They're written by LYUpload_options() HTUnEscaped, + * don't want to change that for now... so pass through + * without more unescaping. Directory names containing + * '#' will probably fail.. + */ + if (LYUpload(line_url)) ++LYforce_no_cache; } else { if (line[strlen(line)-1] == '/') line[strlen(line)-1] = '\0'; - if ((cp = strrchr(line,'/')) == NULL) + if ((cp = strrchr(line,'/')) == NULL) { + FREE(line); return 0; + } /* Construct the appropriate system command taking care to escape all path references to avoid spoofing the shell. */ @@ -1347,12 +1439,20 @@ PUBLIC int local_dired ARGS1( #ifdef OK_ZIP } else if (!strncmp(line,"LYNXDIRED://ZIP",15)) { tp = quote_pathname(line+15); - sprintf(buffer,"%s -rq %s.zip %s", ZIP_PATH, tp, tp); + *cp++ = '\0'; + bp = quote_pathname(cp); + cp = quote_pathname(line+15); + sprintf(buffer,"cd %s; %s -rq %s.zip %s", cp, ZIP_PATH, tp, bp); + FREE(cp); + FREE(bp); FREE(tp); # ifndef ARCHIVE_ONLY } else if (!strncmp(line,"LYNXDIRED://UNZIP",17)) { tp = quote_pathname(line+17); - sprintf(buffer,"%s -q %s", UNZIP_PATH, tp); + *cp = '\0'; + cp = quote_pathname(line+17); + sprintf(buffer,"cd %s; %s -q %s", cp, UNZIP_PATH, tp); + FREE(cp); FREE(tp); # endif /* !ARCHIVE_ONLY */ #endif /* OK_ZIP */ @@ -1383,6 +1483,7 @@ PUBLIC int local_dired ARGS1( } } + FREE(line); LYpop(doc); return 0; } @@ -1402,7 +1503,10 @@ PUBLIC int dired_options ARGS2( struct stat dir_info; FILE *fp0; char *cp,*tp = NULL; - char *escaped; + /* char *escaped; */ + char * dir_url = NULL; + char * path_url = NULL; + BOOLEAN nothing_tagged; int count; struct dired_menu *mp; char buf[2048]; @@ -1430,6 +1534,9 @@ PUBLIC int dired_options ARGS2( else if(!strncmp(cp,"file:",5)) cp += 5; strcpy(dir,cp); + StrAllocCopy(dir_url, cp); + if (dir_url[strlen(dir_url)-1] == '/') + dir_url[strlen(dir_url)-1] = '\0'; HTUnEscape(dir); if (dir[strlen(dir)-1] == '/') dir[strlen(dir)-1] = '\0'; @@ -1441,6 +1548,9 @@ PUBLIC int dired_options ARGS2( else if(!strncmp(cp,"file:",5)) cp += 5; strcpy(path,cp); + StrAllocCopy(path_url,cp); + if (path_url[strlen(path_url)-1] == '/') + path_url[strlen(path_url)-1] = '\0'; HTUnEscape(path); if (path[strlen(path)-1] == '/') path[strlen(path)-1] = '\0'; @@ -1449,17 +1559,22 @@ PUBLIC int dired_options ARGS2( sprintf(tmpbuf,"Unable to get status of %s ",path); _statusline(tmpbuf); sleep(AlertSecs); + FREE(dir_url); + FREE(path_url); return 0; } +#ifdef NOTDEFINED if ((cp = strrchr(path,'.')) != NULL && strlen(path) > strlen(cp)) { *cp = '\0'; tp = strrchr(path,'.'); *cp = '.'; } +#endif /* NOTDEFINED */ } else path[0] = '\0'; - escaped = (char *) HTEscape(path,(unsigned char) 4); + /*escaped = (char *) HTEscape(path,(unsigned char) 4); path_url instead- kw*/ + nothing_tagged = (HTList_isEmpty(tagged)); fprintf(fp0,"<head>\n<title>%s</title></head>\n<body>\n",DIRED_MENU_TITLE); @@ -1468,7 +1583,7 @@ PUBLIC int dired_options ARGS2( fprintf(fp0,"Current directory is %s <br>\n",dir); - if (tagged == NULL) + if (nothing_tagged) if (strlen(path)) fprintf(fp0,"Current selection is %s <p>\n",path); else @@ -1487,9 +1602,9 @@ PUBLIC int dired_options ARGS2( } for (mp = menu_head; mp != NULL; mp = mp->next) { - if (mp->cond != DE_TAG && tagged != NULL) + if (mp->cond != DE_TAG && !nothing_tagged) continue; - if (mp->cond == DE_TAG && tagged == NULL) + if (mp->cond == DE_TAG && nothing_tagged) continue; if (mp->cond == DE_DIR && (dir_info.st_mode & S_IFMT) != S_IFDIR) continue; @@ -1497,9 +1612,12 @@ PUBLIC int dired_options ARGS2( continue; if (strcmp(mp->sfx, &path[strlen(path)-strlen(mp->sfx)]) != 0) continue; - fprintf(fp0, "<a href=\"%s", render_item(mp->href, path, dir, buf)); - fprintf(fp0, "\">%s</a> ", render_item(mp->link, path, dir, buf)); - fprintf(fp0, "%s<br>\n", render_item(mp->rest, path, dir, buf)); + fprintf(fp0, "<a href=\"%s", + render_item(mp->href, path_url, dir_url, buf,2048, YES)); + fprintf(fp0, "\">%s</a> ", + render_item(mp->link, path, dir, buf,2048, NO)); + fprintf(fp0, "%s<br>\n", + render_item(mp->rest, path, dir, buf,2048, NO)); } if (uploaders != NULL) { @@ -1513,7 +1631,9 @@ PUBLIC int dired_options ARGS2( fprintf(fp0,"</body>\n"); fclose(fp0); - FREE(escaped); + /* FREE(escaped); not used any more - kw*/ + FREE(dir_url); + FREE(path_url); LYforce_no_cache = 1; @@ -1534,18 +1654,18 @@ PRIVATE int my_spawn ARGS3( int wstatus; #endif /* NeXT || AIX4 || sony_news */ - rc = 1; /* It will work */ + rc = 1; /* It will work */ + tmpbuf[0] = '\0'; /* empty buffer for alert messages */ stop_curses(); - pid = fork(); /* fork and execute rm */ + pid = fork(); /* fork and execute rm */ switch (pid) { case -1: sprintf(tmpbuf, "Unable to %s due to system error!", msg); - _statusline(tmpbuf); - sleep(AlertSecs); rc = 0; + break; /* don't fall thru! - KW */ case 0: /* child */ execv(path, argv); - exit(-1); /* execv failed, give wait() something to look at */ + exit(-1); /* execv failed, give wait() something to look at */ default: /* parent */ #if defined(NeXT) || defined(AIX4) || defined(sony_news) while (wait(&wstatus) != pid) @@ -1557,8 +1677,6 @@ PRIVATE int my_spawn ARGS3( WTERMSIG(wstatus) != 0) { /* error return */ sprintf(tmpbuf, "Probable failure to %s due to system error!", msg); - _statusline(tmpbuf); - sleep(AlertSecs); rc = 0; } } @@ -1568,7 +1686,19 @@ PRIVATE int my_spawn ARGS3( HadVMSInterrupt = FALSE; } #endif /* VMS */ + + if (rc == 0) { + /* + * Screen may have message from the failed execv'd command. + * Give user time to look at it before screen refresh. + */ + sleep(AlertSecs); + } start_curses(); + if (tmpbuf[0]) { + _statusline(tmpbuf); + sleep(AlertSecs); + } return(rc); } @@ -1616,7 +1746,7 @@ PUBLIC BOOLEAN local_install ARGS3( static char savepath[512]; /* this will be the link that is to be installed */ struct stat dir_info; char *args[5]; - taglink *tag; + HTList *tag; int count = 0; /* Determine the status of the selected item. */ @@ -1671,40 +1801,39 @@ PUBLIC BOOLEAN local_install ARGS3( args[3] = (char *) 0; sprintf(tmpbuf, "install %s", destpath); tag = tagged; - for (;;) { - if (tagged) { - args[1] = tag->name; - if (strncmp("file://localhost", args[1], 16) == 0) - args[1] = tag->name + 16; - } else - args[1] = savepath; - if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0) - return count; - count++; - if (!tagged) - break; - tag = tag->next; - if (!tag) - break; + if (HTList_isEmpty(tagged)) { + args[1] = savepath; + if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0) + return count; + count++; + } else { + char * name; + while ((name = (char *)HTList_nextObject(tag))) { + args[1] = name; + if (strncmp("file://localhost", args[1], 16) == 0) + args[1] = name + 16; + + if (my_spawn(INSTALL_PATH, args, tmpbuf) <= 0) + return count; + count++; + } + clear_tags(); } - if (tagged) - clear_tags(); statusline("Installation complete"); sleep(InfoSecs); return count; } -PRIVATE void clear_tags NOARGS +PUBLIC void clear_tags NOARGS { - taglink *t1; + char *cp = NULL; - while((t1=tagged) != NULL) { - tagged = tagged->next; - FREE(t1->name); - FREE(t1); + while ((cp = HTList_removeLastObject(tagged)) != NULL) { + FREE(cp); } - tagged = NULL; + if (HTList_isEmpty(tagged)) + FREE(tagged); } PUBLIC void add_menu_item ARGS1( @@ -1758,34 +1887,50 @@ PUBLIC void add_menu_item ARGS1( menu_head = new; } -PRIVATE char * render_item ARGS4( +PRIVATE char * render_item ARGS6( char *, s, char *, path, char *, dir, - char *, buf) + char *, buf, + int, bufsize, + BOOLEAN, url_syntax) { char *cp; char *bp; - taglink *t1; - char *taglist; + char overrun = '\0'; + char *taglist = NULL; +#define BP_INC (bp>buf+bufsize-2 ? &overrun : bp++) + /* Buffer overrun could happen for very long + tag list, if %l or %t are used */ bp = buf; - while (*s) { + while (*s && !overrun) { if (*s == '%') { s++; switch (*s) { case '%': - *bp++ = '%'; + *BP_INC = '%'; +#ifdef NOTDEFINED + /* + * These chars come from lynx.cfg or the default, let's + * just assume there won't be any improper %'s there that + * would need escaping. + */ + if(url_syntax) { + *BP_INC = '2'; + *BP_INC = '5'; + } +#endif /* NOTDEFINED */ break; case 'p': cp = path; while (*cp) - *bp++ = *cp++; + *BP_INC = *cp++; break; case 'd': cp = dir; while (*cp) - *bp++ = *cp++; + *BP_INC = *cp++; break; case 'f': cp = strrchr(path, '/'); @@ -1794,32 +1939,59 @@ PRIVATE char * render_item ARGS4( else cp = path; while (*cp) - *bp++ = *cp++; + *BP_INC = *cp++; break; case 'l': case 't': - FREE(taglist); - for (t1=tagged; t1 != NULL; t1 = t1->next) { - if (*s == 'l' && (cp = strrchr(t1->name, '/'))) - cp++; - else - cp = t1->name; - StrAllocCat(taglist, cp); - StrAllocCat(taglist, " "); + if (!HTList_isEmpty(tagged)) { + HTList *cur = tagged; + char *name; + + while(!overrun && + (name = (char *)HTList_nextObject(cur))!=NULL) { + if (*s == 'l' && (cp = strrchr(name, '/'))) + cp++; + else + cp = name; + StrAllocCat(taglist, cp); + StrAllocCat(taglist, " "); /* should this be %20?*/ + } + } + if (taglist) { + /* could HTUnescape here... */ + cp = taglist; + while (*cp) + *BP_INC = *cp++; + FREE(taglist); } - cp = taglist; - while (*cp) - *bp++ = *cp++; break; default: - *bp++ = '%'; - *bp++ =*s; + *BP_INC = '%'; +#ifdef NOTDEFINED + if (url_syntax) { + *BP_INC = '2'; + *BP_INC = '5'; + } +#endif /* NOTDEFINED */ + *BP_INC =*s; break; } - } else - *bp++ =*s; + } else { + /* + * Other chars come from the lynx.cfg or + * the default. Let's assume there isn't + * anything weird there that needs escaping. + */ + *BP_INC =*s; + } s++; } + if (overrun & url_syntax) { + sprintf(buf,"Temporary URL or list would be too long."); + _statusline(buf); + sleep(AlertSecs); + bp = buf; /* set to start, will return empty string as URL */ + } *bp = '\0'; return buf; } diff --git a/src/LYLocal.h b/src/LYLocal.h index 6771898b..66dbff4d 100644 --- a/src/LYLocal.h +++ b/src/LYLocal.h @@ -40,6 +40,9 @@ extern BOOLEAN local_modify PARAMS((document *doc, char **newpath)); extern BOOLEAN local_remove PARAMS((document *doc)); extern BOOLEAN local_install PARAMS((char *destpath, char *srcpath, char **newpath)); +/* MainLoop needs to know about this one for atexit cleanup */ +extern void clear_tags NOPARAMS; + /* Define the PRIVATE routines in case they ever go PUBLIC extern BOOLEAN modify_name PARAMS((char *testpath)); @@ -49,10 +52,10 @@ extern BOOLEAN create_directory PARAMS((char *testpath)); extern BOOLEAN modify_tagged PARAMS((char *testpath)); extern BOOLEAN remove_tagged NOPARAMS; extern BOOLEAN remove_single PARAMS ((char *testpath)); -*/ extern BOOLEAN is_a_file PARAMS((char *testname)); +*/ extern void tagflag PARAMS((int flag, int cur)); -extern void showtags PARAMS((taglink *tag)); +extern void showtags PARAMS((HTList *tag)); extern char * strip_trailing_slash PARAMS((char * dirname)); extern int local_dired PARAMS((document *doc)); extern int dired_options PARAMS ((document *doc, char ** newfile)); diff --git a/src/LYMail.c b/src/LYMail.c index fdb2efea..094e6da8 100644 --- a/src/LYMail.c +++ b/src/LYMail.c @@ -22,8 +22,11 @@ PRIVATE void remove_tildes PARAMS((char *string)); /* ** mailform() sends form content to the mailto address(es). - FM */ -PUBLIC void mailform ARGS3(char *,mailto_address, char *,mailto_subject, - char *,mailto_content) +PUBLIC void mailform ARGS4( + char *, mailto_address, + char *, mailto_subject, + char *, mailto_content, + char *, mailto_type) { FILE *fd; char *address = NULL; @@ -46,42 +49,31 @@ PUBLIC void mailform ARGS3(char *,mailto_address, char *,mailto_subject, StrAllocCopy(address, mailto_address); /* - * Check for a ?subject=foo. - FM + * Check for a ?searchpart with subject=foo. - FM */ subject[0] = '\0'; - if ((cp = strchr(address, '?')) != NULL && - strcasecomp(cp+1, "subject=")) { - *cp = '\0'; - cp += 9; - strncpy(subject, cp, 70); - subject[70] = '\0'; - HTUnEscape(subject); - } - - /* - * Unescape any hex escaped pounds. - FM - */ - while ((cp1 = strstr(address, "%23")) != NULL) { - *cp1 = '#'; - cp0 = (cp1 + 1); - cp1 = (cp0 + 2); - for (i = 0; cp1[i]; i++) { - cp0[i] = cp1[i]; + if ((cp = strchr(address, '?')) != NULL) { + *cp++ = '\0'; + while (*cp != '\0' && strncasecomp(cp, "subject=", 8)) + cp++; + cp0 = (cp - 1); + if ((*cp != '\0') && + (*cp0 == '\0' || *cp0 == '&' || *cp0 == ';')) { + if ((cp1 = strchr(cp, '&')) != NULL) { + *cp1 = '\0'; + } else if ((cp1 = strchr(cp, ';')) != NULL) { + *cp1 = '\0'; + } + strncpy(subject, cp, 70); + subject[70] = '\0'; + HTUnEscape(subject); } - cp0[i] = '\0'; } /* - * Unescape any hex escaped percents. - FM + * Unescape the address field. - FM */ - while ((cp1 = strstr(address, "%25")) != NULL) { - cp0 = (cp1 + 1); - cp1 = (cp0 + 2); - for (i = 0; cp1[i]; i++) { - cp0[i] = cp1[i]; - } - cp0[i] = '\0'; - } + HTUnEscape(address); /* * Convert any Explorer semi-colon Internet address @@ -134,6 +126,10 @@ PUBLIC void mailform ARGS3(char *,mailto_address, char *,mailto_subject, return; } + if (mailto_type && *mailto_type) { + fprintf(fd, "Mime-Version: 1.0\n"); + fprintf(fd, "Content-Type: %s\n", mailto_type); + } fprintf(fd,"To: %s\n", address); if (personal_mail_address && *personal_mail_address) fprintf(fd,"From: %s\n", personal_mail_address); @@ -141,13 +137,21 @@ PUBLIC void mailform ARGS3(char *,mailto_address, char *,mailto_subject, _statusline(SENDING_FORM_CONTENT); #endif /* UNIX */ #ifdef VMS - sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail."); + sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail.txt"); if ((fd = fopen(tmpfile,"w")) == NULL) { HTAlert(FORM_MAILTO_FAILED); FREE(address); return; } - + 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); + } #endif /* VMS */ /* @@ -242,35 +246,15 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address, StrAllocCopy(address, owner_address); /* - * Check for a ?subject=foo and trim it. - FM + * Check for a ?searchpart and trim it. - FM */ - if ((cp = strchr(address, '?')) != NULL && strcasecomp(cp+1, "subject=")) + if ((cp = strchr(address, '?')) != NULL && strchr(cp+1, '=') != NULL) *cp = '\0'; /* - * Unescape any hex escaped pounds. - FM - */ - while((cp1 = strstr(address, "%23")) != NULL) { - *cp1 = '#'; - cp0 = (cp1 + 1); - cp1 = (cp0 + 2); - for (i = 0; cp1[i]; i++) { - cp0[i] = cp1[i]; - } - cp0[i] = '\0'; - } - - /* - * Unescape any hex escaped percents. - FM + * Unescape the address field. - FM */ - while ((cp1 = strstr(address, "%25")) != NULL) { - cp0 = (cp1 + 1); - cp1 = (cp0 + 2); - for (i = 0; cp1[i]; i++) { - cp0[i] = cp1[i]; - } - cp0[i] = '\0'; - } + HTUnEscape(address); /* * Convert any Explorer semi-colon Internet address @@ -304,7 +288,7 @@ PUBLIC void mailmsg ARGS4(int,cur, char *,owner_address, fprintf(fd,"X-Mailer: Lynx, Version %s\n\n",LYNX_VERSION); #endif /* UNIX */ #ifdef VMS - sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail."); + sprintf(tmpfile,"%s%s",lynx_temp_space, "temp_mail.txt"); if ((fd = fopen(tmpfile,"w")) == NULL) { FREE(address); return; @@ -417,22 +401,39 @@ PUBLIC void reply_by_mail ARGS3( } tempname(tmpfile,NEW_FILE); + if (((cp = strrchr(tmpfile, '.')) != NULL) && +#ifdef VMS + NULL == strchr(cp, ']') && +#endif /* VMS */ + NULL == strchr(cp, '/')) { + *cp = '\0'; + strcat(tmpfile, ".txt"); + } if ((fd = fopen(tmpfile,"w")) == NULL) { HTAlert(MAILTO_URL_TEMPOPEN_FAILED); return; } /* - * Check for a ?subject=foo. - FM + * Check for a ?searchpart with subject=foo. - FM */ subject[0] = '\0'; - if ((cp = strchr(address, '?')) != NULL && - strcasecomp(cp+1, "subject=")) { - *cp = '\0'; - cp += 9; - strncpy(subject, cp, 70); - subject[70] = '\0'; - HTUnEscape(subject); + if ((cp = strchr(address, '?')) != NULL) { + *cp++ = '\0'; + while (*cp != '\0' && strncasecomp(cp, "subject=", 8)) + cp++; + cp0 = (cp - 1); + if ((*cp != '\0') && + (*cp0 == '\0' || *cp0 == '&' || *cp0 == ';')) { + if ((cp1 = strchr(cp, '&')) != NULL) { + *cp1 = '\0'; + } else if ((cp1 = strchr(cp, ';')) != NULL) { + *cp1 = '\0'; + } + strncpy(subject, cp, 70); + subject[70] = '\0'; + HTUnEscape(subject); + } } if (subject[0] == '\0' && title && *title) { strncpy(subject, title, 70); @@ -440,31 +441,11 @@ PUBLIC void reply_by_mail ARGS3( } /* - * Unescape any hex escaped pounds. - FM + * Unescape the address field. - FM */ - while ((cp1 = strstr(address, "%23")) != NULL) { - *cp1 = '#'; - cp0 = (cp1 + 1); - cp1 = (cp0 + 2); - for (i = 0; cp1[i]; i++) { - cp0[i] = cp1[i]; - } - cp0[i] = '\0'; - } + HTUnEscape(address); /* - * Unescape any hex escaped percents. - FM - */ - while ((cp1 = strstr(address, "%25")) != NULL) { - cp0 = (cp1 + 1); - cp1 = (cp0 + 2); - for (i = 0; cp1[i]; i++) { - cp0[i] = cp1[i]; - } - cp0[i] = '\0'; - } - - /* * Convert any Explorer semi-colon Internet address * separators to commas. - FM */ diff --git a/src/LYMail.h b/src/LYMail.h index 9dd72931..b14ab5f4 100644 --- a/src/LYMail.h +++ b/src/LYMail.h @@ -1,5 +1,4 @@ - #ifndef LYMAIL_H #define LYMAIL_H @@ -7,13 +6,19 @@ #include "LYStructs.h" #endif /* LYSTRUCTS_H */ -extern void mailform PARAMS((char *mailto_address, char *mailto_subject, - char *mailto_content)); -extern void mailmsg PARAMS((int cur, char *owner_address, - char *filename, char *linkname)); -extern void reply_by_mail PARAMS((char *mail_address, - char *filename, char *title)); - +extern void mailform PARAMS(( + char * mailto_address, + char * mailto_subject, + char * mailto_content, + char * mailto_type)); +extern void mailmsg PARAMS(( + int cur, + char * owner_address, + char * filename, + char * linkname)); +extern void reply_by_mail PARAMS(( + char * mail_address, + char * filename, + char * title)); #endif /* LYMAIL_H */ - diff --git a/src/LYMain.c b/src/LYMain.c index fe4703ca..963a528a 100644 --- a/src/LYMain.c +++ b/src/LYMain.c @@ -1,10 +1,15 @@ #include "HTUtils.h" #include "tcp.h" -#include "HTInit.h" +#include "HTParse.h" +#include "HTAccess.h" +#include "HTList.h" #include "HTFile.h" +#ifdef VMS +#include "HTVMSUtils.h" +#endif /* VMS */ +#include "HTInit.h" #include "LYCurses.h" #include "HTML.h" -#include "HTAccess.h" #include "LYUtils.h" #include "LYGlobalDefs.h" #include "LYSignal.h" @@ -16,12 +21,9 @@ #include "LYReadCFG.h" #include "LYrcFile.h" #include "LYKeymap.h" -#include "HTParse.h" -#ifdef VMS -#include "HTVMSUtils.h" -#endif /* VMS */ #include "LYList.h" #include "LYJump.h" +#include "LYBookmark.h" #ifndef VMS #ifdef SYSLOG_REQUESTED_URLS @@ -83,7 +85,7 @@ PUBLIC char *syslog_txt = NULL; /* syslog arb text for session */ PUBLIC BOOLEAN lynx_edit_mode = FALSE; PUBLIC BOOLEAN no_dired_support = FALSE; PUBLIC BOOLEAN dir_list_style = MIXED_STYLE; -PUBLIC taglink *tagged = NULL; +PUBLIC HTList *tagged = NULL; #ifdef OK_OVERRIDE PUBLIC BOOLEAN prev_lynx_edit_mode = FALSE; #endif /* OK_OVERRIDE */ @@ -177,6 +179,8 @@ PUBLIC BOOLEAN no_suspend = FALSE; PUBLIC BOOLEAN no_editor = FALSE; PUBLIC BOOLEAN no_shell = FALSE; PUBLIC BOOLEAN no_bookmark = FALSE; +PUBLIC BOOLEAN no_multibook = FALSE; +PUBLIC BOOLEAN no_bookmark_exec = FALSE; PUBLIC BOOLEAN no_option_save = FALSE; PUBLIC BOOLEAN no_print = FALSE; PUBLIC BOOLEAN no_download = FALSE; @@ -184,7 +188,6 @@ PUBLIC BOOLEAN no_disk_save = FALSE; PUBLIC BOOLEAN no_exec = FALSE; PUBLIC BOOLEAN no_lynxcgi = FALSE; PUBLIC BOOLEAN exec_frozen = FALSE; -PUBLIC BOOLEAN no_bookmark_exec = FALSE; PUBLIC BOOLEAN no_goto = FALSE; PUBLIC BOOLEAN no_goto_cso = FALSE; PUBLIC BOOLEAN no_goto_file = FALSE; @@ -220,7 +223,8 @@ PUBLIC char *homepage = NULL; /* home page or main screen */ PUBLIC char *editor = NULL; /* the name of the current editor */ PUBLIC char *jumpfile = NULL; /* the name of the default jumps file */ PUBLIC char *jumpprompt = NULL; /* the default jumps prompt */ -PUBLIC char *bookmark_page = NULL; /* the name of the current bookmark page */ +PUBLIC char *bookmark_page = NULL; /* the name of the default bookmark page */ +PUBLIC char *BookmarkPage = NULL; /* the name of the current bookmark page */ PUBLIC char *startfile = NULL; /* the first file */ PUBLIC char *helpfile = NULL; /* the main help file */ PUBLIC char *helpfilepath = NULL; /* the path to the help file set */ @@ -276,9 +280,9 @@ PUBLIC int more = FALSE; /* is there more text to display? */ PUBLIC int InfoSecs; /* Seconds to sleep() for Information messages */ PUBLIC int MessageSecs; /* Seconds to sleep() for important Messages */ PUBLIC int AlertSecs; /* Seconds to sleep() for HTAlert() messages */ -PUBLIC BOOLEAN bookmark_start=FALSE; -PUBLIC char *LYUserAgent=NULL; /* Lynx User-Agent header */ -PUBLIC char *LYUserAgentDefault=NULL; /* Lynx default User-Agent header */ +PUBLIC BOOLEAN bookmark_start = FALSE; +PUBLIC char *LYUserAgent = NULL; /* Lynx User-Agent header */ +PUBLIC char *LYUserAgentDefault = NULL; /* Lynx default User-Agent header */ PUBLIC BOOLEAN LYNoRefererHeader=FALSE; /* Never send Referer header? */ PUBLIC BOOLEAN LYNoRefererForThis=FALSE;/* No Referer header for this URL? */ PUBLIC BOOLEAN LYNoFromHeader=FALSE; /* Never send From header? */ @@ -288,6 +292,11 @@ PUBLIC BOOLEAN LYisConfiguredForX = FALSE; PUBLIC char *URLDomainPrefixes = NULL; PUBLIC char *URLDomainSuffixes = NULL; PUBLIC BOOLEAN startfile_ok = FALSE; +PUBLIC BOOLEAN LYSelectPopups = USE_SELECT_POPUPS; +PUBLIC BOOLEAN LYUseDefSelPop = TRUE; /* Command line -popup toggle */ +PUBLIC int LYMultiBookmarks = MULTI_BOOKMARK_SUPPORT; +PUBLIC BOOLEAN LYMBMBlocked = BLOCK_MULTI_BOOKMARKS; +PUBLIC BOOLEAN LYMBMAdvanced = ADVANCED_MULTI_BOOKMARKS; /* These are declared in cutil.h for current freeWAIS libraries. - FM */ #ifdef DECLARE_WAIS_LOGFILES @@ -367,6 +376,11 @@ PRIVATE void free_lynx_globals NOARGS FREE(helpfilepath); FREE(aboutfilepath); FREE(bookmark_page); + FREE(BookmarkPage); + for (i = 0; i <= MBM_V_MAXFILES; i++) { + FREE(MBM_A_subbookmark[i]); + FREE(MBM_A_subdescript[i]); + } FREE(editor); FREE(authentication_info[0]); FREE(authentication_info[1]); @@ -431,14 +445,23 @@ PUBLIC int main ARGS2(int,argc, char **,argv) * Initialize our startup and global variables. */ #ifdef ULTRIX - /* Need this for ultrix. */ + /* + * Need this for ultrix. + */ terminal = getenv("TERM"); if ((terminal == NULL) || !strncasecomp(terminal, "xterm", 5)) terminal = "vt100"; #endif /* ULTRIX */ - /* Zero the links and history struct array. */ + /* + * Zero the links and history struct arrays. + */ memset((void *)links, 0, sizeof(linkstruct)*MAXLINKS); memset((void *)history, 0, sizeof(histstruct)*MAXHIST); + /* + * Zero the MultiBookmark arrays. + */ + memset((void *)MBM_A_subbookmark, 0, sizeof(char)*(MBM_V_MAXFILES+1)); + memset((void *)MBM_A_subdescript, 0, sizeof(char)*(MBM_V_MAXFILES+1)); #ifndef VMS #ifdef SYSLOG_REQUESTED_URLS openlog("lynx", LOG_PID, LOG_LOCAL5); @@ -840,10 +863,36 @@ PUBLIC int main ARGS2(int,argc, char **,argv) if (keypad_mode == NUMBERS_AS_ARROWS) set_numbers_as_arrows(); - /* disable news posting if no posting command */ + /* + * Check the -popup command line toggle. - FM + */ + if (LYUseDefSelPop == FALSE) { + if (LYSelectPopups == TRUE) + LYSelectPopups = FALSE; + else + LYSelectPopups = TRUE; + } + + /* + * Disable news posting if no posting command. + */ if (*inews_path == '\0' || !strcasecomp(inews_path,"none")) no_newspost = TRUE; + /* + * Disable multiple bookmark support if not interactive, + * so it doesn't crash on curses functions, or if the + * support was blocked via userdefs.h and/or lynx.cfg, + * or via command line restrictions. - FM + */ + if (no_multibook) + LYMBMBlocked = TRUE; + if (dump_output_immediately || LYMBMBlocked || no_multibook) { + LYMultiBookmarks = FALSE; + LYMBMBlocked = TRUE; + no_multibook == TRUE; + } + #ifdef VMS set_vms_keys(); #endif /* VMS */ @@ -1015,6 +1064,9 @@ PUBLIC int main ARGS2(int,argc, char **,argv) if (!homepage) StrAllocCopy(homepage, startfile); + /* + * Set up the inside/outside domain restriction flags. - FM + */ if (inlocaldomain()) { #if defined(NO_UTMP) || defined(VMS) /* not selective */ telnet_ok = !no_inside_telnet && !no_outside_telnet && telnet_ok; @@ -1039,12 +1091,15 @@ PUBLIC int main ARGS2(int,argc, char **,argv) } #ifdef SIGTSTP + /* + * Block Control-Z suspending if requested. - FM + */ if (no_suspend) (void) signal(SIGTSTP,SIG_IGN); #endif /* SIGTSTP */ /* - * Here's where we do all the work. + * Check for a valid HEAD request. - FM */ if (HEAD_request && strncmp(startfile, "http", 4)) { fprintf(stderr, @@ -1061,6 +1116,10 @@ PUBLIC int main ARGS2(int,argc, char **,argv) #endif /* SIGTSTP */ exit(-1); } + + /* + * Check for a valid MIME headers request. - FM + */ if (keep_mime_headers && strncmp(startfile, "http", 4)) { fprintf(stderr, "The '-mime_header' switch is for http URLs and cannot be used for\n'%s'.\n", @@ -1076,6 +1135,10 @@ PUBLIC int main ARGS2(int,argc, char **,argv) #endif /* SIGTSTP */ exit(-1); } + + /* + * Check for a valid traversal request. - FM + */ if (traversal && strncmp(startfile, "http", 4)) { fprintf(stderr, "The '-traversal' switch is for http URLs and cannot be used for\n'%s'.\n", @@ -1091,6 +1154,10 @@ PUBLIC int main ARGS2(int,argc, char **,argv) #endif /* SIGTSTP */ exit(-1); } + + /* + * Set up our help and about file base paths. - FM + */ StrAllocCopy(helpfilepath, helpfile); if ((cp=strrchr(helpfilepath, '/')) != NULL) *cp = '\0'; @@ -1100,9 +1167,32 @@ PUBLIC int main ARGS2(int,argc, char **,argv) StrAllocCat(aboutfilepath, "/about_lynx/"); } StrAllocCat(helpfilepath, "/"); - if (!bookmark_page || *bookmark_page == '\0') + + + /* + * Make sure our bookmark default strings + * are all allocated and synchronized. - FM + */ + if (!bookmark_page || *bookmark_page == '\0') { StrAllocCopy(bookmark_page, "lynx_bookmarks.html"); + StrAllocCopy(BookmarkPage, bookmark_page); + StrAllocCopy(MBM_A_subbookmark[0], bookmark_page); + StrAllocCopy(MBM_A_subdescript[0], "Default"); + } + if (!BookmarkPage || *BookmarkPage == '\0') { + StrAllocCopy(BookmarkPage, bookmark_page); + StrAllocCopy(MBM_A_subbookmark[0], bookmark_page); + StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT); + } + + /* + * Here's where we do all the work. + */ if (dump_output_immediately) { + /* + * Finish setting up and start a + * NON-INTERACTIVE session. - FM + */ if (crawl && !number_links) { keypad_mode = NUMBERS_AS_ARROWS; } else if (!nolist) { @@ -1124,6 +1214,10 @@ PUBLIC int main ARGS2(int,argc, char **,argv) (void) signal(SIGTSTP,SIG_DFL); #endif /* SIGTSTP */ } else { + /* + * Finish setting up and start an + * INTERACTIVE session. - FM + */ if (setup(terminal)) { if (display != NULL && *display != '\0') { LYisConfiguredForX = TRUE; @@ -1253,6 +1347,7 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc) printf("\ jump disable the 'j' (jump) command\n\ mail disallow mail\n\ + multibook disallow multiple bookmark files\n\ news_post disallow USENET News posting setting in the O)ptions menu\n\ option_save disallow saving options in .lynxrc\n"); #if defined(NO_UTMP) || defined(VMS) /* not selective */ @@ -1345,8 +1440,8 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc) emacs_keys = TRUE; } else if (strncmp(argv[0], "-version", 8) == 0) { - printf("\n%s Version %s\n(c)GNU General Public License\n\ -<URL:http://www.nyu.edu/pages/wsn/subir/lynx.html>\n\n", + printf("\n%s Version %s\n(c)1996 GNU General Public License\n\ +<URL:http://lynx.browser.org/>\n\n", LYNX_NAME, LYNX_VERSION); exit(0); @@ -1369,6 +1464,9 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc) } else if (strncmp(argv[0], "-noreferer", 10) == 0) { LYNoRefererHeader = TRUE; + } else if (strncmp(argv[0], "-popup", 6) == 0) { + LYUseDefSelPop = FALSE; + } else if (strncmp(argv[0], "-crawl", 6) == 0) { crawl = TRUE; LYcols=80; @@ -1583,6 +1681,7 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc) /* Include mime headers and force source dump */ keep_mime_headers = TRUE; dump_output_immediately = TRUE; + HTOutputFormat = HTAtom_for("www/dump"); LYcols=999; } else if (strncmp(argv[0], "-error_file", 11) == 0) { /* Output return @@ -1726,6 +1825,8 @@ PRIVATE void parse_arg ARGS3(char **, argv, int *, i, int, argc) #endif /* SOCKS */ printf(" -nostatus disable the miscellaneous information messages\n"); printf(" -number_links force numbering of links\n"); + printf(" -popup toggles handling of single-choice SELECT options via\n"); + printf(" popup windows or as lists of radio buttons\n"); printf(" -post_data user data for post forms, read from stdin,\n"); printf(" terminated by '---' on a line\n"); printf(" -print enable print functions (DEFAULT)\n"); diff --git a/src/LYMainLoop.c b/src/LYMainLoop.c index bbef7371..83567743 100644 --- a/src/LYMainLoop.c +++ b/src/LYMainLoop.c @@ -2,8 +2,12 @@ #include "tcp.h" #include "HTAccess.h" #include "HTParse.h" +#include "HTList.h" +#include "HTFTP.h" +#include "HTTP.h" #include "LYCurses.h" #include "LYGlobalDefs.h" +#include "HTAlert.h" #include "LYUtils.h" #include "GridText.h" #include "LYStrings.h" @@ -28,9 +32,6 @@ #include "LYTraversal.h" #include "LYCharSets.h" #include "LYCharUtils.h" -#include "HTFTP.h" -#include "HTTP.h" -#include "HTAlert.h" #ifdef VMS #include "HTVMSUtils.h" @@ -80,13 +81,18 @@ PRIVATE void free_mainloop_variables NOARGS FREE(newdoc.address); FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); FREE(curdoc.title); FREE(curdoc.address); FREE(curdoc.post_data); FREE(curdoc.post_content_type); + FREE(curdoc.bookmark); FREE(traversal_host); FREE(traversal_link_to_add); FREE(CurrentUserAgent); +#ifdef DIRED_SUPPORT + clear_tags(); +#endif /* DIRED_SUPPORT */ return; } @@ -107,7 +113,8 @@ int mainloop NOARGS int newline=0; char prev_target[512]; char user_input_buffer[1024]; - char *owner_address=NULL; /* holds the responsible owner's address */ + char *owner_address=NULL; /* holds the responsible owner's address */ + char *ownerS_address=NULL; /* holds owner's address during source fetch */ BOOLEAN first_file=TRUE; BOOLEAN refresh_screen=FALSE; BOOLEAN force_load = FALSE; @@ -121,6 +128,7 @@ int mainloop NOARGS int CurrentCharSet_flag = current_char_set; BOOLEAN show_dotfiles_flag = show_dotfiles; BOOLEAN LYRawMode_flag = LYRawMode; + BOOLEAN LYSelectPopups_flag = LYSelectPopups; char cfile[128]; FILE *cfp; char *cp, *toolbar; @@ -137,7 +145,6 @@ int mainloop NOARGS char *tp; char tmpbuf[1024]; struct stat dir_info; - taglink *t1, *t2=NULL; #endif /* DIRED_SUPPORT */ /* @@ -153,12 +160,14 @@ int mainloop NOARGS newdoc.title = NULL; newdoc.post_data = NULL; newdoc.post_content_type = NULL; + newdoc.bookmark = NULL; curdoc.address = NULL; curdoc.title = NULL; curdoc.post_data = NULL; curdoc.post_content_type = NULL; + curdoc.bookmark = NULL; atexit(free_mainloop_variables); - if (strcmp(startfile, homepage)) + if (startfile && homepage && strcmp(startfile, homepage)) HTAddGotoURL(homepage); HTAddGotoURL(startfile); initialize: @@ -206,12 +215,14 @@ initialize: goto initialize; } else { /* - * See if a bookmark page exists. If it does, - * replace newdoc.address with it's name + * See if a bookmark page exists. If it does, + * replace newdoc.address with it's name */ - if (get_bookmark_filename(&newdoc.address) != NULL) { + if ((cp = get_bookmark_filename(&newdoc.address)) != NULL && + *cp != '\0' && strcmp(cp, " ")) { LYforce_HTML_mode = TRUE; /* force HTML */ - StrAllocCopy(newdoc.title, "Bookmark File"); + StrAllocCopy(newdoc.title, BOOKMARK_TITLE); + StrAllocCopy(newdoc.bookmark, BookmarkPage); StrAllocCopy(startrealm, newdoc.address); FREE(newdoc.post_data); FREE(newdoc.post_content_type); @@ -276,14 +287,18 @@ try_again: /* * Make SURE this is an appropriate request. - FM */ - if (!strncmp(newdoc.address, "http", 4)) + if (newdoc.address && + !strncmp(newdoc.address, "http", 4)) newdoc.isHEAD = TRUE; HEAD_request = FALSE; } LYRequestTitle = newdoc.title; + if (newdoc.bookmark) + LYforce_HTML_mode = TRUE; if (LYValidate && startfile_ok && + newdoc.address && startfile && homepage && (!strcmp(newdoc.address, startfile) || !strcmp(newdoc.address, homepage))) { LYPermitURL = TRUE; @@ -366,6 +381,7 @@ try_again: */ LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */ FREE(newdoc.address); /* to pop last doc */ + FREE(newdoc.bookmark); LYJumpFileURL = FALSE; reloading = FALSE; LYPermitURL = FALSE; @@ -394,10 +410,11 @@ try_again: */ if (first_file && homepage && #ifdef VMS - strcasecomp(homepage, startfile) != 0) { + strcasecomp(homepage, startfile) != 0) #else - strcmp(homepage, startfile) != 0) { + strcmp(homepage, startfile) != 0) #endif /* VMS */ + { /* * Couldn't return to the first file but there is a * homepage we can use instead. Useful for when the @@ -411,6 +428,7 @@ try_again: StrAllocCopy(newdoc.address, homepage); FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); StrAllocCopy(startfile, homepage); newdoc.isHEAD = FALSE; } else { @@ -447,9 +465,9 @@ try_again: if (traversal) { /* - * During traversal build up lists of all links - * traversed. Traversal mode is a special - * feature for traversing http links in the web. + * During traversal build up lists of all links + * traversed. Traversal mode is a special + * feature for traversing http links in the web. */ if (traversal_link_to_add) { /* Add the address we sought to TRAVERSE_FILE */ @@ -457,7 +475,8 @@ try_again: add_to_table(traversal_link_to_add); FREE(traversal_link_to_add); } - if (curdoc.address && curdoc.title) + if (curdoc.address && curdoc.title && + strncasecomp(curdoc.address, "LYNXIMGMAP:", 11)) /* Add the address we got to TRAVERSE_FOUND_FILE */ add_to_traverse_list(curdoc.address, curdoc.title); } @@ -472,6 +491,7 @@ try_again: !strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE)) { StrAllocCopy(newdoc.address, curdoc.address); StrAllocCopy(newdoc.title, curdoc.title); + StrAllocCopy(newdoc.bookmark, curdoc.bookmark); newdoc.line = curdoc.line; newdoc.link = curdoc.link; } @@ -506,12 +526,18 @@ try_again: StrAllocCopy(curdoc.address, newdoc.address); StrAllocCopy(curdoc.post_data, newdoc.post_data); StrAllocCopy(curdoc.post_content_type, newdoc.post_content_type); + StrAllocCopy(curdoc.bookmark, newdoc.bookmark); curdoc.isHEAD = newdoc.isHEAD; /* * Reset WWW present mode so that if we were getting * the source, we get rendered HTML from now on. */ + if (ownerS_address != NULL) { + if (HTOutputFormat == WWW_SOURCE && !HText_getOwner()) + HText_setMainTextOwner(ownerS_address); + FREE(ownerS_address); + } HTOutputFormat = WWW_PRESENT; /* * Reset all of the other relevant flags. - FM @@ -595,7 +621,8 @@ try_again: * Set up the crawl output stuff. */ if (curdoc.address && !lookup(curdoc.address)) { - crawl_ok = TRUE; + if (strncasecomp(curdoc.address, "LYNXIMGMAP:", 11)) + crawl_ok = TRUE; add_to_table(curdoc.address); } /* @@ -644,7 +671,7 @@ try_again: HText_pageDisplay(newline, prev_target); #ifdef DIRED_SUPPORT - if (lynx_edit_mode && nlinks > 0 && tagged != NULL) + if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged)) showtags(tagged); #endif /* DIRED_SUPPORT */ /* if more equals true then there is more @@ -685,7 +712,7 @@ try_again: HText_pageDisplay(newline, prev_target); #ifdef DIRED_SUPPORT - if (lynx_edit_mode && nlinks > 0 && tagged != NULL) + if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged)) showtags(tagged); #endif /* DIRED_SUPPORT */ if (user_mode == NOVICE_MODE) @@ -968,10 +995,15 @@ new_keyboard_input: */ rlink_exists = (nlinks > 0 && links[curdoc.link].lname != NULL); if (rlink_exists) { - rlink_allowed = (!lookup_reject(links[curdoc.link].lname) && - !strncmp(traversal_host, - links[curdoc.link].lname, - strlen(traversal_host))); + rlink_allowed = + (!lookup_reject(links[curdoc.link].lname) && + traversal_host && links[curdoc.link].lname && + !strncmp(traversal_host, + (strncasecomp(links[curdoc.link].lname, + "LYNXIMGMAP:", 11) + ? + links[curdoc.link].lname : (links[curdoc.link].lname + 11)), + strlen(traversal_host))); } else { rlink_allowed = FALSE; } @@ -1003,7 +1035,9 @@ new_keyboard_input: } else { StrAllocCopy(traversal_link_to_add, links[curdoc.link].lname); - crawl_ok = TRUE; + if (strncasecomp(traversal_link_to_add, + "LYNXIMGMAP:", 11)) + crawl_ok = TRUE; c = RTARROW; } } else { /* no good right link, so only down and left arrow ok*/ @@ -1091,6 +1125,7 @@ new_cmd: /* a goto point for new input without going if (are_different(&curdoc, &newdoc)) { FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; } force_load = TRUE; /* force MainLoop to reload */ @@ -1107,10 +1142,13 @@ new_cmd: /* a goto point for new input without going break; case LYK_SOURCE: /* toggle view source mode */ - if (HTisDocumentSource()) + if (HTisDocumentSource()) { HTOutputFormat = WWW_PRESENT; - else + } else { + if (HText_getOwner()) + StrAllocCopy(ownerS_address, HText_getOwner()); HTOutputFormat = WWW_SOURCE; + } HTuncache_current_document(); FREE(curdoc.address); /* so it doesn't get pushed */ break; @@ -1381,7 +1419,7 @@ new_cmd: /* a goto point for new input without going } else if (old_c != real_c) { old_c = real_c; - _statusline(ALREADY_AT_FIRST); + _statusline(ALREADY_AT_BEGIN); sleep(MessageSecs); } break; @@ -1537,7 +1575,7 @@ new_cmd: /* a goto point for new input without going break; case LYK_HISTORY: /* show the history page */ - if (strcmp(curdoc.title, HISTORY_PAGE_TITLE)) { + if (curdoc.title && strcmp(curdoc.title, HISTORY_PAGE_TITLE)) { /* * Don't do this if already viewing history page. * @@ -1562,6 +1600,7 @@ new_cmd: /* a goto point for new input without going FREE(curdoc.address); /* so it doesn't get pushed */ FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; LYpop(&curdoc); @@ -1626,8 +1665,11 @@ new_cmd: /* a goto point for new input without going /* * Do nothing if it's disabled. - FM */ - if (links[curdoc.link].form->disabled == YES) + if (links[curdoc.link].form->disabled == YES) { + HTOutputFormat = WWW_PRESENT; + LYforce_no_cache = FALSE; break; + } /* * Make sure we have an action. - FM */ @@ -1636,6 +1678,8 @@ new_cmd: /* a goto point for new input without going == '\0') { _statusline(NO_FORM_ACTION); sleep(MessageSecs); + HTOutputFormat = WWW_PRESENT; + LYforce_no_cache = FALSE; break; } /* @@ -1645,6 +1689,8 @@ new_cmd: /* a goto point for new input without going if (links[curdoc.link].form->submit_method == URL_MAIL_METHOD && no_mail) { HTAlert(FORM_MAILTO_DISALLOWED); + HTOutputFormat = WWW_PRESENT; + LYforce_no_cache = FALSE; break; } /* @@ -1656,6 +1702,8 @@ new_cmd: /* a goto point for new input without going links[curdoc.link].form->submit_action, "file:", 5)) { HTAlert(FILE_ACTIONS_DISALLOWED); + HTOutputFormat = WWW_PRESENT; + LYforce_no_cache = FALSE; break; } #ifdef NOTDEFINED /* We're disabling form inputs instead of using this. - FM */ @@ -1669,6 +1717,8 @@ new_cmd: /* a goto point for new input without going "multipart/form-data")) { HTAlert( "Enctype multipart/form-data not yet supported! Cannot submit."); + HTOutputFormat = WWW_PRESENT; + LYforce_no_cache = FALSE; break; } } @@ -1697,10 +1747,7 @@ new_cmd: /* a goto point for new input without going if (strncasecomp(curdoc.address, "file:", 5)) { HTAlert(FILE_SERVED_LINKS_DISALLOWED); break; - } else if (bookmark_page && - (strstr(curdoc.address, bookmark_page) || - !strcmp(curdoc.title, - MOSAIC_BOOKMARK_TITLE))) { + } else if (curdoc.bookmark != NULL) { HTAlert(FILE_BOOKMARKS_DISALLOWED); break; } @@ -1717,16 +1764,15 @@ new_cmd: /* a goto point for new input without going if (are_different(&curdoc, &newdoc)) { FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); } - if (!no_jump && lynxjumpfile && + if (!no_jump && lynxjumpfile && curdoc.address && !strcmp(lynxjumpfile, curdoc.address)) { LYJumpFileURL = TRUE; LYUserSpecifiedURL = TRUE; - } else if (!strcmp(curdoc.title, HISTORY_PAGE_TITLE) || - (bookmark_page && - (strstr(curdoc.address, bookmark_page) || - !strcmp(curdoc.title, - MOSAIC_BOOKMARK_TITLE))) || + } else if (curdoc.title && + !strcmp(curdoc.title, HISTORY_PAGE_TITLE) || + curdoc.bookmark != NULL || (lynxjumpfile && !strcmp(lynxjumpfile, curdoc.address))) { LYUserSpecifiedURL = TRUE; @@ -1739,7 +1785,11 @@ new_cmd: /* a goto point for new input without going #ifdef DIRED_SUPPORT if (lynx_edit_mode) { HTuncache_current_document(); - HTUnEscape(newdoc.address); + /* Unescaping any slash chars in the URL, + * but avoid double unescaping and too-early + * unescaping of other chars. - KW + */ + HTUnEscapeSome(newdoc.address,"/"); strip_trailing_slash(newdoc.address); } #endif /* DIRED_SUPPORT */ @@ -1777,8 +1827,8 @@ new_cmd: /* a goto point for new input without going * Ask the user. */ _statusline(URL_TO_OPEN); - if ((ch=LYgetstr(user_input_buffer, VISIBLE, - sizeof(user_input_buffer), recall)) < 0 ) { + if ((ch = LYgetstr(user_input_buffer, VISIBLE, + sizeof(user_input_buffer), recall)) < 0 ) { /* * User cancelled the Goto via ^G. * Restore user_input_buffer and break. - FM @@ -1821,8 +1871,8 @@ check_recall: * Roll around to the last URL in the list. - FM */ URLNum = 0; - if ((cp=(char *)HTList_objectAt(Goto_URLs, - URLNum)) != NULL) { + if ((cp = (char *)HTList_objectAt(Goto_URLs, + URLNum)) != NULL) { strcpy(user_input_buffer, cp); if (goto_buffer && *temp && !strcmp(temp, user_input_buffer)) { @@ -1833,8 +1883,9 @@ check_recall: } else { _statusline(EDIT_A_PREV_GOTO); } - if ((ch=LYgetstr(user_input_buffer, VISIBLE, - sizeof(user_input_buffer), recall)) < 0) { + if ((ch = LYgetstr(user_input_buffer, VISIBLE, + sizeof(user_input_buffer), + recall)) < 0) { /* * User cancelled the Goto via ^G. * Restore user_input_buffer and break. - FM @@ -1877,8 +1928,9 @@ check_recall: } else { _statusline(EDIT_A_PREV_GOTO); } - if ((ch=LYgetstr(user_input_buffer, VISIBLE, - sizeof(user_input_buffer), recall)) < 0) { + if ((ch = LYgetstr(user_input_buffer, VISIBLE, + sizeof(user_input_buffer), + recall)) < 0) { /* * User cancelled the Goto via ^G. * Restore user_input_buffer and break. - FM @@ -2063,8 +2115,8 @@ check_recall: #ifdef VMS /* - * On VMS, a file://localhost/ URL means - * a listing for the login directory. - FM + * On VMS, a file://localhost/ URL means + * a listing for the login directory. - FM */ if (!strcmp(user_input_buffer, "file://localhost/")) strcat(user_input_buffer, @@ -2074,12 +2126,13 @@ check_recall: StrAllocCopy(newdoc.address, user_input_buffer); newdoc.isHEAD = FALSE; /* - * Might be an anchor in the same doc from a POST - * form. If so, dont't free the content. -- FM + * Might be an anchor in the same doc from a POST + * form. If so, dont't free the content. -- FM */ if (are_different(&curdoc, &newdoc)) { FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); } force_load = TRUE; LYUserSpecifiedURL = TRUE; @@ -2098,6 +2151,7 @@ check_recall: StrAllocCopy(newdoc.title, "Help Screen"); FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; } break; @@ -2118,6 +2172,7 @@ check_recall: StrAllocCopy(newdoc.title, "System Index"); /* name it */ FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; } /* end else */ } /* end if */ @@ -2177,6 +2232,7 @@ check_recall: StrAllocCopy(newdoc.title, "Entry into main screen"); FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; highlight(OFF,curdoc.link); #ifdef DIRED_SUPPORT @@ -2212,6 +2268,7 @@ check_recall: CurrentCharSet_flag != current_char_set || show_dotfiles_flag != show_dotfiles || LYRawMode_flag != LYRawMode || + LYSelectPopups_flag != LYSelectPopups || strcmp(CurrentUserAgent, (LYUserAgent ? LYUserAgent : ""))) { HTuncache_current_document(); @@ -2222,6 +2279,7 @@ check_recall: CurrentCharSet_flag = current_char_set; show_dotfiles_flag = show_dotfiles; LYRawMode_flag = LYRawMode; + LYSelectPopups_flag = LYSelectPopups; StrAllocCopy(CurrentUserAgent, (LYUserAgent ? LYUserAgent : "")); } @@ -2264,6 +2322,7 @@ check_recall: StrAllocCopy(newdoc.address, use_this_url_instead); FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; FREE(use_this_url_instead); force_load = TRUE; @@ -2318,90 +2377,124 @@ check_recall: break; case LYK_COMMENT: /* reply by mail */ - if (!owner_address) { + if (!owner_address && + strncasecomp(curdoc.address, "http", 4)) { if (old_c != real_c) { - old_c = real_c; - _statusline(NO_OWNER); - sleep(MessageSecs); + old_c = real_c; + _statusline(NO_OWNER); + sleep(MessageSecs); } - } else if (no_mail) { - if (old_c != real_c) { - old_c = real_c; - _statusline(MAIL_DISALLOWED); - sleep(MessageSecs); - } - } else { + } else if (no_mail) { + if (old_c != real_c) { + old_c = real_c; + _statusline(MAIL_DISALLOWED); + sleep(MessageSecs); + } + } else { _statusline(CONFIRM_COMMENT); c = LYgetch(); if (TOUPPER(c) == 'Y') { - - if (is_url(owner_address) != MAILTO_URL_TYPE) { - /* the address is a url */ - /* just follow the link */ - - StrAllocCopy(newdoc.address, owner_address); - - } else { - /* the owner_address is a mailto: url type */ - cp = HText_getRevTitle(); - if (strchr(owner_address,':')!=NULL) - /* send a reply. The address is after the colon */ - reply_by_mail(strchr(owner_address,':')+1, - curdoc.address, - (cp ? cp : "")); - else - reply_by_mail(owner_address, curdoc.address, - (cp ? cp : "")); - - refresh_screen=TRUE; /* to force a showpage */ - } + if (!owner_address) { + /* + * No owner defined, so make a guess and + * and offer it to the user. - FM + */ + char *address = NULL; + char *path = HTParse(curdoc.address, "", PARSE_PATH); + if (path != NULL) { + HTUnEscape(path); + if (*path == '~' && strlen(path) > 1) { + /* + * It's a ~user URL so guess user@host. - FM + */ + if ((cp = strchr((path+1), '/')) != NULL) + *cp = '\0'; + StrAllocCopy(address, "mailto:"); + StrAllocCat(address, (path+1)); + StrAllocCat(address, "@"); + } + FREE(path); + } + if (address == NULL) + /* + * Wasn't a ~user URL so guess WebMaster@host. - FM + */ + StrAllocCopy(address, "mailto:WebMaster@"); + StrAllocCat(address, + HTParse(curdoc.address, "", PARSE_HOST)); + _user_message(NO_OWNER_USE, address); + c = LYgetch(); + if (TOUPPER(c) == 'Y') { + StrAllocCopy(owner_address, address); + FREE(address); + } else { + FREE(address); + break; + } + } + if (is_url(owner_address) != MAILTO_URL_TYPE) { + /* + * The address is a URL. Just follow the link. + */ + StrAllocCopy(newdoc.address, owner_address); + } else { + /* + * The owner_address is a mailto: URL. + */ + cp = HText_getRevTitle(); + if (strchr(owner_address,':')!=NULL) + /* + * Send a reply. The address is after the colon. + */ + reply_by_mail(strchr(owner_address,':')+1, + curdoc.address, + (cp ? cp : "")); + else + reply_by_mail(owner_address, curdoc.address, + (cp ? cp : "")); + + refresh_screen=TRUE; /* to force a showpage */ + } } } break; #ifdef DIRED_SUPPORT - case LYK_TAG_LINK: /* tag or untag the current link */ - if (lynx_edit_mode && nlinks > 0 && !no_dired_support) { - if (dir_list_style == MIXED_STYLE) { - if (!strcmp(links[curdoc.link].hightext,"../")) - break; - } else if (!strncmp(links[curdoc.link].hightext,"Up to ",6)) - break; - t1 = tagged; - while (t1 != NULL) { - if (!strcmp(links[curdoc.link].lname,t1->name)) { - if (t1 == tagged) - tagged = t1->next; - else - t2->next = t1->next; - FREE(t1->name); - FREE(t1); - tagflag(OFF,curdoc.link); + case LYK_TAG_LINK: /* tag or untag the current link */ + if (lynx_edit_mode && nlinks > 0 && !no_dired_support) { + if (!strcmp(links[curdoc.link].hightext, "..")) + break; /* Never tag the parent directory */ + if (dir_list_style == MIXED_STYLE) { + if (!strcmp(links[curdoc.link].hightext, "../")) + break; + } else if (!strncmp(links[curdoc.link].hightext,"Up to ",6)) break; - } - t2 = t1; - t1 = t1->next; - } - if (t1 == NULL) { - t1 = (taglink *) malloc(sizeof(taglink)); - if (tagged == NULL) - tagged = t1; - else - t2->next = t1; - t1->next = NULL; - t1->name = NULL; - StrAllocCopy(t1->name,links[curdoc.link].lname); - tagflag(ON,curdoc.link); - } - if (curdoc.link < nlinks-1) { - highlight(OFF, curdoc.link); - curdoc.link++; - } else if (!more && newline==1 && curdoc.link==nlinks-1) { - highlight(OFF,curdoc.link); - curdoc.link = 0; - } else if (more) { /* next page */ - newline += (display_lines); - } + { + /* + * HTList-based management of tag list, see LYLocal.c - KW + */ + HTList * t1 = tagged; + char * tagname = NULL; + BOOLEAN found = FALSE; + + while ((tagname = (char *)HTList_nextObject(t1)) != NULL) { + if (!strcmp(links[curdoc.link].lname,tagname)) { + found = TRUE; + HTList_removeObject(tagged, tagname); + FREE(tagname); + tagflag(OFF,curdoc.link); + break; + } + } + if (!found) { + if (tagged == NULL) + tagged = HTList_new(); + tagname = NULL; + StrAllocCopy(tagname,links[curdoc.link].lname); + HTList_addObject(tagged,tagname); + tagflag(ON,curdoc.link); + } + } } break; @@ -2469,7 +2562,7 @@ check_recall: } else { if (((dir_info.st_mode) & S_IFMT) == S_IFREG) { strcpy(tmpbuf,cp); - HTUnEscape(tmpbuf); + HTUnEscapeSome(tmpbuf,"/"); if (edit_current_file(tmpbuf,curdoc.link,newline)) { HTuncache_current_document(); @@ -2524,31 +2617,38 @@ check_recall: case LYK_DEL_BOOKMARK: /* delete home page link */ #ifdef DIRED_SUPPORT case LYK_REMOVE: /* remove files and directories */ - if (lynx_edit_mode && nlinks > 0 && !no_dired_support) + c = 'N'; + if (lynx_edit_mode && nlinks > 0 && !no_dired_support) { local_remove(&curdoc); - else + c = 'Y'; + } else #endif /* DIRED_SUPPORT */ - if (bookmark_page && (strstr(curdoc.address, bookmark_page) || - !strcmp(curdoc.title, MOSAIC_BOOKMARK_TITLE))) { + if (curdoc.bookmark != NULL) { _statusline(CONFIRM_BOOKMARK_DELETE); c = LYgetch(); if (TOUPPER(c) != 'Y') break; - remove_bookmark_link(links[curdoc.link].anchor_number-1); + remove_bookmark_link(links[curdoc.link].anchor_number-1, + curdoc.bookmark); } else { /* behave like REFRESH for backward compatability */ - refresh_screen=TRUE; + refresh_screen = TRUE; break; } - HTuncache_current_document(); - StrAllocCopy(newdoc.address, curdoc.address); - FREE(curdoc.address); - newdoc.line = curdoc.line; - if (curdoc.link == nlinks-1) - /* if we deleted the last link on the page */ - newdoc.link=curdoc.link-1; - else - newdoc.link=curdoc.link; + if (TOUPPER(c) == 'Y') { + HTuncache_current_document(); + StrAllocCopy(newdoc.address, curdoc.address); + FREE(curdoc.address); + newdoc.line = curdoc.line; + if (curdoc.link == nlinks-1) { + /* + * We deleted the last link on the page. - FM + */ + newdoc.link = curdoc.link-1; + } else { + newdoc.link = curdoc.link; + } + } break; #ifdef DIRED_SUPPORT @@ -2560,7 +2660,7 @@ check_recall: case LYK_INFO: /* show document info */ /* don't do if already viewing info page */ - if (strcmp(curdoc.title, SHOWINFO_TITLE)) { + if (strcmp((curdoc.title ? curdoc.title : ""), SHOWINFO_TITLE)) { showinfo(&curdoc, lines_in_file, &newdoc, owner_address); LYforce_no_cache = TRUE; if (LYValidate || check_realm) @@ -2583,7 +2683,8 @@ check_recall: } /* don't do if already viewing print options page */ - if (strcmp(curdoc.title, PRINT_OPTIONS_TITLE)) { + if (strcmp((curdoc.title ? curdoc.title : ""), + PRINT_OPTIONS_TITLE)) { if (print_options(&newdoc.address, lines_in_file) < 0) break; @@ -2595,7 +2696,8 @@ check_recall: case LYK_LIST: /* list links in the current document */ /* don't do if already viewing list page */ - if (strcmp(curdoc.title, LIST_PAGE_TITLE)) { + if (strcmp((curdoc.title ? curdoc.title : ""), + LIST_PAGE_TITLE)) { if (showlist(&newdoc.address, TRUE) < 0) break; refresh_screen=TRUE; /* redisplay */ @@ -2632,7 +2734,8 @@ check_recall: case LYK_DIRED_MENU: /* provide full file management menu */ /* don't do if not allowed or already viewing the menu */ if (lynx_edit_mode && !no_dired_support && - strcmp(curdoc.title, DIRED_MENU_TITLE)) { + strcmp((curdoc.title ? curdoc.title : ""), + DIRED_MENU_TITLE)) { dired_options(&curdoc,&newdoc.address); refresh_screen=TRUE; /* redisplay */ } @@ -2649,35 +2752,58 @@ check_recall: break; } - if (strcmp(curdoc.title, HISTORY_PAGE_TITLE) && - strcmp(curdoc.title, SHOWINFO_TITLE) && - strcmp(curdoc.title, PRINT_OPTIONS_TITLE) && + if (strcmp((curdoc.title ? curdoc.title : ""), + HISTORY_PAGE_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + SHOWINFO_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + PRINT_OPTIONS_TITLE) && #ifdef DIRED_SUPPORT - strcmp(curdoc.title, DIRED_MENU_TITLE) && - strcmp(curdoc.title, PERMIT_OPTIONS_TITLE) && - strcmp(curdoc.title, UPLOAD_OPTIONS_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + DIRED_MENU_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + PERMIT_OPTIONS_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + UPLOAD_OPTIONS_TITLE) && #endif /* DIRED_SUPPORT */ - strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE) && - strcmp(curdoc.title, LIST_PAGE_TITLE)) { - + strcmp((curdoc.title ? curdoc.title : ""), + DOWNLOAD_OPTIONS_TITLE) && + strcmp((curdoc.title ? curdoc.title : ""), + LIST_PAGE_TITLE)) { if (nlinks > 0) { - if (curdoc.post_data == NULL) { + if (curdoc.post_data == NULL && + curdoc.bookmark == NULL) { /* - * Document doesn't have POST content, so - * we can save either that of the link. - FM + * Document doesn't have POST content, + * and is not a bookmark file, so we can + * save either that or the link. - FM */ _statusline(BOOK_D_L_OR_CANCEL); c = LYgetch(); if (TOUPPER(c) == 'D') { save_bookmark_link(curdoc.address, curdoc.title); - break; + refresh_screen = TRUE; /* MultiBookmark support */ + goto check_add_bookmark_to_self; } } else { - /* - * Only offer the link in a document - * with POST content. - FM - */ - _statusline(BOOK_L_OR_CANCEL); + if (LYMultiBookmarks == FALSE && + curdoc.bookmark != NULL) { + /* + * If multiple bookmarks are disabled, offer + * the L)ink or C)ancel, but with wording + * which indicates that the link already + * exists in this bookmark file. - FM + */ + _statusline(MULTIBOOKMARKS_SELF); + } else { + /* + * Only offer the link in a document with + * POST content, or if the current document + * is a bookmark file and multiple bookmarks + * are enabled. - FM + */ + _statusline(BOOK_L_OR_CANCEL); + } c = LYgetch(); } if (TOUPPER(c) == 'L') { @@ -2704,6 +2830,17 @@ check_recall: if (TOUPPER(c) == 'D') save_bookmark_link(curdoc.address, curdoc.title); } +check_add_bookmark_to_self: + if (curdoc.bookmark && BookmarkPage && + !strcmp(curdoc.bookmark, BookmarkPage)) { + HTuncache_current_document(); + StrAllocCopy(newdoc.address, curdoc.address); + StrAllocCopy(newdoc.bookmark, curdoc.bookmark); + FREE(curdoc.address); + newdoc.line = curdoc.line; + newdoc.link = curdoc.link; + } + FREE(temp); } else { if (old_c != real_c) { old_c = real_c; @@ -2711,6 +2848,7 @@ check_recall: sleep(MessageSecs); } } + refresh_screen = TRUE; /* MultiBookmark support */ break; case LYK_VIEW_BOOKMARK: /* v to view home page */ @@ -2723,13 +2861,20 @@ check_recall: break; } - /* see if a bookmark exists - * if it does replace newdoc.address with it's name + /* + * See if a bookmark exists. + * If it does replace newdoc.address with it's name. */ - if (get_bookmark_filename(&newdoc.address) != NULL) { + if ((cp = get_bookmark_filename(&newdoc.address)) != NULL) { + if (*cp == '\0' || !strcmp(cp, " ") || + !strcmp(curdoc.address, newdoc.address)) { + refresh_screen = TRUE; /* MultiBookmark support */ + break; + } LYforce_HTML_mode = TRUE; /* force HTML */ LYforce_no_cache = TRUE; /*force the document to be reloaded*/ - StrAllocCopy(newdoc.title, "Bookmark File"); + StrAllocCopy(newdoc.title, BOOKMARK_TITLE); + StrAllocCopy(newdoc.bookmark, BookmarkPage); FREE(newdoc.post_data); FREE(newdoc.post_content_type); newdoc.isHEAD = FALSE; @@ -2743,6 +2888,7 @@ check_recall: sleep(MessageSecs); } } + refresh_screen = TRUE; /* MultiBookmark support */ break; case LYK_SHELL: /* shell escape */ @@ -2779,18 +2925,35 @@ check_recall: } /* don't do if already viewing download options page */ - if (0==strcmp(curdoc.title, DOWNLOAD_OPTIONS_TITLE)) + if (0==strcmp((curdoc.title ? curdoc.title : ""), + DOWNLOAD_OPTIONS_TITLE)) break; if (nlinks > 0) { if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) { - if (old_c != real_c) { + if (links[curdoc.link].form->type == F_SUBMIT_TYPE) { + if (links[curdoc.link].form->submit_method == + URL_MAIL_METHOD) { + if (old_c != real_c) { + old_c = real_c; + _statusline(NO_DOWNLOAD_MAILTO_ACTION); + sleep(MessageSecs); + } + break; + } + HTOutputFormat = HTAtom_for("www/download"); + LYforce_no_cache = TRUE; + cmd = LYK_ACTIVATE; + goto new_cmd; + } + if (old_c != real_c) { old_c = real_c; _statusline(NO_DOWNLOAD_INPUT); sleep(MessageSecs); } - } else if (0==strcmp(curdoc.title, PRINT_OPTIONS_TITLE)) { + } else if (0==strcmp((curdoc.title ? curdoc.title : ""), + PRINT_OPTIONS_TITLE)) { if (old_c != real_c) { old_c = real_c; _statusline(NO_DOWNLOAD_PRINT_OP); @@ -2798,14 +2961,16 @@ check_recall: } #ifdef DIRED_SUPPORT - } else if (0==strcmp(curdoc.title, UPLOAD_OPTIONS_TITLE)) { + } else if (0==strcmp((curdoc.title ? curdoc.title : ""), + UPLOAD_OPTIONS_TITLE)) { if (old_c != real_c) { old_c = real_c; _statusline(NO_DOWNLOAD_UPLOAD_OP); sleep(MessageSecs); } - } else if (0==strcmp(curdoc.title, PERMIT_OPTIONS_TITLE)) { + } else if (0==strcmp((curdoc.title ? curdoc.title : ""), + PERMIT_OPTIONS_TITLE)) { if (old_c != real_c) { old_c = real_c; _statusline(NO_DOWNLOAD_PERMIT_OP); @@ -2822,10 +2987,12 @@ check_recall: FREE(temp); #endif /* DIRED_SUPPORT */ - } else if (0==strcmp(curdoc.title, HISTORY_PAGE_TITLE)) { + } else if (0==strcmp((curdoc.title ? curdoc.title : ""), + HISTORY_PAGE_TITLE)) { int number = atoi(links[curdoc.link].lname+9); StrAllocCopy(newdoc.address, history[number].address); StrAllocCopy(newdoc.title, links[curdoc.link].hightext); + StrAllocCopy(newdoc.address, history[number].bookmark); FREE(newdoc.post_data); FREE(newdoc.post_content_type); if (history[number].post_data) @@ -2839,7 +3006,7 @@ check_recall: HTOutputFormat = HTAtom_for("www/download"); LYUserSpecifiedURL = TRUE; /*force the document to be reloaded*/ - LYforce_no_cache = TRUE; + LYforce_no_cache = TRUE; force_load = TRUE; /* force MainLoop to reload */ } else if (!strncasecomp(links[curdoc.link].lname, @@ -2864,12 +3031,13 @@ check_recall: if (are_different(&curdoc, &newdoc)) { FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; } newdoc.link = 0; HTOutputFormat = HTAtom_for("www/download"); /*force the document to be reloaded*/ - LYforce_no_cache = TRUE; + LYforce_no_cache = TRUE; force_load = TRUE; /* force MainLoop to reload */ } } else if (old_c != real_c) { @@ -2882,7 +3050,8 @@ check_recall: #ifdef DIRED_SUPPORT case LYK_UPLOAD: /* don't do if already viewing upload options page */ - if (0==strcmp(curdoc.title, UPLOAD_OPTIONS_TITLE)) + if (0==strcmp((curdoc.title ? curdoc.title : ""), + UPLOAD_OPTIONS_TITLE)) break; if (lynx_edit_mode && !no_dired_support) { @@ -3023,6 +3192,7 @@ check_recall: StrAllocCopy(newdoc.address, "LYNXKEYMAP:"); FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; /* * If vi_keys changed, the keymap did too, @@ -3092,6 +3262,7 @@ check_recall: StrAllocCopy(lynxjumpfile, ret); FREE(newdoc.post_data); FREE(newdoc.post_content_type); + FREE(newdoc.bookmark); newdoc.isHEAD = FALSE; FREE(ret); LYUserSpecifiedURL = TRUE; diff --git a/src/LYMap.c b/src/LYMap.c index a147a79b..9720586b 100644 --- a/src/LYMap.c +++ b/src/LYMap.c @@ -212,6 +212,7 @@ PRIVATE int LYLoadIMGmap ARGS4 ( WWWDoc.address = address; WWWDoc.post_data = NULL; WWWDoc.post_content_type = NULL; + WWWDoc.bookmark = NULL; WWWDoc.isHEAD = FALSE; LYforce_no_cache = TRUE; reloading = TRUE; @@ -246,6 +247,7 @@ PRIVATE int LYLoadIMGmap ARGS4 ( WWWDoc.address = address; WWWDoc.post_data = NULL; WWWDoc.post_content_type = NULL; + WWWDoc.bookmark = NULL; WWWDoc.isHEAD = FALSE; LYforce_no_cache = TRUE; reloading = TRUE; diff --git a/src/LYNews.c b/src/LYNews.c index 1ace9b6b..2bdab054 100644 --- a/src/LYNews.c +++ b/src/LYNews.c @@ -49,6 +49,7 @@ PUBLIC int LYNewsPost ARGS2(document *,newdoc, BOOLEAN,followup) 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; if(!HTLoadAbsolute(&WWWDoc)) { FREE(newsgroups); diff --git a/src/LYOptions.c b/src/LYOptions.c index deb94e8b..345c7d0e 100644 --- a/src/LYOptions.c +++ b/src/LYOptions.c @@ -14,6 +14,7 @@ #include "LYKeymap.h" #include "LYrcFile.h" #include "HTAlert.h" +#include "LYBookmark.h" #include "LYLeaks.h" @@ -29,7 +30,8 @@ BOOLEAN term_options; PRIVATE void terminate_options PARAMS((int sig)); -PUBLIC int boolean_choice PARAMS((int status, int line, char **choices)); +PRIVATE int boolean_choice PARAMS((int status, int line, + int column, char **choices)); #define MAXCHOICES 10 @@ -60,13 +62,12 @@ PRIVATE void option_statusline ARGS1(char *,text) refresh(); } - PUBLIC void options NOARGS { #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS int itmp; #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */ - int response=0, ch; + int response, ch; /* if the user changes the display I need memory to put it in */ char display_option[256]; #ifndef VMS @@ -106,98 +107,113 @@ PUBLIC void options NOARGS term_options = FALSE; signal(SIGINT, terminate_options); +draw_options: + response = 0; clear(); - move(0,5); + move(0, 5); if (bold_H1 || bold_headers) start_bold(); printw(" Options Menu (%s Version %s)", LYNX_NAME, LYNX_VERSION); if (bold_H1 || bold_headers) stop_bold(); - move(L_EDITOR,5); + move(L_EDITOR, 5); printw("E)ditor : %s", ((editor && *editor) ? editor : "NONE")); - move(L_DISPLAY,5); + move(L_DISPLAY, 5); printw("D)ISPLAY variable : %s", ((display && *display) ? display : "NONE")); - move(L_MAIL_ADDRESS,5); + move(L_MAIL_ADDRESS, 5); printw("P)ersonal mail address : %s", ((personal_mail_address && *personal_mail_address) ? personal_mail_address : "NONE")); - move(L_HOME,5); - printw("B)ookmark file : %s", + move(L_HOME, 5); + printw("mu(L)ti-bookmarks: %s", + (LYMultiBookmarks ? (LYMBMAdvanced ? + "ADVANCED" : "STANDARD") : "OFF")); + move(L_HOME, B_BOOK); + if (LYMultiBookmarks) { + printw("review/edit B)ookmarks files"); + } else { + printw("B)ookmark file: %s", ((bookmark_page && *bookmark_page) ? bookmark_page : "NONE")); + } - move(L_FTPSTYPE,5); + move(L_FTPSTYPE, 5); printw("F)TP sort criteria : %s",(HTfileSortMethod==FILE_BY_NAME ? "By Filename" : (HTfileSortMethod==FILE_BY_SIZE ? "By Size" : (HTfileSortMethod==FILE_BY_TYPE ? "By Type" : "By Date")))); - move(L_SSEARCH,5); + move(L_SSEARCH, 5); printw("S)earching type : %s",(case_sensitive ? "CASE SENSITIVE" : "CASE INSENSITIVE")); - move(L_CHARSET,5); + move(L_CHARSET, 5); printw("display (C)haracter set : %s", LYchar_set_names[current_char_set]); - move(L_RAWMODE,5); + move(L_RAWMODE, 5); printw("Raw 8-bit or CJK m(O)de : %s", (LYRawMode ? "ON" : "OFF")); - move(L_LANGUAGE,5); + move(L_LANGUAGE, 5); printw("preferred document lan(G)uage: %s", ((language && *language) ? language : "NONE")); - move(L_PREF_CHARSET,5); + move(L_PREF_CHARSET, 5); printw("preferred document c(H)arset : %s", ((pref_charset && *pref_charset) ? pref_charset : "NONE")); - move(L_VIKEYS,5); - printw("V)I keys : %s", (vi_keys ? "ON" : "OFF")); + move(L_BOOL_A, B_VIKEYS); + printw("V)I keys: %s", (vi_keys ? "ON" : "OFF")); - move(L_EMACSKEYS,5); - printw("e(M)acs keys : %s", (emacs_keys ? "ON" : "OFF")); + move(L_BOOL_A, B_EMACSKEYS); + printw("e(M)acs keys: %s", (emacs_keys ? "ON" : "OFF")); - move(L_KEYPAD,5); + move(L_BOOL_A, B_SHOW_DOTFILES); + printw("sho(W) dot files: %s", + ((!no_dotfiles && show_dotfiles) ? "ON" : "OFF")); + + move(L_SELECT_POPUPS, 5); + printw("popups for selec(T) fields : %s", + (LYSelectPopups ? "ON" : "OFF")); + + move(L_KEYPAD, 5); printw("K)eypad mode : %s", (keypad_mode == NUMBERS_AS_ARROWS ? "Numbers act as arrows" : "Links are numbered")); - move(L_LINEED,5); + move(L_LINEED, 5); printw("li(N)e edit style : %s", LYLineeditNames[current_lineedit]); #ifdef DIRED_SUPPORT - move(L_DIRED,5); + move(L_DIRED, 5); printw("l(I)st directory style : %s", (dir_list_style == FILES_FIRST ? "Files first " : (dir_list_style == MIXED_STYLE ? "Mixed style " : "Directories first "))); #endif /* DIRED_SUPPORT */ - move(L_SHOW_DOTFILES,5); - printw("sho(W) dot files : %s", - ((!no_dotfiles && show_dotfiles) ? "ON" : "OFF")); - - move(L_USER_MODE,5); + move(L_USER_MODE, 5); printw("U)ser mode : %s", (user_mode == NOVICE_MODE ? "Novice" : (user_mode == INTERMEDIATE_MODE ? "Intermediate" : "Advanced"))); - move(L_USER_AGENT,5); + move(L_USER_AGENT, 5); printw("user (A)gent : %s", ((LYUserAgent && *LYUserAgent) ? LYUserAgent : "NONE")); + #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS - move(L_EXEC,5); - printw("L)ocal execution links : "); + move(L_EXEC, 5); + printw("local e(X)ecution links : "); #ifndef NEVER_ALLOW_REMOTE_EXEC addstr((local_exec ? "ALWAYS ON" : (local_exec_on_local_files ? "FOR LOCAL FILES ONLY" : @@ -230,9 +246,10 @@ PUBLIC void options NOARGS addstr("'"); addstr(TO_RETURN_SEGMENT); - while(TOUPPER(response) != 'R' && response != LTARROW && - response != '>' && !term_options && response != 7 && - response != 3) { + while (TOUPPER(response) != 'R' && + !LYisNonAlnumKeyname(response, LYK_PREV_DOC) && + response != '>' && !term_options && + response != 7 && response != 3) { move(LYlines-2, 0); start_reverse(); @@ -243,7 +260,11 @@ PUBLIC void options NOARGS response = LYgetch(); if (term_options || response == 7 || response == 3) response = 'R'; - switch(response) { + if (LYisNonAlnumKeyname(response, LYK_REFRESH)) { + clearok(curscr, TRUE); + goto draw_options; + } + switch (response) { case 'e': /* change the editor */ case 'E': if (no_editor) { @@ -275,8 +296,10 @@ PUBLIC void options NOARGS StrAllocCopy(editor, display_option); addstr(display_option); } + clrtoeol(); option_statusline(VALUE_ACCEPTED); } + response = ' '; break; case 'd': /* change the display */ @@ -298,16 +321,19 @@ PUBLIC void options NOARGS if ((term_options || ch == -1) || (display != NULL && #ifdef VMS - 0 == strcasecomp(display, display_option))) { + 0 == strcasecomp(display, display_option))) #else - 0 == strcmp(display, display_option))) { + 0 == strcmp(display, display_option))) #endif /* VMS */ + { /* * Cancelled, or a non-NULL display string * wasn't changed. - FM */ addstr((display && *display) ? display : "NONE"); + clrtoeol(); option_statusline(VALUE_ACCEPTED); + response = ' '; break; } else if (*display_option == '\0') { if ((display == NULL) || @@ -317,7 +343,9 @@ PUBLIC void options NOARGS * wasn't changed. - FM */ addstr("NONE"); + clrtoeol(); option_statusline(VALUE_ACCEPTED); + response = ' '; break; } } @@ -340,6 +368,7 @@ PUBLIC void options NOARGS display = NULL; } addstr(display ? display : "NONE"); + clrtoeol(); if ((display == NULL && *display_option == '\0') || (display != NULL && 0 == strcmp(display, display_option))) { @@ -359,6 +388,46 @@ PUBLIC void options NOARGS option_statusline(FAILED_CLEAR_SET_DISPLAY); } } + response = ' '; + break; + + case 'l': + case 'L': + if (LYMBMBlocked) { + option_statusline(MULTIBOOKMARKS_DISALLOWED); + response = ' '; + break; + } + choices[0] = NULL; + StrAllocCopy(choices[0],"OFF "); + choices[1] = NULL; + StrAllocCopy(choices[1],"STANDARD"); + choices[2] = NULL; + StrAllocCopy(choices[2],"ADVANCED"); + choices[3] = NULL; + LYMultiBookmarks = boolean_choice(LYMultiBookmarks * + (1 + LYMBMAdvanced), + L_HOME, C_MULTI, + choices); + FREE(choices[0]); + FREE(choices[1]); + FREE(choices[2]); + if (LYMultiBookmarks == 2) { + LYMultiBookmarks = TRUE; + LYMBMAdvanced = TRUE; + } else { + LYMBMAdvanced = FALSE; + } + + move(L_HOME, B_BOOK); + clrtoeol(); + if (LYMultiBookmarks) { + printw("review/edit B)ookmarks files"); + } else { + printw("B)ookmark file: %s", + ((bookmark_page && *bookmark_page) ? bookmark_page : "NONE")); + } + response = ' '; break; case 'b': /* change the bookmark page location */ @@ -367,34 +436,41 @@ PUBLIC void options NOARGS * change the bookmark page */ if (!no_bookmark) { + if (LYMultiBookmarks) { + edit_bookmarks(); + signal(SIGINT, terminate_options); + goto draw_options; + } if (bookmark_page && *bookmark_page) strcpy(display_option, bookmark_page); else { /* clear the NONE */ - move(L_HOME, COL_OPTION_VALUES); - addstr(" "); + move(L_HOME, C_DEFAULT); + clrtoeol(); *display_option = '\0'; } option_statusline(ACCEPT_DATA); - move(L_HOME, COL_OPTION_VALUES); + move(L_HOME, C_DEFAULT); standout(); ch = LYgetstr(display_option, VISIBLE, sizeof(display_option), NORECALL); standend(); - move(L_HOME, COL_OPTION_VALUES); - if (term_options || ch == -1) { + move(L_HOME, C_DEFAULT); + if (term_options || + ch == -1 || *display_option == '\0') { addstr((bookmark_page && *bookmark_page) ? bookmark_page : "NONE"); - } else if (*display_option == '\0') { - FREE(bookmark_page); - addstr("NONE"); } else { StrAllocCopy(bookmark_page, display_option); + StrAllocCopy(MBM_A_subbookmark[0], + bookmark_page); addstr(display_option); } + clrtoeol(); option_statusline(VALUE_ACCEPTED); } else { /* anonymous */ option_statusline(BOOKMARK_CHANGE_DISALLOWED); } + response = ' '; break; case 'f': @@ -410,10 +486,11 @@ PUBLIC void options NOARGS StrAllocCopy(choices[3],"By Date "); choices[4] = NULL; HTfileSortMethod = boolean_choice(HTfileSortMethod, - L_FTPSTYPE, choices); + L_FTPSTYPE, -1, choices); FREE(choices[0]); FREE(choices[1]); FREE(choices[2]); + response = ' '; break; case 'p': /* change personal mail address for From headers */ @@ -443,27 +520,30 @@ PUBLIC void options NOARGS StrAllocCopy(personal_mail_address, display_option); addstr(display_option); } + clrtoeol(); option_statusline(VALUE_ACCEPTED); + response = ' '; break; case 's': case 'S': - /* copy strings into choice array */ - choices[0] = NULL; - StrAllocCopy(choices[0],"CASE INSENSITIVE"); - choices[1] = NULL; - StrAllocCopy(choices[1],"CASE SENSITIVE "); - choices[2] = NULL; - case_sensitive = boolean_choice(case_sensitive, - L_SSEARCH, choices); - FREE(choices[0]); - FREE(choices[1]); + /* copy strings into choice array */ + choices[0] = NULL; + StrAllocCopy(choices[0],"CASE INSENSITIVE"); + choices[1] = NULL; + StrAllocCopy(choices[1],"CASE SENSITIVE "); + choices[2] = NULL; + case_sensitive = boolean_choice(case_sensitive, + L_SSEARCH, -1, choices); + FREE(choices[0]); + FREE(choices[1]); + response = ' '; break; case 'c': case 'C': current_char_set = boolean_choice(current_char_set, - L_CHARSET, LYchar_set_names); + L_CHARSET, -1, LYchar_set_names); /* * Set the raw 8-bit or CJK mode defaults and * character set if changed. - FM @@ -478,6 +558,7 @@ PUBLIC void options NOARGS clrtoeol(); addstr(LYRawMode ? "ON " : "OFF"); } + response = ' '; break; case 'o': @@ -489,7 +570,7 @@ PUBLIC void options NOARGS StrAllocCopy(choices[1], "ON "); choices[2] = NULL; LYRawMode = boolean_choice(LYRawMode, - L_RAWMODE, choices); + L_RAWMODE, -1, choices); /* * Set the LYUseDefaultRawMode value and character * handling if LYRawMode was changed. - FM @@ -502,6 +583,7 @@ PUBLIC void options NOARGS } FREE(choices[0]); FREE(choices[1]); + response = ' '; break; case 'g': /* change language preference */ @@ -530,7 +612,9 @@ PUBLIC void options NOARGS StrAllocCopy(language, display_option); addstr(display_option); } + clrtoeol(); option_statusline(VALUE_ACCEPTED); + response = ' '; break; case 'h': /* change character set preference */ @@ -559,7 +643,9 @@ PUBLIC void options NOARGS StrAllocCopy(pref_charset, display_option); addstr(display_option); } + clrtoeol(); option_statusline(VALUE_ACCEPTED); + response = ' '; break; case 'v': @@ -570,13 +656,16 @@ PUBLIC void options NOARGS choices[1] = NULL; StrAllocCopy(choices[1],"ON "); choices[2] = NULL; - vi_keys = boolean_choice(vi_keys, L_VIKEYS, choices); + vi_keys = boolean_choice(vi_keys, + L_BOOL_A, C_VIKEYS, + choices); if (vi_keys) set_vi_keys(); else reset_vi_keys(); FREE(choices[0]); FREE(choices[1]); + response = ' '; break; case 'M': @@ -587,14 +676,53 @@ PUBLIC void options NOARGS choices[1] = NULL; StrAllocCopy(choices[1],"ON "); choices[2] = NULL; - emacs_keys = boolean_choice(emacs_keys, L_EMACSKEYS, - choices); + emacs_keys = boolean_choice(emacs_keys, + L_BOOL_A, C_EMACSKEYS, + choices); if (emacs_keys) set_emacs_keys(); else reset_emacs_keys(); FREE(choices[0]); FREE(choices[1]); + response = ' '; + break; + + case 'W': + case 'w': + if (no_dotfiles) { + option_statusline(DOTFILE_ACCESS_DISABLED); + } else { + /* copy strings into choice array */ + choices[0] = NULL; + StrAllocCopy(choices[0],"OFF"); + choices[1] = NULL; + StrAllocCopy(choices[1],"ON "); + choices[2] = NULL; + show_dotfiles = boolean_choice(show_dotfiles, + L_BOOL_A, + C_SHOW_DOTFILES, + choices); + FREE(choices[0]); + FREE(choices[1]); + } + response = ' '; + break; + + case 't': + case 'T': + /* copy strings into choice array */ + choices[0] = NULL; + StrAllocCopy(choices[0], "OFF"); + choices[1] = NULL; + StrAllocCopy(choices[1], "ON "); + choices[2] = NULL; + LYSelectPopups = boolean_choice(LYSelectPopups, + L_SELECT_POPUPS, -1, + choices); + FREE(choices[0]); + FREE(choices[1]); + response = ' '; break; case 'k': @@ -606,19 +734,21 @@ PUBLIC void options NOARGS StrAllocCopy(choices[1],"Links are numbered "); choices[2] = NULL; keypad_mode = boolean_choice(keypad_mode, - L_KEYPAD, choices); + L_KEYPAD, -1, choices); if (keypad_mode == NUMBERS_AS_ARROWS) set_numbers_as_arrows(); else reset_numbers_as_arrows(); FREE(choices[0]); FREE(choices[1]); + response = ' '; break; case 'n': case 'N': current_lineedit = boolean_choice(current_lineedit, - L_LINEED, LYLineeditNames); + L_LINEED, -1, LYLineeditNames); + response = ' '; break; #ifdef DIRED_SUPPORT @@ -633,32 +763,14 @@ PUBLIC void options NOARGS StrAllocCopy(choices[2],"Mixed style "); choices[3] = NULL; dir_list_style = boolean_choice(dir_list_style, - L_DIRED, choices); + L_DIRED, -1, choices); FREE(choices[0]); FREE(choices[1]); FREE(choices[2]); + response = ' '; break; #endif /* DIRED_SUPPORT */ - case 'W': - case 'w': - if (no_dotfiles) { - option_statusline(DOTFILE_ACCESS_DISABLED); - } else { - /* copy strings into choice array */ - choices[0] = NULL; - StrAllocCopy(choices[0],"OFF"); - choices[1] = NULL; - StrAllocCopy(choices[1],"ON "); - choices[2] = NULL; - show_dotfiles = boolean_choice(show_dotfiles, - L_SHOW_DOTFILES, - choices); - FREE(choices[0]); - FREE(choices[1]); - } - break; - case 'u': case 'U': /* copy strings into choice array */ @@ -670,7 +782,7 @@ PUBLIC void options NOARGS StrAllocCopy(choices[2],"Advanced "); choices[3] = NULL; user_mode = boolean_choice(user_mode, - L_USER_MODE, choices); + L_USER_MODE, -1, choices); FREE(choices[0]); FREE(choices[1]); FREE(choices[2]); @@ -678,6 +790,7 @@ PUBLIC void options NOARGS display_lines = LYlines-4; else display_lines = LYlines-2; + response = ' '; break; case 'a': @@ -710,6 +823,7 @@ PUBLIC void options NOARGS StrAllocCopy(LYUserAgent, display_option); addstr(display_option); } + clrtoeol(); if (LYUserAgent && *LYUserAgent && !strstr(LYUserAgent, "Lynx") && !strstr(LYUserAgent, "lynx")) { @@ -720,23 +834,24 @@ PUBLIC void options NOARGS } else { /* disallowed */ option_statusline(UA_COPYRIGHT_WARNING); } + response = ' '; break; #ifdef ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS - case 'l': /* local exec */ - case 'L': - if(!exec_frozen) { + case 'x': /* local exec */ + case 'X': + if (!exec_frozen) { #ifndef NEVER_ALLOW_REMOTE_EXEC - if(local_exec) { - itmp=2; - } else { + if (local_exec) { + itmp = 2; + } else { #else { #endif /* NEVER_ALLOW_REMOTE_EXEC */ - if(local_exec_on_local_files) - itmp=1; + if (local_exec_on_local_files) + itmp= 1; else - itmp=0; + itmp = 0; } /* copy strings into choice array */ choices[0] = NULL; @@ -748,7 +863,7 @@ PUBLIC void options NOARGS StrAllocCopy(choices[2],"ALWAYS ON "); choices[3] = NULL; #endif /* NEVER_ALLOW_REMOTE_EXEC */ - itmp = boolean_choice(itmp, L_EXEC, choices); + itmp = boolean_choice(itmp, L_EXEC, -1, choices); FREE(choices[0]); FREE(choices[1]); @@ -757,23 +872,27 @@ PUBLIC void options NOARGS #endif /* NEVER_ALLOW_REMOTE_EXEC */ switch(itmp) { case 0: - local_exec=FALSE; - local_exec_on_local_files=FALSE; + local_exec = FALSE; + local_exec_on_local_files = FALSE; + response = ' '; break; case 1: - local_exec=FALSE; - local_exec_on_local_files=TRUE; + local_exec = FALSE; + local_exec_on_local_files = TRUE; + response = ' '; break; #ifndef NEVER_ALLOW_REMOTE_EXEC case 2: - local_exec=TRUE; - local_exec_on_local_files=FALSE; + local_exec = TRUE; + local_exec_on_local_files = FALSE; + response = ' '; break; #endif /* NEVER_ALLOW_REMOTE_EXEC */ } /* end switch */ } else { option_statusline(CHANGE_OF_SETTING_DISALLOWED); } + response = ' '; break; #endif /* ALLOW_USERS_TO_CHANGE_EXEC_WITHIN_OPTIONS */ @@ -805,72 +924,329 @@ PUBLIC void options NOARGS option_statusline(R_TO_RETURN_TO_LYNX); } } /* end switch */ - } /* end while */ + } /* end while */ - term_options = FALSE; - signal(SIGINT, cleanup_sig); + term_options = FALSE; + signal(SIGINT, cleanup_sig); } - /* take a boolean status and prompt the user for a new status * and return it */ -PUBLIC int boolean_choice ARGS3(int,status, int,line, char **,choices) +PRIVATE int boolean_choice ARGS4( + int, status, + int, line, + int, column, + char **, choices) { - int response=0; - int number=0; + int response = 0; + int number = 0; + int col = (column >= 0 ? column : COL_OPTION_VALUES); - for (; choices[number] != NULL; number++) - ; /* empty loop body */ + for (; choices[number] != NULL; number++) + ; /* empty loop body */ - number--; - - option_statusline(ACCEPT_DATA); - /* highlight the current selection */ - move(line, COL_OPTION_VALUES); - standout(); - addstr(choices[status]); + number--; - standend(); - option_statusline(ANY_KEY_CHANGE_RET_ACCEPT); - standout(); + option_statusline(ACCEPT_DATA); + /* + * Highlight the current selection. + */ + move(line, col); + standout(); + addstr(choices[status]); - while(1) { - move(line, COL_OPTION_VALUES); - response = LYgetch(); - if (term_options || response == 7 || response == 3) - response = '\n'; - if(response != '\n' && response != '\r') { - if(status == number) - status = 0; /* go over the top and around */ - else - status++; - addstr(choices[status]); - refresh(); - } else { - /* unhighlight selection */ - move(line, COL_OPTION_VALUES); - standend(); - addstr(choices[status]); + standend(); + option_statusline(ANY_KEY_CHANGE_RET_ACCEPT); + standout(); - option_statusline(VALUE_ACCEPTED); - return(status); - } + while (1) { + move(line, col); + response = LYgetch(); + if (term_options || response == 7 || response == 3) + response = '\n'; + if (response != '\n' && response != '\r') { + if (status == number) + status = 0; /* go over the top and around */ + else + status++; + addstr(choices[status]); + refresh(); + } else { + /* + * Unhighlight selection. + */ + move(line, col); + standend(); + addstr(choices[status]); + + option_statusline(VALUE_ACCEPTED); + return(status); } + } } - PRIVATE void terminate_options ARGS1(int,sig) { - term_options=TRUE; - /* Reassert the AST */ - signal(SIGINT, terminate_options); + term_options=TRUE; + /* Reassert the AST */ + signal(SIGINT, terminate_options); #ifdef VMS - /* refresh the screen to get rid of the "interrupt" message */ - if (!dump_output_immediately) { + /* refresh the screen to get rid of the "interrupt" message */ + if (!dump_output_immediately) { + clearok(curscr, TRUE); + refresh(); + } +#endif /* VMS */ +} + +/* + * Multi-Bookmark On-Line editing support. - FMG & FM + */ +PUBLIC void edit_bookmarks NOARGS +{ + int response = 0, def_response = 0, ch; + int MBM_current = 1; +#define MULTI_OFFSET 8 + int a; /* misc counter */ + char MBM_tmp_line[256]; /* buffer for LYgetstr */ + + /* + * We need (MBM_V_MAXFILES + MULTI_OFFSET) lines to display + * the whole list at once. Otherwise break it up into two + * segments. We know it won't be less than that because + * 'o'ptions needs 23-24 at LEAST. + */ + term_options = FALSE; + signal(SIGINT, terminate_options); + +draw_bookmark_list: + clear(); + move(0, 5); + if (bold_H1 || bold_headers) + start_bold(); + if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) + printw("Editing Bookmark DESCRIPTION and FILEPATH (%d of 2)", + MBM_current); + else + printw(" Editing Bookmark DESCRIPTION and FILEPATH"); + if (bold_H1 || bold_headers) + stop_bold(); + + if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) { + for (a = ((MBM_V_MAXFILES/2 + 1) * (MBM_current - 1)); + a <= ((float)MBM_V_MAXFILES/2 * MBM_current); a++) { + move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), 5); + printw("%c : %s", (a + 'A'), + (!MBM_A_subdescript[a] ? "" : MBM_A_subdescript[a])); + move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), 35); + printw("| %s", + (!MBM_A_subbookmark[a] ? "" : MBM_A_subbookmark[a])); + } + } else { + for (a = 0; a <= MBM_V_MAXFILES; a++) { + move(3 + a, 5); + printw("%c : %s", (a + 'A'), + (!MBM_A_subdescript[a] ? "" : MBM_A_subdescript[a])); + move(3 + a, 35); + printw("| %s", + (!MBM_A_subbookmark[a] ? "" : MBM_A_subbookmark[a])); + } + } + + /* + * Only needed when we have 2 screens. + */ + if (LYlines < MBM_V_MAXFILES + MULTI_OFFSET) { + move((LYlines - 4), 0); + start_reverse(); + addstr(MULTIBOOKMARKS_MOVE); + stop_reverse(); + } + + move((LYlines - 3), 0); + if (!no_option_save) { + addstr("'"); + standout(); + addstr(">"); + standend(); + addstr("'"); + addstr(TO_SAVE_SEGMENT); + } + addstr(OR_SEGMENT); + addstr("'"); + standout(); + addstr("^G"); + standend(); + addstr("'"); + addstr(TO_RETURN_SEGMENT); + + while (!term_options && + !LYisNonAlnumKeyname(response, LYK_PREV_DOC) && + response != 7 && response != 3 && + response != '>') { + + move((LYlines - 2), 0); + start_reverse(); + addstr("Letter: "); + stop_reverse(); + + refresh(); + response = (def_response ? def_response : LYgetch()); + def_response = 0; + + /* + * Check for a cancel. + */ + if (term_options || + response == 7 || response == 3 || + LYisNonAlnumKeyname(response, LYK_PREV_DOC)) + continue; + + /* + * Check for a save. + */ + if (response == '>') { + if (!no_option_save) { + option_statusline(SAVING_OPTIONS); + if (save_rc()) + option_statusline(OPTIONS_SAVED); + else + HTAlert(OPTIONS_NOT_SAVED); + } else { + option_statusline(R_TO_RETURN_TO_LYNX); + /* + * Change response so that we don't exit + * the options menu. + */ + response = ' '; + } + continue; + } + + /* + * Check for a refresh. + */ + if (LYisNonAlnumKeyname(response, LYK_REFRESH)) { clearok(curscr, TRUE); - refresh(); + continue; } -#endif /* VMS */ + + /* + * Move between the screens - if we can't show it all at once. + */ + if ((response == ']' || + LYisNonAlnumKeyname(response, LYK_NEXT_PAGE)) && + LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) { + MBM_current++; + if (MBM_current >= 3) + MBM_current = 1; + goto draw_bookmark_list; + } + if ((response == '[' || + LYisNonAlnumKeyname(response, LYK_PREV_PAGE)) && + LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) { + MBM_current--; + if (MBM_current <= 0) + MBM_current = 2; + goto draw_bookmark_list; + } + + /* + * Instead of using 26 case statements, we set up + * a scan through the letters and edit the lines + * that way. + */ + for (a = 0; a <= MBM_V_MAXFILES; a++) { + if ((TOUPPER(response) - 'A') == a) { + if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) { + if (MBM_current == 1 && a > (MBM_V_MAXFILES/2)) { + MBM_current = 2; + def_response = response; + goto draw_bookmark_list; + } + if (MBM_current == 2 && a < (MBM_V_MAXFILES/2)) { + MBM_current = 1; + def_response = response; + goto draw_bookmark_list; + } + } + option_statusline(ACCEPT_DATA); + + if (a > 0) { + standout(); + if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) + move( + (3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), + 9); + else + move((3 + a), 9); + strcpy(MBM_tmp_line, + (!MBM_A_subdescript[a] ? + "" : MBM_A_subdescript[a])); + ch = LYgetstr(MBM_tmp_line, VISIBLE, + sizeof(MBM_tmp_line), NORECALL); + standend(); + + if (strlen(MBM_tmp_line) < 1) { + FREE(MBM_A_subdescript[a]); + } else { + StrAllocCopy(MBM_A_subdescript[a], MBM_tmp_line); + } + if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) + move( + (3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), + 5); + else + move((3 + a), 5); + printw("%c : %s", (a + 'A'), + (!MBM_A_subdescript[a] ? + "" : MBM_A_subdescript[a])); + clrtoeol(); + refresh(); + } + + if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) + move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current - 1)), + 35); + else + move((3 + a), 35); + printw("| "); + + standout(); + strcpy(MBM_tmp_line, + (!MBM_A_subbookmark[a] ? "" : MBM_A_subbookmark[a])); + ch = LYgetstr(MBM_tmp_line, VISIBLE, + sizeof(MBM_tmp_line), NORECALL); + standend(); + + if (*MBM_tmp_line == '\0') { + if (a == 0) + StrAllocCopy(MBM_A_subbookmark[a], bookmark_page); + else + FREE(MBM_A_subbookmark[a]); + } else { + StrAllocCopy(MBM_A_subbookmark[a], MBM_tmp_line); + if (a == 0) { + StrAllocCopy(bookmark_page, MBM_A_subbookmark[a]); + } + } + if (LYlines < (MBM_V_MAXFILES + MULTI_OFFSET)) + move((3 + a) - ((MBM_V_MAXFILES/2 + 1)*(MBM_current-1)), + 35); + else + move((3 + a), 35); + printw("| %s", (!MBM_A_subbookmark[a] ? + "" : MBM_A_subbookmark[a])); + clrtoeol(); + move(LYlines-1, 0); + clrtoeol(); + break; + } + } /* end for */ + } /* end while */ + + term_options = FALSE; + signal(SIGINT, cleanup_sig); } diff --git a/src/LYOptions.h b/src/LYOptions.h index f154ebec..f89159aa 100644 --- a/src/LYOptions.h +++ b/src/LYOptions.h @@ -7,7 +7,12 @@ extern void options NOPARAMS; /* values for options */ #define L_EDITOR 2 #define L_DISPLAY 3 + #define L_HOME 4 +#define C_MULTI 24 +#define B_BOOK 34 +#define C_DEFAULT 50 + #define L_FTPSTYPE 5 #define L_MAIL_ADDRESS 6 #define L_SSEARCH 7 @@ -15,22 +20,28 @@ extern void options NOPARAMS; #define L_RAWMODE 9 #define L_LANGUAGE 10 #define L_PREF_CHARSET 11 -#define L_VIKEYS 12 -#define L_EMACSKEYS 13 + +#define L_BOOL_A 12 +#define B_VIKEYS 5 +#define C_VIKEYS 15 +#define B_EMACSKEYS 22 +#define C_EMACSKEYS 36 +#define B_SHOW_DOTFILES 44 +#define C_SHOW_DOTFILES 62 + +#define L_SELECT_POPUPS 13 #define L_KEYPAD 14 #define L_LINEED 15 #ifdef DIRED_SUPPORT #define L_DIRED 16 -#define L_SHOW_DOTFILES 17 -#define L_USER_MODE 18 -#define L_USER_AGENT 19 -#define L_EXEC 20 -#else -#define L_SHOW_DOTFILES 16 #define L_USER_MODE 17 #define L_USER_AGENT 18 #define L_EXEC 19 +#else +#define L_USER_MODE 16 +#define L_USER_AGENT 17 +#define L_EXEC 18 #endif /* DIRED_SUPPORT */ #endif /* LYOPTIONS_H */ diff --git a/src/LYPrint.c b/src/LYPrint.c index 34c17363..8e14c938 100644 --- a/src/LYPrint.c +++ b/src/LYPrint.c @@ -83,19 +83,30 @@ PUBLIC int printfile ARGS1(document *,newdoc) 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; if(!HTLoadAbsolute(&WWWDoc)) return(NOT_FOUND); - StrAllocCopy(sug_filename, newdoc->address); /* must be freed */ + /* + * Load the suggested filename string. - FM + */ + if (HText_getSugFname() != NULL) + StrAllocCopy(sug_filename, HText_getSugFname()); /* must be freed */ + else + StrAllocCopy(sug_filename, newdoc->address); /* must be freed */ /* * Get the number of lines in the file. */ if ((cp = (char *)strstr(link_info, "lines=")) != NULL) { - /* terminate prev string here */ + /* + * Terminate prev string here. + */ *cp = '\0'; - /* number of characters in "lines=" */ + /* + * Number of characters in "lines=". + */ cp += 6; lines_in_file = atoi(cp); @@ -145,7 +156,7 @@ PUBLIC int printfile ARGS1(document *,newdoc) retry: strcpy(filename, sug_filename); /* add suggestion info */ /* make the sug_filename conform to system specs */ change_sug_filename(filename); - if ((len = strlen(filename)) > 4) { + if (!(HTisDocumentSource()) && (len = strlen(filename)) > 4) { len -= 5; if (!strcasecomp((filename + len), ".html")) { filename[len] = '\0'; @@ -330,6 +341,18 @@ PUBLIC int printfile ARGS1(document *,newdoc) goto retry; } + if (HTisDocumentSource()) { + /* + * Added the document's URL as a BASE tag + * to the top of the file. May create + * technically invalid HTML, but will help + * get any partial or relative URLs resolved + * properly if no BASE tag is present to + * replace it. - FM + */ + fprintf(outfile_fp, "<BASE HREF=\"%s\">\n", + newdoc->address); + } print_wwwfile_to_fd(outfile_fp,0); if (keypad_mode) printlist(outfile_fp,FALSE); @@ -376,13 +399,41 @@ PUBLIC int printfile ARGS1(document *,newdoc) } else { remove(tempfile); /* remove duplicates */ } + if (HTisDocumentSource()) { + if ((len = strlen(tempfile)) > 3) { + len -= 4; + if (!strcasecomp((filename + len), ".txt")) { + filename[len] = '\0'; + strcat(filename, ".html"); + } + } + } else if ((len = strlen(tempfile)) > 4) { + len -= 5; + if (!strcasecomp((filename + len), ".html")) { + filename[len] = '\0'; + strcat(filename, ".txt"); + } + } if((outfile_fp = fopen(tempfile, "w")) == NULL) { HTAlert(UNABLE_TO_OPEN_TEMPFILE); break; } /* write the contents to a temp file */ - fprintf(outfile_fp, "X-URL: %s\n", newdoc->address); + if (HTisDocumentSource()) { + /* + * Added the document's URL as a BASE tag to + * the top of the message body. May create + * technically invalid HTML, but will help + * get any partial or relative URLs resolved + * properly if no BASE tag is present to + * replace it. - FM + */ + fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n", + newdoc->address); + } else { + fprintf(outfile_fp, "X-URL: %s\n\n", newdoc->address); + } print_wwwfile_to_fd(outfile_fp, 0); if (keypad_mode) printlist(outfile_fp, FALSE); @@ -410,9 +461,45 @@ PUBLIC int printfile ARGS1(document *,newdoc) break; } - fprintf(outfile_fp, "X-URL: %s\n", newdoc->address); + if (HTisDocumentSource()) { + /* + * Add Content-Type, Content-Location, and + * Content-Base headers for HTML source. - FM + * Also add Mime-Version header. - HM + */ + fprintf(outfile_fp, "Mime-Version: 1.0\n"); + fprintf(outfile_fp, "Content-Type: text/html"); + if (HTLoadedDocumentCharset() != NULL) { + fprintf(outfile_fp, "; charset=%s\n", + HTLoadedDocumentCharset()); + } else { + fprintf(outfile_fp, "\n"); + } + fprintf(outfile_fp, "Content-Location: %s\n", + newdoc->address); + fprintf(outfile_fp, "Content-Base: %s\n", + newdoc->address); + } else { + /* + * Add an X-URL header for rendered HTML or + * plain text. - FM + */ + fprintf(outfile_fp, "X-URL: %s\n", newdoc->address); + } fprintf(outfile_fp, "To: %s\nSubject:%s\n\n", user_response, sug_filename); + if (HTisDocumentSource()) { + /* + * Added the document's URL as a BASE tag to + * the top of the message body. May create + * technically invalid HTML, but will help + * get any partial or relative URLs resolved + * properly if no BASE tag is present to + * replace it. - FM + */ + fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n", + newdoc->address); + } print_wwwfile_to_fd(outfile_fp, 0); if (keypad_mode) printlist(outfile_fp, FALSE); @@ -464,6 +551,18 @@ PUBLIC int printfile ARGS1(document *,newdoc) signal(SIGINT, SIG_IGN); #endif /* !VMS */ + if (HTisDocumentSource()) { + /* + * Added the document's URL as a BASE tag + * to the top of the file. May create + * technically invalid HTML, but will help + * get any partial or relative URLs resolved + * properly if no BASE tag is present to + * replace it. - FM + */ + fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n", + newdoc->address); + } print_wwwfile_to_fd(outfile_fp, 0); if (keypad_mode) printlist(outfile_fp, FALSE); @@ -538,6 +637,18 @@ PUBLIC int printfile ARGS1(document *,newdoc) break; } + if (HTisDocumentSource()) { + /* + * Added the document's URL as a BASE tag + * to the top of the file. May create + * technically invalid HTML, but will help + * get any partial or relative URLs resolved + * properly if no BASE tag is present to + * replace it. - FM + */ + fprintf(outfile_fp, "<BASE HREF=\"%s\">\n\n", + newdoc->address); + } print_wwwfile_to_fd(outfile_fp, 0); if (keypad_mode) printlist(outfile_fp, FALSE); diff --git a/src/LYReadCFG.c b/src/LYReadCFG.c index bc9f6c0e..686eb13e 100644 --- a/src/LYReadCFG.c +++ b/src/LYReadCFG.c @@ -12,6 +12,7 @@ #include "LYCgi.h" #include "LYCurses.h" #include "LYSignal.h" +#include "LYBookmark.h" #ifdef DIRED_SUPPORT #include "LYLocal.h" @@ -590,7 +591,19 @@ PUBLIC void read_cfg ARGS1( user_mode = ADVANCED_MODE; } else if(!strncasecomp(buffer,"DEFAULT_BOOKMARK_FILE:",22)) { - StrAllocCopy(bookmark_page,buffer+22); + StrAllocCopy(bookmark_page, buffer+22); + StrAllocCopy(BookmarkPage, bookmark_page); + StrAllocCopy(MBM_A_subbookmark[0], bookmark_page); + StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT); + + } else if(!strncasecomp(buffer,"MULTI_BOOKMARK_SUPPORT:",23)) { + LYMultiBookmarks = is_true(buffer+23); + + } else if(!strncasecomp(buffer,"BLOCK_MULTI_BOOKMARKS:",22)) { + LYMBMBlocked = is_true(buffer+22); + + } else if(!strncasecomp(buffer,"ADVANCED_MULTI_BOOKMARKS:",25)) { + LYMBMAdvanced = is_true(buffer+25); } else if(!system_editor && !strncasecomp(buffer,"DEFAULT_EDITOR:",15)) { @@ -957,6 +970,9 @@ PUBLIC void read_cfg ARGS1( HTNewsChunkSize = HTNewsMaxChunk; } + } else if(!strncasecomp(buffer,"USE_SELECT_POPUPS:",17)) { + LYSelectPopups = is_true(buffer+17); + #if defined(VMS) && defined(VAXC) && !defined(__DECC) } else if (!strncasecomp(buffer, "DEFAULT_VIRTUAL_MEMORY_SIZE:", 28)) { HTVirtualMemorySize = atoi(buffer+28); diff --git a/src/LYShowInfo.c b/src/LYShowInfo.c index fb6e5c5e..9566967e 100644 --- a/src/LYShowInfo.c +++ b/src/LYShowInfo.c @@ -11,6 +11,7 @@ #include "LYShowInfo.h" #include "LYSignal.h" #include "LYCharUtils.h" +#include "GridText.h" #include "LYLeaks.h" @@ -97,9 +98,9 @@ PUBLIC int showinfo ARGS4( fprintf(fp0,"<h2>%s Version %s</h2>\n", LYNX_NAME, LYNX_VERSION); #ifdef DIRED_SUPPORT - if (lynx_edit_mode) { + if (lynx_edit_mode && nlinks > 0) { fprintf(fp0, - "<h2>Directory that you are currently viewing</h2>\n<pre>"); + "<h2>Directory that you are currently viewing</h2>\n<pre>"); cp = doc->address; if (!strncmp(cp, "file://localhost", 16)) @@ -109,8 +110,8 @@ PUBLIC int showinfo ARGS4( strcpy(temp, cp); HTUnEscape(temp); - fprintf(fp0," Name: %s\n", temp); - fprintf(fp0," URL: %s\n", doc->address); + fprintf(fp0," <em>Name:</em> %s\n", temp); + fprintf(fp0," <em> URL:</em> %s\n", doc->address); cp = links[doc->link].lname; if (!strncmp(cp, "file://localhost", 16)) @@ -126,16 +127,18 @@ PUBLIC int showinfo ARGS4( char modes[80]; if (((dir_info.st_mode) & S_IFMT) == S_IFDIR) { fprintf(fp0, - "\nDirectory that you have currently selected\n\n"); + "\nDirectory that you have currently selected\n\n"); } else if (((dir_info.st_mode) & S_IFMT) == S_IFREG) { - fprintf(fp0, "\nFile that you have currently selected\n\n"); + fprintf(fp0, + "\nFile that you have currently selected\n\n"); } else if (((dir_info.st_mode) & S_IFMT) == S_IFLNK) { fprintf(fp0, - "\nSymbolic link that you have currently selected\n\n"); + "\nSymbolic link that you have currently selected\n\n"); } else { - fprintf(fp0, "\nItem that you have currently selected\n\n"); + fprintf(fp0, + "\nItem that you have currently selected\n\n"); } - fprintf(fp0," Full name: %s\n", temp); + fprintf(fp0," <em>Full name:</em> %s\n", temp); if (((dir_info.st_mode) & S_IFMT) == S_IFLNK) { char buf[1025]; int buf_size; @@ -145,16 +148,16 @@ PUBLIC int showinfo ARGS4( } else { strcpy(buf, "Unable to follow link"); } - fprintf(fp0, " Points to file: %s\n", buf); + fprintf(fp0, " <em>Points to file:</em> %s\n", buf); } pw = getpwuid(dir_info.st_uid); if (pw) - fprintf(fp0, " Name of owner: %s\n", pw->pw_name); + fprintf(fp0, " <em>Name of owner:</em> %s\n", pw->pw_name); grp = getgrgid(dir_info.st_gid); if (grp && grp->gr_name) - fprintf(fp0, " Group name: %s\n", grp->gr_name); + fprintf(fp0, " <em>Group name:</em> %s\n", grp->gr_name); if (((dir_info.st_mode) & S_IFMT) == S_IFREG) { - sprintf(temp, " File size: %ld (bytes)\n", + sprintf(temp, " <em>File size:</em> %ld (bytes)\n", (long)dir_info.st_size); fprintf(fp0, "%s", temp); } @@ -162,16 +165,16 @@ PUBLIC int showinfo ARGS4( * Include date and time information. */ cp = ctime(&dir_info.st_ctime); - fprintf(fp0, " Creation date: %s", cp); + fprintf(fp0, " <em>Creation date:</em> %s", cp); cp = ctime(&dir_info.st_mtime); - fprintf(fp0, " Last modified: %s", cp); + fprintf(fp0, " <em>Last modified:</em> %s", cp); cp = ctime(&dir_info.st_atime); - fprintf(fp0, " Last accessed: %s\n", cp); + fprintf(fp0, " <em>Last accessed:</em> %s\n", cp); - fprintf(fp0, " Access Permissions\n"); - fprintf(fp0, " Owner: "); + fprintf(fp0, " <em>Access Permissions</em>\n"); + fprintf(fp0, " <em>Owner:</em> "); modes[0] = '\0'; modes[1] = '\0'; /* In case there are no permissions */ modes[2] = '\0'; @@ -190,7 +193,7 @@ PUBLIC int showinfo ARGS4( } fprintf(fp0, "%s\n", (char *)&modes[2]); /* Skip leading ', ' */ - fprintf(fp0, " Group: "); + fprintf(fp0, " <em>Group:</em> "); modes[0] = '\0'; modes[1] = '\0'; /* In case there are no permissions */ modes[2] = '\0'; @@ -209,7 +212,7 @@ PUBLIC int showinfo ARGS4( } fprintf(fp0, "%s\n", (char *)&modes[2]); /* Skip leading ', ' */ - fprintf(fp0, " World: "); + fprintf(fp0, " <em>World:</em> "); modes[0] = '\0'; modes[1] = '\0'; /* In case there are no permissions */ modes[2] = '\0'; @@ -232,21 +235,33 @@ PUBLIC int showinfo ARGS4( } else { #endif /* DIRED_SUPPORT */ - fprintf(fp0, "<h2>File that you are currently viewing</h2>\n<dl compact>"); + fprintf(fp0, + "<h2>File that you are currently viewing</h2>\n<dl compact>"); StrAllocCopy(Title, doc->title); LYEntify(&Title, TRUE); - fprintf(fp0,"<dt>Linkname: %s\n", Title); + fprintf(fp0,"<dt><em>Linkname:</em> %s\n", Title); StrAllocCopy(Address, doc->address); LYEntify(&Address, FALSE); - fprintf(fp0, "<dt> URL: %s\n", Address); + fprintf(fp0, + "<dt> <em>URL:</em> %s\n", Address); + + if ((cp = HText_getServer()) != NULL && *cp != '\0') + fprintf(fp0, "<dt><em> Server:</em> %s\n", cp); + + if ((cp = HText_getDate()) != NULL && *cp != '\0') + fprintf(fp0, "<dt><em> Date:</em> %s\n", cp); + + if ((cp = HText_getLastModified()) != NULL && *cp != '\0') + fprintf(fp0, "<dt><em>Last Mod:</em> %s\n", cp); if (doc->post_data) { StrAllocCopy(Address, doc->post_data); LYEntify(&Address, FALSE); - fprintf(fp0, "<dt>Post Data: %s\n", Address); - fprintf(fp0, "<dt>Post Content Type: %s\n", doc->post_content_type); + fprintf(fp0, "<dt><em>Post Data:</em> <xmp>%s</xmp>\n", Address); + fprintf(fp0, + "<dt><em>Post Content Type:</em> %s\n", doc->post_content_type); } if (owner_address) { @@ -255,34 +270,41 @@ PUBLIC int showinfo ARGS4( } else { StrAllocCopy(Address, "None"); } - fprintf(fp0, "<dt>Owner(s): %s\n", Address); + fprintf(fp0, "<dt><em>Owner(s):</em> %s\n", Address); - fprintf(fp0, "<dt> size: %d lines\n", size_of_file); + fprintf(fp0, + "<dt> <em>size:</em> %d lines\n", size_of_file); - fprintf(fp0, "<dt> mode: %s\n", + fprintf(fp0, "<dt> <em>mode:</em> %s\n", (lynx_mode == FORMS_LYNX_MODE ? "forms mode" : "normal")); fprintf(fp0, "</dl>\n"); /* end of list */ if (nlinks > 0) { fprintf(fp0, - "<h2>Link that you currently have selected</h2>\n<dl compact>"); + "<h2>Link that you currently have selected</h2>\n<dl compact>"); StrAllocCopy(Title, links[doc->link].hightext); LYEntify(&Title, TRUE); - fprintf(fp0, "<dt>Linkname: %s\n", Title); + fprintf(fp0, "<dt><em>Linkname:</em> %s\n", Title); if (lynx_mode == FORMS_LYNX_MODE && links[doc->link].type == WWW_FORM_LINK_TYPE) { if (links[doc->link].form->submit_method) { int method = links[doc->link].form->submit_method; - fprintf(fp0, "<dt> Method: %s\n", + char *enctype = links[doc->link].form->submit_enctype; + + fprintf(fp0, "<dt> <em>Method:</em> %s\n", (method == URL_POST_METHOD) ? "POST" : (method == URL_MAIL_METHOD) ? "(email)" : "GET"); + fprintf(fp0, "<dt> <em>Enctype:</em> %s\n", + (enctype && + *enctype ? + enctype : "application/x-www-form-urlencoded")); } if (links[doc->link].form->submit_action) { StrAllocCopy(Address, links[doc->link].form->submit_action); LYEntify(&Address, FALSE); - fprintf(fp0, "<dt> Action: %s\n", Address); + fprintf(fp0, "<dt> <em>Action:</em> %s\n", Address); } if (!(links[doc->link].form->submit_method && links[doc->link].form->submit_action)) { @@ -295,7 +317,7 @@ PUBLIC int showinfo ARGS4( } else { StrAllocCopy(Title, ""); } - fprintf(fp0, "<dt>Filename: %s\n", Title); + fprintf(fp0, "<dt><em>Filename:</em> %s\n", Title); } fprintf(fp0, "</dl>\n"); /* end of list */ diff --git a/src/LYStructs.h b/src/LYStructs.h index 1be79aed..6ef5d8a7 100644 --- a/src/LYStructs.h +++ b/src/LYStructs.h @@ -33,15 +33,9 @@ typedef struct _document { int link; int line; BOOL isHEAD; + char * bookmark; } document; -#ifdef DIRED_SUPPORT -typedef struct _taglink { - char *name; - struct _taglink *next; -} taglink; -#endif - #ifndef HTFORMS_H #include "HTForms.h" #endif /* HTFORMS_H */ @@ -54,6 +48,7 @@ typedef struct _histstruct { int link; int page; BOOL isHEAD; + char * bookmark; } histstruct; extern histstruct history[MAXHIST]; diff --git a/src/LYUtils.c b/src/LYUtils.c index d775f493..d1cf11f7 100644 --- a/src/LYUtils.c +++ b/src/LYUtils.c @@ -3,6 +3,7 @@ #include "HTParse.h" #include "HTAccess.h" #include "HTCJK.h" +#include "HTAlert.h" #include "LYCurses.h" #include "LYUtils.h" #include "LYStrings.h" @@ -1431,14 +1432,24 @@ PUBLIC void change_sug_filename ARGS1(char *,fname) /** Replace all but the last period with _'s, or second **/ /** to last if last is followed by a terminal Z or z, **/ + /** or GZ or gz, **/ /** e.g., convert foo.tar.Z to **/ /** foo.tar_Z **/ + /** or, convert foo.tar.gz to **/ + /** foo.tar-gz **/ j = strlen(fname) - 1; if ((dot = strrchr(fname, '.')) != NULL) { - if (((fname[j] == 'Z' || fname[j] == 'z') && fname[j-1] == '.') && - (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { - *dot = '_'; - dot = strrchr(fname, '.'); + if (TOUPPER(fname[j]) == 'Z') { + if ((fname[j-1] == '.') && + (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { + *dot = '_'; + dot = strrchr(fname, '.'); + } else if (((TOUPPER(fname[j-1]) == 'G') && + fname[j-2] == '.') && + (((cp = strchr(fname, '.')) != NULL) && cp < dot)) { + *dot = '-'; + dot = strrchr(fname, '.'); + } } cp = fname; while ((cp = strchr(cp, '.')) != NULL && cp < dot) @@ -1592,6 +1603,8 @@ PRIVATE char *restrict_name[] = { "editor" , "shell" , "bookmark" , + "multibook" , + "bookmark_exec" , "option_save" , "print" , "download" , @@ -1599,7 +1612,6 @@ PRIVATE char *restrict_name[] = { "exec" , "lynxcgi" , "exec_frozen" , - "bookmark_exec" , "goto" , "jump" , "file_url" , @@ -1633,6 +1645,8 @@ PRIVATE BOOLEAN *restrict_flag[] = { &no_editor , &no_shell , &no_bookmark , + &no_multibook , + &no_bookmark_exec, &no_option_save, &no_print , &no_download , @@ -1640,7 +1654,6 @@ PRIVATE BOOLEAN *restrict_flag[] = { &no_exec , &no_lynxcgi , &exec_frozen , - &no_bookmark_exec, &no_goto , &no_jump , &no_file_url , @@ -2132,7 +2145,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3( { char DomainPrefix[80], *StartP, *EndP; char DomainSuffix[80], *StartS, *EndS; - char *Str = NULL, *StrColon = NULL; + char *Str = NULL, *StrColon = NULL, *MsgStr = NULL; char *Host = NULL, *HostColon = NULL; char *Path = NULL; struct hostent *phost; @@ -2176,9 +2189,16 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3( * Do a DNS test on the potential host field * as presently trimmed. - FM */ + if (LYCursesON) { + StrAllocCopy(MsgStr, "Looking up "); + StrAllocCat(MsgStr, Str); + StrAllocCat(MsgStr, " first."); + HTProgress(MsgStr); + } if ((phost = gethostbyname(Str)) != NULL) { GotHost = TRUE; FREE(Str); + FREE(MsgStr); return GotHost; } @@ -2232,15 +2252,36 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3( isdigit(HostColon[1])) { *HostColon = '\0'; } + if (LYCursesON) { + StrAllocCopy(MsgStr, "Looking up "); + StrAllocCat(MsgStr, Host); + StrAllocCat(MsgStr, ", guessing..."); + HTProgress(MsgStr); + } GotHost = ((phost = gethostbyname(Host)) != NULL); if (HostColon != NULL) { *HostColon = ':'; } if (GotHost == FALSE) { + /* + * Give the user chance to interrupt lookup cycles. - KW + */ + if (LYCursesON && HTCheckForInterrupt()) { + if (TRACE) { + fprintf(stderr, + "*** LYExpandHostForURL interrupted while %s failed to resolve\n", + Host); + } + FREE(Str); + FREE(MsgStr); + FREE(Host); + return FALSE; /* We didn't find a valid name. */ + } + /* ** Advance to the next suffix, or end of suffix list. - FM */ - StartS = ((EndS == '\0') ? EndS : (EndS + 1)); + StartS = ((*EndS == '\0') ? EndS : (EndS + 1)); while ((*StartS) && (WHITE(*StartS) || *StartS == ',')) { StartS++; /* Skip whitespace and separators */ } @@ -2256,7 +2297,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3( /* ** Advance to the next prefix, or end of prefix list. - FM */ - StartP = ((EndP == '\0') ? EndP : (EndP + 1)); + StartP = ((*EndP == '\0') ? EndP : (EndP + 1)); while ((*StartP) && (WHITE(*StartP) || *StartP == ',')) { StartP++; /* Skip whitespace and separators */ } @@ -2290,6 +2331,7 @@ PUBLIC BOOLEAN LYExpandHostForURL ARGS3( * Clean up and return the last test result. - FM */ FREE(Str); + FREE(MsgStr); FREE(Host); return GotHost; } @@ -2591,3 +2633,76 @@ putenv (string) return 0; } #endif /* NO_PUTENV */ + +#ifdef VMS +/* + * This function appends fname to the home path and returns + * the full path and filename in VMS syntax. The fname + * string can be just a filename, or include a subirectory + * off the home directory, in which chase fname should + * with "./" (e.g., ./BM/lynx_bookmarks.html). - FM + */ +PUBLIC void LYVMS_HomePathAndFilename ARGS3( + char *, fbuffer, + int, fbuffer_size, + char *, fname) +{ + char *home = NULL; + char *temp = NULL; + int len; + + /* + * Make sure we have a buffer and string. - FM + */ + if (!fbuffer) + return; + if (!(fname && *fname) || fbuffer_size < 1) { + fbuffer[0] = '\0'; + return; + } + + /* + * Set up home string and length. - FM + */ + StrAllocCopy(home, Home_Dir()); + if (!(home && *home)) + StrAllocCopy(home, "Error:"); + len = fbuffer_size - strlen(home) - 1; + if (len < 0) { + len = 0; + home[fbuffer_size] = '\0'; + } + + /* + * Check whether we have a subdirectory path or just a filename. - FM + */ + if (!strncmp(fname, "./", 2)) { + /* + * We have a subdirectory path. - FM + */ + if (home[strlen(home)-1] == ']') { + /* + * We got the home directory, so convert it to + * SHELL syntax and append subdirectory path, + * then convert that to VMS syntax. - FM + */ + temp = (char *)calloc(1, (strlen(home) + strlen(fname) + 10)); + sprintf(temp, "%s%s", HTVMS_wwwName(home), (fname + 1)); + sprintf(fbuffer, "%.*s", + (fbuffer_size - 1), HTVMS_name("", temp)); + FREE(temp); + } else { + /* + * This will fail, but we need something in the buffer. - FM + */ + sprintf(fbuffer,"%s%.*s", home, len, fname); + } + } else { + /* + * We have a file in the home directory. - FM + */ + sprintf(fbuffer,"%s%.*s", home, len, fname); + } + FREE(home); +} +#endif /* VMS */ diff --git a/src/LYUtils.h b/src/LYUtils.h index d9fb84b6..7e91f071 100644 --- a/src/LYUtils.h +++ b/src/LYUtils.h @@ -47,7 +47,10 @@ extern BOOLEAN LYExpandHostForURL PARAMS(( extern BOOLEAN LYAddSchemeForURL PARAMS(( char **AllocatedString, char *default_scheme)); #ifdef VMS -extern void Define_VMSLogical PARAMS((char *LogicalName, char *LogicalValue)); +extern void Define_VMSLogical PARAMS(( + char *LogicalName, char *LogicalValue)); +extern void LYVMS_HomePathAndFilename PARAMS(( + char *fbuffer, int fbuffer_size, char * fname)); #endif /* VMS */ /* Whether or not the status line must be shown. diff --git a/src/LYrcFile.c b/src/LYrcFile.c index 504a0a57..9b8aaa39 100644 --- a/src/LYrcFile.c +++ b/src/LYrcFile.c @@ -6,6 +6,7 @@ #include "LYStrings.h" #include "LYGlobalDefs.h" #include "LYCharSets.h" +#include "LYBookmark.h" #include "LYLeaks.h" @@ -16,6 +17,10 @@ PUBLIC void read_rc() FILE *fp; char *cp, *cp2; int number_sign; + char MBM_line[256]; + int MBM_counter, MBM_counter2; + char *MBM_cp, *MBM_cp2, *MBM_cp1; + int MBM_i1, MBM_i2; /* make a name */ #ifdef UNIX @@ -113,18 +118,92 @@ PUBLIC void read_rc() StrAllocCopy(editor, cp); /* bookmark file */ - } else if ((cp=LYstrstr(line_buffer,"bookmark_file"))!=NULL && - cp-line_buffer < number_sign) { + } else if ((cp = LYstrstr(line_buffer, "bookmark_file")) != NULL && + cp-line_buffer < number_sign) { - if ((cp2 = (char *)strchr(cp,'=')) != NULL) + if ((cp2 = (char *)strchr(cp,'=')) != NULL) cp = cp2+1; - while (isspace(*cp)) cp++; /* get rid of spaces */ - - StrAllocCopy(bookmark_page, cp); + while (isspace(*cp)) + cp++; /* get rid of spaces */ + + /* + * Since this is the "default" saveto, we save it. + */ + StrAllocCopy(bookmark_page, cp); + StrAllocCopy(BookmarkPage, cp); + StrAllocCopy(MBM_A_subbookmark[0], cp); + StrAllocCopy(MBM_A_subdescript[0], MULTIBOOKMARKS_DEFAULT); + + } else if ((cp = LYstrstr(line_buffer, "multi_bookmark")) != NULL && + cp-line_buffer < number_sign) { + /* + * Found the root, now cycle through all the + * possible spaces and match specific ones. + */ + for (MBM_counter = 1; + MBM_counter <= MBM_V_MAXFILES; MBM_counter++) { + sprintf(MBM_line, "multi_bookmark%c", (MBM_counter + 'A')); + + if ((cp = LYstrstr(line_buffer, MBM_line)) != NULL && + cp-line_buffer < number_sign) { + if ((MBM_cp1 = (char *)strchr(cp, '=')) == NULL) { + break; + } else { + if ((MBM_cp2 = (char *)strchr(cp, ',')) == NULL) { + break; + } else { + MBM_i2 = 0; + /* + * skip over the '='. + */ + MBM_cp1++; + while (MBM_cp1 && MBM_cp1 != MBM_cp2) { + /* + * Skip spaces. + */ + if (isspace(*MBM_cp1)) { + MBM_cp1++; + continue; + } else { + MBM_line[MBM_i2++] = *MBM_cp1++; + } + } + MBM_line[MBM_i2++] = '\0'; + + StrAllocCopy(MBM_A_subbookmark[MBM_counter], + MBM_line); + + /* + * Now get the description ',' and ->. + */ + MBM_cp1 = (char *)strchr(cp, ','); + + MBM_i2 = 0; + /* + * Skip over the ','. + */ + MBM_cp1++; + /* + * Eat spaces in front of description. + */ + while (isspace(*MBM_cp1)) + MBM_cp1++; + while (*MBM_cp1) + MBM_line[MBM_i2++] = *MBM_cp1++; + MBM_line[MBM_i2++] = '\0'; + + StrAllocCopy(MBM_A_subdescript[MBM_counter], + MBM_line); + + break; + } + } + } + } /* personal_mail_address */ - } else if ((cp=LYstrstr(line_buffer,"personal_mail_address"))!=NULL && + } else if((cp=LYstrstr(line_buffer,"personal_mail_address"))!=NULL && cp-line_buffer < number_sign) { if ((cp2 = (char *)strchr(cp,'=')) != NULL) @@ -223,9 +302,31 @@ PUBLIC void read_rc() else emacs_keys=FALSE; + /* multi bookmarks */ + } else if ((cp = LYstrstr(line_buffer, "sub_bookmarks")) != NULL && + cp-line_buffer < number_sign) { + + if ((cp2 = (char *)strchr(cp, '=')) != NULL) + cp = (cp2 + 1); + + while (isspace(*cp)) + cp++; /* get rid of spaces */ + + if (!strncmp(cp, "on", 2) || !strncmp(cp, "ON", 2)) + LYMultiBookmarks = TRUE; + else if (!strncmp(cp, "standard", 8) || + !strncmp(cp, "STANDARD", 8)) { + LYMultiBookmarks = TRUE; + LYMBMAdvanced = FALSE; + } else if (!strncmp(cp, "advanced", 8) || + !strncmp(cp, "ADVANCED", 8)) { + LYMultiBookmarks = TRUE; + LYMBMAdvanced = TRUE; + } else + LYMultiBookmarks = FALSE; } else if ((cp=LYstrstr(line_buffer,"keypad_mode"))!=NULL && - cp-line_buffer < number_sign) { + cp-line_buffer < number_sign) { if ((cp2 = (char *)strchr(cp,'=')) != NULL) cp = cp2+1; @@ -292,6 +393,20 @@ PUBLIC void read_rc() #endif /* DIRED_SUPPORT */ + /* select popups */ + } else if ((cp=LYstrstr(line_buffer,"select_popups")) != NULL && + cp-line_buffer < number_sign) { + + if ((cp2 = (char * )strchr(cp,'=')) != NULL) + cp = cp2+1; + + while (isspace(*cp)) cp++; /* get rid of spaces */ + + if (!strncasecomp(cp, "off", 3)) + LYSelectPopups = FALSE; + else + LYSelectPopups = TRUE; + } /* end of if */ } /* end of while */ @@ -304,6 +419,7 @@ PUBLIC int save_rc () char rcfile[256]; FILE *fp; int i; + int MBM_c; /* make a name */ #ifdef UNIX @@ -392,7 +508,8 @@ PUBLIC int save_rc () #if defined(EXEC_LINKS) || defined(EXEC_SCRIPTS) /* local_exec */ - fprintf(fp,"# if run all execution links is on then all local exection links will\n\ + fprintf(fp,"\ +# if run all execution links is on then all local exection links will\n\ # be executed when they are selected.\n\ #\n\ # WARNING - this is potentially VERY dangerous. Since you may view\n\ @@ -402,10 +519,11 @@ PUBLIC int save_rc () # or compromise security. This should only be set to on if you\n\ # are viewing trusted source information\n"); - fprintf(fp,"run_all_execution_links=%s\n\n",(local_exec ? "on" : "off")); + fprintf(fp, "run_all_execution_links=%s\n\n",(local_exec ? "on" : "off")); /* local_exec_on_local_files */ - fprintf(fp,"# if run all execution links is on then all local exection links that\n\ + fprintf(fp,"\ +# if run all execution links is on then all local exection links that\n\ # are found in LOCAL files will be executed when they are selected.\n\ # This is different from \"run all execution links\" in that only files\n\ # that reside on the local system will have execution link permissions\n\ @@ -438,7 +556,34 @@ PUBLIC int save_rc () # ^N - down ^p - up\n\ # ^B - left ^F - right\n\ # will be enabled.\n"); - fprintf(fp,"emacs_keys=%s\n\n",(emacs_keys ? "on" : "off")); + fprintf(fp, "emacs_keys=%s\n\n", (emacs_keys ? "on" : "off")); + + /* multiple bookmarks - on or off */ + fprintf(fp,"\ +# If sub_bookmarks are turned on then all bookmark operations\n\ +# will first prompt the user to select an active sub-bookmark file.\n\ +# If the default lynx bookmarks file is defined, it will be used as\n\ +# the default selection. When this option is set to 'advanced', and\n\ +# the user mode is advanced, the 'v'iew bookmark command will invoke\n\ +# a statusline prompt instead of the menu seen in novice and intermediate\n\ +# user modes. When this option is set to 'standard', the menu will be\n\ +# presented regardless of user mode. If this option is set to 'off',\n\ +# sub-bookmark files are disabled.\n"); + fprintf(fp,"sub_bookmarks=%s\n\n", (LYMultiBookmarks ? + (LYMBMAdvanced ? "advanced" : "standard") : "off")); + + /* multiple bookmarks support - list out sub-bookmarks */ + fprintf(fp,"\ +# The following allow you to define sub-bookmark files and definitions.\n\ +# Format is <keyword><letter>=<filename>,<description>\n\ +# Up to MBM_V_MAXFILES (26 MAX) are allowed.\n\ +# We start with 'multi_bookmarkB' since 'A' is reserved!\n"); + for (MBM_c = 1; MBM_c <= MBM_V_MAXFILES; MBM_c++) + fprintf(fp,"multi_bookmark%c=%s%s%s\n", (MBM_c + 'A'), + (MBM_A_subbookmark[MBM_c] ? MBM_A_subbookmark[MBM_c] : ""), + (MBM_A_subbookmark[MBM_c] ? "," : ""), + (MBM_A_subdescript[MBM_c] ? MBM_A_subdescript[MBM_c] : "")); + fprintf(fp,"\n"); /* keypad mode */ fprintf(fp,"\ @@ -513,6 +658,17 @@ PUBLIC int save_rc () "DIRECTORIES_FIRST"))); #endif /* DIRED_SUPPORT */ + /* select popups */ + fprintf(fp, "\ +# select_popups specifies whether the OPTIONs in a SELECT block which\n\ +# lacks a MULTIPLE attribute are presented as a vertical list of radio\n\ +# buttons or via a popup menu. Note that if the MULTIPLE attribute is\n\ +# present in the SELECT start tag, Lynx always will create a vertical list\n\ +# of checkboxes for the OPTIONs. A value of \"on\" will set popup menus\n\ +# as the default while a value of \"off\" will set use of radio boxes.\n\ +# The default can be overridden via the -popup command line toggle.\n"); + fprintf(fp, "select_popups=%s\n\n",(LYSelectPopups ? "on" : "off")); + fclose(fp); /* get rid of any copies of the .lynxrc file that VMS creates */ |