1 /*
2 * $LynxId: LYMainLoop.c,v 1.217 2013/05/05 20:36:20 tom Exp $
3 */
4 #include <HTUtils.h>
5 #include <HTAccess.h>
6 #include <HTParse.h>
7 #include <HTList.h>
8 #include <HTML.h>
9 #include <HTFTP.h>
10 #include <HTFile.h>
11 #include <HTTP.h>
12 #include <HTAABrow.h>
13 #include <HTNews.h>
14 #include <LYCurses.h>
15 #include <LYStyle.h>
16 #include <LYGlobalDefs.h>
17 #include <HTAlert.h>
18 #include <LYUtils.h>
19 #include <GridText.h>
20 #include <LYStrings.h>
21 #include <LYOptions.h>
22 #include <LYSignal.h>
23 #include <LYGetFile.h>
24 #include <HTForms.h>
25 #include <LYSearch.h>
26 #include <LYClean.h>
27 #include <LYHistory.h>
28 #include <LYPrint.h>
29 #include <LYMail.h>
30 #include <LYEdit.h>
31 #include <LYShowInfo.h>
32 #include <LYBookmark.h>
33 #include <LYKeymap.h>
34 #include <LYJump.h>
35 #include <LYDownload.h>
36 #include <LYList.h>
37 #include <LYMap.h>
38 #include <LYTraversal.h>
39 #include <LYCharSets.h>
40 #include <LYCharUtils.h>
41 #include <LYCookie.h>
42 #include <LYMainLoop.h>
43 #include <LYPrettySrc.h>
44
45 #ifdef USE_SESSIONS
46 #include <LYSession.h>
47 #endif
48
49 #ifdef KANJI_CODE_OVERRIDE
50 #include <HTCJK.h>
51 #endif
52
53 #define LinkIsTextarea(linkNumber) \
54 (links[linkNumber].type == WWW_FORM_LINK_TYPE && \
55 links[linkNumber].l_form->type == F_TEXTAREA_TYPE)
56
57 #define LinkIsTextLike(linkNumber) \
58 (links[linkNumber].type == WWW_FORM_LINK_TYPE && \
59 F_TEXTLIKE(links[linkNumber].l_form->type))
60
61 #ifdef KANJI_CODE_OVERRIDE
str_kcode(HTkcode code)62 char *str_kcode(HTkcode code)
63 {
64 char *p;
65 static char buff[8];
66
67 if (current_char_set == TRANSPARENT) {
68 p = "THRU";
69 } else if (!LYRawMode) {
70 p = "RAW";
71 } else {
72 switch (code) {
73 case NOKANJI:
74 p = "AUTO";
75 break;
76
77 case EUC:
78 p = "EUC+";
79 break;
80
81 case SJIS:
82 p = "SJIS";
83 break;
84
85 case JIS:
86 p = " JIS";
87 break;
88
89 default:
90 p = " ???";
91 break;
92 }
93 }
94
95 if (no_table_center) {
96 buff[0] = '!';
97 strcpy(buff + 1, p);
98 } else {
99 strcpy(buff, p);
100 }
101
102 return buff;
103 }
104 #endif
105
106 #ifdef WIN_EX
107
str_sjis(char * to,char * from)108 static char *str_sjis(char *to, char *from)
109 {
110 if (!LYRawMode) {
111 strcpy(to, from);
112 #ifdef KANJI_CODE_OVERRIDE
113 } else if (last_kcode == EUC) {
114 EUC_TO_SJIS(from, to);
115 } else if (last_kcode == SJIS) {
116 strcpy(to, from);
117 #endif
118 } else {
119 TO_SJIS((unsigned char *) from, (unsigned char *) to);
120 }
121 return to;
122 }
123
set_ws_title(char * str)124 static void set_ws_title(char *str)
125 {
126 SetConsoleTitle(str);
127 }
128
129 #endif /* WIN_EX */
130
131 #if defined(USE_EXTERNALS) || defined(WIN_EX)
132 #include <LYExtern.h>
133 #endif
134
135 #ifdef __EMX__
136 #include <io.h>
137 #endif
138
139 #ifdef DIRED_SUPPORT
140 #include <LYLocal.h>
141 #include <LYUpload.h>
142 #endif /* DIRED_SUPPORT */
143
144 #include <LYexit.h>
145 #include <LYLeaks.h>
146
147 /* two constants: */
148 HTLinkType *HTInternalLink = 0;
149 HTAtom *WWW_SOURCE = 0;
150
151 #define NONINTERNAL_OR_PHYS_DIFFERENT(p,n) \
152 ((track_internal_links && \
153 (!curdoc.internal_link || are_phys_different(p,n))) || \
154 are_different(p,n))
155
156 #define NO_INTERNAL_OR_DIFFERENT(c,n) \
157 (track_internal_links || are_different(c,n))
158
159 static void exit_immediately_with_error_message(int state, int first_file);
160 static void status_link(char *curlink_name, int show_more, int show_indx);
161 static void show_main_statusline(const LinkInfo curlink, int for_what);
162 static void form_noviceline(int);
163 static int are_different(DocInfo *doc1, DocInfo *doc2);
164
165 static int are_phys_different(DocInfo *doc1, DocInfo *doc2);
166
167 #define FASTTAB
168
sametext(char * een,char * twee)169 static int sametext(char *een,
170 char *twee)
171 {
172 if (een && twee)
173 return (strcmp(een, twee) == 0);
174 return TRUE;
175 }
176
177 HTList *Goto_URLs = NULL; /* List of Goto URLs */
178
179 char *LYRequestTitle = NULL; /* newdoc.title in calls to getfile() */
180 char *LYRequestReferer = NULL; /* Referer, may be set in getfile() */
181
182 static bstring *prev_target = NULL;
183
184 #ifdef DISP_PARTIAL
185 BOOLEAN display_partial = FALSE; /* could be enabled in HText_new() */
186 int NumOfLines_partial = 0; /* number of lines displayed in partial mode */
187 #endif
188
189 static int Newline = 0;
190 static DocInfo newdoc;
191 static DocInfo curdoc;
192 static char *traversal_host = NULL;
193 static char *traversal_link_to_add = NULL;
194 static char *owner_address = NULL; /* Holds the responsible owner's address */
195 static char *ownerS_address = NULL; /* Holds owner's address during source fetch */
196
197 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
198 static BOOL textinput_activated = FALSE;
199
200 #else
201 #define textinput_activated TRUE /* a current text input is always active */
202 #endif
203 #ifdef INACTIVE_INPUT_STYLE_VH
204 BOOL textinput_redrawn = FALSE;
205
206 /*must be public since used in LYhighlight(..) */
207 #endif
208
209 #ifdef LY_FIND_LEAKS
210 /*
211 * Function for freeing allocated mainloop() variables. - FM
212 */
free_mainloop_variables(void)213 static void free_mainloop_variables(void)
214 {
215 LYFreeDocInfo(&newdoc);
216 LYFreeDocInfo(&curdoc);
217
218 #ifdef USE_COLOR_STYLE
219 FREE(curdoc.style);
220 FREE(newdoc.style);
221 #endif
222 FREE(traversal_host);
223 FREE(traversal_link_to_add);
224 FREE(owner_address);
225 FREE(ownerS_address);
226 #ifdef DIRED_SUPPORT
227 clear_tags();
228 reset_dired_menu();
229 #endif /* DIRED_SUPPORT */
230 FREE(WWW_Download_File); /* LYGetFile.c/HTFWriter.c */
231 FREE(LYRequestReferer);
232
233 return;
234 }
235 #endif /* LY_FIND_LEAKS */
236
237 #ifndef NO_LYNX_TRACE
TracelogOpenFailed(void)238 static void TracelogOpenFailed(void)
239 {
240 WWW_TraceFlag = FALSE;
241 if (LYCursesON) {
242 HTUserMsg(TRACELOG_OPEN_FAILED);
243 } else {
244 fprintf(stderr, "%s\n", TRACELOG_OPEN_FAILED);
245 exit_immediately(EXIT_FAILURE);
246 }
247 }
248
LYReopenTracelog(BOOLEAN * trace_flag_ptr)249 static BOOLEAN LYReopenTracelog(BOOLEAN *trace_flag_ptr)
250 {
251 CTRACE((tfp, "\nTurning off TRACE for fetch of log.\n"));
252 LYCloseTracelog();
253 if ((LYTraceLogFP = LYAppendToTxtFile(LYTraceLogPath)) == NULL) {
254 TracelogOpenFailed();
255 return FALSE;
256 }
257 if (TRACE) {
258 WWW_TraceFlag = FALSE;
259 *trace_flag_ptr = TRUE;
260 }
261 return TRUE;
262 }
263
turn_trace_back_on(BOOLEAN * trace_flag_ptr)264 static void turn_trace_back_on(BOOLEAN *trace_flag_ptr)
265 {
266 if (*trace_flag_ptr == TRUE) {
267 WWW_TraceFlag = TRUE;
268 *trace_flag_ptr = FALSE;
269 fprintf(tfp, "Turning TRACE back on.\n\n");
270 }
271 }
272 #else
273 #define LYReopenTracelog(flag) TRUE
274 #define turn_trace_back_on(flag) /*nothing */
275 #endif /* NO_LYNX_TRACE */
276
TraceFP(void)277 FILE *TraceFP(void)
278 {
279 #ifndef NO_LYNX_TRACE
280 if (LYTraceLogFP != 0) {
281 return LYTraceLogFP;
282 }
283 #endif /* NO_LYNX_TRACE */
284 return stderr;
285 }
286
LYOpenTraceLog(void)287 BOOLEAN LYOpenTraceLog(void)
288 {
289 #ifndef NO_LYNX_TRACE
290 if (TRACE && LYUseTraceLog && LYTraceLogFP == NULL) {
291 /*
292 * If we can't open it for writing, give up. Otherwise, on VMS close
293 * it, delete it and any versions from previous sessions so they don't
294 * accumulate, and open it again. - FM
295 */
296 if ((LYTraceLogFP = LYNewTxtFile(LYTraceLogPath)) == NULL) {
297 TracelogOpenFailed();
298 return FALSE;
299 }
300 #ifdef VMS
301 LYCloseTracelog();
302 HTSYS_remove(LYTraceLogPath);
303 if ((LYTraceLogFP = LYNewTxtFile(LYTraceLogPath)) == NULL) {
304 TracelogOpenFailed();
305 return FALSE;
306 }
307 #endif /* VMS */
308 fflush(stdout);
309 fflush(stderr);
310 fprintf(tfp, "\t\t%s (%s)\n\n", LYNX_TRACELOG_TITLE, LYNX_VERSION);
311 /*
312 * If TRACE is on, indicate whether the anonymous restrictions are set.
313 * - FM, LP, kw
314 *
315 * This is only a summary for convenience - it doesn't take the case of
316 * individual -restrictions= options into account. - kw
317 */
318 if (LYValidate) {
319 if (LYRestricted && had_restrictions_default) {
320 CTRACE((tfp,
321 "Validate and some anonymous restrictions are set.\n"));
322 } else if (had_restrictions_default) {
323 CTRACE((tfp,
324 "Validate restrictions set, restriction \"default\" was given.\n"));
325 } else if (LYRestricted) {
326 CTRACE((tfp,
327 "Validate restrictions set, additional anonymous restrictions ignored.\n"));
328 } else {
329 CTRACE((tfp, "Validate restrictions are set.\n"));
330 }
331 /* But none of the above can actually happen, since there should
332 * never be a Trace Log with -validate. If it appears in a log
333 * file something went wrong! */
334 } else if (LYRestricted) {
335 if (had_restrictions_all) {
336 CTRACE((tfp,
337 "Anonymous restrictions set, restriction \"all\" was given.\n"));
338 } else {
339 CTRACE((tfp, "Anonymous restrictions are set.\n"));
340 }
341 } else if (had_restrictions_all && had_restrictions_default) {
342 CTRACE((tfp, "Restrictions \"all\" and \"default\" were given.\n"));
343 } else if (had_restrictions_default) {
344 CTRACE((tfp, "Restriction \"default\" was given.\n"));
345 } else if (had_restrictions_all) {
346 CTRACE((tfp, "\"all\" restrictions are set.\n"));
347 }
348 }
349 #endif /* NO_LYNX_TRACE */
350 return TRUE;
351 }
352
LYCloseTracelog(void)353 void LYCloseTracelog(void)
354 {
355 #ifndef NO_LYNX_TRACE
356 if (LYTraceLogFP != 0) {
357 fflush(stdout);
358 fflush(stderr);
359 fclose(LYTraceLogFP);
360 LYTraceLogFP = 0;
361 }
362 #endif /* NO_LYNX_TRACE */
363 }
364
handle_LYK_TRACE_TOGGLE(void)365 void handle_LYK_TRACE_TOGGLE(void)
366 {
367 #ifndef NO_LYNX_TRACE
368 WWW_TraceFlag = (BOOLEAN) !WWW_TraceFlag;
369 if (LYOpenTraceLog())
370 HTUserMsg(WWW_TraceFlag ? TRACE_ON : TRACE_OFF);
371 #else
372 HTUserMsg(TRACE_DISABLED);
373 #endif /* NO_LYNX_TRACE */
374 }
375
LYSetNewline(int value)376 void LYSetNewline(int value)
377 {
378 Newline = value;
379 }
380
381 #define LYSetNewline(value) Newline = value
382
LYGetNewline(void)383 int LYGetNewline(void)
384 {
385 return Newline;
386 }
387
388 #define LYGetNewline() Newline
389
LYChgNewline(int adjust)390 void LYChgNewline(int adjust)
391 {
392 LYSetNewline(Newline + adjust);
393 }
394
395 #define LYChgNewline(adjust) Newline += (adjust)
396
397 #ifdef USE_SOURCE_CACHE
398 static BOOLEAN from_source_cache = FALSE;
399
400 /*
401 * Like HTreparse_document(), but also set the flag.
402 */
reparse_document(void)403 static BOOLEAN reparse_document(void)
404 {
405 BOOLEAN result;
406
407 from_source_cache = TRUE; /* set for LYMainLoop_pageDisplay() */
408 if ((result = HTreparse_document()) != FALSE) {
409 from_source_cache = TRUE; /* set for mainloop refresh */
410 } else {
411 from_source_cache = FALSE;
412 }
413 return result;
414 }
415 #endif /* USE_SOURCE_CACHE */
416
417 /*
418 * Prefer reparsing if we can, but reload if we must - to force regeneration
419 * of the display.
420 */
reparse_or_reload(int * cmd)421 static BOOLEAN reparse_or_reload(int *cmd)
422 {
423 #ifdef USE_SOURCE_CACHE
424 if (reparse_document()) {
425 return FALSE;
426 }
427 #endif
428 *cmd = LYK_RELOAD;
429 return TRUE;
430 }
431
432 /*
433 * Functions for setting the current address
434 */
set_address(DocInfo * doc,const char * address)435 static void set_address(DocInfo *doc, const char *address)
436 {
437 StrAllocCopy(doc->address, address);
438 }
439
copy_address(DocInfo * dst,DocInfo * src)440 static void copy_address(DocInfo *dst, DocInfo *src)
441 {
442 StrAllocCopy(dst->address, src->address);
443 }
444
free_address(DocInfo * doc)445 static void free_address(DocInfo *doc)
446 {
447 FREE(doc->address);
448 }
449
move_address(DocInfo * dst,DocInfo * src)450 static void move_address(DocInfo *dst, DocInfo *src)
451 {
452 copy_address(dst, src);
453 free_address(src);
454 }
455
456 #ifdef DISP_PARTIAL
457 /*
458 * This is for traversal call from within partial mode in LYUtils.c
459 * and HTFormat.c It simply calls HText_pageDisplay() but utilizes
460 * LYMainLoop.c static variables to manage proper newline position
461 * in case of #fragment
462 */
LYMainLoop_pageDisplay(int line_num)463 BOOL LYMainLoop_pageDisplay(int line_num)
464 {
465 const char *pound;
466 int prev_newline = LYGetNewline();
467
468 /*
469 * Override Newline with a new value if user scrolled the document while
470 * loading (in LYUtils.c).
471 */
472 LYSetNewline(line_num);
473
474 #ifdef USE_SOURCE_CACHE
475 /*
476 * reparse_document() acts on 'curdoc' which always on top of the
477 * history stack: no need to resolve #fragment position since
478 * we already know it (curdoc.line).
479 * So bypass here. Sorry for possible confusion...
480 */
481 if (!from_source_cache)
482 #endif
483 /*
484 * If the requested URL has the #fragment, and we are not popped
485 * from the history stack, and have not scrolled the document yet -
486 * we should calculate correct newline position for the fragment.
487 * (This is a bit suboptimal since HTFindPoundSelector() traverse
488 * anchors list each time, so we have a quadratic complexity
489 * and may load CPU in a worst case).
490 */
491 if (display_partial
492 && newdoc.line == 1 && line_num == 1 && prev_newline == 1
493 && (pound = findPoundSelector(newdoc.address))
494 && *pound && *(pound + 1)) {
495 if (HTFindPoundSelector(pound + 1)) {
496 /* HTFindPoundSelector will initialize www_search_result */
497 LYSetNewline(www_search_result);
498 } else {
499 LYSetNewline(prev_newline); /* restore ??? */
500 return NO; /* no repaint */
501 }
502 }
503
504 HText_pageDisplay(LYGetNewline(), prev_target->str);
505 return YES;
506 }
507 #endif /* DISP_PARTIAL */
508
set_curdoc_link(int nextlink)509 static BOOL set_curdoc_link(int nextlink)
510 {
511 BOOL result = FALSE;
512
513 if (curdoc.link != nextlink
514 && nextlink >= 0
515 && nextlink < nlinks) {
516 if (curdoc.link >= 0 && curdoc.link < nlinks) {
517 LYhighlight(FALSE, curdoc.link, prev_target->str);
518 result = TRUE;
519 }
520 curdoc.link = nextlink;
521 }
522 return result;
523 }
524
525 /*
526 * Setup newdoc to jump to the given line.
527 *
528 * FIXME: prefer to also jump to the link given in a URL fragment, but the
529 * interface of getfile() does not provide that ability yet.
530 */
goto_line(int nextline)531 static void goto_line(int nextline)
532 {
533 int n;
534 int old_link = newdoc.link;
535
536 newdoc.link = 0;
537 for (n = 0; n < nlinks; ++n) {
538 if (nextline == links[n].anchor_line_num + 1) {
539 CTRACE((tfp, "top_of_screen %d\n", HText_getTopOfScreen() + 1));
540 CTRACE((tfp, "goto_line(%d) -> link %d -> %d\n", nextline,
541 old_link, n));
542 newdoc.link = n;
543 break;
544 }
545 }
546 }
547
548 #ifdef USE_MOUSE
set_curdoc_link_by_mouse(int nextlink)549 static void set_curdoc_link_by_mouse(int nextlink)
550 {
551 if (set_curdoc_link(nextlink)) {
552 LYhighlight(TRUE, nextlink, prev_target->str);
553 LYmsec_delay(20);
554 }
555 }
556 #else
557 #define set_curdoc_link_by_mouse(nextlink) set_curdoc_link(nextlink)
558 #endif
559
do_change_link(void)560 static int do_change_link(void)
561 {
562 #ifdef USE_MOUSE
563 /* Is there a mouse-clicked link waiting? */
564 int mouse_tmp = get_mouse_link();
565
566 /* If yes, use it as the link */
567 if (mouse_tmp != -1) {
568 if (mouse_tmp < 0 || mouse_tmp >= nlinks) {
569 char *msgtmp = NULL;
570
571 HTSprintf0(&msgtmp,
572 gettext("Internal error: Invalid mouse link %d!"),
573 mouse_tmp);
574 HTAlert(msgtmp);
575 FREE(msgtmp);
576 return (-1); /* indicates unexpected error */
577 }
578 set_curdoc_link_by_mouse(mouse_tmp);
579 }
580 #endif /* USE_MOUSE */
581 return (0); /* indicates OK */
582 }
583
584 #ifdef DIRED_SUPPORT
585 #define DIRED_UNCACHE_1 if (LYAutoUncacheDirLists < 1) /*nothing*/ ;\
586 else HTuncache_current_document()
587 #define DIRED_UNCACHE_2 if (LYAutoUncacheDirLists < 2) /*nothing*/ ;\
588 else HTuncache_current_document()
589 #endif /* DIRED_SUPPORT */
590
do_check_goto_URL(bstring ** user_input,char ** old_user_input,BOOLEAN * force_load)591 static void do_check_goto_URL(bstring **user_input,
592 char **old_user_input,
593 BOOLEAN *force_load)
594 {
595 static BOOLEAN always = TRUE;
596 /* *INDENT-OFF* */
597 static struct {
598 const char *name;
599 BOOLEAN *flag;
600 } table[] = {
601 { STR_FILE_URL, &no_file_url },
602 { STR_FILE_URL, &no_goto_file },
603 { STR_LYNXEXEC, &no_goto_lynxexec },
604 { STR_LYNXPROG, &no_goto_lynxprog },
605 { STR_LYNXCGI, &no_goto_lynxcgi },
606 { STR_CSO_URL, &no_goto_cso },
607 { STR_FINGER_URL, &no_goto_finger },
608 { STR_FTP_URL, &no_goto_ftp },
609 { STR_GOPHER_URL, &no_goto_gopher },
610 { STR_HTTP_URL, &no_goto_http },
611 { STR_HTTPS_URL, &no_goto_https },
612 { STR_MAILTO_URL, &no_goto_mailto },
613 { STR_RLOGIN_URL, &no_goto_rlogin },
614 { STR_TELNET_URL, &no_goto_telnet },
615 { STR_TN3270_URL, &no_goto_tn3270 },
616 { STR_WAIS_URL, &no_goto_wais },
617 #ifndef DISABLE_BIBP
618 { STR_BIBP_URL, &no_goto_bibp },
619 #endif
620 #ifndef DISABLE_NEWS
621 { STR_NEWS_URL, &no_goto_news },
622 { STR_NNTP_URL, &no_goto_nntp },
623 { STR_SNEWS_URL, &no_goto_snews },
624 #endif
625 #ifdef EXEC_LINKS
626 { STR_LYNXEXEC, &local_exec_on_local_files },
627 { STR_LYNXPROG, &local_exec_on_local_files },
628 #endif /* EXEC_LINKS */
629 { STR_LYNXCFG, &no_goto_configinfo },
630 { STR_LYNXCFLAGS, &no_goto_configinfo },
631 { STR_LYNXCOOKIE, &always },
632 #ifdef USE_CACHEJAR
633 { STR_LYNXCACHE, &always },
634 #endif
635 { STR_LYNXDIRED, &always },
636 { STR_LYNXDOWNLOAD, &always },
637 { STR_LYNXOPTIONS, &always },
638 { STR_LYNXPRINT, &always },
639 };
640 /* *INDENT-ON* */
641
642 unsigned n;
643 BOOLEAN found = FALSE;
644
645 /* allow going to anchors */
646 if ((*user_input)->str[0] == '#') {
647 if ((*user_input)->str[1] &&
648 HTFindPoundSelector((*user_input)->str + 1)) {
649 /* HTFindPoundSelector will initialize www_search_result,
650 so we do nothing else. */
651 HTAddGotoURL((*user_input)->str);
652 trimPoundSelector(curdoc.address);
653 StrAllocCat(curdoc.address, (*user_input)->str);
654 }
655 } else {
656 /*
657 * If it's not a URL then make it one.
658 */
659 StrAllocCopy(*old_user_input, (*user_input)->str);
660 LYEnsureAbsoluteURL(old_user_input, "", TRUE);
661 BStrCopy0((*user_input), *old_user_input);
662 FREE(*old_user_input);
663
664 for (n = 0; n < TABLESIZE(table); n++) {
665 if (*(table[n].flag)
666 && !StrNCmp((*user_input)->str,
667 table[n].name,
668 strlen(table[n].name))) {
669 found = TRUE;
670 HTUserMsg2(GOTO_XXXX_DISALLOWED, table[n].name);
671 break;
672 }
673 }
674 if (found) {
675 ;
676 } else if (LYValidate &&
677 !isHTTP_URL((*user_input)->str) &&
678 !isHTTPS_URL((*user_input)->str)) {
679 HTUserMsg(GOTO_NON_HTTP_DISALLOWED);
680
681 } else {
682 set_address(&newdoc, (*user_input)->str);
683 newdoc.isHEAD = FALSE;
684 /*
685 * Might be an anchor in the same doc from a POST form. If so,
686 * dont't free the content. -- FM
687 */
688 if (are_different(&curdoc, &newdoc)) {
689 /*
690 * Make a name for this new URL.
691 */
692 StrAllocCopy(newdoc.title,
693 gettext("A URL specified by the user"));
694 LYFreePostData(&newdoc);
695 FREE(newdoc.bookmark);
696 newdoc.safe = FALSE;
697 newdoc.internal_link = FALSE;
698 *force_load = TRUE;
699 #ifdef DIRED_SUPPORT
700 if (lynx_edit_mode) {
701 DIRED_UNCACHE_2;
702 }
703 #endif /* DIRED_SUPPORT */
704 }
705 LYUserSpecifiedURL = TRUE;
706 HTAddGotoURL(newdoc.address);
707 }
708 }
709 }
710
711 /* returns FALSE if user cancelled input or URL was invalid, TRUE otherwise */
do_check_recall(int ch,bstring ** user_input,char ** old_user_input,int URLTotal,int * URLNum,RecallType recall,BOOLEAN * FirstURLRecall)712 static BOOL do_check_recall(int ch,
713 bstring **user_input,
714 char **old_user_input,
715 int URLTotal,
716 int *URLNum,
717 RecallType recall,
718 BOOLEAN *FirstURLRecall)
719 {
720 char *cp;
721 BOOL ret = FALSE;
722
723 if (*old_user_input == 0)
724 StrAllocCopy(*old_user_input, "");
725
726 for (;;) {
727 #ifdef WIN_EX /* 1998/10/11 (Sun) 10:41:05 */
728 int len = strlen((*user_input)->str);
729
730 if (len >= 3) {
731 if (len < MAX_LINE - 1
732 && LYIsHtmlSep((*user_input)->str[len - 3])
733 && LYIsDosDrive((*user_input)->str + len - 2))
734 LYAddPathSep0((*user_input)->str);
735
736 } else if (len == 2 && (*user_input)->str[1] == ':') {
737 if (LYIsDosDrive((*user_input)->str)) {
738 LYAddPathSep0((*user_input)->str);
739 } else {
740 HTUserMsg2(WWW_ILLEGAL_URL_MESSAGE, (*user_input)->str);
741 BStrCopy0((*user_input), *old_user_input);
742 FREE(*old_user_input);
743 ret = FALSE;
744 break;
745 }
746 }
747 #endif
748 /*
749 * Get rid of leading spaces (and any other spaces).
750 */
751 LYTrimAllStartfile((*user_input)->str);
752 if (isBEmpty(*user_input) &&
753 !(recall && (ch == UPARROW || ch == DNARROW))) {
754 BStrCopy0((*user_input), *old_user_input);
755 FREE(*old_user_input);
756 HTInfoMsg(CANCELLED);
757 ret = FALSE;
758 break;
759 }
760 if (recall && ch == UPARROW) {
761 if (*FirstURLRecall) {
762 /*
763 * Use last URL in the list. - FM
764 */
765 *FirstURLRecall = FALSE;
766 *URLNum = 0;
767 } else {
768 /*
769 * Go back to the previous URL in the list. - FM
770 */
771 *URLNum += 1;
772 }
773 if (*URLNum >= URLTotal)
774 /*
775 * Roll around to the last URL in the list. - FM
776 */
777 *URLNum = 0;
778 if ((cp = (char *) HTList_objectAt(Goto_URLs,
779 *URLNum)) != NULL) {
780 BStrCopy0((*user_input), cp);
781 if (goto_buffer
782 && **old_user_input
783 && !strcmp(*old_user_input, (*user_input)->str)) {
784 _statusline(EDIT_CURRENT_GOTO);
785 } else if ((goto_buffer && URLTotal == 2) ||
786 (!goto_buffer && URLTotal == 1)) {
787 _statusline(EDIT_THE_PREV_GOTO);
788 } else {
789 _statusline(EDIT_A_PREV_GOTO);
790 }
791 if ((ch = LYgetBString(user_input, VISIBLE, 0, recall)) < 0) {
792 /*
793 * User cancelled the Goto via ^G. Restore
794 * user_input and break. - FM
795 */
796 BStrCopy0((*user_input), *old_user_input);
797 FREE(*old_user_input);
798 HTInfoMsg(CANCELLED);
799 ret = FALSE;
800 break;
801 }
802 continue;
803 }
804 } else if (recall && ch == DNARROW) {
805 if (*FirstURLRecall) {
806 /*
807 * Use the first URL in the list. - FM
808 */
809 *FirstURLRecall = FALSE;
810 *URLNum = URLTotal - 1;
811 } else {
812 /*
813 * Advance to the next URL in the list. - FM
814 */
815 *URLNum -= 1;
816 }
817 if (*URLNum < 0)
818 /*
819 * Roll around to the first URL in the list. - FM
820 */
821 *URLNum = URLTotal - 1;
822 if ((cp = (char *) HTList_objectAt(Goto_URLs, *URLNum)) != NULL) {
823 BStrCopy0((*user_input), cp);
824 if (goto_buffer && **old_user_input &&
825 !strcmp(*old_user_input, (*user_input)->str)) {
826 _statusline(EDIT_CURRENT_GOTO);
827 } else if ((goto_buffer && URLTotal == 2) ||
828 (!goto_buffer && URLTotal == 1)) {
829 _statusline(EDIT_THE_PREV_GOTO);
830 } else {
831 _statusline(EDIT_A_PREV_GOTO);
832 }
833 if ((ch = LYgetBString(user_input, VISIBLE, 0, recall)) < 0) {
834 /*
835 * User cancelled the Goto via ^G. Restore
836 * user_input and break. - FM
837 */
838 BStrCopy0((*user_input), *old_user_input);
839 FREE(*old_user_input);
840 HTInfoMsg(CANCELLED);
841 ret = FALSE;
842 break;
843 }
844 continue;
845 }
846 } else {
847 ret = TRUE;
848 break;
849 }
850 }
851 return ret;
852 }
853
do_cleanup_after_delete(void)854 static void do_cleanup_after_delete(void)
855 {
856 HTuncache_current_document();
857 move_address(&newdoc, &curdoc);
858 newdoc.line = curdoc.line;
859 if (curdoc.link == nlinks - 1) {
860 /*
861 * We deleted the last link on the page. - FM
862 */
863 newdoc.link = curdoc.link - 1;
864 } else {
865 newdoc.link = curdoc.link;
866 }
867 }
868
find_link_near_col(int col,int delta)869 static int find_link_near_col(int col,
870 int delta)
871 {
872 int i;
873
874 for (i = curdoc.link; delta > 0 ? (i < nlinks) : (i >= 0); i += delta) {
875 if ((links[i].ly - links[curdoc.link].ly) * delta > 0) {
876 int cy = links[i].ly, best = -1, dist = 1000000;
877
878 while ((delta > 0 ? (i < nlinks) : (i >= 0)) && cy == links[i].ly) {
879 int cx = links[i].lx;
880 const char *text = LYGetHiliteStr(i, 0);
881
882 if (text != NULL)
883 cx += (int) strlen(text) / 2;
884 cx -= col;
885 if (cx < 0)
886 cx = -cx;
887 if (cx < dist) {
888 dist = cx;
889 best = i;
890 }
891 i += delta;
892 }
893 return (best);
894 }
895 }
896 return (-1);
897 }
898
899 /*
900 * This is a special feature to traverse every http link derived from startfile
901 * and check for errors or create crawl output files. Only URLs that begin
902 * with "traversal_host" are searched - this keeps the search from crossing to
903 * other servers (a feature, not a bug!).
904 */
DoTraversal(int c,BOOLEAN * crawl_ok)905 static int DoTraversal(int c,
906 BOOLEAN *crawl_ok)
907 {
908 BOOLEAN rlink_rejected = FALSE;
909 BOOLEAN rlink_exists;
910 BOOLEAN rlink_allowed;
911
912 rlink_exists = (BOOL) (nlinks > 0 &&
913 links[curdoc.link].type != WWW_FORM_LINK_TYPE &&
914 links[curdoc.link].lname != NULL);
915
916 if (rlink_exists) {
917 rlink_rejected = lookup_reject(links[curdoc.link].lname);
918 if (!rlink_rejected &&
919 traversal_host &&
920 links[curdoc.link].lname) {
921 if (!isLYNXIMGMAP(links[curdoc.link].lname)) {
922 rlink_allowed = (BOOL) !StrNCmp(traversal_host,
923 links[curdoc.link].lname,
924 strlen(traversal_host));
925 } else {
926 rlink_allowed = (BOOL) !StrNCmp(traversal_host,
927 links[curdoc.link].lname + LEN_LYNXIMGMAP,
928 strlen(traversal_host));
929 }
930 } else {
931 rlink_allowed = FALSE;
932 }
933 } else {
934 rlink_allowed = FALSE;
935 }
936 if (rlink_exists && rlink_allowed) {
937 if (lookup_link(links[curdoc.link].lname)) {
938 if (more_links ||
939 (curdoc.link > -1 && curdoc.link < nlinks - 1)) {
940 c = DNARROW;
941 } else {
942 if (STREQ(curdoc.title, "Entry into main screen") ||
943 (nhist <= 0)) {
944 if (!dump_output_immediately) {
945 cleanup();
946 exit_immediately(EXIT_FAILURE);
947 }
948 c = -1;
949 } else {
950 c = LTARROW;
951 }
952 }
953 } else {
954 StrAllocCopy(traversal_link_to_add,
955 links[curdoc.link].lname);
956 if (!isLYNXIMGMAP(traversal_link_to_add))
957 *crawl_ok = TRUE;
958 c = RTARROW;
959 }
960 } else { /* no good right link, so only down and left arrow ok */
961 if (rlink_exists /* && !rlink_rejected */ )
962 /* uncomment in previous line to avoid duplicates - kw */
963 add_to_reject_list(links[curdoc.link].lname);
964 if (more_links ||
965 (curdoc.link > -1 && curdoc.link < nlinks - 1)) {
966 c = DNARROW;
967 } else {
968 /*
969 * curdoc.title doesn't always work, so bail out if the history
970 * list is empty.
971 */
972 if (STREQ(curdoc.title, "Entry into main screen") ||
973 (nhist <= 0)) {
974 if (!dump_output_immediately) {
975 cleanup();
976 exit_immediately(EXIT_FAILURE);
977 }
978 c = -1;
979 } else {
980 c = LTARROW;
981 }
982 }
983 }
984 CTRACE((tfp, "DoTraversal(%d:%d) -> %s\n",
985 nlinks > 0 ? curdoc.link : 0,
986 nlinks,
987 LYKeycodeToString(c, FALSE)));
988 return c;
989 }
990
check_history(void)991 static BOOLEAN check_history(void)
992 {
993 const char *base;
994
995 if (!curdoc.post_data)
996 /*
997 * Normal case - List Page is not associated with post data. - kw
998 */
999 return TRUE;
1000
1001 if (nhist > 0
1002 && !LYresubmit_posts
1003 && HDOC(nhist - 1).post_data
1004 && BINEQ(curdoc.post_data, HDOC(nhist - 1).post_data)
1005 && (base = HText_getContentBase()) != 0) {
1006 char *text = !isLYNXIMGMAP(HDOC(nhist - 1).address)
1007 ? HDOC(nhist - 1).address
1008 : HDOC(nhist - 1).address + LEN_LYNXIMGMAP;
1009
1010 if (!StrNCmp(base, text, strlen(base))) {
1011 /*
1012 * Normal case - as best as we can check, the document at the top
1013 * of the history stack seems to be the document the List Page is
1014 * about (or a LYNXIMGMAP derived from it), and LYresubmit_posts is
1015 * not set, so don't prompt here. If we actually have to repeat a
1016 * POST because, against expectations, the underlying document
1017 * isn't cached any more, HTAccess will prompt for confirmation,
1018 * unless we had LYK_NOCACHE -kw
1019 */
1020 return TRUE;
1021 }
1022 }
1023 return FALSE;
1024 }
1025
handle_LYK_ACTIVATE(int * c,int cmd GCC_UNUSED,BOOLEAN * try_internal GCC_UNUSED,BOOLEAN * refresh_screen,BOOLEAN * force_load,int real_cmd)1026 static int handle_LYK_ACTIVATE(int *c,
1027 int cmd GCC_UNUSED,
1028 BOOLEAN *try_internal GCC_UNUSED,
1029 BOOLEAN *refresh_screen,
1030 BOOLEAN *force_load,
1031 int real_cmd)
1032 {
1033 if (do_change_link() == -1) {
1034 LYforce_no_cache = FALSE;
1035 reloading = FALSE;
1036 return 1; /* mouse stuff was confused, ignore - kw */
1037 }
1038 if (nlinks > 0) {
1039 if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
1040 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
1041 if (real_cmd == LYK_ACTIVATE && textfields_need_activation &&
1042 F_TEXTLIKE(links[curdoc.link].l_form->type)) {
1043
1044 textinput_activated = TRUE;
1045 show_main_statusline(links[curdoc.link], FOR_INPUT);
1046 textfields_need_activation = textfields_activation_option;
1047
1048 return 0;
1049 }
1050 #endif
1051 /*
1052 * Don't try to submit forms with bad actions. - FM
1053 */
1054 if (links[curdoc.link].l_form->type == F_SUBMIT_TYPE ||
1055 links[curdoc.link].l_form->type == F_IMAGE_SUBMIT_TYPE ||
1056 links[curdoc.link].l_form->type == F_TEXT_SUBMIT_TYPE) {
1057 /*
1058 * Do nothing if it's disabled. - FM
1059 */
1060 if (links[curdoc.link].l_form->disabled == YES) {
1061 HTOutputFormat = WWW_PRESENT;
1062 LYforce_no_cache = FALSE;
1063 reloading = FALSE;
1064 return 0;
1065 }
1066 /*
1067 * Make sure we have an action. - FM
1068 */
1069 if (isEmpty(links[curdoc.link].l_form->submit_action)) {
1070 HTUserMsg(NO_FORM_ACTION);
1071 HTOutputFormat = WWW_PRESENT;
1072 LYforce_no_cache = FALSE;
1073 reloading = FALSE;
1074 return 0;
1075 }
1076 /*
1077 * Check for no_mail if the form action is a mailto URL. - FM
1078 */
1079 if (links[curdoc.link].l_form->submit_method
1080 == URL_MAIL_METHOD && no_mail) {
1081 HTAlert(FORM_MAILTO_DISALLOWED);
1082 HTOutputFormat = WWW_PRESENT;
1083 LYforce_no_cache = FALSE;
1084 reloading = FALSE;
1085 return 0;
1086 }
1087 /*
1088 * Make sure this isn't a spoof in an account with restrictions
1089 * on file URLs. - FM
1090 */
1091 if (no_file_url &&
1092 isFILE_URL(links[curdoc.link].l_form->submit_action)) {
1093 HTAlert(FILE_ACTIONS_DISALLOWED);
1094 HTOutputFormat = WWW_PRESENT;
1095 LYforce_no_cache = FALSE;
1096 reloading = FALSE;
1097 return 0;
1098 }
1099 /*
1100 * Make sure this isn't a spoof attempt via an internal URL. -
1101 * FM
1102 */
1103 if (isLYNXCOOKIE(links[curdoc.link].l_form->submit_action) ||
1104 #ifdef USE_CACHEJAR
1105 isLYNXCACHE(links[curdoc.link].l_form->submit_action) ||
1106 #endif
1107 #ifdef DIRED_SUPPORT
1108 #ifdef OK_PERMIT
1109 (isLYNXDIRED(links[curdoc.link].l_form->submit_action) &&
1110 (no_dired_support ||
1111 strncasecomp((links[curdoc.link].l_form->submit_action
1112 + 10),
1113 "//PERMIT_LOCATION", 17) ||
1114 !LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS))) ||
1115 #else
1116 isLYNXDIRED(links[curdoc.link].l_form->submit_action) ||
1117 #endif /* OK_PERMIT */
1118 #endif /* DIRED_SUPPORT */
1119 isLYNXDOWNLOAD(links[curdoc.link].l_form->submit_action) ||
1120 isLYNXHIST(links[curdoc.link].l_form->submit_action) ||
1121 isLYNXKEYMAP(links[curdoc.link].l_form->submit_action) ||
1122 isLYNXIMGMAP(links[curdoc.link].l_form->submit_action) ||
1123 isLYNXPRINT(links[curdoc.link].l_form->submit_action) ||
1124 isLYNXEXEC(links[curdoc.link].l_form->submit_action) ||
1125 isLYNXPROG(links[curdoc.link].l_form->submit_action)) {
1126
1127 HTAlert(SPECIAL_ACTION_DISALLOWED);
1128 CTRACE((tfp, "LYMainLoop: Rejected '%s'\n",
1129 links[curdoc.link].l_form->submit_action));
1130 HTOutputFormat = WWW_PRESENT;
1131 LYforce_no_cache = FALSE;
1132 reloading = FALSE;
1133 return 0;
1134 }
1135 #ifdef NOTDEFINED /* We're disabling form inputs instead of using this. - FM */
1136 /*
1137 * Check for enctype and let user know we don't yet support
1138 * multipart/form-data - FM
1139 */
1140 if (links[curdoc.link].l_form->submit_enctype) {
1141 if (!strcmp(links[curdoc.link].l_form->submit_enctype,
1142 "multipart/form-data")) {
1143 HTAlert(gettext("Enctype multipart/form-data not yet supported! Cannot submit."));
1144 HTOutputFormat = WWW_PRESENT;
1145 LYforce_no_cache = FALSE;
1146 reloading = FALSE;
1147 return 0;
1148 }
1149 }
1150 #endif /* NOTDEFINED */
1151 if (check_realm) {
1152 LYPermitURL = TRUE;
1153 }
1154 if (no_filereferer == TRUE && isFILE_URL(curdoc.address)) {
1155 LYNoRefererForThis = TRUE;
1156 }
1157 if (links[curdoc.link].l_form->submit_method != URL_MAIL_METHOD) {
1158 StrAllocCopy(newdoc.title,
1159 LYGetHiliteStr(curdoc.link, 0));
1160 }
1161 }
1162
1163 /*
1164 * Normally we don't get here for text input fields, but it can
1165 * happen as a result of mouse positioning. In that case the
1166 * statusline will not have updated info, so update it now. - kw
1167 */
1168 if (F_TEXTLIKE(links[curdoc.link].l_form->type)) {
1169 show_formlink_statusline(links[curdoc.link].l_form,
1170 (real_cmd == LYK_NOCACHE ||
1171 real_cmd == LYK_DOWNLOAD ||
1172 real_cmd == LYK_HEAD ||
1173 (real_cmd == LYK_MOUSE_SUBMIT &&
1174 !textinput_activated)) ?
1175 FOR_PANEL : FOR_INPUT);
1176 if (user_mode == NOVICE_MODE &&
1177 textinput_activated &&
1178 (real_cmd == LYK_ACTIVATE ||
1179 real_cmd == LYK_MOUSE_SUBMIT)) {
1180 form_noviceline(FormIsReadonly(links[curdoc.link].l_form));
1181 }
1182 }
1183
1184 *c = change_form_link(curdoc.link,
1185 &newdoc, refresh_screen,
1186 FALSE,
1187 (real_cmd == LYK_MOUSE_SUBMIT ||
1188 real_cmd == LYK_NOCACHE ||
1189 real_cmd == LYK_DOWNLOAD ||
1190 real_cmd == LYK_HEAD));
1191 if (*c != LKC_DONE || *refresh_screen) {
1192 /*
1193 * Cannot have been a submit field for which newdoc was filled
1194 * in. - kw
1195 */
1196 if ((links[curdoc.link].l_form->type == F_SUBMIT_TYPE ||
1197 links[curdoc.link].l_form->type == F_IMAGE_SUBMIT_TYPE ||
1198 links[curdoc.link].l_form->type == F_TEXT_SUBMIT_TYPE) &&
1199 links[curdoc.link].l_form->submit_method
1200 != URL_MAIL_METHOD) {
1201 /*
1202 * Try to undo change of newdoc.title done above.
1203 */
1204 if (HText_getTitle()) {
1205 StrAllocCopy(newdoc.title, HText_getTitle());
1206 } else if (curdoc.title) {
1207 StrAllocCopy(newdoc.title, curdoc.title);
1208 }
1209 }
1210 } else {
1211 if (HTOutputFormat == HTAtom_for("www/download") &&
1212 newdoc.post_data != NULL &&
1213 newdoc.safe == FALSE) {
1214
1215 if ((HText_POSTReplyLoaded(&newdoc) == TRUE) &&
1216 HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
1217 HTInfoMsg(CANCELLED);
1218 HTOutputFormat = WWW_PRESENT;
1219 LYforce_no_cache = FALSE;
1220 copy_address(&newdoc, &curdoc);
1221 StrAllocCopy(newdoc.title, curdoc.title);
1222 BStrCopy(newdoc.post_data, curdoc.post_data);
1223 StrAllocCopy(newdoc.post_content_type,
1224 curdoc.post_content_type);
1225 StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
1226 newdoc.isHEAD = curdoc.isHEAD;
1227 newdoc.safe = curdoc.safe;
1228 newdoc.internal_link = curdoc.internal_link;
1229 return 0;
1230 }
1231 }
1232 /*
1233 * Moved here from earlier to only apply when it should.
1234 * Anyway, why should realm checking be overridden for form
1235 * submissions, this seems to be an unnecessary loophole?? But
1236 * that's the way it was, maybe there is some reason. However,
1237 * at least make sure this doesn't weaken restrictions implied
1238 * by -validate!
1239 * - kw 1999-05-25
1240 */
1241 if (check_realm && !LYValidate) {
1242 LYPermitURL = TRUE;
1243 }
1244 }
1245 if (*c == LKC_DONE) {
1246 *c = DO_NOTHING;
1247 } else if (*c == 23) {
1248 *c = DO_NOTHING;
1249 *refresh_screen = TRUE;
1250 } else {
1251 /* Avoid getting stuck with repeatedly calling
1252 * handle_LYK_ACTIVATE(), instead of calling change_form_link()
1253 * directly from mainloop(), for text input fields. - kw
1254 */
1255 switch (LKC_TO_C(*c)) {
1256 case '\n':
1257 case '\r':
1258 default:
1259 if ((real_cmd == LYK_ACTIVATE ||
1260 real_cmd == LYK_MOUSE_SUBMIT) &&
1261 F_TEXTLIKE(links[curdoc.link].l_form->type) &&
1262 textinput_activated) {
1263 return 3;
1264 }
1265 break;
1266 }
1267 }
1268 return 2;
1269 } else {
1270 /*
1271 * Not a forms link.
1272 *
1273 * Make sure this isn't a spoof in an account with restrictions on
1274 * file URLs. - FM
1275 */
1276 if (no_file_url && isFILE_URL(links[curdoc.link].lname)) {
1277 if (!isFILE_URL(curdoc.address) &&
1278 !((isLYNXKEYMAP(curdoc.address) ||
1279 #ifndef USE_CACHEJAR
1280 isLYNXCOOKIE(curdoc.address)) &&
1281 #else
1282 isLYNXCOOKIE(curdoc.address) ||
1283 isLYNXCACHE(curdoc.address)) &&
1284 #endif
1285 !StrNCmp(links[curdoc.link].lname,
1286 helpfilepath,
1287 strlen(helpfilepath)))) {
1288 HTAlert(FILE_SERVED_LINKS_DISALLOWED);
1289 reloading = FALSE;
1290 return 0;
1291 } else if (curdoc.bookmark != NULL) {
1292 HTAlert(FILE_BOOKMARKS_DISALLOWED);
1293 reloading = FALSE;
1294 return 0;
1295 }
1296 }
1297 /*
1298 * Make sure this isn't a spoof attempt via an internal URL in a
1299 * non-internal document. - FM
1300 */
1301 if ((isLYNXCOOKIE(links[curdoc.link].lname) &&
1302 (strcmp(NonNull(curdoc.title), COOKIE_JAR_TITLE) ||
1303 !isLYNXCOOKIE(curdoc.address))) ||
1304 #ifdef USE_CACHEJAR
1305 (isLYNXCACHE(links[curdoc.link].lname) &&
1306 (strcmp(NonNull(curdoc.title), CACHE_JAR_TITLE) ||
1307 !isLYNXCACHE(curdoc.address))) ||
1308 #endif
1309 #ifdef DIRED_SUPPORT
1310 (isLYNXDIRED(links[curdoc.link].lname) &&
1311 !LYIsUIPage(curdoc.address, UIP_DIRED_MENU) &&
1312 !LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS) &&
1313 #ifdef OK_INSTALL
1314 !LYIsUIPage(curdoc.address, UIP_INSTALL) &&
1315 #endif /* OK_INSTALL */
1316 !LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS)) ||
1317 #endif /* DIRED_SUPPORT */
1318 (isLYNXDOWNLOAD(links[curdoc.link].lname) &&
1319 !LYIsUIPage(curdoc.address, UIP_DOWNLOAD_OPTIONS)) ||
1320 (isLYNXHIST(links[curdoc.link].lname) &&
1321 !LYIsUIPage(curdoc.address, UIP_HISTORY) &&
1322 !LYIsUIPage(curdoc.address, UIP_LIST_PAGE) &&
1323 !LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE)) ||
1324 (isLYNXPRINT(links[curdoc.link].lname) &&
1325 !LYIsUIPage(curdoc.address, UIP_PRINT_OPTIONS))) {
1326 HTAlert(SPECIAL_VIA_EXTERNAL_DISALLOWED);
1327 HTOutputFormat = WWW_PRESENT;
1328 LYforce_no_cache = FALSE;
1329 reloading = FALSE;
1330 return 0;
1331 }
1332 #ifdef USE_EXTERNALS
1333 if (run_external(links[curdoc.link].lname, TRUE)) {
1334 *refresh_screen = TRUE;
1335 return 0;
1336 }
1337 #endif /* USE_EXTERNALS */
1338
1339 /*
1340 * Follow a normal link or anchor.
1341 */
1342 set_address(&newdoc, links[curdoc.link].lname);
1343 StrAllocCopy(newdoc.title, LYGetHiliteStr(curdoc.link, 0));
1344 /*
1345 * For internal links, retain POST content if present. If we are
1346 * on the List Page, prevent pushing it on the history stack.
1347 * Otherwise set try_internal to signal that the top of the loop
1348 * should attempt to reposition directly, without calling getfile.
1349 * - kw
1350 */
1351 if (track_internal_links) {
1352 /*
1353 * Might be an internal link anchor in the same doc. If so, take
1354 * the try_internal shortcut if we didn't fall through from
1355 * LYK_NOCACHE. - kw
1356 */
1357 newdoc.internal_link =
1358 (links[curdoc.link].type == WWW_INTERN_LINK_TYPE);
1359 if (newdoc.internal_link) {
1360 /*
1361 * Special case of List Page document with an internal link
1362 * indication, which may really stand for an internal link
1363 * within the document the List Page is about. - kw
1364 */
1365 if (LYIsListpageTitle(NonNull(curdoc.title)) &&
1366 (LYIsUIPage(curdoc.address, UIP_LIST_PAGE) ||
1367 LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE))) {
1368 if (check_history()) {
1369 LYinternal_flag = TRUE;
1370 } else {
1371 HTLastConfirmCancelled(); /* reset flag */
1372 if (!confirm_post_resub(newdoc.address,
1373 newdoc.title,
1374 ((LYresubmit_posts &&
1375 HText_POSTReplyLoaded(&newdoc))
1376 ? 1
1377 : 2),
1378 2)) {
1379 if (HTLastConfirmCancelled() ||
1380 (LYresubmit_posts &&
1381 cmd != LYK_NOCACHE &&
1382 !HText_POSTReplyLoaded(&newdoc))) {
1383 /* cancel the whole thing */
1384 LYforce_no_cache = FALSE;
1385 reloading = FALSE;
1386 copy_address(&newdoc, &curdoc);
1387 StrAllocCopy(newdoc.title, curdoc.title);
1388 newdoc.internal_link = curdoc.internal_link;
1389 HTInfoMsg(CANCELLED);
1390 return 1;
1391 } else if (LYresubmit_posts &&
1392 cmd != LYK_NOCACHE) {
1393 /* If LYresubmit_posts is set, and the
1394 answer was No, and the key wasn't
1395 NOCACHE, and we have a cached copy,
1396 then use it. - kw */
1397 LYforce_no_cache = FALSE;
1398 } else {
1399 /* if No, but not ^C or ^G, drop
1400 * the post data. Maybe the link
1401 * wasn't meant to be internal after
1402 * all, here we can recover from that
1403 * assumption. - kw */
1404 LYFreePostData(&newdoc);
1405 newdoc.internal_link = FALSE;
1406 HTAlert(DISCARDING_POST_DATA);
1407 }
1408 }
1409 }
1410 /*
1411 * Don't push the List Page if we follow an internal link
1412 * given by it. - kw
1413 */
1414 free_address(&curdoc);
1415 } else if (cmd != LYK_NOCACHE) {
1416 *try_internal = TRUE;
1417 }
1418 if (!(LYresubmit_posts && newdoc.post_data))
1419 LYinternal_flag = TRUE;
1420 /* We still set force_load so that history pushing
1421 * etc. will be done. - kw
1422 */
1423 *force_load = TRUE;
1424 return 1;
1425 } else {
1426 /*
1427 * Free POST content if not an internal link. - kw
1428 */
1429 LYFreePostData(&newdoc);
1430 }
1431 }
1432 /*
1433 * Might be an anchor in the same doc from a POST form. If so,
1434 * don't free the content. -- FM
1435 */
1436 if (are_different(&curdoc, &newdoc)) {
1437 LYFreePostData(&newdoc);
1438 FREE(newdoc.bookmark);
1439 if (isLYNXMESSAGES(newdoc.address))
1440 LYforce_no_cache = TRUE;
1441 }
1442 if (!no_jump && lynxjumpfile && curdoc.address &&
1443 !strcmp(lynxjumpfile, curdoc.address)) {
1444 LYJumpFileURL = TRUE;
1445 LYUserSpecifiedURL = TRUE;
1446 } else if ((curdoc.title &&
1447 (LYIsUIPage(curdoc.address, UIP_HISTORY) ||
1448 !strcmp(curdoc.title, HISTORY_PAGE_TITLE))) ||
1449 curdoc.bookmark != NULL ||
1450 (lynxjumpfile &&
1451 curdoc.address &&
1452 !strcmp(lynxjumpfile, curdoc.address))) {
1453 LYUserSpecifiedURL = TRUE;
1454 } else if (no_filereferer == TRUE &&
1455 curdoc.address != NULL &&
1456 isFILE_URL(curdoc.address)) {
1457 LYNoRefererForThis = TRUE;
1458 }
1459 newdoc.link = 0;
1460 *force_load = TRUE; /* force MainLoop to reload */
1461 #ifdef USE_PRETTYSRC
1462 psrc_view = FALSE; /* we get here if link is not internal */
1463 #endif
1464
1465 #if defined(DIRED_SUPPORT) && !defined(__DJGPP__)
1466 if (lynx_edit_mode) {
1467 DIRED_UNCACHE_2;
1468 /*
1469 * Unescaping any slash chars in the URL, but avoid double
1470 * unescaping and too-early unescaping of other chars. - KW
1471 */
1472 HTUnEscapeSome(newdoc.address, "/");
1473 /* avoid stripping final slash for root dir - kw */
1474 if (strcasecomp(newdoc.address, "file://localhost/"))
1475 strip_trailing_slash(newdoc.address);
1476 }
1477 #endif /* DIRED_SUPPORT && !__DJGPP__ */
1478 if (isLYNXCOOKIE(curdoc.address)
1479 #ifdef USE_CACHEJAR
1480 || isLYNXCACHE(curdoc.address)
1481 #endif
1482 ) {
1483 HTuncache_current_document();
1484 }
1485 }
1486 }
1487 return 0;
1488 }
1489 /*
1490 * If the given form link does not point to the requested type, search for
1491 * the first link belonging to the form which does. If there are none,
1492 * return null.
1493 */
1494 #define SameFormAction(form,submit) \
1495 ((submit) \
1496 ? (F_SUBMITLIKE((form)->type)) \
1497 : ((form)->type == F_RESET_TYPE))
1498
FindFormAction(FormInfo * given,BOOLEAN submit)1499 static FormInfo *FindFormAction(FormInfo * given, BOOLEAN submit)
1500 {
1501 FormInfo *result = NULL;
1502 FormInfo *fi;
1503 int i;
1504
1505 if (given == NULL) {
1506 HTAlert(LINK_NOT_IN_FORM);
1507 } else if (SameFormAction(given, submit)) {
1508 result = given;
1509 } else {
1510 for (i = 0; i < nlinks; i++) {
1511 if ((fi = links[i].l_form) != 0 &&
1512 fi->number == given->number &&
1513 (SameFormAction(fi, submit))) {
1514 result = fi;
1515 break;
1516 }
1517 }
1518 }
1519 return result;
1520 }
1521
MakeFormAction(FormInfo * given,BOOLEAN submit)1522 static FormInfo *MakeFormAction(FormInfo * given, BOOLEAN submit)
1523 {
1524 FormInfo *result = 0;
1525
1526 if (given != 0) {
1527 result = typecalloc(FormInfo);
1528
1529 if (result == NULL)
1530 outofmem(__FILE__, "MakeFormAction");
1531
1532 *result = *given;
1533 if (submit) {
1534 if (result->submit_action == 0) {
1535 PerFormInfo *pfi = HText_PerFormInfo(result->number);
1536
1537 *result = pfi->data;
1538 }
1539 result->type = F_SUBMIT_TYPE;
1540 } else {
1541 result->type = F_RESET_TYPE;
1542 }
1543 result->number = given->number;
1544 }
1545 return result;
1546 }
1547
handle_LYK_SUBMIT(int cur,DocInfo * doc,BOOLEAN * refresh_screen)1548 static void handle_LYK_SUBMIT(int cur, DocInfo *doc, BOOLEAN *refresh_screen)
1549 {
1550 FormInfo *form = FindFormAction(links[cur].l_form, TRUE);
1551 FormInfo *make = NULL;
1552 char *save_submit_action = NULL;
1553
1554 if (form == 0) {
1555 make = MakeFormAction(links[cur].l_form, TRUE);
1556 form = make;
1557 }
1558
1559 StrAllocCopy(save_submit_action, form->submit_action);
1560 form->submit_action = HTPrompt(EDIT_SUBMIT_URL, form->submit_action);
1561
1562 if (isEmpty(form->submit_action) ||
1563 (!isLYNXCGI(form->submit_action) &&
1564 StrNCmp(form->submit_action, "http", 4))) {
1565 HTUserMsg(FORM_ACTION_NOT_HTTP_URL);
1566 } else {
1567 HTInfoMsg(SUBMITTING_FORM);
1568 HText_SubmitForm(form, doc, form->name, form->value);
1569 *refresh_screen = TRUE;
1570 }
1571
1572 StrAllocCopy(form->submit_action, save_submit_action);
1573 FREE(make);
1574 }
1575
handle_LYK_RESET(int cur,BOOLEAN * refresh_screen)1576 static void handle_LYK_RESET(int cur, BOOLEAN *refresh_screen)
1577 {
1578 FormInfo *form = FindFormAction(links[cur].l_form, FALSE);
1579 FormInfo *make = NULL;
1580
1581 if (form == 0) {
1582 make = MakeFormAction(links[cur].l_form, FALSE);
1583 form = make;
1584 }
1585
1586 if (form != 0) {
1587 HTInfoMsg(RESETTING_FORM);
1588 HText_ResetForm(form);
1589 *refresh_screen = TRUE;
1590 FREE(make);
1591 }
1592 }
1593
1594 #ifdef USE_ADDRLIST_PAGE
handle_LYK_ADDRLIST(int * cmd)1595 static BOOLEAN handle_LYK_ADDRLIST(int *cmd)
1596 {
1597 /*
1598 * Don't do if already viewing list addresses page.
1599 */
1600 if (LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE)) {
1601 /*
1602 * Already viewing list page, so get out.
1603 */
1604 *cmd = LYK_PREV_DOC;
1605 return TRUE;
1606 }
1607
1608 /*
1609 * Print address list page to file.
1610 */
1611 if (showlist(&newdoc, FALSE) < 0)
1612 return FALSE;
1613 StrAllocCopy(newdoc.title, ADDRLIST_PAGE_TITLE);
1614 /*
1615 * showlist will set newdoc's other fields. It may leave post_data intact
1616 * so the list can be used to follow internal links in the current document
1617 * even if it is a POST response. - kw
1618 */
1619
1620 if (LYValidate || check_realm) {
1621 LYPermitURL = TRUE;
1622 StrAllocCopy(lynxlistfile, newdoc.address);
1623 }
1624 return FALSE;
1625 }
1626 #endif /* USE_ADDRLIST_PAGE */
1627
handle_LYK_ADD_BOOKMARK(BOOLEAN * refresh_screen,int * old_c,int real_c)1628 static void handle_LYK_ADD_BOOKMARK(BOOLEAN *refresh_screen,
1629 int *old_c,
1630 int real_c)
1631 {
1632 int c;
1633
1634 if (LYValidate) {
1635 if (*old_c != real_c) {
1636 *old_c = real_c;
1637 HTUserMsg(BOOKMARKS_DISABLED);
1638 }
1639 return;
1640 }
1641
1642 if (!LYIsUIPage(curdoc.address, UIP_HISTORY) &&
1643 !LYIsUIPage(curdoc.address, UIP_SHOWINFO) &&
1644 !LYIsUIPage(curdoc.address, UIP_PRINT_OPTIONS) &&
1645 #ifdef DIRED_SUPPORT
1646 !LYIsUIPage(curdoc.address, UIP_DIRED_MENU) &&
1647 !LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS) &&
1648 !LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS) &&
1649 #endif /* DIRED_SUPPORT */
1650 !LYIsUIPage(curdoc.address, UIP_DOWNLOAD_OPTIONS) &&
1651 !isLYNXCOOKIE(curdoc.address) &&
1652 #ifdef USE_CACHEJAR
1653 !isLYNXCACHE(curdoc.address) &&
1654 #endif
1655 !LYIsUIPage(curdoc.address, UIP_OPTIONS_MENU) &&
1656 ((nlinks <= 0) ||
1657 (links[curdoc.link].lname != NULL &&
1658 !isLYNXHIST(links[curdoc.link].lname) &&
1659 !isLYNXPRINT(links[curdoc.link].lname) &&
1660 !isLYNXDIRED(links[curdoc.link].lname) &&
1661 !isLYNXDOWNLOAD(links[curdoc.link].lname) &&
1662 !isLYNXCOOKIE(links[curdoc.link].lname) &&
1663 #ifdef USE_CACHEJAR
1664 !isLYNXCACHE(links[curdoc.link].lname) &&
1665 #endif
1666 !isLYNXPRINT(links[curdoc.link].lname)))) {
1667 if (nlinks > 0) {
1668 if (curdoc.post_data == NULL &&
1669 curdoc.bookmark == NULL &&
1670 !LYIsUIPage(curdoc.address, UIP_LIST_PAGE) &&
1671 !LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE) &&
1672 !LYIsUIPage(curdoc.address, UIP_VLINKS)) {
1673 /*
1674 * The document doesn't have POST content, and is not a
1675 * bookmark file, nor is the list or visited links page, so we
1676 * can save either that or the link. - FM
1677 */
1678 _statusline(BOOK_D_L_OR_CANCEL);
1679 if ((c = LYgetch_single()) == 'D') {
1680 save_bookmark_link(curdoc.address, curdoc.title);
1681 *refresh_screen = TRUE; /* MultiBookmark support */
1682 goto check_add_bookmark_to_self;
1683 }
1684 } else {
1685 if (LYMultiBookmarks == MBM_OFF &&
1686 curdoc.bookmark != NULL &&
1687 strstr(curdoc.address,
1688 (*bookmark_page == '.'
1689 ? (bookmark_page + 1)
1690 : bookmark_page)) != NULL) {
1691 /*
1692 * If multiple bookmarks are disabled, offer the L)ink or
1693 * C)ancel, but with wording which indicates that the link
1694 * already exists in this bookmark file. - FM
1695 */
1696 _statusline(MULTIBOOKMARKS_SELF);
1697 } else if (curdoc.post_data != NULL &&
1698 links[curdoc.link].type == WWW_INTERN_LINK_TYPE) {
1699 /*
1700 * Internal link, and document has POST content.
1701 */
1702 HTUserMsg(NOBOOK_POST_FORM);
1703 return;
1704 } else {
1705 /*
1706 * Only offer the link in a document with POST content, or
1707 * if the current document is a bookmark file and multiple
1708 * bookmarks are enabled. - FM
1709 */
1710 _statusline(BOOK_L_OR_CANCEL);
1711 }
1712 c = LYgetch_single();
1713 }
1714 if (c == 'L') {
1715 if (curdoc.post_data != NULL &&
1716 links[curdoc.link].type == WWW_INTERN_LINK_TYPE) {
1717 /*
1718 * Internal link, and document has POST content.
1719 */
1720 HTUserMsg(NOBOOK_POST_FORM);
1721 return;
1722 }
1723 /*
1724 * User does want to save the link. - FM
1725 */
1726 if (links[curdoc.link].type != WWW_FORM_LINK_TYPE) {
1727 save_bookmark_link(links[curdoc.link].lname,
1728 LYGetHiliteStr(curdoc.link, 0));
1729 *refresh_screen = TRUE; /* MultiBookmark support */
1730 } else {
1731 HTUserMsg(NOBOOK_FORM_FIELD);
1732 return;
1733 }
1734 } else {
1735 return;
1736 }
1737 } else if (curdoc.post_data != NULL) {
1738 /*
1739 * No links, and document has POST content. - FM
1740 */
1741 HTUserMsg(NOBOOK_POST_FORM);
1742 return;
1743 } else if (curdoc.bookmark != NULL) {
1744 /*
1745 * It's a bookmark file from which all of the links were deleted.
1746 * - FM
1747 */
1748 HTUserMsg(BOOKMARKS_NOLINKS);
1749 return;
1750 } else {
1751 _statusline(BOOK_D_OR_CANCEL);
1752 if (LYgetch_single() == 'D') {
1753 save_bookmark_link(curdoc.address, curdoc.title);
1754 *refresh_screen = TRUE; /* MultiBookmark support */
1755 } else {
1756 return;
1757 }
1758 }
1759 check_add_bookmark_to_self:
1760 if (curdoc.bookmark && BookmarkPage &&
1761 !strcmp(curdoc.bookmark, BookmarkPage)) {
1762 HTuncache_current_document();
1763 move_address(&newdoc, &curdoc);
1764 StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
1765 newdoc.line = curdoc.line;
1766 newdoc.link = curdoc.link;
1767 newdoc.internal_link = FALSE;
1768 }
1769 } else {
1770 if (*old_c != real_c) {
1771 *old_c = real_c;
1772 HTUserMsg(NOBOOK_HSML);
1773 }
1774 }
1775 }
1776
handle_LYK_CLEAR_AUTH(int * old_c,int real_c)1777 static void handle_LYK_CLEAR_AUTH(int *old_c,
1778 int real_c)
1779 {
1780 if (*old_c != real_c) {
1781 *old_c = real_c;
1782 if (HTConfirm(CLEAR_ALL_AUTH_INFO)) {
1783 FREE(authentication_info[0]);
1784 FREE(authentication_info[1]);
1785 FREE(proxyauth_info[0]);
1786 FREE(proxyauth_info[1]);
1787 HTClearHTTPAuthInfo();
1788 #ifndef DISABLE_NEWS
1789 HTClearNNTPAuthInfo();
1790 #endif
1791 #ifndef DISABLE_FTP
1792 HTClearFTPPassword();
1793 #endif
1794 HTUserMsg(AUTH_INFO_CLEARED);
1795 } else {
1796 HTUserMsg(CANCELLED);
1797 }
1798 }
1799 }
1800
handle_LYK_COMMAND(bstring ** user_input)1801 static int handle_LYK_COMMAND(bstring **user_input)
1802 {
1803 LYKeymapCode ch;
1804 Kcmd *mp;
1805 char *src, *tmp;
1806
1807 BStrCopy0((*user_input), "");
1808 _statusline(": ");
1809 if (LYgetBString(user_input, VISIBLE, 0, RECALL_CMD) >= 0) {
1810 src = LYSkipBlanks((*user_input)->str);
1811 tmp = LYSkipNonBlanks(src);
1812 *tmp = 0;
1813 ch = ((mp = LYStringToKcmd(src)) != 0) ? mp->code : LYK_UNKNOWN;
1814 CTRACE((tfp, "LYK_COMMAND(%s.%s) = %d\n", src, tmp, (int) ch));
1815 if (ch == 0) {
1816 return *src ? -1 : 0;
1817 }
1818 /* FIXME: reuse the rest of the buffer for parameters */
1819 return ch;
1820 }
1821 return 0;
1822 }
1823
handle_LYK_COMMENT(BOOLEAN * refresh_screen,char ** owner_address_p,int * old_c,int real_c)1824 static void handle_LYK_COMMENT(BOOLEAN *refresh_screen,
1825 char **owner_address_p,
1826 int *old_c,
1827 int real_c)
1828 {
1829 int c;
1830
1831 if (!*owner_address_p &&
1832 strncasecomp(curdoc.address, "http", 4)) {
1833 if (*old_c != real_c) {
1834 *old_c = real_c;
1835 HTUserMsg(NO_OWNER);
1836 }
1837 } else if (no_mail) {
1838 if (*old_c != real_c) {
1839 *old_c = real_c;
1840 HTUserMsg(MAIL_DISALLOWED);
1841 }
1842 } else {
1843 if (HTConfirmDefault(CONFIRM_COMMENT, NO)) {
1844 if (!*owner_address_p) {
1845 /*
1846 * No owner defined, so make a guess and and offer it to the
1847 * user. - FM
1848 */
1849 char *address = NULL;
1850 char *temp = HTParse(curdoc.address, "", PARSE_PATH);
1851 char *cp;
1852
1853 if (temp != NULL) {
1854 HTUnEscape(temp);
1855 if (LYIsTilde(*temp) && strlen(temp) > 1) {
1856 /*
1857 * It's a ~user URL so guess user@host. - FM
1858 */
1859 if ((cp = strchr((temp + 1), '/')) != NULL)
1860 *cp = '\0';
1861 StrAllocCopy(address, STR_MAILTO_URL);
1862 StrAllocCat(address, (temp + 1));
1863 StrAllocCat(address, "@");
1864 }
1865 FREE(temp);
1866 }
1867 if (address == NULL)
1868 /*
1869 * Wasn't a ~user URL so guess WebMaster@host. - FM
1870 */
1871 StrAllocCopy(address, "mailto:WebMaster@");
1872 temp = HTParse(curdoc.address, "", PARSE_HOST);
1873 StrAllocCat(address, temp);
1874 HTSprintf0(&temp, NO_OWNER_USE, address);
1875 c = HTConfirmDefault(temp, NO);
1876 FREE(temp);
1877 if (c == YES) {
1878 StrAllocCopy(*owner_address_p, address);
1879 FREE(address);
1880 } else {
1881 FREE(address);
1882 return;
1883 }
1884 }
1885 if (is_url(*owner_address_p) != MAILTO_URL_TYPE) {
1886 /*
1887 * The address is a URL. Just follow the link.
1888 */
1889 set_address(&newdoc, *owner_address_p);
1890 newdoc.internal_link = FALSE;
1891 } else {
1892 /*
1893 * The owner_address is a mailto: URL.
1894 */
1895 const char *kp = HText_getRevTitle();
1896 const char *id = HText_getMessageID();
1897 char *tmptitle = NULL;
1898
1899 if (!kp && HTMainAnchor) {
1900 kp = HTAnchor_subject(HTMainAnchor);
1901 if (non_empty(kp)) {
1902 if (strncasecomp(kp, "Re: ", 4)) {
1903 StrAllocCopy(tmptitle, "Re: ");
1904 StrAllocCat(tmptitle, kp);
1905 kp = tmptitle;
1906 }
1907 }
1908 }
1909
1910 if (strchr(*owner_address_p, ':') != NULL)
1911 /*
1912 * Send a reply. The address is after the colon.
1913 */
1914 reply_by_mail(strchr(*owner_address_p, ':') + 1,
1915 curdoc.address,
1916 NonNull(kp), id);
1917 else
1918 reply_by_mail(*owner_address_p, curdoc.address,
1919 NonNull(kp), id);
1920
1921 FREE(tmptitle);
1922 *refresh_screen = TRUE; /* to force a showpage */
1923 }
1924 }
1925 }
1926 }
1927
1928 #ifdef USE_CACHEJAR
handle_LYK_CACHE_JAR(int * cmd)1929 static BOOLEAN handle_LYK_CACHE_JAR(int *cmd)
1930 {
1931 /*
1932 * Don't do this if already viewing cache jar.
1933 */
1934 if (!isLYNXCACHE(curdoc.address)) {
1935 set_address(&newdoc, STR_LYNXCACHE "/");
1936 LYFreePostData(&newdoc);
1937 FREE(newdoc.bookmark);
1938 newdoc.isHEAD = FALSE;
1939 newdoc.safe = FALSE;
1940 newdoc.internal_link = FALSE;
1941 LYforce_no_cache = TRUE;
1942 if (LYValidate || check_realm) {
1943 LYPermitURL = TRUE;
1944 }
1945 } else {
1946 /*
1947 * If already in the cache jar, get out.
1948 */
1949 *cmd = LYK_PREV_DOC;
1950 return TRUE;
1951 }
1952 return FALSE;
1953 }
1954 #endif /* USE_CACHEJAR */
1955
handle_LYK_COOKIE_JAR(int * cmd)1956 static BOOLEAN handle_LYK_COOKIE_JAR(int *cmd)
1957 {
1958 /*
1959 * Don't do if already viewing the cookie jar.
1960 */
1961 if (!isLYNXCOOKIE(curdoc.address)) {
1962 set_address(&newdoc, "LYNXCOOKIE:/");
1963 LYFreePostData(&newdoc);
1964 FREE(newdoc.bookmark);
1965 newdoc.isHEAD = FALSE;
1966 newdoc.safe = FALSE;
1967 newdoc.internal_link = FALSE;
1968 LYforce_no_cache = TRUE;
1969 if (LYValidate || check_realm) {
1970 LYPermitURL = TRUE;
1971 }
1972 } else {
1973 /*
1974 * If already in the cookie jar, get out.
1975 */
1976 *cmd = LYK_PREV_DOC;
1977 return TRUE;
1978 }
1979 return FALSE;
1980 }
1981
1982 #if defined(DIRED_SUPPORT)
handle_LYK_CREATE(void)1983 static void handle_LYK_CREATE(void)
1984 {
1985 if (lynx_edit_mode && !no_dired_support) {
1986 if (local_create(&curdoc) > 0) {
1987 DIRED_UNCACHE_1;
1988 move_address(&newdoc, &curdoc);
1989 LYFreePostData(&newdoc);
1990 FREE(newdoc.bookmark);
1991 newdoc.isHEAD = FALSE;
1992 newdoc.safe = FALSE;
1993 newdoc.line = curdoc.line;
1994 newdoc.link = curdoc.link > -1 ? curdoc.link : 0;
1995 LYclear();
1996 }
1997 }
1998 }
1999 #endif /* DIRED_SUPPORT */
2000
handle_LYK_DEL_BOOKMARK(BOOLEAN * refresh_screen,int * old_c,int real_c)2001 static void handle_LYK_DEL_BOOKMARK(BOOLEAN *refresh_screen,
2002 int *old_c,
2003 int real_c)
2004 {
2005 if (curdoc.bookmark != NULL) {
2006 if (HTConfirmDefault(CONFIRM_BOOKMARK_DELETE, NO) != YES)
2007 return;
2008 remove_bookmark_link(links[curdoc.link].anchor_number - 1,
2009 curdoc.bookmark);
2010 } else { /* behave like REFRESH for backward compatibility */
2011 *refresh_screen = TRUE;
2012 if (*old_c != real_c) {
2013 *old_c = real_c;
2014 lynx_force_repaint();
2015 }
2016 return;
2017 }
2018 do_cleanup_after_delete();
2019 }
2020
2021 #if defined(DIRED_SUPPORT) || defined(VMS)
handle_LYK_DIRED_MENU(BOOLEAN * refresh_screen,int * old_c GCC_UNUSED,int real_c GCC_UNUSED)2022 static void handle_LYK_DIRED_MENU(BOOLEAN *refresh_screen,
2023 int *old_c GCC_UNUSED,
2024 int real_c GCC_UNUSED)
2025 {
2026 #ifdef VMS
2027 char *cp, *temp = 0;
2028 const char *test = HTGetProgramPath(ppCSWING);
2029
2030 /*
2031 * Check if the CSwing Directory/File Manager is available. Will be
2032 * disabled if CSWING path is NULL, zero-length, or "none" (case
2033 * insensitive), if no_file_url was set via the file_url restriction, if
2034 * no_goto_file was set for the anonymous account, or if HTDirAccess was
2035 * set to HT_DIR_FORBID or HT_DIR_SELECTIVE via the -nobrowse or -selective
2036 * switches. - FM
2037 */
2038 if (isEmpty(test) ||
2039 !strcasecomp(test, "none") ||
2040 no_file_url || no_goto_file ||
2041 HTDirAccess == HT_DIR_FORBID ||
2042 HTDirAccess == HT_DIR_SELECTIVE) {
2043 if (*old_c != real_c) {
2044 *old_c = real_c;
2045 HTUserMsg(DFM_NOT_AVAILABLE);
2046 }
2047 return;
2048 }
2049
2050 /*
2051 * If we are viewing a local directory listing or a local file which is not
2052 * temporary, invoke CSwing with the URLs directory converted to VMS path
2053 * specs and passed as the argument, so we start up CSwing positioned on
2054 * that node of the directory tree. Otherwise, pass the current default
2055 * directory as the argument. - FM
2056 */
2057 if (LYisLocalFile(curdoc.address) &&
2058 strncasecomp(curdoc.address,
2059 lynx_temp_space, strlen(lynx_temp_space))) {
2060 /*
2061 * We are viewing a local directory or a local file which is not
2062 * temporary. - FM
2063 */
2064 struct stat stat_info;
2065
2066 cp = HTParse(curdoc.address, "", PARSE_PATH | PARSE_PUNCTUATION);
2067 HTUnEscape(cp);
2068 if (HTStat(cp, &stat_info) == -1) {
2069 CTRACE((tfp, "mainloop: Can't stat %s\n", cp));
2070 FREE(cp);
2071 HTSprintf0(&temp, "%s []", HTGetProgramPath(ppCSWING));
2072 *refresh_screen = TRUE; /* redisplay */
2073 } else {
2074 char *VMSdir = NULL;
2075
2076 if (S_ISDIR(stat_info.st_mode)) {
2077 /*
2078 * We're viewing a local directory. Make that the CSwing
2079 * argument. - FM
2080 */
2081 LYAddPathSep(&cp);
2082 StrAllocCopy(VMSdir, HTVMS_name("", cp));
2083 FREE(cp);
2084 } else {
2085 /*
2086 * We're viewing a local file. Make its directory the CSwing
2087 * argument. - FM
2088 */
2089 StrAllocCopy(VMSdir, HTVMS_name("", cp));
2090 FREE(cp);
2091 if ((cp = strrchr(VMSdir, ']')) != NULL) {
2092 *(cp + 1) = '\0';
2093 } else if ((cp = strrchr(VMSdir, ':')) != NULL) {
2094 *(cp + 1) = '\0';
2095 }
2096 }
2097 HTSprintf0(&temp, "%s %s", HTGetProgramPath(ppCSWING), VMSdir);
2098 FREE(VMSdir);
2099 /*
2100 * Uncache the current document in case we change, move, or delete
2101 * it during the CSwing session. - FM
2102 */
2103 /* could use DIRED_UNCACHE_1 but it's currently only defined
2104 for dired - kw */
2105 HTuncache_current_document();
2106 move_address(&newdoc, &curdoc);
2107 StrAllocCopy(newdoc.title, NonNull(curdoc.title));
2108 StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
2109 newdoc.line = curdoc.line;
2110 newdoc.link = curdoc.link;
2111 }
2112 } else {
2113 /*
2114 * We're not viewing a local directory or file. Pass CSwing the
2115 * current default directory as an argument and don't uncache the
2116 * current document. - FM
2117 */
2118 HTSprintf0(&temp, "%s []", HTGetProgramPath(ppCSWING));
2119 *refresh_screen = TRUE; /* redisplay */
2120 }
2121 stop_curses();
2122 LYSystem(temp);
2123 start_curses();
2124 FREE(temp);
2125 #else
2126 /*
2127 * Don't do if not allowed or already viewing the menu.
2128 */
2129 if (lynx_edit_mode && !no_dired_support &&
2130 !LYIsUIPage(curdoc.address, UIP_DIRED_MENU) &&
2131 strcmp(NonNull(curdoc.title), DIRED_MENU_TITLE)) {
2132 dired_options(&curdoc, &newdoc.address);
2133 *refresh_screen = TRUE; /* redisplay */
2134 }
2135 #endif /* VMS */
2136 }
2137 #endif /* defined(DIRED_SUPPORT) || defined(VMS) */
2138
handle_LYK_DOWNLOAD(int * cmd,int * old_c,int real_c)2139 static int handle_LYK_DOWNLOAD(int *cmd,
2140 int *old_c,
2141 int real_c)
2142 {
2143
2144 /*
2145 * Don't do if both download and disk_save are restricted.
2146 */
2147 if (LYValidate ||
2148 (no_download && !override_no_download && no_disk_save)) {
2149 if (*old_c != real_c) {
2150 *old_c = real_c;
2151 HTUserMsg(DOWNLOAD_DISABLED);
2152 }
2153 return 0;
2154 }
2155
2156 /*
2157 * Don't do if already viewing download options page.
2158 */
2159 if (LYIsUIPage(curdoc.address, UIP_DOWNLOAD_OPTIONS))
2160 return 0;
2161
2162 if (do_change_link() == -1)
2163 return 1; /* mouse stuff was confused, ignore - kw */
2164 if (nlinks > 0) {
2165 if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
2166 if (links[curdoc.link].l_form->type == F_SUBMIT_TYPE ||
2167 links[curdoc.link].l_form->type == F_IMAGE_SUBMIT_TYPE ||
2168 links[curdoc.link].l_form->type == F_TEXT_SUBMIT_TYPE) {
2169 if (links[curdoc.link].l_form->submit_method ==
2170 URL_MAIL_METHOD) {
2171 if (*old_c != real_c) {
2172 *old_c = real_c;
2173 HTUserMsg(NO_DOWNLOAD_MAILTO_ACTION);
2174 }
2175 return 0;
2176 }
2177 if (isLYNXOPTIONS(links[curdoc.link].l_form->submit_action)) {
2178 if (*old_c != real_c) {
2179 *old_c = real_c;
2180 HTUserMsg(NO_DOWNLOAD_SPECIAL);
2181 }
2182 return 0;
2183 }
2184 HTOutputFormat = HTAtom_for("www/download");
2185 LYforce_no_cache = TRUE;
2186 *cmd = LYK_ACTIVATE;
2187 return 2;
2188 }
2189 if (*old_c != real_c) {
2190 *old_c = real_c;
2191 HTUserMsg(NO_DOWNLOAD_INPUT);
2192 }
2193
2194 } else if (isLYNXCOOKIE(curdoc.address)) {
2195 if (*old_c != real_c) {
2196 *old_c = real_c;
2197 HTUserMsg(NO_DOWNLOAD_COOKIES);
2198 }
2199 } else if (LYIsUIPage(curdoc.address, UIP_PRINT_OPTIONS)) {
2200 if (*old_c != real_c) {
2201 *old_c = real_c;
2202 HTUserMsg(NO_DOWNLOAD_PRINT_OP);
2203 }
2204 #ifdef DIRED_SUPPORT
2205 } else if (LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS)) {
2206 if (*old_c != real_c) {
2207 *old_c = real_c;
2208 HTUserMsg(NO_DOWNLOAD_UPLOAD_OP);
2209 }
2210
2211 } else if (LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS)) {
2212 if (*old_c != real_c) {
2213 *old_c = real_c;
2214 HTUserMsg(NO_DOWNLOAD_PERMIT_OP);
2215 }
2216
2217 } else if (lynx_edit_mode && !no_dired_support &&
2218 !strstr(links[curdoc.link].lname, "/SugFile=")) {
2219 /*
2220 * Don't bother making a /tmp copy of the local file.
2221 */
2222 static DocInfo temp;
2223
2224 copy_address(&temp, &newdoc);
2225 set_address(&newdoc, links[curdoc.link].lname);
2226 if (LYdownload_options(&newdoc.address,
2227 links[curdoc.link].lname) < 0)
2228 copy_address(&newdoc, &temp);
2229 else
2230 newdoc.internal_link = FALSE;
2231 LYFreeDocInfo(&temp);
2232 #endif /* DIRED_SUPPORT */
2233
2234 } else if (LYIsUIPage(curdoc.address, UIP_HISTORY) &&
2235 isLYNXHIST(links[curdoc.link].lname)) {
2236 int number = atoi(links[curdoc.link].lname + LEN_LYNXHIST);
2237
2238 if (number >= nhist || number < 0) {
2239 HTUserMsg(NO_DOWNLOAD_SPECIAL);
2240 return 0;
2241 }
2242 if ((HDOC(number).post_data != NULL &&
2243 HDOC(number).safe != TRUE) &&
2244 HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
2245 HTInfoMsg(CANCELLED);
2246 return 0;
2247 }
2248 /*
2249 * OK, we download from history page, restore URL from stack.
2250 */
2251 copy_address(&newdoc, &HDOC(number));
2252 StrAllocCopy(newdoc.title, LYGetHiliteStr(curdoc.link, 0));
2253 StrAllocCopy(newdoc.bookmark, HDOC(number).bookmark);
2254 LYFreePostData(&newdoc);
2255 if (HDOC(number).post_data)
2256 BStrCopy(newdoc.post_data,
2257 HDOC(number).post_data);
2258 if (HDOC(number).post_content_type)
2259 StrAllocCopy(newdoc.post_content_type,
2260 HDOC(number).post_content_type);
2261 newdoc.isHEAD = HDOC(number).isHEAD;
2262 newdoc.safe = HDOC(number).safe;
2263 newdoc.internal_link = FALSE;
2264 newdoc.link = (user_mode == NOVICE_MODE) ? 1 : 0;
2265 HTOutputFormat = HTAtom_for("www/download");
2266 LYUserSpecifiedURL = TRUE;
2267 /*
2268 * Force the document to be reloaded.
2269 */
2270 LYforce_no_cache = TRUE;
2271
2272 } else if (!StrNCmp(links[curdoc.link].lname, "data:", 5)) {
2273 if (*old_c != real_c) {
2274 *old_c = real_c;
2275 HTAlert(UNSUPPORTED_DATA_URL);
2276 }
2277
2278 } else if (isLYNXCOOKIE(links[curdoc.link].lname) ||
2279 #ifdef USE_CACHEJAR
2280 isLYNXCACHE(links[curdoc.link].lname) ||
2281 #endif
2282 isLYNXDIRED(links[curdoc.link].lname) ||
2283 isLYNXDOWNLOAD(links[curdoc.link].lname) ||
2284 isLYNXPRINT(links[curdoc.link].lname) ||
2285 isLYNXOPTIONS(links[curdoc.link].lname) ||
2286 isLYNXHIST(links[curdoc.link].lname) ||
2287 /* handled above if valid - kw */
2288 /* @@@ should next two be downloadable? - kw */
2289 isLYNXHIST(links[curdoc.link].lname) ||
2290 isLYNXCFLAGS(links[curdoc.link].lname) ||
2291 isLYNXEXEC(links[curdoc.link].lname) ||
2292 isLYNXPROG(links[curdoc.link].lname)) {
2293 HTUserMsg(NO_DOWNLOAD_SPECIAL);
2294
2295 } else if (isMAILTO_URL(links[curdoc.link].lname)) {
2296 HTUserMsg(NO_DOWNLOAD_MAILTO_LINK);
2297
2298 /*
2299 * From here on we could have a remote host, so check if that's
2300 * allowed.
2301 *
2302 * We copy all these checks from getfile() to LYK_DOWNLOAD here
2303 * because LYNXDOWNLOAD:// will NOT be pushing the previous
2304 * document into the history stack so preserve getfile() from
2305 * returning a wrong status (NULLFILE).
2306 */
2307 } else if (local_host_only &&
2308 !(LYisLocalHost(links[curdoc.link].lname) ||
2309 LYisLocalAlias(links[curdoc.link].lname))) {
2310 HTUserMsg(ACCESS_ONLY_LOCALHOST);
2311 } else { /* Not a forms, options or history link */
2312 /*
2313 * Follow a normal link or anchor. Note that if it's an anchor
2314 * within the same document, entire document will be downloaded.
2315 */
2316 set_address(&newdoc, links[curdoc.link].lname);
2317 StrAllocCopy(newdoc.title, LYGetHiliteStr(curdoc.link, 0));
2318 /*
2319 * Might be an internal link in the same doc from a POST form. If
2320 * so, don't free the content. - kw
2321 */
2322 if (track_internal_links) {
2323 if (links[curdoc.link].type != WWW_INTERN_LINK_TYPE) {
2324 LYFreePostData(&newdoc);
2325 FREE(newdoc.bookmark);
2326 newdoc.isHEAD = FALSE;
2327 newdoc.safe = FALSE;
2328 }
2329 } else {
2330 /*
2331 * Might be an anchor in the same doc from a POST form. If so,
2332 * don't free the content. -- FM
2333 */
2334 if (are_different(&curdoc, &newdoc)) {
2335 LYFreePostData(&newdoc);
2336 FREE(newdoc.bookmark);
2337 newdoc.isHEAD = FALSE;
2338 newdoc.safe = FALSE;
2339 }
2340 }
2341 newdoc.internal_link = FALSE;
2342 newdoc.link = (user_mode == NOVICE_MODE) ? 1 : 0;
2343 HTOutputFormat = HTAtom_for("www/download");
2344 /*
2345 * Force the document to be reloaded.
2346 */
2347 LYforce_no_cache = TRUE;
2348 }
2349 } else if (*old_c != real_c) {
2350 *old_c = real_c;
2351 HTUserMsg(NO_DOWNLOAD_CHOICE);
2352 }
2353 return 0;
2354 }
2355
handle_LYK_DOWN_xxx(int * old_c,int real_c,int scroll_by)2356 static void handle_LYK_DOWN_xxx(int *old_c,
2357 int real_c,
2358 int scroll_by)
2359 {
2360 int i;
2361
2362 if (more_text) {
2363 LYChgNewline(scroll_by);
2364 if (nlinks > 0 && curdoc.link > -1 &&
2365 links[curdoc.link].ly > scroll_by) {
2366 newdoc.link = curdoc.link;
2367 for (i = 0; links[i].ly <= scroll_by; i++)
2368 --newdoc.link;
2369 }
2370 } else if (*old_c != real_c) {
2371 *old_c = real_c;
2372 HTInfoMsg(ALREADY_AT_END);
2373 }
2374 }
2375
handle_LYK_DOWN_HALF(int * old_c,int real_c)2376 static void handle_LYK_DOWN_HALF(int *old_c,
2377 int real_c)
2378 {
2379 handle_LYK_DOWN_xxx(old_c, real_c, display_lines / 2);
2380 }
2381
handle_LYK_DOWN_LINK(int * follow_col,int * old_c,int real_c)2382 static void handle_LYK_DOWN_LINK(int *follow_col,
2383 int *old_c,
2384 int real_c)
2385 {
2386 if (curdoc.link < (nlinks - 1)) { /* more links? */
2387 int newlink;
2388
2389 if (*follow_col == -1) {
2390 const char *text = LYGetHiliteStr(curdoc.link, 0);
2391
2392 *follow_col = links[curdoc.link].lx;
2393
2394 if (text != NULL)
2395 *follow_col += (int) strlen(text) / 2;
2396 }
2397
2398 newlink = find_link_near_col(*follow_col, 1);
2399 if (newlink > -1) {
2400 set_curdoc_link(newlink);
2401 } else if (more_text) { /* next page */
2402 LYChgNewline(display_lines);
2403 } else if (*old_c != real_c) {
2404 *old_c = real_c;
2405 HTUserMsg(NO_LINKS_BELOW);
2406 return;
2407 }
2408 } else if (more_text) { /* next page */
2409 LYChgNewline(display_lines);
2410 } else if (*old_c != real_c) {
2411 *old_c = real_c;
2412 HTInfoMsg(ALREADY_AT_END);
2413 }
2414 }
2415
handle_LYK_DOWN_TWO(int * old_c,int real_c)2416 static void handle_LYK_DOWN_TWO(int *old_c,
2417 int real_c)
2418 {
2419 handle_LYK_DOWN_xxx(old_c, real_c, 2);
2420 }
2421
handle_LYK_DWIMEDIT(int * cmd,int * old_c,int real_c)2422 static int handle_LYK_DWIMEDIT(int *cmd,
2423 int *old_c,
2424 int real_c)
2425 {
2426 #ifdef TEXTAREA_AUTOEXTEDIT
2427 /*
2428 * If we're in a forms TEXTAREA, invoke the editor on *its* contents,
2429 * rather than attempting to edit the html source document. KED
2430 */
2431 if (nlinks > 0 &&
2432 LinkIsTextarea(curdoc.link)) {
2433 *cmd = LYK_EDIT_TEXTAREA;
2434 return 2;
2435 }
2436
2437 /*
2438 * If we're in a forms TEXT type, tell user the request is bogus (though in
2439 * reality, without this trap, if the document with the TEXT field is
2440 * local, the editor *would* be invoked on the source .html file; eg, the
2441 * o(ptions) form tempfile).
2442 *
2443 * [This is done to avoid possible user confusion, due to auto invocation
2444 * of the editor on the TEXTAREA's contents via the above if() statement.]
2445 */
2446 if (nlinks > 0 &&
2447 links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
2448 links[curdoc.link].l_form->type == F_TEXT_TYPE) {
2449 HTUserMsg(CANNOT_EDIT_FIELD);
2450 return 1;
2451 }
2452
2453 if (no_editor) {
2454 if (*old_c != real_c) {
2455 *old_c = real_c;
2456 HTUserMsg(ANYEDIT_DISABLED);
2457 }
2458 return 1;
2459 }
2460 #endif /* TEXTAREA_AUTOEXTEDIT */
2461 return 0;
2462 }
2463
handle_LYK_ECGOTO(int * ch,bstring ** user_input,char ** old_user_input,int * old_c,int real_c)2464 static int handle_LYK_ECGOTO(int *ch,
2465 bstring **user_input,
2466 char **old_user_input,
2467 int *old_c,
2468 int real_c)
2469 {
2470 if (no_goto && !LYValidate) {
2471 /*
2472 * Go to not allowed. - FM
2473 */
2474 if (*old_c != real_c) {
2475 *old_c = real_c;
2476 HTUserMsg(GOTO_DISALLOWED);
2477 }
2478 return 0;
2479 }
2480 #ifdef DIRED_SUPPORT
2481 if (LYIsUIPage(curdoc.address, UIP_DIRED_MENU) ||
2482 LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS) ||
2483 LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS)) {
2484 /*
2485 * Disallow editing of File Management URLs. - FM
2486 */
2487 if (*old_c != real_c) {
2488 *old_c = real_c;
2489 HTUserMsg(EDIT_FM_MENU_URLS_DISALLOWED);
2490 }
2491 return 0;
2492 }
2493 #endif /* DIRED_SUPPORT */
2494
2495 /*
2496 * Save the current user_input string, and load the current
2497 * document's address.
2498 */
2499 StrAllocCopy(*old_user_input, (*user_input)->str);
2500 BStrCopy0((*user_input), curdoc.address);
2501
2502 /*
2503 * Warn the user if the current document has POST data associated with it.
2504 * - FM
2505 */
2506 if (curdoc.post_data)
2507 HTAlert(CURRENT_DOC_HAS_POST_DATA);
2508
2509 /*
2510 * Offer the current document's URL for editing. - FM
2511 */
2512 _statusline(EDIT_CURDOC_URL);
2513 if (((*ch = LYgetBString(user_input, VISIBLE, 0, RECALL_URL)) >= 0) &&
2514 !isBEmpty(*user_input) &&
2515 strcmp((*user_input)->str, curdoc.address)) {
2516 LYTrimAllStartfile((*user_input)->str);
2517 if (!isBEmpty(*user_input)) {
2518 return 2;
2519 }
2520 }
2521 /*
2522 * User cancelled via ^G, a full deletion, or not modifying the URL. - FM
2523 */
2524 HTInfoMsg(CANCELLED);
2525 BStrCopy0((*user_input), *old_user_input);
2526 FREE(*old_user_input);
2527 return 0;
2528 }
2529
handle_LYK_EDIT(int * old_c,int real_c)2530 static void handle_LYK_EDIT(int *old_c,
2531 int real_c)
2532 {
2533 #ifdef DIRED_SUPPORT
2534 char *cp;
2535 char *tp = NULL;
2536 struct stat dir_info;
2537 #endif /* DIRED_SUPPORT */
2538
2539 if (no_editor) {
2540 if (*old_c != real_c) {
2541 *old_c = real_c;
2542 HTUserMsg(EDIT_DISABLED);
2543 }
2544 }
2545 #ifdef DIRED_SUPPORT
2546 /*
2547 * Allow the user to edit the link rather than curdoc in edit mode.
2548 */
2549 else if (lynx_edit_mode &&
2550 non_empty(editor) && !no_dired_support) {
2551 if (nlinks > 0) {
2552 cp = links[curdoc.link].lname;
2553 if (is_url(cp) == FILE_URL_TYPE) {
2554 cp = HTfullURL_toFile(cp);
2555 StrAllocCopy(tp, cp);
2556 FREE(cp);
2557
2558 if (stat(tp, &dir_info) == -1) {
2559 HTAlert(NO_STATUS);
2560 } else {
2561 if (S_ISREG(dir_info.st_mode)) {
2562 StrAllocCopy(tp, links[curdoc.link].lname);
2563 HTUnEscapeSome(tp, "/");
2564 if (edit_current_file(tp, curdoc.link, -1)) {
2565 DIRED_UNCACHE_1;
2566 move_address(&newdoc, &curdoc);
2567 #ifdef NO_SEEK_OLD_POSITION
2568 /*
2569 * Go to top of file.
2570 */
2571 newdoc.line = 1;
2572 newdoc.link = 0;
2573 #else
2574 /*
2575 * Seek old position, which probably changed.
2576 */
2577 newdoc.line = curdoc.line;
2578 newdoc.link = curdoc.link;
2579 #endif /* NO_SEEK_OLD_POSITION */
2580 LYclear(); /* clear the screen */
2581 }
2582 }
2583 }
2584 FREE(tp);
2585 }
2586 }
2587 }
2588 #endif /* DIRED_SUPPORT */
2589 else if (non_empty(editor)) {
2590 if (edit_current_file(newdoc.address, curdoc.link, LYGetNewline())) {
2591 HTuncache_current_document();
2592 LYforce_no_cache = TRUE; /*force reload of document */
2593 free_address(&curdoc); /* so it doesn't get pushed */
2594 #ifdef NO_SEEK_OLD_POSITION
2595 /*
2596 * Go to top of file.
2597 */
2598 newdoc.line = 1;
2599 newdoc.link = 0;
2600 #else
2601 /*
2602 * Seek old position, which probably changed.
2603 */
2604 newdoc.line = curdoc.line;
2605 newdoc.link = curdoc.link;
2606 #endif /* NO_SEEK_OLD_POSITION */
2607 LYclear(); /* clear the screen */
2608 }
2609
2610 } else {
2611 if (*old_c != real_c) {
2612 *old_c = real_c;
2613 HTUserMsg(NO_EDITOR);
2614 }
2615 }
2616 }
2617
handle_LYK_DWIMHELP(const char ** cshelpfile)2618 static void handle_LYK_DWIMHELP(const char **cshelpfile)
2619 {
2620 /*
2621 * Currently a help file different from the main 'helpfile' is shown only
2622 * if current link is a text input form field. - kw
2623 */
2624 if (curdoc.link >= 0 && curdoc.link < nlinks &&
2625 !FormIsReadonly(links[curdoc.link].l_form) &&
2626 LinkIsTextLike(curdoc.link)) {
2627 *cshelpfile = LYLineeditHelpURL();
2628 }
2629 }
2630
handle_LYK_EDIT_TEXTAREA(BOOLEAN * refresh_screen,int * old_c,int real_c)2631 static void handle_LYK_EDIT_TEXTAREA(BOOLEAN *refresh_screen,
2632 int *old_c,
2633 int real_c)
2634 {
2635 if (no_editor) {
2636 if (*old_c != real_c) {
2637 *old_c = real_c;
2638 HTUserMsg(ANYEDIT_DISABLED);
2639 }
2640 } else if (isEmpty(editor)) {
2641 if (*old_c != real_c) {
2642 *old_c = real_c;
2643 HTUserMsg(NO_EDITOR);
2644 }
2645 } else if (LinkIsTextarea(curdoc.link)) {
2646 /*
2647 * if the current link is in a form TEXTAREA, it requires handling
2648 * for the possible multiple lines.
2649 */
2650
2651 /* stop screen */
2652 stop_curses();
2653
2654 (void) HText_EditTextArea(&links[curdoc.link]);
2655
2656 /*
2657 * TODO:
2658 * Move cursor "n" lines from the current line to position it on the
2659 * 1st trailing blank line in the now edited TEXTAREA. If the target
2660 * line/ anchor requires us to scroll up/down, position the target in
2661 * the approximate center of the screen.
2662 */
2663
2664 /* curdoc.link += n; */
2665 /* works, except for page crossing, */
2666 /* damnit; why is nothing ever easy */
2667
2668 /* start screen */
2669 start_curses();
2670 *refresh_screen = TRUE;
2671
2672 } else if (LinkIsTextLike(curdoc.link)) {
2673 /*
2674 * other text fields are single-line
2675 */
2676 stop_curses();
2677 HText_EditTextField(&links[curdoc.link]);
2678 start_curses();
2679 *refresh_screen = TRUE;
2680 } else {
2681
2682 HTInfoMsg(NOT_IN_TEXTAREA_NOEDIT);
2683 }
2684 }
2685
handle_LYK_ELGOTO(int * ch,bstring ** user_input,char ** old_user_input,int * old_c,int real_c)2686 static int handle_LYK_ELGOTO(int *ch,
2687 bstring **user_input,
2688 char **old_user_input,
2689 int *old_c,
2690 int real_c)
2691 {
2692 if (no_goto && !LYValidate) {
2693 /*
2694 * Go to not allowed. - FM
2695 */
2696 if (*old_c != real_c) {
2697 *old_c = real_c;
2698 HTUserMsg(GOTO_DISALLOWED);
2699 }
2700 return 0;
2701 }
2702 if (!(nlinks > 0 && curdoc.link > -1) ||
2703 (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
2704 links[curdoc.link].l_form->type != F_SUBMIT_TYPE &&
2705 links[curdoc.link].l_form->type != F_IMAGE_SUBMIT_TYPE &&
2706 links[curdoc.link].l_form->type != F_TEXT_SUBMIT_TYPE)) {
2707 /*
2708 * No links on page, or not a normal link or form submit button. - FM
2709 */
2710 if (*old_c != real_c) {
2711 *old_c = real_c;
2712 HTUserMsg(NOT_ON_SUBMIT_OR_LINK);
2713 }
2714 return 0;
2715 }
2716 if ((links[curdoc.link].type == WWW_FORM_LINK_TYPE) &&
2717 (isEmpty(links[curdoc.link].l_form->submit_action))) {
2718 /*
2719 * Form submit button with no ACTION defined. - FM
2720 */
2721 if (*old_c != real_c) {
2722 *old_c = real_c;
2723 HTUserMsg(NO_FORM_ACTION);
2724 }
2725 return 0;
2726 }
2727 #ifdef DIRED_SUPPORT
2728 if (isLYNXDIRED(links[curdoc.link].lname) ||
2729 LYIsUIPage(curdoc.address, UIP_DIRED_MENU) ||
2730 LYIsUIPage(curdoc.address, UIP_PERMIT_OPTIONS) ||
2731 LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS)) {
2732 /*
2733 * Disallow editing of File Management URLs. - FM
2734 */
2735 if (*old_c != real_c) {
2736 *old_c = real_c;
2737 HTUserMsg(EDIT_FM_MENU_URLS_DISALLOWED);
2738 }
2739 return 0;
2740 }
2741 #endif /* DIRED_SUPPORT */
2742
2743 /*
2744 * Save the current user_input string, and load the current link's
2745 * address. - FM
2746 */
2747 StrAllocCopy(*old_user_input, (*user_input)->str);
2748 BStrCopy0((*user_input),
2749 ((links[curdoc.link].type == WWW_FORM_LINK_TYPE)
2750 ? links[curdoc.link].l_form->submit_action
2751 : links[curdoc.link].lname));
2752 /*
2753 * Offer the current link's URL for editing. - FM
2754 */
2755 _statusline(EDIT_CURLINK_URL);
2756 if (((*ch = LYgetBString(user_input, VISIBLE, 0, RECALL_URL)) >= 0) &&
2757 !isBEmpty(*user_input) &&
2758 strcmp((*user_input)->str,
2759 ((links[curdoc.link].type == WWW_FORM_LINK_TYPE)
2760 ? links[curdoc.link].l_form->submit_action
2761 : links[curdoc.link].lname))) {
2762 LYTrimAllStartfile((*user_input)->str);
2763 if (!isBEmpty(*user_input)) {
2764 return 2;
2765 }
2766 }
2767 /*
2768 * User cancelled via ^G, a full deletion, or not modifying the URL. - FM
2769 */
2770 HTInfoMsg(CANCELLED);
2771 BStrCopy0((*user_input), *old_user_input);
2772 FREE(*old_user_input);
2773 return 0;
2774 }
2775
2776 #ifdef USE_EXTERNALS
handle_LYK_EXTERN_LINK(BOOLEAN * refresh_screen)2777 static void handle_LYK_EXTERN_LINK(BOOLEAN *refresh_screen)
2778 {
2779 if ((nlinks > 0) && (links[curdoc.link].lname != NULL)) {
2780 run_external(links[curdoc.link].lname, FALSE);
2781 *refresh_screen = TRUE;
2782 }
2783 }
2784
handle_LYK_EXTERN_PAGE(BOOLEAN * refresh_screen)2785 static void handle_LYK_EXTERN_PAGE(BOOLEAN *refresh_screen)
2786 {
2787 if (curdoc.address != NULL) {
2788 run_external(curdoc.address, FALSE);
2789 *refresh_screen = TRUE;
2790 }
2791 }
2792 #endif
2793
handle_LYK_FASTBACKW_LINK(int * cmd,int * old_c,int real_c)2794 static BOOLEAN handle_LYK_FASTBACKW_LINK(int *cmd,
2795 int *old_c,
2796 int real_c)
2797 {
2798 int samepage = 0, nextlink = curdoc.link;
2799 int res;
2800 BOOLEAN code = FALSE;
2801
2802 if (nlinks > 1) {
2803
2804 /*
2805 * If in textarea, move to first link or textarea group before it if
2806 * there is one on this screen. - kw
2807 */
2808 if (LinkIsTextarea(curdoc.link)) {
2809 int thisgroup = links[curdoc.link].l_form->number;
2810 char *thisname = links[curdoc.link].l_form->name;
2811
2812 if (curdoc.link > 0 &&
2813 !(LinkIsTextarea(0) &&
2814 links[0].l_form->number == thisgroup &&
2815 sametext(links[0].l_form->name, thisname))) {
2816 do
2817 nextlink--;
2818 while
2819 (LinkIsTextarea(nextlink) &&
2820 links[nextlink].l_form->number == thisgroup &&
2821 sametext(links[nextlink].l_form->name, thisname));
2822 samepage = 1;
2823
2824 } else if (!more_text && LYGetNewline() == 1 &&
2825 (LinkIsTextarea(0) &&
2826 links[0].l_form->number == thisgroup &&
2827 sametext(links[0].l_form->name, thisname)) &&
2828 !(LinkIsTextarea(nlinks - 1) &&
2829 links[nlinks - 1].l_form->number == thisgroup &&
2830 sametext(links[nlinks - 1].l_form->name, thisname))) {
2831 nextlink = nlinks - 1;
2832 samepage = 1;
2833
2834 } else if (!more_text && LYGetNewline() == 1 && curdoc.link > 0) {
2835 nextlink = 0;
2836 samepage = 1;
2837 }
2838 } else if (curdoc.link > 0) {
2839 nextlink--;
2840 samepage = 1;
2841 } else if (!more_text && LYGetNewline() == 1) {
2842 nextlink = nlinks - 1;
2843 samepage = 1;
2844 }
2845 }
2846
2847 if (samepage) {
2848 /*
2849 * If the link as determined so far is part of a group of textarea
2850 * fields, try to use the first of them that's on the screen instead.
2851 * - kw
2852 */
2853 if (nextlink > 0 &&
2854 LinkIsTextarea(nextlink)) {
2855 int thisgroup = links[nextlink].l_form->number;
2856 char *thisname = links[nextlink].l_form->name;
2857
2858 if (LinkIsTextarea(0) &&
2859 links[0].l_form->number == thisgroup &&
2860 sametext(links[0].l_form->name, thisname)) {
2861 nextlink = 0;
2862 } else
2863 while
2864 (nextlink > 1 &&
2865 LinkIsTextarea(nextlink - 1) &&
2866 links[nextlink - 1].l_form->number == thisgroup &&
2867 sametext(links[nextlink - 1].l_form->name, thisname)) {
2868 nextlink--;
2869 }
2870 }
2871 set_curdoc_link(nextlink);
2872
2873 } else if (LYGetNewline() > 1 && /* need a previous page */
2874 (res = HTGetLinkOrFieldStart(curdoc.link,
2875 &Newline, &newdoc.link,
2876 -1, TRUE)) != NO) {
2877 if (res == LINK_DO_ARROWUP) {
2878 /*
2879 * It says we should use the normal PREV_LINK mechanism, so we'll
2880 * do that. - kw
2881 */
2882 if (nlinks > 0)
2883 curdoc.link = 0;
2884 *cmd = LYK_PREV_LINK;
2885 code = TRUE;
2886 } else {
2887 LYChgNewline(1); /* our line counting starts with 1 not 0 */
2888 }
2889 } else if (*old_c != real_c) {
2890 *old_c = real_c;
2891 HTInfoMsg(NO_LINKS_ABOVE);
2892 }
2893 return code;
2894 }
2895
handle_LYK_FASTFORW_LINK(int * old_c,int real_c)2896 static void handle_LYK_FASTFORW_LINK(int *old_c,
2897 int real_c)
2898 {
2899 int samepage = 0, nextlink = curdoc.link;
2900
2901 if (nlinks > 1) {
2902
2903 /*
2904 * If in textarea, move to first link or field after it if there is one
2905 * on this screen. - kw
2906 */
2907 if (LinkIsTextarea(curdoc.link)) {
2908 int thisgroup = links[curdoc.link].l_form->number;
2909 char *thisname = links[curdoc.link].l_form->name;
2910
2911 if (curdoc.link < nlinks - 1 &&
2912 !(LinkIsTextarea(nlinks - 1) &&
2913 links[nlinks - 1].l_form->number == thisgroup &&
2914 sametext(links[nlinks - 1].l_form->name, thisname))) {
2915 do
2916 nextlink++;
2917 while
2918 (LinkIsTextarea(nextlink) &&
2919 links[nextlink].l_form->number == thisgroup &&
2920 sametext(links[nextlink].l_form->name, thisname));
2921 samepage = 1;
2922 } else if (!more_text && LYGetNewline() == 1 && curdoc.link > 0) {
2923 nextlink = 0;
2924 samepage = 1;
2925 }
2926 } else if (curdoc.link < nlinks - 1) {
2927 nextlink++;
2928 samepage = 1;
2929 } else if (!more_text && LYGetNewline() == 1 && curdoc.link > 0) {
2930 nextlink = 0;
2931 samepage = 1;
2932 }
2933 }
2934
2935 if (samepage) {
2936 set_curdoc_link(nextlink);
2937 } else if (!more_text && LYGetNewline() == 1 && curdoc.link == nlinks - 1) {
2938 /*
2939 * At the bottom of list and there is only one page. Move to the top
2940 * link on the page.
2941 */
2942 set_curdoc_link(0);
2943
2944 } else if (more_text && /* need a later page */
2945 HTGetLinkOrFieldStart(curdoc.link,
2946 &Newline, &newdoc.link,
2947 1, TRUE) != NO) {
2948 LYChgNewline(1); /* our line counting starts with 1 not 0 */
2949 /* nothing more to do here */
2950
2951 } else if (*old_c != real_c) {
2952 *old_c = real_c;
2953 HTInfoMsg(NO_LINKS_BELOW);
2954 }
2955 return;
2956 }
2957
handle_LYK_FIRST_LINK(void)2958 static void handle_LYK_FIRST_LINK(void)
2959 {
2960 int i = curdoc.link;
2961
2962 for (;;) {
2963 if (--i < 0
2964 || links[i].ly != links[curdoc.link].ly) {
2965 set_curdoc_link(i + 1);
2966 break;
2967 }
2968 }
2969 }
2970
handle_LYK_GOTO(int * ch,bstring ** user_input,char ** old_user_input,RecallType * recall,int * URLTotal,int * URLNum,BOOLEAN * FirstURLRecall,int * old_c,int real_c)2971 static BOOLEAN handle_LYK_GOTO(int *ch,
2972 bstring **user_input,
2973 char **old_user_input,
2974 RecallType * recall,
2975 int *URLTotal,
2976 int *URLNum,
2977 BOOLEAN *FirstURLRecall,
2978 int *old_c,
2979 int real_c)
2980 {
2981
2982 if (no_goto && !LYValidate) {
2983 if (*old_c != real_c) {
2984 *old_c = real_c;
2985 HTUserMsg(GOTO_DISALLOWED);
2986 }
2987 return FALSE;
2988 }
2989
2990 StrAllocCopy(*old_user_input, (*user_input)->str);
2991 if (!goto_buffer)
2992 BStrCopy0((*user_input), "");
2993
2994 *URLTotal = (Goto_URLs ? HTList_count(Goto_URLs) : 0);
2995 if (goto_buffer && !isBEmpty(*user_input)) {
2996 *recall = ((*URLTotal > 1) ? RECALL_URL : NORECALL);
2997 *URLNum = 0;
2998 *FirstURLRecall = FALSE;
2999 } else {
3000 *recall = ((*URLTotal >= 1) ? RECALL_URL : NORECALL);
3001 *URLNum = *URLTotal;
3002 *FirstURLRecall = TRUE;
3003 }
3004
3005 /*
3006 * Ask the user.
3007 */
3008 _statusline(URL_TO_OPEN);
3009 if ((*ch = LYgetBString(user_input, VISIBLE, 0, *recall)) < 0) {
3010 /*
3011 * User cancelled the Goto via ^G. Restore user_input and
3012 * break. - FM
3013 */
3014 BStrCopy0((*user_input), *old_user_input);
3015 FREE(*old_user_input);
3016 HTInfoMsg(CANCELLED);
3017 return FALSE;
3018 }
3019 return TRUE;
3020 }
3021
handle_LYK_GROW_TEXTAREA(BOOLEAN * refresh_screen)3022 static void handle_LYK_GROW_TEXTAREA(BOOLEAN *refresh_screen)
3023 {
3024 /*
3025 * See if the current link is in a form TEXTAREA.
3026 */
3027 if (LinkIsTextarea(curdoc.link)) {
3028
3029 HText_ExpandTextarea(&links[curdoc.link], TEXTAREA_EXPAND_SIZE);
3030
3031 *refresh_screen = TRUE;
3032
3033 } else {
3034
3035 HTInfoMsg(NOT_IN_TEXTAREA);
3036 }
3037 }
3038
handle_LYK_HEAD(int * cmd)3039 static BOOLEAN handle_LYK_HEAD(int *cmd)
3040 {
3041 int c;
3042
3043 if (nlinks > 0 &&
3044 (links[curdoc.link].type != WWW_FORM_LINK_TYPE ||
3045 links[curdoc.link].l_form->type == F_SUBMIT_TYPE ||
3046 links[curdoc.link].l_form->type == F_IMAGE_SUBMIT_TYPE ||
3047 links[curdoc.link].l_form->type == F_TEXT_SUBMIT_TYPE)) {
3048 /*
3049 * We have links, and the current link is a normal link or a form's
3050 * submit button. - FM
3051 */
3052 _statusline(HEAD_D_L_OR_CANCEL);
3053 c = LYgetch_single();
3054 if (c == 'D') {
3055 char *scheme = !isLYNXIMGMAP(curdoc.address)
3056 ? curdoc.address
3057 : curdoc.address + LEN_LYNXIMGMAP;
3058
3059 if (LYCanDoHEAD(scheme) != TRUE) {
3060 HTUserMsg(DOC_NOT_HTTP_URL);
3061 } else {
3062 /*
3063 * Check if this is a reply from a POST, and if so, seek
3064 * confirmation if the safe element is not set. - FM
3065 */
3066 if ((curdoc.post_data != NULL &&
3067 curdoc.safe != TRUE) &&
3068 HTConfirm(CONFIRM_POST_DOC_HEAD) == FALSE) {
3069 HTInfoMsg(CANCELLED);
3070 } else {
3071 HEAD_request = TRUE;
3072 LYforce_no_cache = TRUE;
3073 StrAllocCopy(newdoc.title, curdoc.title);
3074 if (HTLoadedDocumentIsHEAD()) {
3075 HText_setNoCache(HTMainText);
3076 free_address(&curdoc);
3077 } else {
3078 StrAllocCat(newdoc.title, " - HEAD");
3079 }
3080 }
3081 }
3082 } else if (c == 'L') {
3083 if (links[curdoc.link].type != WWW_FORM_LINK_TYPE &&
3084 StrNCmp(links[curdoc.link].lname, "http", 4) &&
3085 StrNCmp(links[curdoc.link].lname, "LYNXIMGMAP:http", 15) &&
3086 LYCanDoHEAD(links[curdoc.link].lname) != TRUE &&
3087 (links[curdoc.link].type != WWW_INTERN_LINK_TYPE ||
3088 !curdoc.address ||
3089 StrNCmp(curdoc.address, "http", 4))) {
3090 HTUserMsg(LINK_NOT_HTTP_URL);
3091 } else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
3092 FormIsReadonly(links[curdoc.link].l_form)) {
3093 HTUserMsg(FORM_ACTION_DISABLED);
3094 } else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
3095 links[curdoc.link].l_form->submit_action != 0 &&
3096 !isLYNXCGI(links[curdoc.link].l_form->submit_action) &&
3097 StrNCmp(links[curdoc.link].l_form->submit_action,
3098 "http", 4)) {
3099 HTUserMsg(FORM_ACTION_NOT_HTTP_URL);
3100 } else if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
3101 links[curdoc.link].l_form->submit_method ==
3102 URL_POST_METHOD &&
3103 HTConfirm(CONFIRM_POST_LINK_HEAD) == FALSE) {
3104 HTInfoMsg(CANCELLED);
3105 } else {
3106 HEAD_request = TRUE;
3107 LYforce_no_cache = TRUE;
3108 *cmd = LYK_ACTIVATE;
3109 return TRUE;
3110 }
3111 }
3112 } else {
3113 /*
3114 * We can offer only this document for a HEAD request. Check if this
3115 * is a reply from a POST, and if so, seek confirmation if the safe
3116 * element is not set. - FM
3117 */
3118 if ((curdoc.post_data != NULL &&
3119 curdoc.safe != TRUE) &&
3120 HTConfirm(CONFIRM_POST_DOC_HEAD) == FALSE) {
3121 HTInfoMsg(CANCELLED);
3122 } else {
3123 if (nlinks > 0) {
3124 /*
3125 * The current link is a non-submittable form link, so prompt
3126 * the user to make it clear that the HEAD request would be for
3127 * the current document, not the form link. - FM
3128 */
3129 _statusline(HEAD_D_OR_CANCEL);
3130 c = LYgetch_single();
3131 } else {
3132 /*
3133 * No links, so we can just assume that the user wants a HEAD
3134 * request for the current document. - FM
3135 */
3136 c = 'D';
3137 }
3138 if (c == 'D') {
3139 char *scheme = !isLYNXIMGMAP(curdoc.address)
3140 ? curdoc.address
3141 : curdoc.address + LEN_LYNXIMGMAP;
3142
3143 /*
3144 * The user didn't cancel, so check if a HEAD request is
3145 * appropriate for the current document. - FM
3146 */
3147 if (LYCanDoHEAD(scheme) != TRUE) {
3148 HTUserMsg(DOC_NOT_HTTP_URL);
3149 } else {
3150 HEAD_request = TRUE;
3151 LYforce_no_cache = TRUE;
3152 StrAllocCopy(newdoc.title, curdoc.title);
3153 if (HTLoadedDocumentIsHEAD()) {
3154 HText_setNoCache(HTMainText);
3155 free_address(&curdoc);
3156 } else {
3157 StrAllocCat(newdoc.title, " - HEAD");
3158 }
3159 }
3160 }
3161 }
3162 }
3163 return FALSE;
3164 }
3165
handle_LYK_HELP(const char ** cshelpfile)3166 static void handle_LYK_HELP(const char **cshelpfile)
3167 {
3168 char *my_value = NULL;
3169
3170 if (*cshelpfile == NULL)
3171 *cshelpfile = helpfile;
3172 StrAllocCopy(my_value, *cshelpfile);
3173 LYEnsureAbsoluteURL(&my_value, *cshelpfile, FALSE);
3174 if (!STREQ(curdoc.address, my_value)) {
3175 /*
3176 * Set the filename.
3177 */
3178 set_address(&newdoc, my_value);
3179 /*
3180 * Make a name for this help file.
3181 */
3182 StrAllocCopy(newdoc.title, gettext("Help Screen"));
3183 LYFreePostData(&newdoc);
3184 FREE(newdoc.bookmark);
3185 newdoc.isHEAD = FALSE;
3186 newdoc.safe = FALSE;
3187 newdoc.internal_link = FALSE;
3188 }
3189 FREE(my_value);
3190 *cshelpfile = NULL; /* reset pointer - kw */
3191 }
3192
handle_LYK_HISTORICAL(void)3193 static void handle_LYK_HISTORICAL(void)
3194 {
3195 #ifdef USE_SOURCE_CACHE
3196 if (!HTcan_reparse_document()) {
3197 #endif
3198 /*
3199 * Check if this is a reply from a POST, and if so, seek confirmation
3200 * of reload if the safe element is not set. - FM
3201 */
3202 if ((curdoc.post_data != NULL &&
3203 curdoc.safe != TRUE) &&
3204 confirm_post_resub(curdoc.address, NULL, 0, 0) == FALSE) {
3205 HTInfoMsg(WILL_NOT_RELOAD_DOC);
3206 } else {
3207 HText_setNoCache(HTMainText);
3208 move_address(&newdoc, &curdoc);
3209 newdoc.line = curdoc.line;
3210 newdoc.link = curdoc.link;
3211 }
3212 #ifdef USE_SOURCE_CACHE
3213 } /* end if no bypass */
3214 #endif
3215 historical_comments = (BOOLEAN) !historical_comments;
3216 if (minimal_comments) {
3217 HTAlert(historical_comments ?
3218 HISTORICAL_ON_MINIMAL_OFF : HISTORICAL_OFF_MINIMAL_ON);
3219 } else {
3220 HTAlert(historical_comments ?
3221 HISTORICAL_ON_VALID_OFF : HISTORICAL_OFF_VALID_ON);
3222 }
3223 #ifdef USE_SOURCE_CACHE
3224 (void) reparse_document();
3225 #endif
3226 return;
3227 }
3228
handle_LYK_HISTORY(int ForcePush)3229 static BOOLEAN handle_LYK_HISTORY(int ForcePush)
3230 {
3231 if (curdoc.title && !LYIsUIPage(curdoc.address, UIP_HISTORY)) {
3232 /*
3233 * Don't do this if already viewing history page.
3234 *
3235 * Push the current file so that the history list contains the current
3236 * file for printing purposes. Pop the file afterwards to prevent
3237 * multiple copies.
3238 */
3239 if (TRACE && !LYUseTraceLog && LYCursesON) {
3240 LYHideCursor(); /* make sure cursor is down */
3241 #ifdef USE_SLANG
3242 LYaddstr("\n");
3243 #endif /* USE_SLANG */
3244 LYrefresh();
3245 }
3246 LYpush(&curdoc, ForcePush);
3247
3248 /*
3249 * Print history options to file.
3250 */
3251 if (showhistory(&newdoc.address) < 0) {
3252 LYpop(&curdoc);
3253 return TRUE;
3254 }
3255 LYRegisterUIPage(newdoc.address, UIP_HISTORY);
3256 StrAllocCopy(newdoc.title, HISTORY_PAGE_TITLE);
3257 LYFreePostData(&newdoc);
3258 FREE(newdoc.bookmark);
3259 newdoc.isHEAD = FALSE;
3260 newdoc.safe = FALSE;
3261 newdoc.internal_link = FALSE;
3262 newdoc.link = 1; /*@@@ bypass "recent statusline messages" link */
3263 free_address(&curdoc); /* so it doesn't get pushed */
3264
3265 if (LYValidate || check_realm) {
3266 LYPermitURL = TRUE;
3267 }
3268 return TRUE;
3269 } /* end if StrNCmp */
3270 return FALSE;
3271 }
3272
handle_LYK_IMAGE_TOGGLE(int * cmd)3273 static BOOLEAN handle_LYK_IMAGE_TOGGLE(int *cmd)
3274 {
3275 clickable_images = (BOOLEAN) !clickable_images;
3276
3277 HTUserMsg(clickable_images ?
3278 CLICKABLE_IMAGES_ON : CLICKABLE_IMAGES_OFF);
3279 return reparse_or_reload(cmd);
3280 }
3281
handle_LYK_INDEX(int * old_c,int real_c)3282 static void handle_LYK_INDEX(int *old_c,
3283 int real_c)
3284 {
3285 /*
3286 * Make sure we are not in the index already.
3287 */
3288 if (!STREQ(curdoc.address, indexfile)) {
3289
3290 if (indexfile[0] == '\0') { /* no defined index */
3291 if (*old_c != real_c) {
3292 *old_c = real_c;
3293 HTUserMsg(NO_INDEX_FILE);
3294 }
3295
3296 } else {
3297 #ifdef KANJI_CODE_OVERRIDE
3298 if (HTCJK == JAPANESE) {
3299 last_kcode = NOKANJI; /* AUTO */
3300 }
3301 #endif
3302 #ifdef USE_PROGRAM_DIR
3303 if (is_url(indexfile) == 0) {
3304 char *tmp = NULL;
3305
3306 HTSprintf0(&tmp, "%s\\%s", program_dir, indexfile);
3307 FREE(indexfile);
3308 LYLocalFileToURL(&indexfile, tmp);
3309 FREE(tmp);
3310 }
3311 #endif
3312 set_address(&newdoc, indexfile);
3313 StrAllocCopy(newdoc.title, gettext("System Index")); /* name it */
3314 LYFreePostData(&newdoc);
3315 FREE(newdoc.bookmark);
3316 newdoc.isHEAD = FALSE;
3317 newdoc.safe = FALSE;
3318 newdoc.internal_link = FALSE;
3319 } /* end else */
3320 } /* end if */
3321 }
3322
handle_LYK_INDEX_SEARCH(BOOLEAN * force_load,int ForcePush,int * old_c,int real_c)3323 static void handle_LYK_INDEX_SEARCH(BOOLEAN *force_load,
3324 int ForcePush,
3325 int *old_c,
3326 int real_c)
3327 {
3328 if (is_www_index) {
3329 /*
3330 * Perform a database search.
3331 *
3332 * do_www_search will try to go out and get the document. If it
3333 * returns TRUE, a new document was returned and is named in the
3334 * newdoc.address.
3335 */
3336 newdoc.isHEAD = FALSE;
3337 newdoc.safe = FALSE;
3338 if (do_www_search(&newdoc) == NORMAL) {
3339 /*
3340 * Yah, the search succeeded.
3341 */
3342 if (TRACE && !LYUseTraceLog && LYCursesON) {
3343 /*
3344 * Make sure cursor is down.
3345 */
3346 LYHideCursor();
3347 #ifdef USE_SLANG
3348 LYaddstr("\n");
3349 #endif /* USE_SLANG */
3350 LYrefresh();
3351 }
3352 LYpush(&curdoc, ForcePush);
3353 /*
3354 * Make the curdoc.address the newdoc.address so that getfile
3355 * doesn't try to get the newdoc.address. Since we have already
3356 * gotten it.
3357 */
3358 copy_address(&curdoc, &newdoc);
3359 BStrCopy(newdoc.post_data, curdoc.post_data);
3360 StrAllocCopy(newdoc.post_content_type, curdoc.post_content_type);
3361 newdoc.internal_link = FALSE;
3362 curdoc.line = -1;
3363 LYSetNewline(0);
3364 } else if (use_this_url_instead != NULL) {
3365 /*
3366 * Got back a redirecting URL. Check it out.
3367 */
3368 HTUserMsg2(WWW_USING_MESSAGE, use_this_url_instead);
3369
3370 /*
3371 * Make a name for this URL.
3372 */
3373 StrAllocCopy(newdoc.title,
3374 "A URL specified by redirection");
3375 set_address(&newdoc, use_this_url_instead);
3376 LYFreePostData(&newdoc);
3377 FREE(newdoc.bookmark);
3378 newdoc.isHEAD = FALSE;
3379 newdoc.safe = FALSE;
3380 newdoc.internal_link = FALSE;
3381 FREE(use_this_url_instead);
3382 *force_load = TRUE;
3383 } else {
3384 /*
3385 * Yuk, the search failed. Restore the old file.
3386 */
3387 copy_address(&newdoc, &curdoc);
3388 BStrCopy(newdoc.post_data, curdoc.post_data);
3389 StrAllocCopy(newdoc.post_content_type,
3390 curdoc.post_content_type);
3391 StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
3392 newdoc.isHEAD = curdoc.isHEAD;
3393 newdoc.safe = curdoc.safe;
3394 newdoc.internal_link = curdoc.internal_link;
3395 }
3396 } else if (*old_c != real_c) {
3397 *old_c = real_c;
3398 HTUserMsg(NOT_ISINDEX);
3399 }
3400 }
3401
handle_LYK_INFO(int * cmd)3402 static BOOLEAN handle_LYK_INFO(int *cmd)
3403 {
3404 /*
3405 * Don't do if already viewing info page.
3406 */
3407 if (!LYIsUIPage(curdoc.address, UIP_SHOWINFO)) {
3408 if (do_change_link() != -1
3409 && LYShowInfo(&curdoc, &newdoc, owner_address) >= 0) {
3410 LYRegisterUIPage(newdoc.address, UIP_SHOWINFO);
3411 StrAllocCopy(newdoc.title, SHOWINFO_TITLE);
3412 LYFreePostData(&newdoc);
3413 FREE(newdoc.bookmark);
3414 newdoc.isHEAD = FALSE;
3415 newdoc.safe = FALSE;
3416 newdoc.internal_link = FALSE;
3417 LYforce_no_cache = TRUE;
3418 if (LYValidate || check_realm)
3419 LYPermitURL = TRUE;
3420 }
3421 } else {
3422 /*
3423 * If already in info page, get out.
3424 */
3425 *cmd = LYK_PREV_DOC;
3426 return TRUE;
3427 }
3428 return FALSE;
3429 }
3430
handle_LYK_INLINE_TOGGLE(int * cmd)3431 static BOOLEAN handle_LYK_INLINE_TOGGLE(int *cmd)
3432 {
3433 pseudo_inline_alts = (BOOLEAN) !pseudo_inline_alts;
3434
3435 HTUserMsg(pseudo_inline_alts ?
3436 PSEUDO_INLINE_ALTS_ON : PSEUDO_INLINE_ALTS_OFF);
3437 return reparse_or_reload(cmd);
3438 }
3439
handle_LYK_INSERT_FILE(BOOLEAN * refresh_screen,int * old_c,int real_c)3440 static void handle_LYK_INSERT_FILE(BOOLEAN *refresh_screen,
3441 int *old_c,
3442 int real_c)
3443 {
3444 /*
3445 * See if the current link is in a form TEXTAREA.
3446 */
3447 if (LinkIsTextarea(curdoc.link)) {
3448
3449 /*
3450 * Reject attempts to use this for gaining access to local files when
3451 * such access is restricted: if no_file_url was set via the file_url
3452 * restriction, if no_goto_file was set for the anonymous account, or
3453 * if HTDirAccess was set to HT_DIR_FORBID or HT_DIR_SELECTIVE via the
3454 * -nobrowse or -selective switches, it is assumed that inserting files
3455 * or checking for existence of files needs to be denied. - kw
3456 */
3457 if (no_file_url || no_goto_file ||
3458 HTDirAccess == HT_DIR_FORBID ||
3459 HTDirAccess == HT_DIR_SELECTIVE) {
3460 if (*old_c != real_c) {
3461 *old_c = real_c;
3462 if (no_goto_file)
3463 HTUserMsg2(GOTO_XXXX_DISALLOWED, STR_FILE_URL);
3464 else
3465 HTUserMsg(NOAUTH_TO_ACCESS_FILES);
3466 HTInfoMsg(FILE_INSERT_CANCELLED);
3467 }
3468 return;
3469 }
3470
3471 (void) HText_InsertFile(&links[curdoc.link]);
3472
3473 /*
3474 * TODO:
3475 * Move cursor "n" lines from the current line to position it on the
3476 * 1st line following the text that was inserted. If the target
3477 * line/anchor requires us to scroll up/down, position the target in
3478 * the approximate center of the screen.
3479 *
3480 * [Current behavior leaves cursor on the same line relative to the
3481 * start of the TEXTAREA that it was on before the insertion. This is
3482 * the same behavior that occurs with (my) editor, so this TODO will
3483 * stay unimplemented.]
3484 */
3485
3486 *refresh_screen = TRUE;
3487
3488 } else {
3489
3490 HTInfoMsg(NOT_IN_TEXTAREA);
3491 }
3492 }
3493
3494 #if defined(DIRED_SUPPORT) && defined(OK_INSTALL)
handle_LYK_INSTALL(void)3495 static void handle_LYK_INSTALL(void)
3496 {
3497 if (lynx_edit_mode && nlinks > 0 && !no_dired_support)
3498 local_install(NULL, links[curdoc.link].lname, &newdoc.address);
3499 }
3500 #endif
3501
3502 static const char *hexy = "0123456789ABCDEF";
3503
3504 #define HEX(n) hexy[(n) & 0xf]
3505 /*
3506 * URL-encode a parameter which can then be appended to a URI.
3507 * RFC-3986 lists reserved characters, which should be encoded.
3508 */
urlencode(char * str)3509 static char *urlencode(char *str)
3510 {
3511 char *result = NULL;
3512 char *ptr;
3513 int ch;
3514
3515 if (str != NULL) {
3516 result = malloc(strlen(str) * 3 + 1);
3517 ptr = result;
3518
3519 assert(result);
3520
3521 while ((ch = UCH(*str++)) != 0) {
3522 if (ch == ' ') {
3523 *ptr = '+';
3524 ptr++;
3525 } else if (ch > 127 ||
3526 strchr(":/?#[]@!$&'()*+,;=", ch) != 0) {
3527 *ptr++ = '%';
3528 *ptr++ = HEX(ch >> 4);
3529 *ptr++ = HEX(ch);
3530 } else {
3531 *ptr++ = (char) ch;
3532 }
3533 }
3534 *ptr = '\0';
3535 }
3536
3537 return result;
3538 }
3539
3540 /*
3541 * Fill in "%s" marker(s) in the url_template by prompting the user for the
3542 * values.
3543 */
check_JUMP_param(char ** url_template)3544 static BOOLEAN check_JUMP_param(char **url_template)
3545 {
3546 int param = 1;
3547 char *subs;
3548 char *result = *url_template;
3549 char *encoded = NULL;
3550 int code = TRUE;
3551 bstring *input = NULL;
3552
3553 CTRACE((tfp, "check_JUMP_param: %s\n", result));
3554
3555 while ((subs = strstr(result, "%s")) != 0) {
3556 char prompt[MAX_LINE];
3557 RecallType recall = NORECALL;
3558
3559 CTRACE((tfp, "Prompt for query param%d: %s\n", param, result));
3560
3561 sprintf(prompt, gettext("Query parameter %d: "), param++);
3562 statusline(prompt);
3563 BStrCopy0(input, "");
3564
3565 if (encoded)
3566 FREE(encoded);
3567
3568 if (LYgetBString(&input, VISIBLE, 0, recall) < 0) {
3569 /*
3570 * cancelled via ^G
3571 */
3572 HTInfoMsg(CANCELLED);
3573 code = FALSE;
3574 break;
3575 } else if ((encoded = urlencode(input->str)) != '\0') {
3576 int subs_at = (int) (subs - result);
3577 int fill_in = (int) strlen(encoded) - 2;
3578 size_t have = strlen(result);
3579 size_t want = strlen(encoded) + have - 1;
3580 int n;
3581 char *update = realloc(result, want + 1);
3582
3583 if (update == 0) {
3584 HTInfoMsg(NOT_ENOUGH_MEMORY);
3585 code = FALSE;
3586 break;
3587 }
3588
3589 CTRACE((tfp, " reply: %s\n", input->str));
3590 CTRACE((tfp, " coded: %s\n", encoded));
3591
3592 result = update;
3593 result[want] = '\0';
3594 for (n = (int) want; (n - fill_in) >= subs_at; --n) {
3595 result[n] = result[n - fill_in];
3596 }
3597 for (n = subs_at; encoded[n - subs_at] != '\0'; ++n) {
3598 result[n] = encoded[n - subs_at];
3599 }
3600 CTRACE((tfp, " subst: %s\n", result));
3601 } else {
3602 HTInfoMsg(CANCELLED);
3603 code = FALSE;
3604 break;
3605 }
3606 }
3607 BStrFree(input);
3608 FREE(encoded);
3609 *url_template = result;
3610 return (BOOLEAN) code;
3611 }
3612
fill_JUMP_Params(char ** addressp)3613 static void fill_JUMP_Params(char **addressp)
3614 {
3615 if (LYJumpFileURL) {
3616 check_JUMP_param(addressp);
3617 }
3618 }
3619
handle_LYK_JUMP(int c,bstring ** user_input,char ** old_user_input GCC_UNUSED,RecallType * recall GCC_UNUSED,BOOLEAN * FirstURLRecall GCC_UNUSED,int * URLNum GCC_UNUSED,int * URLTotal GCC_UNUSED,int * ch GCC_UNUSED,int * old_c,int real_c)3620 static BOOLEAN handle_LYK_JUMP(int c,
3621 bstring **user_input,
3622 char **old_user_input GCC_UNUSED,
3623 RecallType * recall GCC_UNUSED,
3624 BOOLEAN *FirstURLRecall GCC_UNUSED,
3625 int *URLNum GCC_UNUSED,
3626 int *URLTotal GCC_UNUSED,
3627 int *ch GCC_UNUSED,
3628 int *old_c,
3629 int real_c)
3630 {
3631 char *ret;
3632
3633 if (no_jump || JThead == NULL) {
3634 if (*old_c != real_c) {
3635 *old_c = real_c;
3636 if (no_jump)
3637 HTUserMsg(JUMP_DISALLOWED);
3638 else
3639 HTUserMsg(NO_JUMPFILE);
3640 }
3641 } else {
3642 LYJumpFileURL = TRUE;
3643 if ((ret = LYJump(c)) != NULL) {
3644 #ifdef PERMIT_GOTO_FROM_JUMP
3645 if (!strncasecomp(ret, "Go ", 3)) {
3646 LYJumpFileURL = FALSE;
3647 StrAllocCopy(*old_user_input, (*user_input)->str);
3648 *URLTotal = (Goto_URLs ? HTList_count(Goto_URLs) : 0);
3649 *recall = ((*URLTotal >= 1) ? RECALL_URL : NORECALL);
3650 *URLNum = *URLTotal;
3651 *FirstURLRecall = TRUE;
3652 if (!strcasecomp(ret, "Go :")) {
3653 if (recall) {
3654 *ch = UPARROW;
3655 return TRUE;
3656 }
3657 FREE(*old_user_input);
3658 HTUserMsg(NO_RANDOM_URLS_YET);
3659 return FALSE;
3660 }
3661 ret = HTParse((ret + 3), startfile, PARSE_ALL);
3662 BStrCopy0((*user_input), ret);
3663 FREE(ret);
3664 return TRUE;
3665 }
3666 #endif /* PERMIT_GOTO_FROM_JUMP */
3667 ret = HTParse(ret, startfile, PARSE_ALL);
3668 if (!LYTrimStartfile(ret)) {
3669 LYRemoveBlanks((*user_input)->str);
3670 }
3671 if (check_JUMP_param(&ret)) {
3672 set_address(&newdoc, ret);
3673 StrAllocCopy(lynxjumpfile, ret);
3674 LYFreePostData(&newdoc);
3675 FREE(newdoc.bookmark);
3676 newdoc.isHEAD = FALSE;
3677 newdoc.safe = FALSE;
3678 newdoc.internal_link = FALSE;
3679 LYUserSpecifiedURL = TRUE;
3680 }
3681 FREE(ret);
3682 } else {
3683 LYJumpFileURL = FALSE;
3684 }
3685 }
3686 return FALSE;
3687 }
3688
handle_LYK_KEYMAP(BOOLEAN * vi_keys_flag,BOOLEAN * emacs_keys_flag,int * old_c,int real_c)3689 static void handle_LYK_KEYMAP(BOOLEAN *vi_keys_flag,
3690 BOOLEAN *emacs_keys_flag,
3691 int *old_c,
3692 int real_c)
3693 {
3694 if (*old_c != real_c) {
3695 *old_c = real_c;
3696 set_address(&newdoc, STR_LYNXKEYMAP);
3697 StrAllocCopy(newdoc.title, CURRENT_KEYMAP_TITLE);
3698 LYFreePostData(&newdoc);
3699 FREE(newdoc.bookmark);
3700 newdoc.isHEAD = FALSE;
3701 newdoc.safe = FALSE;
3702 newdoc.internal_link = FALSE;
3703 /*
3704 * If vi_keys changed, the keymap did too, so force no cache, and reset
3705 * the flag. - FM
3706 */
3707 if (*vi_keys_flag != vi_keys ||
3708 *emacs_keys_flag != emacs_keys) {
3709 LYforce_no_cache = TRUE;
3710 *vi_keys_flag = vi_keys;
3711 *emacs_keys_flag = emacs_keys;
3712 }
3713 #if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
3714 /*
3715 * Remember whether we are in dired menu so we can display the right
3716 * keymap.
3717 */
3718 if (!no_dired_support) {
3719 prev_lynx_edit_mode = lynx_edit_mode;
3720 }
3721 #endif /* DIRED_SUPPORT && OK_OVERRIDE */
3722 LYforce_no_cache = TRUE;
3723 }
3724 }
3725
handle_LYK_LAST_LINK(void)3726 static void handle_LYK_LAST_LINK(void)
3727 {
3728 int i = curdoc.link;
3729
3730 for (;;) {
3731 if (++i >= nlinks
3732 || links[i].ly != links[curdoc.link].ly) {
3733 set_curdoc_link(i - 1);
3734 break;
3735 }
3736 }
3737 }
3738
handle_LYK_LEFT_LINK(void)3739 static void handle_LYK_LEFT_LINK(void)
3740 {
3741 if (curdoc.link > 0 &&
3742 links[curdoc.link].ly == links[curdoc.link - 1].ly) {
3743 set_curdoc_link(curdoc.link - 1);
3744 }
3745 }
3746
handle_LYK_LIST(int * cmd)3747 static BOOLEAN handle_LYK_LIST(int *cmd)
3748 {
3749 /*
3750 * Don't do if already viewing list page.
3751 */
3752 if (!strcmp(NonNull(curdoc.title), LIST_PAGE_TITLE) &&
3753 LYIsUIPage(curdoc.address, UIP_LIST_PAGE)) {
3754 /*
3755 * Already viewing list page, so get out.
3756 */
3757 *cmd = LYK_PREV_DOC;
3758 return TRUE;
3759 }
3760
3761 /*
3762 * Print list page to file.
3763 */
3764 if (showlist(&newdoc, TRUE) < 0)
3765 return FALSE;
3766 StrAllocCopy(newdoc.title, LIST_PAGE_TITLE);
3767 /*
3768 * showlist will set newdoc's other fields. It may leave post_data intact
3769 * so the list can be used to follow internal links in the current document
3770 * even if it is a POST response. - kw
3771 */
3772
3773 if (LYValidate || check_realm) {
3774 LYPermitURL = TRUE;
3775 StrAllocCopy(lynxlistfile, newdoc.address);
3776 }
3777 return FALSE;
3778 }
3779
handle_LYK_MAIN_MENU(int * old_c,int real_c)3780 static void handle_LYK_MAIN_MENU(int *old_c,
3781 int real_c)
3782 {
3783 /*
3784 * If its already the homepage then don't reload it.
3785 */
3786 if (!STREQ(curdoc.address, homepage)) {
3787
3788 if (HTConfirmDefault(CONFIRM_MAIN_SCREEN, NO) == YES) {
3789 set_address(&newdoc, homepage);
3790 StrAllocCopy(newdoc.title, gettext("Entry into main screen"));
3791 LYFreePostData(&newdoc);
3792 FREE(newdoc.bookmark);
3793 newdoc.isHEAD = FALSE;
3794 newdoc.safe = FALSE;
3795 newdoc.internal_link = FALSE;
3796 LYhighlight(FALSE, curdoc.link, prev_target->str);
3797 #ifdef DIRED_SUPPORT
3798 if (lynx_edit_mode) {
3799 DIRED_UNCACHE_2;
3800 }
3801 #endif /* DIRED_SUPPORT */
3802 }
3803 } else {
3804 if (*old_c != real_c) {
3805 *old_c = real_c;
3806 HTUserMsg(IN_MAIN_SCREEN);
3807 }
3808 }
3809 }
3810
handle_LYK_MINIMAL(void)3811 static void handle_LYK_MINIMAL(void)
3812 {
3813 if (!historical_comments) {
3814 #ifdef USE_SOURCE_CACHE
3815 if (!HTcan_reparse_document()) {
3816 #endif
3817 /*
3818 * Check if this is a reply from a POST, and if so, seek
3819 * confirmation of reload if the safe element is not set. - FM
3820 */
3821 if ((curdoc.post_data != NULL &&
3822 curdoc.safe != TRUE) &&
3823 confirm_post_resub(curdoc.address, NULL, 0, 0) == FALSE) {
3824 HTInfoMsg(WILL_NOT_RELOAD_DOC);
3825 } else {
3826 HText_setNoCache(HTMainText);
3827 move_address(&newdoc, &curdoc);
3828 newdoc.line = curdoc.line;
3829 newdoc.link = curdoc.link;
3830 }
3831 #ifdef USE_SOURCE_CACHE
3832 } /* end if no bypass */
3833 #endif
3834 }
3835 minimal_comments = (BOOLEAN) !minimal_comments;
3836 if (!historical_comments) {
3837 HTAlert(minimal_comments ?
3838 MINIMAL_ON_IN_EFFECT : MINIMAL_OFF_VALID_ON);
3839 } else {
3840 HTAlert(minimal_comments ?
3841 MINIMAL_ON_BUT_HISTORICAL : MINIMAL_OFF_HISTORICAL_ON);
3842 }
3843 #ifdef USE_SOURCE_CACHE
3844 (void) reparse_document();
3845 #endif
3846 return;
3847 }
3848
3849 #if defined(DIRED_SUPPORT)
handle_LYK_MODIFY(BOOLEAN * refresh_screen)3850 static void handle_LYK_MODIFY(BOOLEAN *refresh_screen)
3851 {
3852 if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
3853 int ret;
3854
3855 ret = local_modify(&curdoc, &newdoc.address);
3856 if (ret == PERMIT_FORM_RESULT) { /* Permit form thrown up */
3857 *refresh_screen = TRUE;
3858 } else if (ret) {
3859 DIRED_UNCACHE_1;
3860 move_address(&newdoc, &curdoc);
3861 LYFreePostData(&newdoc);
3862 FREE(newdoc.bookmark);
3863 newdoc.isHEAD = FALSE;
3864 newdoc.safe = FALSE;
3865 newdoc.internal_link = FALSE;
3866 newdoc.line = curdoc.line;
3867 newdoc.link = curdoc.link;
3868 LYclear();
3869 }
3870 }
3871 }
3872 #endif /* DIRED_SUPPORT */
3873
3874 #ifdef EXP_NESTED_TABLES
handle_LYK_NESTED_TABLES(int * cmd)3875 static BOOLEAN handle_LYK_NESTED_TABLES(int *cmd)
3876 {
3877 nested_tables = (BOOLEAN) !nested_tables;
3878 HTUserMsg(nested_tables ? NESTED_TABLES_ON : NESTED_TABLES_OFF);
3879 return reparse_or_reload(cmd);
3880 }
3881 #endif
3882
handle_LYK_OPTIONS(int * cmd,BOOLEAN * refresh_screen)3883 static BOOLEAN handle_LYK_OPTIONS(int *cmd,
3884 BOOLEAN *refresh_screen)
3885 {
3886 #ifndef NO_OPTION_MENU
3887 if (!LYUseFormsOptions) {
3888 BOOLEAN LYUseDefaultRawMode_flag = LYUseDefaultRawMode;
3889 BOOLEAN LYSelectPopups_flag = LYSelectPopups;
3890 BOOLEAN verbose_img_flag = verbose_img;
3891 BOOLEAN keypad_mode_flag = (BOOL) keypad_mode;
3892 BOOLEAN show_dotfiles_flag = show_dotfiles;
3893 BOOLEAN user_mode_flag = (BOOL) user_mode;
3894 int CurrentAssumeCharSet_flag = UCLYhndl_for_unspec;
3895 int CurrentCharSet_flag = current_char_set;
3896 int HTfileSortMethod_flag = HTfileSortMethod;
3897 char *CurrentUserAgent = NULL;
3898 char *CurrentNegoLanguage = NULL;
3899 char *CurrentNegoCharset = NULL;
3900
3901 StrAllocCopy(CurrentUserAgent, NonNull(LYUserAgent));
3902 StrAllocCopy(CurrentNegoLanguage, NonNull(language));
3903 StrAllocCopy(CurrentNegoCharset, NonNull(pref_charset));
3904
3905 LYoptions(); /** do the old-style options stuff **/
3906
3907 if (keypad_mode_flag != keypad_mode ||
3908 (user_mode_flag != user_mode &&
3909 (user_mode_flag == NOVICE_MODE ||
3910 user_mode == NOVICE_MODE)) ||
3911 (((HTfileSortMethod_flag != HTfileSortMethod) ||
3912 (show_dotfiles_flag != show_dotfiles)) &&
3913 (isFILE_URL(curdoc.address) ||
3914 isFTP_URL(curdoc.address))) ||
3915 CurrentCharSet_flag != current_char_set ||
3916 CurrentAssumeCharSet_flag != UCLYhndl_for_unspec ||
3917 verbose_img_flag != verbose_img ||
3918 LYUseDefaultRawMode_flag != LYUseDefaultRawMode ||
3919 LYSelectPopups_flag != LYSelectPopups ||
3920 ((strcmp(CurrentUserAgent, NonNull(LYUserAgent)) ||
3921 strcmp(CurrentNegoLanguage, NonNull(language)) ||
3922 strcmp(CurrentNegoCharset, NonNull(pref_charset))) &&
3923 (!StrNCmp(curdoc.address, "http", 4) ||
3924 isLYNXCGI(curdoc.address)))) {
3925
3926 BOOLEAN canreparse_post = FALSE;
3927
3928 /*
3929 * Check if this is a reply from a POST, and if so, seek
3930 * confirmation of reload if the safe element is not set. - FM
3931 */
3932 if ((curdoc.post_data != NULL &&
3933 curdoc.safe != TRUE) &&
3934 #ifdef USE_SOURCE_CACHE
3935 (!(canreparse_post = HTcan_reparse_document())) &&
3936 #endif
3937 confirm_post_resub(curdoc.address, curdoc.title,
3938 2, 1) == FALSE) {
3939 HTInfoMsg(WILL_NOT_RELOAD_DOC);
3940 } else {
3941 copy_address(&newdoc, &curdoc);
3942 if (((strcmp(CurrentUserAgent, NonNull(LYUserAgent)) ||
3943 strcmp(CurrentNegoLanguage, NonNull(language)) ||
3944 strcmp(CurrentNegoCharset, NonNull(pref_charset))) &&
3945 (StrNCmp(curdoc.address, "http", 4) == 0 ||
3946 !isLYNXCGI(curdoc.address) == 0))) {
3947 /*
3948 * An option has changed which may influence content
3949 * negotiation, and the resource is from a http or https or
3950 * lynxcgi URL (the only protocols which currently do
3951 * anything with this information). Set reloading = TRUE
3952 * so that proxy caches will be flushed, which is necessary
3953 * until the time when all proxies understand HTTP 1.1
3954 * Vary: and all Servers properly use it... Treat like
3955 * case LYK_RELOAD (see comments there). - KW
3956 */
3957 reloading = TRUE;
3958 }
3959 if (HTisDocumentSource()) {
3960 srcmode_for_next_retrieval(1);
3961 }
3962 #ifdef USE_SOURCE_CACHE
3963 if (reloading == FALSE) {
3964 /* one more attempt to be smart enough: */
3965 if (reparse_document()) {
3966 FREE(CurrentUserAgent);
3967 FREE(CurrentNegoLanguage);
3968 FREE(CurrentNegoCharset);
3969 return FALSE;
3970 }
3971 }
3972 #endif
3973 if (canreparse_post &&
3974 confirm_post_resub(curdoc.address, curdoc.title,
3975 2, 1) == FALSE) {
3976 if (HTisDocumentSource()) {
3977 srcmode_for_next_retrieval(0);
3978 }
3979 FREE(CurrentUserAgent);
3980 FREE(CurrentNegoLanguage);
3981 FREE(CurrentNegoCharset);
3982 return FALSE;
3983 }
3984
3985 HEAD_request = HTLoadedDocumentIsHEAD();
3986 HText_setNoCache(HTMainText);
3987 newdoc.line = curdoc.line;
3988 newdoc.link = curdoc.link;
3989 LYforce_no_cache = TRUE;
3990 free_address(&curdoc); /* So it doesn't get pushed. */
3991 }
3992 }
3993 FREE(CurrentUserAgent);
3994 FREE(CurrentNegoLanguage);
3995 FREE(CurrentNegoCharset);
3996 *refresh_screen = TRUE; /* to repaint screen */
3997 return FALSE;
3998 } /* end if !LYUseFormsOptions */
3999 #endif /* !NO_OPTION_MENU */
4000 #ifndef NO_OPTION_FORMS
4001 /*
4002 * Generally stolen from LYK_COOKIE_JAR. Options menu handling is
4003 * done in postoptions(), called from getfile() currently.
4004 *
4005 * postoptions() is also responsible for reloading the document
4006 * before the 'options menu' but only when (a few) important
4007 * options were changed.
4008 *
4009 * It is critical that post_data is freed here since the
4010 * submission of changed options is done via the same protocol as
4011 * LYNXOPTIONS:
4012 */
4013 /*
4014 * Don't do if already viewing options page.
4015 */
4016 if (!LYIsUIPage(curdoc.address, UIP_OPTIONS_MENU)) {
4017
4018 set_address(&newdoc, LYNXOPTIONS_PAGE("/"));
4019 LYFreePostData(&newdoc);
4020 FREE(newdoc.bookmark);
4021 newdoc.isHEAD = FALSE;
4022 newdoc.safe = FALSE;
4023 newdoc.internal_link = FALSE;
4024 LYforce_no_cache = TRUE;
4025 /* change to 'if (check_realm && !LYValidate)' and
4026 make change near top of getfile to forbid
4027 using forms options menu with -validate: - kw */
4028 if (LYValidate || check_realm) {
4029 LYPermitURL = TRUE;
4030 }
4031 } else {
4032 /*
4033 * If already in the options menu, get out.
4034 */
4035 *cmd = LYK_PREV_DOC;
4036 return TRUE;
4037 }
4038 #endif /* !NO_OPTION_FORMS */
4039 return FALSE;
4040 }
4041
handle_NEXT_DOC(void)4042 static void handle_NEXT_DOC(void)
4043 {
4044 if (LYhist_next(&curdoc, &newdoc)) {
4045 free_address(&curdoc); /* avoid push */
4046 return;
4047 }
4048 HTUserMsg(gettext("No next document present"));
4049 }
4050
handle_LYK_NEXT_LINK(int c,int * old_c,int real_c)4051 static void handle_LYK_NEXT_LINK(int c,
4052 int *old_c,
4053 int real_c)
4054 {
4055 if (curdoc.link < nlinks - 1) { /* next link */
4056 LYhighlight(FALSE, curdoc.link, prev_target->str);
4057 #ifdef FASTTAB
4058 /*
4059 * Move to different textarea if TAB in textarea.
4060 */
4061 if (LinkIsTextarea(curdoc.link) &&
4062 c == '\t') {
4063 int thisgroup = links[curdoc.link].l_form->number;
4064 char *thisname = links[curdoc.link].l_form->name;
4065
4066 do
4067 curdoc.link++;
4068 while ((curdoc.link < nlinks - 1) &&
4069 LinkIsTextarea(curdoc.link) &&
4070 links[curdoc.link].l_form->number == thisgroup &&
4071 sametext(links[curdoc.link].l_form->name, thisname));
4072 } else {
4073 curdoc.link++;
4074 }
4075 #else
4076 curdoc.link++;
4077 #endif /* FASTTAB */
4078 /*
4079 * At the bottom of list and there is only one page. Move to the top
4080 * link on the page.
4081 */
4082 } else if (!more_text && LYGetNewline() == 1 && curdoc.link == nlinks - 1) {
4083 set_curdoc_link(0);
4084
4085 } else if (more_text) { /* next page */
4086 LYChgNewline(display_lines);
4087 } else if (*old_c != real_c) {
4088 *old_c = real_c;
4089 HTInfoMsg(ALREADY_AT_END);
4090 }
4091 }
4092
handle_LYK_NEXT_PAGE(int * old_c,int real_c)4093 static void handle_LYK_NEXT_PAGE(int *old_c,
4094 int real_c)
4095 {
4096 if (more_text) {
4097 LYChgNewline(display_lines);
4098 } else if (curdoc.link < nlinks - 1) {
4099 set_curdoc_link(nlinks - 1);
4100 } else if (*old_c != real_c) {
4101 *old_c = real_c;
4102 HTInfoMsg(ALREADY_AT_END);
4103 }
4104 }
4105
handle_LYK_NOCACHE(int * old_c,int real_c)4106 static BOOLEAN handle_LYK_NOCACHE(int *old_c,
4107 int real_c)
4108 {
4109 if (nlinks > 0) {
4110 if (links[curdoc.link].type == WWW_FORM_LINK_TYPE &&
4111 links[curdoc.link].l_form->type != F_SUBMIT_TYPE &&
4112 links[curdoc.link].l_form->type != F_IMAGE_SUBMIT_TYPE &&
4113 links[curdoc.link].l_form->type != F_TEXT_SUBMIT_TYPE) {
4114 if (*old_c != real_c) {
4115 *old_c = real_c;
4116 HTUserMsg(NOT_ON_SUBMIT_OR_LINK);
4117 }
4118 return FALSE;
4119 } else {
4120 LYforce_no_cache = TRUE;
4121 reloading = TRUE;
4122 }
4123 }
4124 return TRUE;
4125 }
4126
handle_LYK_PREV_LINK(int * arrowup,int * old_c,int real_c)4127 static void handle_LYK_PREV_LINK(int *arrowup,
4128 int *old_c,
4129 int real_c)
4130 {
4131 if (curdoc.link > 0) { /* previous link */
4132 set_curdoc_link(curdoc.link - 1);
4133
4134 } else if (!more_text &&
4135 curdoc.link == 0 && LYGetNewline() == 1) { /* at the top of list */
4136 /*
4137 * If there is only one page of data and the user goes off the top,
4138 * just move the cursor to last link on the page.
4139 */
4140 set_curdoc_link(nlinks - 1);
4141
4142 } else if (curdoc.line > 1) { /* previous page */
4143 /*
4144 * Go back to the previous page.
4145 */
4146 int scrollamount = (LYGetNewline() > display_lines
4147 ? display_lines
4148 : LYGetNewline() - 1);
4149
4150 LYChgNewline(-scrollamount);
4151 if (scrollamount < display_lines &&
4152 nlinks > 0 && curdoc.link == 0 &&
4153 links[0].ly - 1 + scrollamount <= display_lines) {
4154 newdoc.link = HText_LinksInLines(HTMainText,
4155 1,
4156 scrollamount) - 1;
4157 } else {
4158 *arrowup = TRUE;
4159 }
4160
4161 } else if (*old_c != real_c) {
4162 *old_c = real_c;
4163 HTInfoMsg(ALREADY_AT_BEGIN);
4164 }
4165 }
4166
4167 #define nhist_1 (nhist - 1) /* workaround for indent */
4168
handle_PREV_DOC(int * cmd,int * old_c,int real_c)4169 static int handle_PREV_DOC(int *cmd,
4170 int *old_c,
4171 int real_c)
4172 {
4173 if (nhist > 0) { /* if there is anything to go back to */
4174 /*
4175 * Check if the previous document is a reply from a POST, and if so,
4176 * seek confirmation of resubmission if the safe element is not set and
4177 * the document is not still in the cache or LYresubmit_posts is set.
4178 * If not confirmed and it is not the startfile, pop it so we go to the
4179 * yet previous document, until we're OK or reach the startfile. If we
4180 * reach the startfile and its not OK or we don't get confirmation,
4181 * cancel. - FM
4182 */
4183 DocAddress WWWDoc;
4184 HTParentAnchor *tmpanchor;
4185 BOOLEAN conf = FALSE, first = TRUE;
4186
4187 HTLastConfirmCancelled(); /* reset flag */
4188 while (nhist > 0) {
4189 conf = FALSE;
4190 if (HDOC(nhist_1).post_data == NULL) {
4191 break;
4192 }
4193 WWWDoc.address = HDOC(nhist_1).address;
4194 WWWDoc.post_data = HDOC(nhist_1).post_data;
4195 WWWDoc.post_content_type =
4196 HDOC(nhist_1).post_content_type;
4197 WWWDoc.bookmark = HDOC(nhist_1).bookmark;
4198 WWWDoc.isHEAD = HDOC(nhist_1).isHEAD;
4199 WWWDoc.safe = HDOC(nhist_1).safe;
4200 tmpanchor = HTAnchor_findAddress(&WWWDoc);
4201 if (HTAnchor_safe(tmpanchor)) {
4202 break;
4203 }
4204 if ((HTAnchor_document(tmpanchor) == NULL &&
4205 (isLYNXIMGMAP(WWWDoc.address) ||
4206 (conf = confirm_post_resub(WWWDoc.address,
4207 HDOC(nhist_1).title,
4208 0, 0))
4209 == FALSE)) ||
4210 ((LYresubmit_posts && !conf &&
4211 (NONINTERNAL_OR_PHYS_DIFFERENT((DocInfo *) &history[(nhist_1)],
4212 &curdoc) ||
4213 NONINTERNAL_OR_PHYS_DIFFERENT((DocInfo *) &history[(nhist_1)],
4214 &newdoc))) &&
4215 !confirm_post_resub(WWWDoc.address,
4216 HDOC(nhist_1).title,
4217 2, 2))) {
4218 if (HTLastConfirmCancelled()) {
4219 if (!first && curdoc.internal_link)
4220 free_address(&curdoc);
4221 *cmd = LYK_DO_NOTHING;
4222 return 2;
4223 }
4224 if (nhist == 1) {
4225 HTInfoMsg(CANCELLED);
4226 *old_c = 0;
4227 *cmd = LYK_DO_NOTHING;
4228 return 2;
4229 } else {
4230 HTUserMsg2(WWW_SKIP_MESSAGE, WWWDoc.address);
4231 do { /* Should be LYhist_prev when _next supports */
4232 LYpop(&curdoc); /* skipping of forms */
4233 } while (nhist > 1
4234 && !are_different((DocInfo *) &history[nhist_1],
4235 &curdoc));
4236 first = FALSE; /* have popped at least one */
4237 continue;
4238 }
4239 } else {
4240 /*
4241 * Break from loop; if user just confirmed to load again
4242 * because document wasn't in cache, set LYforce_no_cache to
4243 * avoid unnecessary repeat question down the road. - kw
4244 */
4245 if (conf)
4246 LYforce_no_cache = TRUE;
4247 break;
4248 }
4249 }
4250
4251 if (!first)
4252 curdoc.internal_link = FALSE;
4253
4254 /*
4255 * Set newdoc.address to empty to pop a file.
4256 */
4257 LYhist_prev_register(&curdoc); /* Why not call _prev instead of zeroing address? */
4258 free_address(&newdoc);
4259 #ifdef DIRED_SUPPORT
4260 if (lynx_edit_mode) {
4261 DIRED_UNCACHE_2;
4262 }
4263 #endif /* DIRED_SUPPORT */
4264 } else if (child_lynx == TRUE) {
4265 return (1); /* exit on left arrow in main screen */
4266
4267 } else if (*old_c != real_c) {
4268 *old_c = real_c;
4269 HTUserMsg(ALREADY_AT_FIRST);
4270 }
4271 return 0;
4272 }
4273
handle_LYK_PREV_PAGE(int * old_c,int real_c)4274 static void handle_LYK_PREV_PAGE(int *old_c,
4275 int real_c)
4276 {
4277 if (LYGetNewline() > 1) {
4278 LYChgNewline(-display_lines);
4279 } else if (curdoc.link > 0) {
4280 set_curdoc_link(0);
4281 } else if (*old_c != real_c) {
4282 *old_c = real_c;
4283 HTInfoMsg(ALREADY_AT_BEGIN);
4284 }
4285 }
4286
handle_LYK_PRINT(BOOLEAN * ForcePush,int * old_c,int real_c)4287 static void handle_LYK_PRINT(BOOLEAN *ForcePush,
4288 int *old_c,
4289 int real_c)
4290 {
4291 if (LYValidate) {
4292 if (*old_c != real_c) {
4293 *old_c = real_c;
4294 HTUserMsg(PRINT_DISABLED);
4295 }
4296 return;
4297 }
4298
4299 /*
4300 * Don't do if already viewing print options page.
4301 */
4302 if (!LYIsUIPage(curdoc.address, UIP_PRINT_OPTIONS)
4303 && print_options(&newdoc.address,
4304 curdoc.address, HText_getNumOfLines()) >= 0) {
4305 LYRegisterUIPage(newdoc.address, UIP_PRINT_OPTIONS);
4306 StrAllocCopy(newdoc.title, PRINT_OPTIONS_TITLE);
4307 LYFreePostData(&newdoc);
4308 FREE(newdoc.bookmark);
4309 newdoc.isHEAD = FALSE;
4310 newdoc.safe = FALSE;
4311 *ForcePush = TRUE; /* see LYpush() and print_options() */
4312 if (check_realm)
4313 LYPermitURL = TRUE;
4314 }
4315 }
4316
handle_LYK_QUIT(void)4317 static BOOLEAN handle_LYK_QUIT(void)
4318 {
4319 int c;
4320
4321 if (LYQuitDefaultYes == TRUE) {
4322 c = HTConfirmDefault(REALLY_QUIT, YES);
4323 } else {
4324 c = HTConfirmDefault(REALLY_QUIT, NO);
4325 }
4326 if (LYQuitDefaultYes == TRUE) {
4327 if (c != NO) {
4328 return (TRUE);
4329 } else {
4330 HTInfoMsg(NO_CANCEL);
4331 }
4332 } else if (c == YES) {
4333 return (TRUE);
4334 } else {
4335 HTInfoMsg(NO_CANCEL);
4336 }
4337 return FALSE;
4338 }
4339
handle_LYK_RAW_TOGGLE(int * cmd)4340 static BOOLEAN handle_LYK_RAW_TOGGLE(int *cmd)
4341 {
4342 if (HTLoadedDocumentCharset()) {
4343 HTUserMsg(gettext("charset for this document specified explicitly, sorry..."));
4344 return FALSE;
4345 } else {
4346 LYUseDefaultRawMode = (BOOL) !LYUseDefaultRawMode;
4347 HTUserMsg(LYRawMode ? RAWMODE_OFF : RAWMODE_ON);
4348 HTMLSetCharacterHandling(current_char_set);
4349 return reparse_or_reload(cmd);
4350 }
4351 }
4352
handle_LYK_RELOAD(int real_cmd)4353 static void handle_LYK_RELOAD(int real_cmd)
4354 {
4355 /*
4356 * Check if this is a reply from a POST, and if so,
4357 * seek confirmation if the safe element is not set. - FM
4358 */
4359 if ((curdoc.post_data != NULL &&
4360 curdoc.safe != TRUE) &&
4361 HTConfirm(CONFIRM_POST_RESUBMISSION) == FALSE) {
4362 HTInfoMsg(CANCELLED);
4363 return;
4364 }
4365
4366 /*
4367 * Check to see if should reload source, or load html
4368 */
4369
4370 if (HTisDocumentSource()) {
4371 if ((forced_UCLYhdnl = HTMainText_Get_UCLYhndl()) >= 0)
4372 force_old_UCLYhndl_on_reload = TRUE;
4373 srcmode_for_next_retrieval(1);
4374 }
4375
4376 HEAD_request = HTLoadedDocumentIsHEAD();
4377 HText_setNoCache(HTMainText);
4378 /*
4379 * Do assume the reloaded document will be the same. - FM
4380 *
4381 * (I don't remember all the reasons why we couldn't assume this. As the
4382 * problems show up, we'll try to fix them, or add warnings. - FM)
4383 */
4384 newdoc.line = curdoc.line;
4385 newdoc.link = curdoc.link;
4386 free_address(&curdoc); /* so it doesn't get pushed */
4387 #ifdef VMS
4388 lynx_force_repaint();
4389 #endif /* VMS */
4390 /*
4391 * Reload should force a cache refresh on a proxy. -- Ari L.
4392 * <luotonen@dxcern.cern.ch>
4393 *
4394 * -- but only if this was really a reload requested by the user, not if we
4395 * jumped here to handle reloading for INLINE_TOGGLE, IMAGE_TOGGLE,
4396 * RAW_TOGGLE, etc. - KW
4397 */
4398 if (real_cmd == LYK_RELOAD)
4399 reloading = REAL_RELOAD;
4400
4401 return;
4402 }
4403
4404 #ifdef DIRED_SUPPORT
handle_LYK_REMOVE(BOOLEAN * refresh_screen)4405 static void handle_LYK_REMOVE(BOOLEAN *refresh_screen)
4406 {
4407 if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
4408 int linkno = curdoc.link; /* may be changed in local_remove - kw */
4409
4410 local_remove(&curdoc);
4411 if (LYAutoUncacheDirLists >= 1)
4412 do_cleanup_after_delete();
4413 else if (curdoc.link != linkno)
4414 *refresh_screen = TRUE;
4415 }
4416 }
4417 #endif /* DIRED_SUPPORT */
4418
handle_LYK_RIGHT_LINK(void)4419 static void handle_LYK_RIGHT_LINK(void)
4420 {
4421 if (curdoc.link < nlinks - 1 &&
4422 links[curdoc.link].ly == links[curdoc.link + 1].ly) {
4423 set_curdoc_link(curdoc.link + 1);
4424 }
4425 }
4426
handle_LYK_SHELL(BOOLEAN * refresh_screen,int * old_c,int real_c)4427 static void handle_LYK_SHELL(BOOLEAN *refresh_screen,
4428 int *old_c,
4429 int real_c)
4430 {
4431 if (!no_shell) {
4432 stop_curses();
4433 printf("%s\r\n", SPAWNING_MSG);
4434 #if defined(__CYGWIN__)
4435 /* handling "exec $SHELL" does not work if $SHELL is null */
4436 if (LYGetEnv("SHELL") == NULL) {
4437 Cygwin_Shell();
4438 } else
4439 #endif
4440 {
4441 static char *shell = NULL;
4442
4443 if (shell == 0)
4444 StrAllocCopy(shell, LYSysShell());
4445 LYSystem(shell);
4446 }
4447 start_curses();
4448 *refresh_screen = TRUE; /* for an HText_pageDisplay() */
4449 } else {
4450 if (*old_c != real_c) {
4451 *old_c = real_c;
4452 HTUserMsg(SPAWNING_DISABLED);
4453 }
4454 }
4455 }
4456
handle_LYK_SOFT_DQUOTES(void)4457 static void handle_LYK_SOFT_DQUOTES(void)
4458 {
4459 #ifdef USE_SOURCE_CACHE
4460 if (!HTcan_reparse_document()) {
4461 #endif
4462 /*
4463 * Check if this is a reply from a POST, and if so, seek confirmation
4464 * of reload if the safe element is not set. - FM
4465 */
4466 if ((curdoc.post_data != NULL &&
4467 curdoc.safe != TRUE) &&
4468 confirm_post_resub(curdoc.address, NULL, 1, 1) == FALSE) {
4469 HTInfoMsg(WILL_NOT_RELOAD_DOC);
4470 } else {
4471 HText_setNoCache(HTMainText);
4472 move_address(&newdoc, &curdoc);
4473 newdoc.line = curdoc.line;
4474 newdoc.link = curdoc.link;
4475 }
4476 #ifdef USE_SOURCE_CACHE
4477 } /* end if no bypass */
4478 #endif
4479 soft_dquotes = (BOOLEAN) !soft_dquotes;
4480 HTUserMsg(soft_dquotes ?
4481 SOFT_DOUBLE_QUOTE_ON : SOFT_DOUBLE_QUOTE_OFF);
4482 #ifdef USE_SOURCE_CACHE
4483 (void) reparse_document();
4484 #endif
4485 return;
4486 }
4487
4488 #define GetAnchorNumber(link) \
4489 ((nlinks > 0 && link >= 0) \
4490 ? links[link].anchor_number \
4491 : -1)
4492 #define GetAnchorLineNo(link) \
4493 ((nlinks > 0 && link >= 0) \
4494 ? links[link].anchor_line_num \
4495 : -1)
4496
4497 /*
4498 * Adjust the top-of-screen line number for the new document if the redisplayed
4499 * screen would not show the given link-number.
4500 */
4501 #ifdef USE_SOURCE_CACHE
wrap_reparse_document(void)4502 static int wrap_reparse_document(void)
4503 {
4504 int result;
4505 int anchor_number = GetAnchorNumber(curdoc.link);
4506 int old_line_num = HText_getAbsLineNumber(HTMainText, anchor_number);
4507 int old_from_top = old_line_num - LYGetNewline() + 1;
4508
4509 /* get the offset for the current anchor */
4510 int old_offset = ((nlinks > 0 && curdoc.link >= 0)
4511 ? links[curdoc.link].sgml_offset
4512 : -1);
4513
4514 CTRACE((tfp, "original anchor %d, topline %d, link %d, offset %d\n",
4515 anchor_number, old_line_num, curdoc.link, old_offset));
4516
4517 /* reparse the document (producing a new anchor list) */
4518 result = reparse_document();
4519
4520 /* readjust top-line and link-number */
4521 if (result && old_offset >= 0) {
4522 int new_anchor = HText_closestAnchor(HTMainText, old_offset);
4523 int new_lineno = HText_getAbsLineNumber(HTMainText, new_anchor);
4524 int top_lineno;
4525
4526 CTRACE((tfp, "old anchor %d -> new anchor %d\n", anchor_number, new_anchor));
4527
4528 if (new_lineno - old_from_top < 0)
4529 old_from_top = new_lineno;
4530
4531 /* Newline and newdoc.line are 1-based,
4532 * but 0-based lines are simpler to work with.
4533 */
4534 top_lineno = HText_getPreferredTopLine(HTMainText, new_lineno -
4535 old_from_top) + 1;
4536 CTRACE((tfp, "preferred top %d\n", top_lineno));
4537
4538 if (top_lineno != LYGetNewline()) {
4539 LYSetNewline(top_lineno);
4540 newdoc.link = HText_anchorRelativeTo(HTMainText, top_lineno - 1, new_anchor);
4541 curdoc.link = newdoc.link;
4542 CTRACE((tfp,
4543 "adjusted anchor %d, topline %d, link %d, offset %d\n",
4544 new_anchor,
4545 top_lineno,
4546 curdoc.link,
4547 HText_locateAnchor(HTMainText, new_anchor)));
4548 } else {
4549 newdoc.link = curdoc.link;
4550 }
4551 }
4552 return result;
4553 }
4554 #endif /* USE_SOURCE_CACHE */
4555
handle_LYK_SOURCE(char ** ownerS_address_p)4556 static void handle_LYK_SOURCE(char **ownerS_address_p)
4557 {
4558 #ifdef USE_SOURCE_CACHE
4559 BOOLEAN canreparse_post = FALSE;
4560 #endif
4561
4562 /*
4563 * Check if this is a reply from a POST, and if so,
4564 * seek confirmation if the safe element is not set. - FM
4565 */
4566 if ((curdoc.post_data != NULL &&
4567 curdoc.safe != TRUE) &&
4568 #ifdef USE_SOURCE_CACHE
4569 (!(canreparse_post = HTcan_reparse_document())) &&
4570 #endif
4571 (curdoc.isHEAD ? HTConfirm(CONFIRM_POST_RESUBMISSION) :
4572 confirm_post_resub(curdoc.address, curdoc.title, 1, 1)) == FALSE) {
4573 HTInfoMsg(CANCELLED);
4574 return;
4575 }
4576
4577 if (HTisDocumentSource()) {
4578 srcmode_for_next_retrieval(-1);
4579 } else {
4580 if (HText_getOwner())
4581 StrAllocCopy(*ownerS_address_p, HText_getOwner());
4582 LYUCPushAssumed(HTMainAnchor);
4583 srcmode_for_next_retrieval(1);
4584 }
4585
4586 #ifdef USE_SOURCE_CACHE
4587 if (wrap_reparse_document()) {
4588 /*
4589 * These normally get cleaned up after getfile() returns;
4590 * since we're not calling getfile(), we have to clean them
4591 * up ourselves. -dsb
4592 */
4593 HTOutputFormat = WWW_PRESENT;
4594 #ifdef USE_PRETTYSRC
4595 if (psrc_view)
4596 HTMark_asSource();
4597 psrc_view = FALSE;
4598 #endif
4599 FREE(*ownerS_address_p); /* not used with source_cache */
4600 LYUCPopAssumed(); /* probably a right place here */
4601 HTMLSetCharacterHandling(current_char_set); /* restore now */
4602
4603 return;
4604 } else if (canreparse_post) {
4605 srcmode_for_next_retrieval(0);
4606 LYUCPopAssumed(); /* probably a right place here */
4607 return;
4608 }
4609 #endif
4610
4611 if (curdoc.title)
4612 StrAllocCopy(newdoc.title, curdoc.title);
4613
4614 free_address(&curdoc); /* so it doesn't get pushed */
4615 LYforce_no_cache = TRUE;
4616 }
4617
handle_LYK_SWITCH_DTD(void)4618 static void handle_LYK_SWITCH_DTD(void)
4619 {
4620 #ifdef USE_SOURCE_CACHE
4621 BOOLEAN canreparse = FALSE;
4622
4623 if (!(canreparse = HTcan_reparse_document())) {
4624 #endif
4625 /*
4626 * Check if this is a reply from a POST, and if so,
4627 * seek confirmation of reload if the safe element
4628 * is not set. - FM, kw
4629 */
4630 if ((curdoc.post_data != NULL &&
4631 curdoc.safe != TRUE) &&
4632 confirm_post_resub(curdoc.address, NULL, 1, 1) == FALSE) {
4633 HTInfoMsg(WILL_NOT_RELOAD_DOC);
4634 } else {
4635 /*
4636 * If currently viewing preparsed source, switching to the other
4637 * DTD parsing may show source differences, so stay in source view
4638 * - kw
4639 */
4640
4641 /* NOTE: this conditional can be considered incorrect -
4642 current behaviour - when viewing source and
4643 LYPreparsedSource==TRUE, pressing ^V will toggle parser mode
4644 AND switch back from the source view to presentation view.-HV
4645 */
4646 if (HTisDocumentSource() && LYPreparsedSource) {
4647 srcmode_for_next_retrieval(1);
4648 }
4649 HText_setNoCache(HTMainText);
4650 move_address(&newdoc, &curdoc);
4651 newdoc.line = curdoc.line;
4652 newdoc.link = curdoc.link;
4653 }
4654 #ifdef USE_SOURCE_CACHE
4655 } /* end if no bypass */
4656 #endif
4657 Old_DTD = !Old_DTD;
4658 HTSwitchDTD(!Old_DTD);
4659 HTUserMsg(Old_DTD ? USING_DTD_0 : USING_DTD_1);
4660 #ifdef USE_SOURCE_CACHE
4661 if (canreparse) {
4662 if (HTisDocumentSource() && LYPreparsedSource) {
4663 srcmode_for_next_retrieval(1);
4664 }
4665 if (!reparse_document()) {
4666 srcmode_for_next_retrieval(0);
4667 }
4668 }
4669 #endif
4670 return;
4671 }
4672
4673 #ifdef DIRED_SUPPORT
handle_LYK_TAG_LINK(void)4674 static void handle_LYK_TAG_LINK(void)
4675 {
4676 if (lynx_edit_mode && nlinks > 0 && !no_dired_support) {
4677 if (!strcmp(LYGetHiliteStr(curdoc.link, 0), ".."))
4678 return; /* Never tag the parent directory */
4679 if (dir_list_style == MIXED_STYLE) {
4680 if (!strcmp(LYGetHiliteStr(curdoc.link, 0), "../"))
4681 return;
4682 } else if (!StrNCmp(LYGetHiliteStr(curdoc.link, 0), "Up to ", 6))
4683 return;
4684 {
4685 /*
4686 * HTList-based management of tag list, see LYLocal.c - KW
4687 */
4688 HTList *t1 = tagged;
4689 char *tagname = NULL;
4690 BOOLEAN found = FALSE;
4691
4692 while ((tagname = (char *) HTList_nextObject(t1)) != NULL) {
4693 if (!strcmp(links[curdoc.link].lname, tagname)) {
4694 found = TRUE;
4695 HTList_removeObject(tagged, tagname);
4696 FREE(tagname);
4697 tagflag(FALSE, curdoc.link);
4698 break;
4699 }
4700 }
4701 if (!found) {
4702 if (tagged == NULL)
4703 tagged = HTList_new();
4704 tagname = NULL;
4705 StrAllocCopy(tagname, links[curdoc.link].lname);
4706 HTList_addObject(tagged, tagname);
4707 tagflag(TRUE, curdoc.link);
4708 }
4709 }
4710 if (curdoc.link < nlinks - 1) {
4711 set_curdoc_link(curdoc.link + 1);
4712 } else if (!more_text && LYGetNewline() == 1 && curdoc.link == nlinks
4713 - 1) {
4714 set_curdoc_link(0);
4715 } else if (more_text) { /* next page */
4716 LYChgNewline(display_lines);
4717 }
4718 }
4719 }
4720 #endif /* DIRED_SUPPORT */
4721
handle_LYK_TOGGLE_HELP(void)4722 static void handle_LYK_TOGGLE_HELP(void)
4723 {
4724 if (user_mode == NOVICE_MODE) {
4725 toggle_novice_line();
4726 noviceline(more_text);
4727 }
4728 }
4729
handle_LYK_TOOLBAR(BOOLEAN * try_internal,BOOLEAN * force_load,int * old_c,int real_c)4730 static void handle_LYK_TOOLBAR(BOOLEAN *try_internal,
4731 BOOLEAN *force_load,
4732 int *old_c,
4733 int real_c)
4734 {
4735 char *cp;
4736 char *toolbar = NULL;
4737
4738 if (!HText_hasToolbar(HTMainText)) {
4739 if (*old_c != real_c) {
4740 *old_c = real_c;
4741 HTUserMsg(NO_TOOLBAR);
4742 }
4743 } else if (*old_c != real_c) {
4744 *old_c = real_c;
4745 cp = trimPoundSelector(curdoc.address);
4746 HTSprintf0(&toolbar, "%s#%s", curdoc.address, LYToolbarName);
4747 restorePoundSelector(cp);
4748 set_address(&newdoc, toolbar);
4749 FREE(toolbar);
4750 *try_internal = TRUE;
4751 *force_load = TRUE; /* force MainLoop to reload */
4752 }
4753 }
4754
handle_LYK_TRACE_LOG(BOOLEAN * trace_flag_ptr)4755 static void handle_LYK_TRACE_LOG(BOOLEAN *trace_flag_ptr)
4756 {
4757 #ifndef NO_LYNX_TRACE
4758 /*
4759 * Check whether we've started a TRACE log in this session. - FM
4760 */
4761 if (LYTraceLogFP == NULL) {
4762 HTUserMsg(NO_TRACELOG_STARTED);
4763 return;
4764 }
4765
4766 /*
4767 * Don't do if already viewing the TRACE log. - FM
4768 */
4769 if (LYIsUIPage(curdoc.address, UIP_TRACELOG))
4770 return;
4771
4772 /*
4773 * If TRACE mode is on, turn it off during this fetch of the TRACE log, so
4774 * we don't enter stuff about this fetch, and set a flag for turning it
4775 * back on when we return to this loop. Note that we'll miss any messages
4776 * about memory exhaustion if it should occur. It seems unlikely that
4777 * anything else bad might happen, but if it does, we'll miss messages
4778 * about that too. We also fflush(), close, and open it again, to make
4779 * sure all stderr messages thus far will be in the log. - FM
4780 */
4781 if (!LYReopenTracelog(trace_flag_ptr))
4782 return;
4783
4784 LYLocalFileToURL(&(newdoc.address), LYTraceLogPath);
4785 LYRegisterUIPage(newdoc.address, UIP_TRACELOG);
4786 StrAllocCopy(newdoc.title, LYNX_TRACELOG_TITLE);
4787 LYFreePostData(&newdoc);
4788 FREE(newdoc.bookmark);
4789 newdoc.isHEAD = FALSE;
4790 newdoc.safe = FALSE;
4791 newdoc.internal_link = FALSE;
4792 if (LYValidate || check_realm) {
4793 LYPermitURL = TRUE;
4794 }
4795 LYforce_no_cache = TRUE;
4796 #else
4797 HTUserMsg(TRACE_DISABLED);
4798 #endif /* NO_LYNX_TRACE */
4799 }
4800
4801 #ifdef DIRED_SUPPORT
handle_LYK_UPLOAD(void)4802 static void handle_LYK_UPLOAD(void)
4803 {
4804 /*
4805 * Don't do if already viewing upload options page.
4806 */
4807 if (LYIsUIPage(curdoc.address, UIP_UPLOAD_OPTIONS))
4808 return;
4809
4810 if (lynx_edit_mode && !no_dired_support) {
4811 LYUpload_options(&(newdoc.address), curdoc.address);
4812 StrAllocCopy(newdoc.title, UPLOAD_OPTIONS_TITLE);
4813 LYFreePostData(&newdoc);
4814 FREE(newdoc.bookmark);
4815 newdoc.isHEAD = FALSE;
4816 newdoc.safe = FALSE;
4817 newdoc.internal_link = FALSE;
4818 /*
4819 * Uncache the current listing so that it will be updated to included
4820 * the uploaded file if placed in the current directory. - FM
4821 */
4822 DIRED_UNCACHE_1;
4823 }
4824 }
4825 #endif /* DIRED_SUPPORT */
4826
handle_LYK_UP_xxx(int * arrowup,int * old_c,int real_c,int scroll_by)4827 static void handle_LYK_UP_xxx(int *arrowup,
4828 int *old_c,
4829 int real_c,
4830 int scroll_by)
4831 {
4832 if (LYGetNewline() > 1) {
4833 if (LYGetNewline() - scroll_by < 1)
4834 scroll_by = LYGetNewline() - 1;
4835 LYChgNewline(-scroll_by);
4836 if (nlinks > 0 && curdoc.link > -1) {
4837 if (links[curdoc.link].ly + scroll_by <= display_lines) {
4838 newdoc.link = curdoc.link +
4839 HText_LinksInLines(HTMainText,
4840 LYGetNewline(),
4841 scroll_by);
4842 } else {
4843 *arrowup = TRUE;
4844 }
4845 }
4846 } else if (*old_c != real_c) {
4847 *old_c = real_c;
4848 HTInfoMsg(ALREADY_AT_BEGIN);
4849 }
4850 }
4851
handle_LYK_UP_HALF(int * arrowup,int * old_c,int real_c)4852 static void handle_LYK_UP_HALF(int *arrowup,
4853 int *old_c,
4854 int real_c)
4855 {
4856 handle_LYK_UP_xxx(arrowup, old_c, real_c, display_lines / 2);
4857 }
4858
handle_LYK_UP_LINK(int * follow_col,int * arrowup,int * old_c,int real_c)4859 static void handle_LYK_UP_LINK(int *follow_col,
4860 int *arrowup,
4861 int *old_c,
4862 int real_c)
4863 {
4864 if (curdoc.link > 0 &&
4865 (links[0].ly != links[curdoc.link].ly ||
4866 !HText_LinksInLines(HTMainText, 1, LYGetNewline() - 1))) {
4867 /* more links before this on screen, and first of them on
4868 a different line or no previous links before this screen? */
4869 int newlink;
4870
4871 if (*follow_col == -1) {
4872 const char *text = LYGetHiliteStr(curdoc.link, 0);
4873
4874 *follow_col = links[curdoc.link].lx;
4875
4876 if (text != NULL)
4877 *follow_col += (int) strlen(text) / 2;
4878 }
4879
4880 newlink = find_link_near_col(*follow_col, -1);
4881 if (newlink > -1) {
4882 set_curdoc_link(newlink);
4883 } else if (*old_c != real_c) {
4884 *old_c = real_c;
4885 HTUserMsg(NO_LINKS_ABOVE);
4886 }
4887
4888 } else if (curdoc.line > 1 && LYGetNewline() > 1) { /* previous page */
4889 int scrollamount = (LYGetNewline() > display_lines
4890 ? display_lines
4891 : LYGetNewline() - 1);
4892
4893 LYChgNewline(-scrollamount);
4894 if (scrollamount < display_lines &&
4895 nlinks > 0 && curdoc.link > -1 &&
4896 links[0].ly - 1 + scrollamount <= display_lines) {
4897 newdoc.link = HText_LinksInLines(HTMainText,
4898 1,
4899 scrollamount) - 1;
4900 } else {
4901 *arrowup = TRUE;
4902 }
4903
4904 } else if (*old_c != real_c) {
4905 *old_c = real_c;
4906 HTInfoMsg(ALREADY_AT_BEGIN);
4907 }
4908 }
4909
handle_LYK_UP_TWO(int * arrowup,int * old_c,int real_c)4910 static void handle_LYK_UP_TWO(int *arrowup,
4911 int *old_c,
4912 int real_c)
4913 {
4914 handle_LYK_UP_xxx(arrowup, old_c, real_c, 2);
4915 }
4916
handle_LYK_VIEW_BOOKMARK(BOOLEAN * refresh_screen,int * old_c,int real_c)4917 static void handle_LYK_VIEW_BOOKMARK(BOOLEAN *refresh_screen,
4918 int *old_c,
4919 int real_c)
4920 {
4921 const char *cp;
4922
4923 if (LYValidate) {
4924 if (*old_c != real_c) {
4925 *old_c = real_c;
4926 HTUserMsg(BOOKMARKS_DISABLED);
4927 }
4928 return;
4929 }
4930
4931 /*
4932 * See if a bookmark exists. If it does replace newdoc.address with its
4933 * name.
4934 */
4935 if ((cp = get_bookmark_filename(&newdoc.address)) != NULL) {
4936 if (*cp == '\0' || !strcmp(cp, " ") ||
4937 !strcmp(curdoc.address, newdoc.address)) {
4938 if (LYMultiBookmarks != MBM_OFF)
4939 *refresh_screen = TRUE;
4940 return;
4941 }
4942 #ifdef KANJI_CODE_OVERRIDE
4943 if (HTCJK == JAPANESE) {
4944 last_kcode = NOKANJI; /* AUTO */
4945 }
4946 #endif
4947 LYforce_no_cache = TRUE; /*force the document to be reloaded */
4948 StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
4949 StrAllocCopy(newdoc.bookmark, BookmarkPage);
4950 LYFreePostData(&newdoc);
4951 newdoc.isHEAD = FALSE;
4952 newdoc.safe = FALSE;
4953 newdoc.internal_link = FALSE;
4954 } else {
4955 if (*old_c != real_c) {
4956 *old_c = real_c;
4957 LYMBM_statusline(BOOKMARKS_NOT_OPEN);
4958 LYSleepAlert();
4959 if (LYMultiBookmarks != MBM_OFF) {
4960 *refresh_screen = TRUE;
4961 }
4962 }
4963 }
4964 }
4965
handle_LYK_VLINKS(int * cmd,BOOLEAN * newdoc_link_is_absolute)4966 static BOOLEAN handle_LYK_VLINKS(int *cmd,
4967 BOOLEAN *newdoc_link_is_absolute)
4968 {
4969 int c;
4970
4971 if (LYIsUIPage(curdoc.address, UIP_VLINKS)) {
4972 /*
4973 * Already viewing visited links page, so get out.
4974 */
4975 *cmd = LYK_PREV_DOC;
4976 return TRUE;
4977 }
4978
4979 /*
4980 * Print visited links page to file.
4981 */
4982 c = LYShowVisitedLinks(&newdoc.address);
4983 if (c < 0) {
4984 HTUserMsg(VISITED_LINKS_EMPTY);
4985 return FALSE;
4986 }
4987 StrAllocCopy(newdoc.title, VISITED_LINKS_TITLE);
4988 LYFreePostData(&newdoc);
4989 FREE(newdoc.bookmark);
4990 newdoc.isHEAD = FALSE;
4991 newdoc.safe = FALSE;
4992 newdoc.internal_link = FALSE;
4993 if (c > 0) {
4994 /* Select a correct link. */
4995 *newdoc_link_is_absolute = TRUE;
4996 newdoc.link = c - 1;
4997 }
4998 if (LYValidate || check_realm) {
4999 LYPermitURL = TRUE;
5000 StrAllocCopy(lynxlinksfile, newdoc.address);
5001 }
5002 return FALSE;
5003 }
5004
handle_LYK_WHEREIS(int cmd,BOOLEAN * refresh_screen)5005 void handle_LYK_WHEREIS(int cmd,
5006 BOOLEAN *refresh_screen)
5007 {
5008 BOOLEAN have_target_onscreen = (BOOLEAN) (!isBEmpty(prev_target) &&
5009 HText_pageHasPrevTarget());
5010 BOOL found;
5011 int oldcur = curdoc.link; /* temporarily remember */
5012 char *remember_old_target = NULL;
5013
5014 if (have_target_onscreen)
5015 StrAllocCopy(remember_old_target, prev_target->str);
5016 else
5017 StrAllocCopy(remember_old_target, "");
5018
5019 if (cmd == LYK_WHEREIS) {
5020 /*
5021 * Reset prev_target to force prompting for a new search string and to
5022 * turn off highlighting if no search string is entered by the user.
5023 */
5024 BStrCopy0(prev_target, "");
5025 }
5026 found = textsearch(&curdoc, &prev_target,
5027 (cmd == LYK_WHEREIS)
5028 ? 0
5029 : ((cmd == LYK_NEXT)
5030 ? 1
5031 : -1));
5032
5033 /*
5034 * Force a redraw to ensure highlighting of hits even when found on the
5035 * same page, or clearing of highlighting if the default search string was
5036 * erased without replacement. - FM
5037 */
5038 /*
5039 * Well let's try to avoid it at least in a few cases
5040 * where it is not needed. - kw
5041 */
5042 if (www_search_result >= 0 && www_search_result != curdoc.line) {
5043 *refresh_screen = TRUE; /* doesn't really matter */
5044 } else if (!found) {
5045 *refresh_screen = have_target_onscreen;
5046 } else if (!have_target_onscreen && found) {
5047 *refresh_screen = TRUE;
5048 } else if (www_search_result == curdoc.line &&
5049 curdoc.link == oldcur &&
5050 curdoc.link >= 0 && nlinks > 0 &&
5051 links[curdoc.link].ly >= (display_lines / 3)) {
5052 *refresh_screen = TRUE;
5053 } else if ((LYcase_sensitive && 0 != strcmp(prev_target->str,
5054 remember_old_target)) ||
5055 (!LYcase_sensitive && 0 != strcasecomp8(prev_target->str,
5056 remember_old_target))) {
5057 *refresh_screen = TRUE;
5058 }
5059 FREE(remember_old_target);
5060 }
5061
5062 /*
5063 * Get a number from the user and follow that link number.
5064 */
handle_LYK_digit(int c,BOOLEAN * force_load,int * old_c,int real_c,BOOLEAN * try_internal GCC_UNUSED)5065 static void handle_LYK_digit(int c,
5066 BOOLEAN *force_load,
5067 int *old_c,
5068 int real_c,
5069 BOOLEAN *try_internal GCC_UNUSED)
5070 {
5071 int lindx = ((nlinks > 0) ? curdoc.link : 0);
5072 int number;
5073 char *temp = NULL;
5074
5075 /* pass cur line num for use in follow_link_number()
5076 * Note: Current line may not equal links[cur].line
5077 */
5078 number = curdoc.line;
5079 switch (follow_link_number(c, lindx, &newdoc, &number)) {
5080 case DO_LINK_STUFF:
5081 /*
5082 * Follow a normal link.
5083 */
5084 set_address(&newdoc, links[lindx].lname);
5085 StrAllocCopy(newdoc.title, LYGetHiliteStr(lindx, 0));
5086 /*
5087 * For internal links, retain POST content if present. If we are on
5088 * the List Page, prevent pushing it on the history stack. Otherwise
5089 * set try_internal to signal that the top of the loop should attempt
5090 * to reposition directly, without calling getfile. - kw
5091 */
5092 if (track_internal_links) {
5093 if (links[lindx].type == WWW_INTERN_LINK_TYPE) {
5094 LYinternal_flag = TRUE;
5095 newdoc.internal_link = TRUE;
5096 if (LYIsListpageTitle(NonNull(curdoc.title)) &&
5097 (LYIsUIPage(curdoc.address, UIP_LIST_PAGE) ||
5098 LYIsUIPage(curdoc.address, UIP_ADDRLIST_PAGE))) {
5099 if (check_history()) {
5100 LYinternal_flag = TRUE;
5101 } else {
5102 HTLastConfirmCancelled(); /* reset flag */
5103 if (!confirm_post_resub(newdoc.address,
5104 newdoc.title,
5105 ((LYresubmit_posts &&
5106 HText_POSTReplyLoaded(&newdoc))
5107 ? 1
5108 : 2),
5109 2)) {
5110 if (HTLastConfirmCancelled() ||
5111 (LYresubmit_posts &&
5112 !HText_POSTReplyLoaded(&newdoc))) {
5113 /* cancel the whole thing */
5114 LYforce_no_cache = FALSE;
5115 reloading = FALSE;
5116 copy_address(&newdoc, &curdoc);
5117 StrAllocCopy(newdoc.title, curdoc.title);
5118 newdoc.internal_link = curdoc.internal_link;
5119 HTInfoMsg(CANCELLED);
5120 if (nlinks > 0)
5121 HText_pageDisplay(curdoc.line, prev_target->str);
5122 break;
5123 } else if (LYresubmit_posts) {
5124 /* If LYresubmit_posts is set, and the
5125 answer was No, and we have a cached
5126 copy, then use it. - kw */
5127 LYforce_no_cache = FALSE;
5128 } else {
5129 /* if No, but not ^C or ^G, drop
5130 * the post data. Maybe the link
5131 * wasn't meant to be internal after
5132 * all, here we can recover from that
5133 * assumption. - kw */
5134 LYFreePostData(&newdoc);
5135 newdoc.internal_link = FALSE;
5136 HTAlert(DISCARDING_POST_DATA);
5137 }
5138 }
5139 }
5140 /*
5141 * Don't push the List Page if we follow an internal link given
5142 * by it. - kw
5143 */
5144 free_address(&curdoc);
5145 } else
5146 *try_internal = TRUE;
5147 if (!(LYresubmit_posts && newdoc.post_data))
5148 LYinternal_flag = TRUE;
5149 *force_load = TRUE;
5150 break;
5151 } else {
5152 /*
5153 * Free POST content if not an internal link. - kw
5154 */
5155 LYFreePostData(&newdoc);
5156 }
5157 }
5158 /*
5159 * Might be an anchor in the same doc from a POST form. If so, don't
5160 * free the content. -- FM
5161 */
5162 if (are_different(&curdoc, &newdoc)) {
5163 LYFreePostData(&newdoc);
5164 FREE(newdoc.bookmark);
5165 newdoc.isHEAD = FALSE;
5166 newdoc.safe = FALSE;
5167 if (isLYNXMESSAGES(newdoc.address))
5168 LYforce_no_cache = TRUE;
5169 }
5170 newdoc.internal_link = FALSE;
5171 *force_load = TRUE; /* force MainLoop to reload */
5172 break;
5173
5174 case DO_GOTOLINK_STUFF:
5175 /*
5176 * Position on a normal link, don't follow it. - KW
5177 */
5178 LYSetNewline(newdoc.line);
5179 newdoc.line = 1;
5180 if (LYGetNewline() == curdoc.line) {
5181 /*
5182 * It's a link in the current page. - FM
5183 */
5184 if (nlinks > 0 && curdoc.link > -1) {
5185 if (curdoc.link == newdoc.link) {
5186 /*
5187 * It's the current link, and presumably reflects a typo in
5188 * the statusline entry, so issue a statusline message for
5189 * the typo-prone users (like me 8-). - FM
5190 */
5191 HTSprintf0(&temp, LINK_ALREADY_CURRENT, number);
5192 HTUserMsg(temp);
5193 FREE(temp);
5194 } else {
5195 /*
5196 * It's a different link on this page,
5197 */
5198 set_curdoc_link(newdoc.link);
5199 newdoc.link = 0;
5200 }
5201 }
5202 }
5203 break; /* nothing more to do */
5204
5205 case DO_GOTOPAGE_STUFF:
5206 /*
5207 * Position on a page in this document. - FM
5208 */
5209 LYSetNewline(newdoc.line);
5210 newdoc.line = 1;
5211 if (LYGetNewline() == curdoc.line) {
5212 /*
5213 * It's the current page, so issue a statusline message for the
5214 * typo-prone users (like me 8-). - FM
5215 */
5216 if (LYGetNewline() <= 1) {
5217 HTInfoMsg(ALREADY_AT_BEGIN);
5218 } else if (!more_text) {
5219 HTInfoMsg(ALREADY_AT_END);
5220 } else {
5221 HTSprintf0(&temp, ALREADY_AT_PAGE, number);
5222 HTUserMsg(temp);
5223 FREE(temp);
5224 }
5225 }
5226 break;
5227
5228 case PRINT_ERROR:
5229 *old_c = real_c;
5230 HTUserMsg(BAD_LINK_NUM_ENTERED);
5231 break;
5232 }
5233 return;
5234 }
5235
5236 #ifdef SUPPORT_CHDIR
5237
5238 /* original implementation by VH */
handle_LYK_CHDIR(void)5239 void handle_LYK_CHDIR(void)
5240 {
5241 static bstring *buf = NULL;
5242 char *p = NULL;
5243
5244 if (no_chdir) {
5245 HTUserMsg(CHDIR_DISABLED);
5246 return;
5247 }
5248
5249 _statusline(gettext("cd to:"));
5250 if (LYgetBString(&buf, VISIBLE, 0, NORECALL) < 0 || isBEmpty(buf)) {
5251 HTInfoMsg(CANCELLED);
5252 return;
5253 }
5254
5255 if (LYIsTilde(buf->str[0]) &&
5256 (LYIsPathSep(buf->str[1]) || buf->str[1] == '\0')) {
5257 HTSprintf0(&p, "%s%s", Home_Dir(), buf->str + 1);
5258 } else {
5259 StrAllocCopy(p, buf->str);
5260 }
5261
5262 CTRACE((tfp, "changing directory to '%s'\n", p));
5263 if (chdir(p)) {
5264 switch (errno) {
5265 case EACCES:
5266 HTInfoMsg(COULD_NOT_ACCESS_DIR);
5267 break;
5268 case ENOENT:
5269 HTInfoMsg(gettext("No such directory"));
5270 break;
5271 case ENOTDIR:
5272 HTInfoMsg(gettext("A component of path is not a directory"));
5273 break;
5274 default:
5275 HTInfoMsg(gettext("failed to change directory"));
5276 break;
5277 }
5278 } else {
5279 #ifdef DIRED_SUPPORT
5280 /*if in dired, load content of other directory */
5281 if (!no_dired_support
5282 && (lynx_edit_mode || (LYIsUIPage(curdoc.address, UIP_DIRED_MENU)))) {
5283 char buf2[LY_MAXPATH];
5284 char *addr = NULL;
5285
5286 Current_Dir(buf2);
5287 LYLocalFileToURL(&addr, buf2);
5288
5289 newdoc.address = addr;
5290 newdoc.isHEAD = FALSE;
5291 StrAllocCopy(newdoc.title, gettext("A URL specified by the user"));
5292 LYFreePostData(&newdoc);
5293 FREE(newdoc.bookmark);
5294 newdoc.safe = FALSE;
5295 newdoc.internal_link = FALSE;
5296 /**force_load = TRUE;*/
5297 if (lynx_edit_mode) {
5298 DIRED_UNCACHE_2;
5299 }
5300 } else
5301 #endif
5302 HTInfoMsg(OPERATION_DONE);
5303 }
5304 FREE(p);
5305 }
5306
handle_LYK_PWD(void)5307 static void handle_LYK_PWD(void)
5308 {
5309 char buffer[LY_MAXPATH];
5310 int save_secs = InfoSecs;
5311 BOOLEAN save_wait = no_pause;
5312
5313 if (Secs2SECS(save_secs) < 1)
5314 InfoSecs = SECS2Secs(1);
5315 no_pause = FALSE;
5316
5317 HTInfoMsg(Current_Dir(buffer));
5318
5319 InfoSecs = save_secs;
5320 no_pause = save_wait;
5321 }
5322 #endif
5323
5324 #ifdef USE_CURSES_PADS
5325 /*
5326 * Having jumps larger than this is counter-productive. Indeed, it is natural
5327 * to expect that when the relevant text appears, one would "overshoot" and
5328 * would scroll 3-4 extra full screens. When going back, the "accumulation"
5329 * logic would again start moving in full screens, so one would overshoot
5330 * again, etc.
5331 *
5332 * Going back, one can fix it in 28 keypresses. The relevant text will appear
5333 * on the screen soon enough for the key-repeat to become not that important,
5334 * and we are still moving in smaller steps than when we overshot. Since key
5335 * repeat is not important, even if we overshoot again, it is going to be by 30
5336 * steps, which is easy to fix by reversing the direction again.
5337 */
repeat_to_delta(int n)5338 static int repeat_to_delta(int n)
5339 {
5340 int threshold = LYcols / 3;
5341
5342 while (threshold > 0) {
5343 if (n >= threshold) {
5344 n = threshold;
5345 break;
5346 }
5347 threshold = (threshold * 2) / 3;
5348 }
5349 return n;
5350 }
5351
handle_LYK_SHIFT_LEFT(BOOLEAN * flag,int count)5352 static void handle_LYK_SHIFT_LEFT(BOOLEAN *flag, int count)
5353 {
5354 if (!LYwideLines) {
5355 HTAlert(SHIFT_VS_LINEWRAP);
5356 return;
5357 }
5358 if (LYshiftWin > 0) {
5359 LYshiftWin -= repeat_to_delta(count);
5360 *flag = TRUE;
5361 }
5362 if (LYshiftWin < 0)
5363 LYshiftWin = 0;
5364 }
5365
handle_LYK_SHIFT_RIGHT(BOOLEAN * flag,int count)5366 static void handle_LYK_SHIFT_RIGHT(BOOLEAN *flag, int count)
5367 {
5368 if (!LYwideLines) {
5369 HTAlert(SHIFT_VS_LINEWRAP);
5370 return;
5371 }
5372 LYshiftWin += repeat_to_delta(count);
5373 *flag = TRUE;
5374 }
5375
handle_LYK_LINEWRAP_TOGGLE(int * cmd,BOOLEAN * flag)5376 static BOOLEAN handle_LYK_LINEWRAP_TOGGLE(int *cmd,
5377 BOOLEAN *flag)
5378 {
5379 static const char *choices[] =
5380 {
5381 "Try to fit screen width",
5382 "No line wrap in columns",
5383 "Wrap columns at screen width",
5384 "Wrap columns at 3/4 screen width",
5385 "Wrap columns at 2/3 screen width",
5386 "Wrap columns at 1/2 screen width",
5387 "Wrap columns at 1/3 screen width",
5388 "Wrap columns at 1/4 screen width",
5389 NULL
5390 };
5391 static int wrap[] =
5392 {
5393 0,
5394 0,
5395 12, /* In units of 1/12 */
5396 9,
5397 8,
5398 6,
5399 4,
5400 3
5401 };
5402 int c;
5403 int code = FALSE;
5404
5405 CTRACE((tfp, "Entering handle_LYK_LINEWRAP_TOGGLE\n"));
5406 if (LYwin != stdscr) {
5407 /* Somehow the mouse is over the number instead of being over the
5408 name, so we decrease x. */
5409 c = LYChoosePopup(!LYwideLines,
5410 LYlines / 2 - 2,
5411 LYcolLimit / 2 - 6,
5412 choices, (int) TABLESIZE(choices) - 1,
5413 FALSE, TRUE);
5414 /*
5415 * LYhandlePopupList() wasn't really meant to be used outside of
5416 * old-style Options menu processing. One result of mis-using it here
5417 * is that we have to deal with side-effects regarding SIGINT signal
5418 * handler and the term_options global variable. - kw
5419 */
5420 if (!term_options) {
5421 CTRACE((tfp,
5422 "...setting LYwideLines %d, LYtableCols %d (have %d and %d)\n",
5423 c, wrap[c],
5424 LYwideLines,
5425 LYtableCols));
5426
5427 LYwideLines = c;
5428 LYtableCols = wrap[c];
5429
5430 if (LYwideLines == 0)
5431 LYshiftWin = 0;
5432 *flag = TRUE;
5433 HTUserMsg(LYwideLines ? LINEWRAP_OFF : LINEWRAP_ON);
5434 code = reparse_or_reload(cmd);
5435 }
5436 }
5437 return (BOOLEAN) code;
5438 }
5439 #endif
5440
5441 #ifdef USE_MAXSCREEN_TOGGLE
handle_LYK_MAXSCREEN_TOGGLE(int * cmd)5442 static BOOLEAN handle_LYK_MAXSCREEN_TOGGLE(int *cmd)
5443 {
5444 static int flag = 0;
5445
5446 CTRACE((tfp, "Entering handle_LYK_MAXSCREEN_TOGGLE\n"));
5447 if (flag) {
5448 CTRACE((tfp, "Calling recoverWindowSize()\n"));
5449 recoverWindowSize();
5450 flag = 0;
5451 } else {
5452 CTRACE((tfp, "Calling maxmizeWindowSize()\n"));
5453 maxmizeWindowSize();
5454 flag = 1;
5455 }
5456 return reparse_or_reload(cmd);
5457 }
5458 #endif
5459
5460 #ifdef LY_FIND_LEAKS
5461 #define CleanupMainLoop() \
5462 BStrFree(prev_target); \
5463 BStrFree(user_input_buffer)
5464 #else
5465 #define CleanupMainLoop() /* nothing */
5466 #endif
5467
5468 /*
5469 * Here's where we do all the work.
5470 * mainloop is basically just a big switch dependent on the users input. I
5471 * have tried to offload most of the work done here to procedures to make it
5472 * more modular, but this procedure still does a lot of variable manipulation.
5473 * This needs some work to make it neater. - Lou Moutilli
5474 * (memoir from the original Lynx - FM)
5475 */
mainloop(void)5476 int mainloop(void)
5477 {
5478 #if defined(WIN_EX) /* 1997/10/08 (Wed) 14:52:06 */
5479 char sjis_buff[MAX_LINE];
5480 char temp_buff[sizeof(sjis_buff) * 4];
5481 #endif
5482 int c = 0;
5483 int real_c = 0;
5484 int old_c = 0;
5485 int pending_form_c = -1;
5486 int cmd = LYK_DO_NOTHING, real_cmd = LYK_DO_NOTHING;
5487 int getresult;
5488 int arrowup = FALSE, show_help = FALSE;
5489 bstring *user_input_buffer = NULL;
5490 const char *cshelpfile = NULL;
5491 BOOLEAN first_file = TRUE;
5492 BOOLEAN popped_doc = FALSE;
5493 BOOLEAN refresh_screen = FALSE;
5494 BOOLEAN force_load = FALSE;
5495 BOOLEAN try_internal = FALSE;
5496 BOOLEAN crawl_ok = FALSE;
5497 BOOLEAN vi_keys_flag = vi_keys;
5498 BOOLEAN emacs_keys_flag = emacs_keys;
5499 BOOLEAN trace_mode_flag = FALSE;
5500 BOOLEAN forced_HTML_mode = LYforce_HTML_mode;
5501 char cfile[128];
5502 FILE *cfp;
5503 char *cp;
5504 int ch = 0;
5505 RecallType recall = NORECALL;
5506 int URLTotal = 0;
5507 int URLNum;
5508 BOOLEAN FirstURLRecall = TRUE;
5509 char *temp = NULL;
5510 BOOLEAN ForcePush = FALSE;
5511 BOOLEAN override_LYresubmit_posts = FALSE;
5512 BOOLEAN newdoc_link_is_absolute = FALSE;
5513 BOOLEAN curlink_is_editable;
5514 BOOLEAN use_last_tfpos;
5515 unsigned int len;
5516 int i;
5517 int follow_col = -1, key_count = 0, last_key = 0;
5518 int tmpNewline;
5519 DocInfo tmpDocInfo;
5520
5521 /* "internal" means "within the same document, with certainty". It includes a
5522 * space so it cannot conflict with any (valid) "TYPE" attributes on A
5523 * elements. [According to which DTD, anyway??] - kw
5524 */
5525 HTInternalLink = HTAtom_for("internal link"); /* init, used as const */
5526
5527 #ifndef WWW_SOURCE
5528 WWW_SOURCE = HTAtom_for("www/source"); /* init, used as const */
5529 #endif
5530
5531 /*
5532 * curdoc.address contains the name of the file that is currently open.
5533 * newdoc.address contains the name of the file that will soon be
5534 * opened if it exits.
5535 * prev_target contains the last search string the user searched for.
5536 * newdoc.title contains the link name that the user last chose to get
5537 * into the current link (file).
5538 */
5539 /* initialize some variables */
5540 newdoc.address = NULL;
5541 newdoc.title = NULL;
5542 newdoc.post_data = NULL;
5543 newdoc.post_content_type = NULL;
5544 newdoc.bookmark = NULL;
5545 newdoc.internal_link = FALSE;
5546 curdoc.address = NULL;
5547 curdoc.title = NULL;
5548 curdoc.post_data = NULL;
5549 curdoc.post_content_type = NULL;
5550 curdoc.bookmark = NULL;
5551 curdoc.internal_link = FALSE;
5552 #ifdef USE_COLOR_STYLE
5553 curdoc.style = NULL;
5554 newdoc.style = NULL;
5555 #endif
5556 #ifndef USE_SESSIONS
5557 nhist = 0;
5558 #endif
5559 BStrCopy0(user_input_buffer, "");
5560 BStrCopy0(prev_target, "");
5561 #ifdef LY_FIND_LEAKS
5562 atexit(free_mainloop_variables);
5563 #endif
5564 initialize:
5565 set_address(&newdoc, startfile);
5566 StrAllocCopy(startrealm, startfile);
5567 StrAllocCopy(newdoc.title, gettext("Entry into main screen"));
5568 newdoc.isHEAD = FALSE;
5569 newdoc.safe = FALSE;
5570 newdoc.line = 1;
5571 newdoc.link = 0;
5572
5573 #ifdef USE_SLANG
5574 if (TRACE && LYCursesON) {
5575 LYaddstr("\n");
5576 LYrefresh();
5577 }
5578 #endif /* USE_SLANG */
5579 CTRACE((tfp, "Entering mainloop, startfile=%s\n", startfile));
5580
5581 if (form_post_data) {
5582 BStrCopy0(newdoc.post_data, form_post_data);
5583 StrAllocCopy(newdoc.post_content_type,
5584 "application/x-www-form-urlencoded");
5585 } else if (form_get_data) {
5586 StrAllocCat(newdoc.address, form_get_data);
5587 }
5588
5589 if (bookmark_start) {
5590 if (LYValidate) {
5591 HTAlert(BOOKMARKS_DISABLED);
5592 bookmark_start = FALSE;
5593 goto initialize;
5594 } else if (traversal) {
5595 HTAlert(BOOKMARKS_NOT_TRAVERSED);
5596 traversal = FALSE;
5597 crawl = FALSE;
5598 bookmark_start = FALSE;
5599 goto initialize;
5600 } else {
5601 const char *cp1;
5602
5603 /*
5604 * See if a bookmark page exists. If it does, replace
5605 * newdoc.address with its name
5606 */
5607 if ((cp1 = get_bookmark_filename(&newdoc.address)) != NULL &&
5608 *cp1 != '\0' && strcmp(cp1, " ")) {
5609 StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
5610 StrAllocCopy(newdoc.bookmark, BookmarkPage);
5611 StrAllocCopy(startrealm, newdoc.address);
5612 LYFreePostData(&newdoc);
5613 newdoc.isHEAD = FALSE;
5614 newdoc.safe = FALSE;
5615 CTRACE((tfp, "Using bookmarks=%s\n", newdoc.address));
5616 } else {
5617 HTUserMsg(BOOKMARKS_NOT_OPEN);
5618 bookmark_start = FALSE;
5619 goto initialize;
5620 }
5621 }
5622 }
5623
5624 FREE(form_post_data);
5625 FREE(form_get_data);
5626
5627 LYSetDisplayLines();
5628
5629 while (TRUE) {
5630 #ifdef USE_COLOR_STYLE
5631 if (curdoc.style != NULL)
5632 force_load = TRUE;
5633 #endif
5634 /*
5635 * If newdoc.address is different from curdoc.address then we need to
5636 * go out and find and load newdoc.address.
5637 */
5638 if (LYforce_no_cache || force_load ||
5639 are_different(&curdoc, &newdoc)) {
5640
5641 force_load = FALSE; /* done */
5642 if (TRACE && LYCursesON) {
5643 LYHideCursor(); /* make sure cursor is down */
5644 #ifdef USE_SLANG
5645 LYaddstr("\n");
5646 #endif /* USE_SLANG */
5647 LYrefresh();
5648 }
5649 try_again:
5650 /*
5651 * Push the old file onto the history stack if we have a current
5652 * doc and a new address. - FM
5653 */
5654 if (curdoc.address && newdoc.address) {
5655 /*
5656 * Don't actually push if this is a LYNXDOWNLOAD URL, because
5657 * that returns NORMAL even if it fails due to a spoof attempt
5658 * or file access problem, and we set the newdoc structure
5659 * elements to the curdoc structure elements under case NORMAL.
5660 * - FM
5661 */
5662 if (!isLYNXDOWNLOAD(newdoc.address)) {
5663 LYpush(&curdoc, ForcePush);
5664 }
5665 } else if (!newdoc.address) {
5666 /*
5667 * If newdoc.address is empty then pop a file and load it. -
5668 * FM
5669 */
5670 LYhist_prev(&newdoc);
5671 popped_doc = TRUE;
5672
5673 /*
5674 * If curdoc had been reached via an internal
5675 * (fragment) link from what we now have just
5676 * popped into newdoc, then override non-caching in
5677 * all cases. - kw
5678 */
5679 if (track_internal_links &&
5680 curdoc.internal_link &&
5681 !are_phys_different(&curdoc, &newdoc)) {
5682 LYinternal_flag = TRUE;
5683 LYoverride_no_cache = TRUE;
5684 LYforce_no_cache = FALSE;
5685 try_internal = TRUE;
5686 } else {
5687 /*
5688 * Force a no_cache override unless it's a bookmark file,
5689 * or it has POST content and LYresubmit_posts is set
5690 * without safe also set, and we are not going to another
5691 * position in the current document or restoring the
5692 * previous document due to a NOT_FOUND or NULLFILE return
5693 * value from getfile(). - FM
5694 */
5695 if ((newdoc.bookmark != NULL) ||
5696 (newdoc.post_data != NULL &&
5697 !newdoc.safe &&
5698 LYresubmit_posts &&
5699 !override_LYresubmit_posts &&
5700 NO_INTERNAL_OR_DIFFERENT(&curdoc, &newdoc))) {
5701 LYoverride_no_cache = FALSE;
5702 } else {
5703 LYoverride_no_cache = TRUE;
5704 }
5705 }
5706 }
5707 override_LYresubmit_posts = FALSE;
5708
5709 if (HEAD_request) {
5710 /*
5711 * Make SURE this is an appropriate request. - FM
5712 */
5713 if (newdoc.address) {
5714 if (LYCanDoHEAD(newdoc.address) == TRUE) {
5715 newdoc.isHEAD = TRUE;
5716 } else if (isLYNXIMGMAP(newdoc.address)) {
5717 if (LYCanDoHEAD(newdoc.address + LEN_LYNXIMGMAP) == TRUE) {
5718 StrAllocCopy(temp, newdoc.address + LEN_LYNXIMGMAP);
5719 free_address(&newdoc);
5720 newdoc.address = temp;
5721 newdoc.isHEAD = TRUE;
5722 temp = NULL;
5723 }
5724 }
5725 }
5726 try_internal = FALSE;
5727 HEAD_request = FALSE;
5728 }
5729
5730 /*
5731 * If we're getting the TRACE log and it's not new, check whether
5732 * its HText structure has been dumped, and if so, fflush() and
5733 * fclose() it to ensure it's fully updated, and then fopen() it
5734 * again. - FM
5735 */
5736 if (LYUseTraceLog == TRUE &&
5737 trace_mode_flag == FALSE &&
5738 LYTraceLogFP != NULL &&
5739 LYIsUIPage(newdoc.address, UIP_TRACELOG)) {
5740 DocAddress WWWDoc;
5741 HTParentAnchor *tmpanchor;
5742
5743 WWWDoc.address = newdoc.address;
5744 WWWDoc.post_data = newdoc.post_data;
5745 WWWDoc.post_content_type = newdoc.post_content_type;
5746 WWWDoc.bookmark = newdoc.bookmark;
5747 WWWDoc.isHEAD = newdoc.isHEAD;
5748 WWWDoc.safe = newdoc.safe;
5749 tmpanchor = HTAnchor_findAddress(&WWWDoc);
5750 if ((HText *) HTAnchor_document(tmpanchor) == NULL) {
5751 if (!LYReopenTracelog(&trace_mode_flag)) {
5752 old_c = 0;
5753 cmd = LYK_PREV_DOC;
5754 goto new_cmd;
5755 }
5756 }
5757 }
5758
5759 LYRequestTitle = newdoc.title;
5760 if (newdoc.bookmark)
5761 LYforce_HTML_mode = TRUE;
5762 if (LYValidate &&
5763 startfile_ok &&
5764 newdoc.address && startfile && homepage &&
5765 (!strcmp(newdoc.address, startfile) ||
5766 !strcmp(newdoc.address, homepage))) {
5767 LYPermitURL = TRUE;
5768 }
5769
5770 /* reset these two variables here before getfile()
5771 * so they will be available in partial mode
5772 * (was previously implemented in case NORMAL).
5773 */
5774 BStrCopy0(prev_target, ""); /* Reset for new coming document */
5775 LYSetNewline(newdoc.line); /* set for LYGetNewline() */
5776
5777 #ifdef USE_PRETTYSRC
5778 psrc_first_tag = TRUE;
5779 #endif
5780 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
5781 textfields_need_activation = textfields_activation_option;
5782 #endif
5783 FREE(LYRequestReferer);
5784 /*
5785 * Don't send Referer if we have to load a document again that we
5786 * got from the history stack. We don't know any more how we
5787 * originally got to that page. Using a Referer based on the
5788 * current HTMainText could only be right by coincidence. - kw
5789 * 1999-11-01
5790 */
5791 if (popped_doc)
5792 LYNoRefererForThis = TRUE;
5793
5794 if (track_internal_links) {
5795 if (try_internal) {
5796 if (newdoc.address &&
5797 isLYNXIMGMAP(newdoc.address)) {
5798 try_internal = FALSE;
5799 } else if (curdoc.address &&
5800 isLYNXIMGMAP(curdoc.address)) {
5801 try_internal = FALSE;
5802 }
5803 }
5804 if (try_internal) {
5805 char *hashp = findPoundSelector(newdoc.address);
5806
5807 if (hashp) {
5808 HTFindPoundSelector(hashp + 1);
5809 }
5810 getresult = (HTMainText != NULL) ? NORMAL : NOT_FOUND;
5811 try_internal = FALSE; /* done */
5812 /* fix up newdoc.address which may have been fragment-only */
5813 if (getresult == NORMAL && (!hashp || hashp == newdoc.address)) {
5814 if (!hashp) {
5815 set_address(&newdoc, HTLoadedDocumentURL());
5816 } else {
5817 StrAllocCopy(temp, HTLoadedDocumentURL());
5818 StrAllocCat(temp, hashp); /* append fragment */
5819 set_address(&newdoc, temp);
5820 FREE(temp);
5821 }
5822 }
5823 } else {
5824 if (newdoc.internal_link && newdoc.address &&
5825 *newdoc.address == '#' && nhist > 0) {
5826 char *cp0;
5827
5828 if (isLYNXIMGMAP(HDOC(nhist_1).address))
5829 cp0 = HDOC(nhist_1).address + LEN_LYNXIMGMAP;
5830 else
5831 cp0 = HDOC(nhist_1).address;
5832 StrAllocCopy(temp, cp0);
5833 (void) trimPoundSelector(temp);
5834 StrAllocCat(temp, newdoc.address);
5835 free_address(&newdoc);
5836 newdoc.address = temp;
5837 temp = NULL;
5838 }
5839 tmpDocInfo = newdoc;
5840 tmpNewline = -1;
5841 fill_JUMP_Params(&newdoc.address);
5842 getresult = getfile(&newdoc, &tmpNewline);
5843 if (!reloading && !popped_doc && (tmpNewline >= 0)) {
5844 LYSetNewline(tmpNewline);
5845 } else {
5846 newdoc.link = tmpDocInfo.link;
5847 }
5848 }
5849 } else {
5850 tmpDocInfo = newdoc;
5851 tmpNewline = -1;
5852 fill_JUMP_Params(&newdoc.address);
5853 getresult = getfile(&newdoc, &tmpNewline);
5854 if (!reloading && !popped_doc && (tmpNewline >= 0)) {
5855 LYSetNewline(tmpNewline);
5856 } else {
5857 newdoc.link = tmpDocInfo.link;
5858 }
5859 }
5860
5861 #ifdef INACTIVE_INPUT_STYLE_VH
5862 textinput_redrawn = FALSE; /* for sure */
5863 #endif
5864
5865 switch (getresult) {
5866
5867 case NOT_FOUND:
5868 /*
5869 * OK! can't find the file, so it must not be around now. Do
5870 * any error logging, if appropriate.
5871 */
5872 LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
5873 LYinternal_flag = FALSE; /* Reset to default. - kw */
5874 turn_trace_back_on(&trace_mode_flag);
5875 if (!first_file && !LYCancelledFetch) {
5876 /*
5877 * Do error mail sending and/or traversal stuff. Note that
5878 * the links[] elements may not be valid at this point, if
5879 * we did call HTuncache_current_document! This should not
5880 * have happened for traversal, but for sending error mail
5881 * check that HTMainText exists for this reason. - kw
5882 */
5883 if (error_logging && nhist > 0 && !popped_doc &&
5884 !LYUserSpecifiedURL &&
5885 HTMainText &&
5886 nlinks > 0 && curdoc.link < nlinks &&
5887 !isLYNXHIST(NonNull(newdoc.address)) &&
5888 #ifdef USE_CACHEJAR
5889 !isLYNXCACHE(NonNull(newdoc.address)) &&
5890 #endif
5891 !isLYNXCOOKIE(NonNull(newdoc.address))) {
5892 char *mail_owner = NULL;
5893
5894 if (owner_address && isMAILTO_URL(owner_address)) {
5895 mail_owner = owner_address + LEN_MAILTO_URL;
5896 }
5897 /*
5898 * Email a bad link message to the owner of the
5899 * document, or to ALERTMAIL if defined, but NOT to
5900 * lynx-dev (it is rejected in mailmsg). - FM, kw
5901 */
5902 #ifndef ALERTMAIL
5903 if (mail_owner)
5904 #endif
5905 mailmsg(curdoc.link,
5906 mail_owner,
5907 HDOC(nhist_1).address,
5908 HDOC(nhist_1).title);
5909 }
5910 if (traversal) {
5911 FILE *ofp;
5912
5913 if ((ofp = LYAppendToTxtFile(TRAVERSE_ERRORS)) == NULL) {
5914 if ((ofp = LYNewTxtFile(TRAVERSE_ERRORS)) == NULL) {
5915 perror(NOOPEN_TRAV_ERR_FILE);
5916 exit_immediately(EXIT_FAILURE);
5917 }
5918 }
5919 if (nhist > 0) {
5920 fprintf(ofp,
5921 "%s %s\tin %s\n",
5922 popped_doc ?
5923 newdoc.address : links[curdoc.link].lname,
5924 links[curdoc.link].target,
5925 HDOC(nhist_1).address);
5926 } else {
5927 fprintf(ofp,
5928 "%s %s\t\n",
5929 popped_doc ?
5930 newdoc.address : links[curdoc.link].lname,
5931 links[curdoc.link].target);
5932 }
5933 LYCloseOutput(ofp);
5934 }
5935 }
5936
5937 /*
5938 * Fall through to do the NULL stuff and reload the old file,
5939 * unless the first file wasn't found or has gone missing.
5940 */
5941 if (!nhist) {
5942 /*
5943 * If nhist = 0 then it must be the first file.
5944 */
5945 CleanupMainLoop();
5946 exit_immediately_with_error_message(NOT_FOUND, first_file);
5947 return (EXIT_FAILURE);
5948 }
5949 /* FALLTHRU */
5950
5951 case NULLFILE:
5952 /*
5953 * Not supposed to return any file.
5954 */
5955 LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
5956 popped_doc = FALSE; /* Was TRUE if popped. - FM */
5957 LYinternal_flag = FALSE; /* Reset to default. - kw */
5958 turn_trace_back_on(&trace_mode_flag);
5959 free_address(&newdoc); /* to pop last doc */
5960 FREE(newdoc.bookmark);
5961 LYJumpFileURL = FALSE;
5962 reloading = FALSE;
5963 LYPermitURL = FALSE;
5964 LYCancelledFetch = FALSE;
5965 ForcePush = FALSE;
5966 LYforce_HTML_mode = FALSE;
5967 force_old_UCLYhndl_on_reload = FALSE;
5968 if (traversal) {
5969 crawl_ok = FALSE;
5970 if (traversal_link_to_add) {
5971 /*
5972 * It's a binary file, or the fetch attempt failed.
5973 * Add it to TRAVERSE_REJECT_FILE so we don't try again
5974 * in this run.
5975 */
5976 if (!lookup_reject(traversal_link_to_add)) {
5977 add_to_reject_list(traversal_link_to_add);
5978 }
5979 FREE(traversal_link_to_add);
5980 }
5981 }
5982 /*
5983 * Make sure the first file was found and has not gone missing.
5984 */
5985 if (!nhist) {
5986 /*
5987 * If nhist = 0 then it must be the first file.
5988 */
5989 if (first_file && homepage &&
5990 !LYSameFilename(homepage, startfile)) {
5991 /*
5992 * Couldn't return to the first file but there is a
5993 * homepage we can use instead. Useful for when the
5994 * first URL causes a program to be invoked. - GL
5995 *
5996 * But first make sure homepage is different from
5997 * startfile (above), then make it the same (below) so
5998 * we don't enter an infinite getfile() loop on on
5999 * failures to find the files. - FM
6000 */
6001 set_address(&newdoc, homepage);
6002 LYFreePostData(&newdoc);
6003 FREE(newdoc.bookmark);
6004 StrAllocCopy(startfile, homepage);
6005 newdoc.isHEAD = FALSE;
6006 newdoc.safe = FALSE;
6007 newdoc.internal_link = FALSE;
6008 goto try_again;
6009 } else {
6010 CleanupMainLoop();
6011 exit_immediately_with_error_message(NULLFILE, first_file);
6012 return (EXIT_FAILURE);
6013 }
6014 }
6015
6016 /*
6017 * If we're going to pop from history because getfile didn't
6018 * succeed, reset LYforce_no_cache first. This would have been
6019 * done in HTAccess.c if the request got that far, but the URL
6020 * may have been handled or rejected in getfile without taking
6021 * care of that. - kw
6022 */
6023 LYforce_no_cache = FALSE;
6024 /*
6025 * Retrieval of a newdoc just failed, and just going to
6026 * try_again would pop the next doc from history and try to get
6027 * it without further questions. This may not be the right
6028 * thing to do if we have POST data, so fake a PREV_DOC key if
6029 * it seems that some prompting should be done. This doesn't
6030 * affect the traversal logic, since with traversal POST data
6031 * can never occur. - kw
6032 */
6033 if (HDOC(nhist - 1).post_data &&
6034 !HDOC(nhist - 1).safe) {
6035 if (HText_POSTReplyLoaded((DocInfo *) &history[(nhist_1)])) {
6036 override_LYresubmit_posts = TRUE;
6037 goto try_again;
6038 }
6039 /* Set newdoc fields, just in case the PREV_DOC gets
6040 * cancelled. - kw
6041 */
6042 if (!curdoc.address) {
6043 set_address(&newdoc, HTLoadedDocumentURL());
6044 StrAllocCopy(newdoc.title, HTLoadedDocumentTitle());
6045 if (HTMainAnchor
6046 && HTMainAnchor->post_data) {
6047 BStrCopy(newdoc.post_data,
6048 HTMainAnchor->post_data);
6049 StrAllocCopy(newdoc.post_content_type,
6050 HTMainAnchor->post_content_type);
6051 } else {
6052 BStrFree(newdoc.post_data);
6053 }
6054 newdoc.isHEAD = HTLoadedDocumentIsHEAD();
6055 newdoc.safe = HTLoadedDocumentIsSafe();
6056 newdoc.internal_link = FALSE;
6057 } else {
6058 copy_address(&newdoc, &curdoc);
6059 StrAllocCopy(newdoc.title, curdoc.title);
6060 BStrCopy(newdoc.post_data, curdoc.post_data);
6061 StrAllocCopy(newdoc.post_content_type,
6062 curdoc.post_content_type);
6063 newdoc.isHEAD = curdoc.isHEAD;
6064 newdoc.safe = curdoc.safe;
6065 newdoc.internal_link = curdoc.internal_link;
6066 newdoc.line = curdoc.line;
6067 newdoc.link = curdoc.link;
6068 }
6069 cmd = LYK_PREV_DOC;
6070 goto new_cmd;
6071 }
6072 override_LYresubmit_posts = TRUE;
6073 goto try_again;
6074
6075 case NORMAL:
6076 /*
6077 * Marvelously, we got the document!
6078 */
6079 LYoverride_no_cache = FALSE; /* Was TRUE if popped. - FM */
6080 LYinternal_flag = FALSE; /* Reset to default. - kw */
6081 turn_trace_back_on(&trace_mode_flag);
6082
6083 /*
6084 * If it's the first file and we're interactive, check whether
6085 * it's a bookmark file which was not accessed via the -book
6086 * switch. - FM
6087 */
6088 if (((first_file == TRUE) &&
6089 (dump_output_immediately == FALSE) &&
6090 isEmpty(newdoc.bookmark)) &&
6091 ((LYisLocalFile(newdoc.address) == TRUE) &&
6092 !(strcmp(NonNull(HText_getTitle()),
6093 BOOKMARK_TITLE))) &&
6094 (temp = HTParse(newdoc.address, "",
6095 PARSE_PATH + PARSE_PUNCTUATION)) != NULL) {
6096 const char *name = wwwName(Home_Dir());
6097
6098 len = (unsigned) strlen(name);
6099 #ifdef VMS
6100 if (!strncasecomp(temp, name, len) &&
6101 strlen(temp) > len)
6102 #else
6103 if (!StrNCmp(temp, name, len) &&
6104 strlen(temp) > len)
6105 #endif /* VMS */
6106 {
6107 /*
6108 * We're interactive and this might be a bookmark file
6109 * entered as a startfile rather than invoked via
6110 * -book. Check if it's in our bookmark file list, and
6111 * if so, reload if with the relevant bookmark elements
6112 * set. - FM
6113 */
6114 cp = NULL;
6115 if (temp[len] == '/') {
6116 if (strchr(&temp[(len + 1)], '/')) {
6117 HTSprintf0(&cp, ".%s", &temp[len]);
6118 } else {
6119 StrAllocCopy(cp, &temp[(len + 1)]);
6120 }
6121 } else {
6122 StrAllocCopy(cp, &temp[len]);
6123 }
6124 for (i = 0; i <= MBM_V_MAXFILES; i++) {
6125 if (MBM_A_subbookmark[i] &&
6126 LYSameFilename(cp, MBM_A_subbookmark[i])) {
6127 StrAllocCopy(BookmarkPage,
6128 MBM_A_subbookmark[i]);
6129 break;
6130 }
6131 }
6132 FREE(cp);
6133 if (i <= MBM_V_MAXFILES) {
6134 FREE(temp);
6135 if (LYValidate) {
6136 HTAlert(BOOKMARKS_DISABLED);
6137 CleanupMainLoop();
6138 return (EXIT_FAILURE);
6139 }
6140 if ((temp = HTParse(newdoc.address, "",
6141 PARSE_ACCESS + PARSE_HOST + PARSE_PUNCTUATION))) {
6142 set_address(&newdoc, temp);
6143 HTuncache_current_document();
6144 free_address(&curdoc);
6145 StrAllocCat(newdoc.address,
6146 wwwName(Home_Dir()));
6147 StrAllocCat(newdoc.address, "/");
6148 StrAllocCat(newdoc.address,
6149 (StrNCmp(BookmarkPage, "./", 2) ?
6150 BookmarkPage :
6151 (BookmarkPage + 2)));
6152 StrAllocCopy(newdoc.title, BOOKMARK_TITLE);
6153 StrAllocCopy(newdoc.bookmark, BookmarkPage);
6154 #ifdef USE_COLOR_STYLE
6155 if (curdoc.style)
6156 StrAllocCopy(newdoc.style, curdoc.style);
6157 #endif
6158 StrAllocCopy(startrealm, newdoc.address);
6159 LYFreePostData(&newdoc);
6160 newdoc.isHEAD = FALSE;
6161 newdoc.safe = FALSE;
6162 FREE(temp);
6163 if (!strcmp(homepage, startfile))
6164 StrAllocCopy(homepage, newdoc.address);
6165 StrAllocCopy(startfile, newdoc.address);
6166 CTRACE((tfp, "Reloading as bookmarks=%s\n",
6167 newdoc.address));
6168 goto try_again;
6169 }
6170 }
6171 }
6172 cp = NULL;
6173 }
6174 FREE(temp);
6175
6176 if (traversal) {
6177 /*
6178 * During traversal build up lists of all links traversed.
6179 * Traversal mode is a special feature for traversing http
6180 * links in the web.
6181 */
6182 if (traversal_link_to_add) {
6183 /*
6184 * Add the address we sought to TRAVERSE_FILE.
6185 */
6186 if (!lookup_link(traversal_link_to_add))
6187 add_to_table(traversal_link_to_add);
6188 FREE(traversal_link_to_add);
6189 }
6190 if (curdoc.address && curdoc.title &&
6191 !isLYNXIMGMAP(curdoc.address))
6192 /*
6193 * Add the address we got to TRAVERSE_FOUND_FILE.
6194 */
6195 add_to_traverse_list(curdoc.address, curdoc.title);
6196 }
6197
6198 /*
6199 * If this was a LYNXDOWNLOAD, we still have curdoc, not a
6200 * newdoc, so reset the address, title and positioning
6201 * elements. - FM
6202 */
6203 if (newdoc.address && curdoc.address &&
6204 isLYNXDOWNLOAD(newdoc.address)) {
6205 copy_address(&newdoc, &curdoc);
6206 StrAllocCopy(newdoc.title, NonNull(curdoc.title));
6207 StrAllocCopy(newdoc.bookmark, curdoc.bookmark);
6208 newdoc.line = curdoc.line;
6209 newdoc.link = curdoc.link;
6210 newdoc.internal_link = FALSE; /* can't be true. - kw */
6211 }
6212
6213 /*
6214 * Set Newline to the saved line. It contains the line the
6215 * user was on if s/he has been in the file before, or it is 1
6216 * if this is a new file.
6217 *
6218 * We already set Newline before getfile() and probably update
6219 * it explicitly if popping from the history stack via LYpop()
6220 * or LYpop_num() within getfile() cycle.
6221 *
6222 * In partial mode, Newline was probably updated in
6223 * LYMainLoop_pageDisplay() if user scrolled the document while
6224 * loading. Incremental loading stage already closed in
6225 * HT*Copy().
6226 */
6227 #ifdef DISP_PARTIAL
6228 /* Newline = newdoc.line; */
6229 display_partial = FALSE; /* for sure, LYNXfoo:/ may be a problem */
6230 #else
6231 /* Should not be needed either if we remove "DISP_PARTIAL" from
6232 * LYHistory.c, but lets leave it as an important comment for
6233 * now.
6234 */
6235 /* Newline = newdoc.line; */
6236 #endif
6237
6238 /*
6239 * If we are going to a target line or the first page of a
6240 * popped document, override any www_search line result.
6241 */
6242 if (LYGetNewline() > 1 || popped_doc == TRUE)
6243 www_search_result = -1;
6244
6245 /*
6246 * Make sure curdoc.line will not be equal to Newline, so we
6247 * get a redraw.
6248 */
6249 curdoc.line = -1;
6250 break;
6251 } /* end switch */
6252
6253 if (TRACE) {
6254 if (!LYTraceLogFP || trace_mode_flag) {
6255 LYSleepAlert(); /* allow me to look at the results */
6256 }
6257 }
6258
6259 /*
6260 * Set the files the same.
6261 */
6262 copy_address(&curdoc, &newdoc);
6263 BStrCopy(curdoc.post_data, newdoc.post_data);
6264 StrAllocCopy(curdoc.post_content_type, newdoc.post_content_type);
6265 StrAllocCopy(curdoc.bookmark, newdoc.bookmark);
6266 #ifdef USE_COLOR_STYLE
6267 StrAllocCopy(curdoc.style, HText_getStyle());
6268 if (curdoc.style != NULL)
6269 style_readFromFile(curdoc.style);
6270 #endif
6271 curdoc.isHEAD = newdoc.isHEAD;
6272 curdoc.internal_link = newdoc.internal_link;
6273
6274 /*
6275 * Set the remaining document elements and add to the visited links
6276 * list. - FM
6277 */
6278 if (ownerS_address != NULL) {
6279 #ifndef USE_PRETTYSRC
6280 if (HTOutputFormat == WWW_SOURCE && !HText_getOwner())
6281 #else
6282 if ((LYpsrc ? psrc_view : HTOutputFormat == WWW_SOURCE)
6283 && !HText_getOwner())
6284 #endif
6285 HText_setMainTextOwner(ownerS_address);
6286 FREE(ownerS_address);
6287 }
6288 if (HText_getTitle()) {
6289 StrAllocCopy(curdoc.title, HText_getTitle());
6290 } else if (!dump_output_immediately) {
6291 StrAllocCopy(curdoc.title, newdoc.title);
6292 }
6293 StrAllocCopy(owner_address, HText_getOwner());
6294 curdoc.safe = HTLoadedDocumentIsSafe();
6295 if (!dump_output_immediately) {
6296 LYAddVisitedLink(&curdoc);
6297 }
6298
6299 /*
6300 * Reset WWW present mode so that if we were getting the source, we
6301 * get rendered HTML from now on.
6302 */
6303 HTOutputFormat = WWW_PRESENT;
6304 #ifdef USE_PRETTYSRC
6305 psrc_view = FALSE;
6306 #endif
6307
6308 HTMLSetCharacterHandling(current_char_set); /* restore, for sure? */
6309
6310 /*
6311 * Reset all of the other relevant flags. - FM
6312 */
6313 LYUserSpecifiedURL = FALSE; /* only set for gotos and jumps */
6314 LYJumpFileURL = FALSE; /* only set for jumps */
6315 LYNoRefererForThis = FALSE; /* always reset on return here */
6316 reloading = FALSE; /* set for RELOAD and NOCACHE keys */
6317 HEAD_request = FALSE; /* only set for HEAD requests */
6318 LYPermitURL = FALSE; /* only for LYValidate or check_realm */
6319 ForcePush = FALSE; /* only set for some PRINT requests. */
6320 LYforce_HTML_mode = FALSE;
6321 force_old_UCLYhndl_on_reload = FALSE;
6322 popped_doc = FALSE;
6323 pending_form_c = -1;
6324
6325 }
6326 /* end if (LYforce_no_cache || force_load || are_different(...)) */
6327 if (dump_output_immediately) {
6328 if (crawl) {
6329 print_crawl_to_fd(stdout, curdoc.address, curdoc.title);
6330 } else if (!dump_links_only) {
6331 print_wwwfile_to_fd(stdout, FALSE, FALSE);
6332 }
6333 CleanupMainLoop();
6334 return ((dump_server_status >= 400) ? EXIT_FAILURE : EXIT_SUCCESS);
6335 }
6336
6337 /*
6338 * If the recent_sizechange variable is set to TRUE then the window
6339 * size changed recently.
6340 */
6341 if (recent_sizechange) {
6342 /*
6343 * First we need to make sure the display library - curses, slang,
6344 * whatever - gets notified about the change, and gets a chance to
6345 * update external structures appropriately. Hopefully the
6346 * stop_curses()/start_curses() sequence achieves this, at least if
6347 * the display library has a way to get the new screen size from
6348 * the OS.
6349 *
6350 * However, at least for ncurses, the update of the internal
6351 * structures will come still too late - the changed screen size is
6352 * detected in doupdate(), which would only be called (indirectly
6353 * through the HText_pageDisplay below) after the WINDOW structures
6354 * are already filled based on the old size. So we notify the
6355 * ncurses library directly here. - kw
6356 */
6357 #if defined(NCURSES) && defined(HAVE_RESIZETERM) && defined(HAVE_WRESIZE)
6358 resizeterm(LYlines, LYcols);
6359 wresize(LYwin, LYlines, LYcols);
6360 #else
6361 #if 0 /* defined(PDCURSES) && defined(HAVE_XCURSES) */
6362 resize_term(LYlines, LYcols);
6363 if (LYwin != 0)
6364 LYwin = resize_window(LYwin, LYlines, LYcols);
6365 refresh();
6366 #else
6367 stop_curses();
6368 start_curses();
6369 LYclear();
6370 #endif
6371 #endif
6372 refresh_screen = TRUE; /* to force a redraw */
6373 if (HTMainText) /* to REALLY force it... - kw */
6374 HText_setStale(HTMainText);
6375 recent_sizechange = FALSE;
6376
6377 LYSetDisplayLines();
6378 }
6379
6380 if (www_search_result != -1) {
6381 /*
6382 * This was a WWW search, set the line to the result of the search.
6383 */
6384 LYSetNewline(www_search_result);
6385 www_search_result = -1; /* reset */
6386 }
6387
6388 if (first_file == TRUE) {
6389 /*
6390 * We can never again have the first file.
6391 */
6392 first_file = FALSE;
6393
6394 /*
6395 * Set the startrealm, and deal as best we can with preserving
6396 * forced HTML mode for a local startfile. - FM
6397 */
6398 temp = HTParse(curdoc.address, "",
6399 PARSE_ACCESS + PARSE_HOST + PARSE_PUNCTUATION);
6400 if (isEmpty(temp)) {
6401 StrAllocCopy(startrealm, NO_NOTHING);
6402 } else {
6403 StrAllocCopy(startrealm, temp);
6404 FREE(temp);
6405 if (!(temp = HTParse(curdoc.address, "",
6406 PARSE_PATH + PARSE_PUNCTUATION))) {
6407 LYAddHtmlSep(&startrealm);
6408 } else {
6409 if (forced_HTML_mode &&
6410 !dump_output_immediately &&
6411 !curdoc.bookmark &&
6412 isFILE_URL(curdoc.address) &&
6413 strlen(temp) > 1) {
6414 /*
6415 * We forced HTML for a local startfile which is not a
6416 * bookmark file and has a path of at least two
6417 * letters. If it doesn't have a suffix mapped to
6418 * text/html, we'll set the entire path (including the
6419 * lead slash) as a "suffix" mapped to text/html to
6420 * ensure it is always treated as an HTML source file.
6421 * We are counting on a tail match to this full path
6422 * for some other URL fetched during the session having
6423 * too low a probability to worry about, but it could
6424 * happen. - FM
6425 */
6426 HTAtom *encoding;
6427
6428 if (HTFileFormat(temp, &encoding, NULL) != WWW_HTML) {
6429 HTSetSuffix(temp, "text/html", "8bit", 1.0);
6430 }
6431 }
6432 if ((cp = strrchr(temp, '/')) != NULL) {
6433 *(cp + 1) = '\0';
6434 StrAllocCat(startrealm, temp);
6435 }
6436 }
6437 }
6438 FREE(temp);
6439 CTRACE((tfp, "Starting realm is '%s'\n\n", startrealm));
6440 if (traversal) {
6441 /*
6442 * Set up the crawl output stuff.
6443 */
6444 if (curdoc.address && !lookup_link(curdoc.address)) {
6445 if (!isLYNXIMGMAP(curdoc.address))
6446 crawl_ok = TRUE;
6447 add_to_table(curdoc.address);
6448 }
6449 /*
6450 * Set up the traversal_host comparison string.
6451 */
6452 if (StrNCmp((curdoc.address ? curdoc.address : "NULL"),
6453 "http", 4)) {
6454 StrAllocCopy(traversal_host, NO_NOTHING);
6455 } else if (check_realm) {
6456 StrAllocCopy(traversal_host, startrealm);
6457 } else {
6458 temp = HTParse(curdoc.address, "",
6459 PARSE_ACCESS + PARSE_HOST + PARSE_PUNCTUATION);
6460 if (isEmpty(temp)) {
6461 StrAllocCopy(traversal_host, NO_NOTHING);
6462 } else {
6463 StrAllocCopy(traversal_host, temp);
6464 LYAddHtmlSep(&traversal_host);
6465 }
6466 FREE(temp);
6467 }
6468 CTRACE((tfp, "Traversal host is '%s'\n\n", traversal_host));
6469 }
6470 if (startfile) {
6471 /*
6472 * If homepage was not equated to startfile, make the homepage
6473 * URL the first goto entry. - FM
6474 */
6475 if (homepage && strcmp(startfile, homepage))
6476 HTAddGotoURL(homepage);
6477 /*
6478 * If we are not starting up with startfile (e.g., had -book),
6479 * or if we are using the startfile and it has no POST content,
6480 * make the startfile URL a goto entry. - FM
6481 */
6482 if (strcmp(startfile, newdoc.address) ||
6483 newdoc.post_data == NULL)
6484 HTAddGotoURL(startfile);
6485 }
6486 if (TRACE) {
6487 refresh_screen = TRUE;
6488 if (!LYTraceLogFP || trace_mode_flag) {
6489 LYSleepAlert();
6490 }
6491 }
6492 }
6493 #ifdef USE_SOURCE_CACHE
6494 /*
6495 * If the parse settings have changed since this HText was
6496 * generated, we need to reparse and redraw it. -dsb
6497 *
6498 * Should be configured to avoid shock for experienced lynx users.
6499 * Currently enabled for cached sources only.
6500 */
6501 if (HTdocument_settings_changed()) {
6502 if (HTcan_reparse_document()) {
6503 HTInfoMsg(gettext("Reparsing document under current settings..."));
6504 reparse_document();
6505 } else {
6506 /*
6507 * Urk. I have no idea how to recover from a failure here.
6508 * At a guess, I'll try reloading. -dsb
6509 */
6510 /* currently disabled ***
6511 HTUserMsg(gettext("Reparsing document under current settings..."));
6512 cmd = LYK_RELOAD;
6513 goto new_cmd;
6514 */
6515 }
6516 }
6517
6518 if (from_source_cache) {
6519 from_source_cache = FALSE; /* reset */
6520 curdoc.line = -1; /* so curdoc.line != Newline, see below */
6521 }
6522 #endif
6523
6524 /*
6525 * If the curdoc.line is different than Newline then there must have
6526 * been a change since last update. Run HText_pageDisplay() to create
6527 * a fresh screen of text output.
6528 *
6529 * If we got new HTMainText go this way. All display_partial calls
6530 * ends here for final redraw.
6531 */
6532 if (curdoc.line != LYGetNewline()) {
6533 #ifdef INACTIVE_INPUT_STYLE_VH
6534 textinput_redrawn = FALSE;
6535 #endif
6536
6537 refresh_screen = FALSE;
6538
6539 HText_pageDisplay(LYGetNewline(), prev_target->str);
6540
6541 #ifdef DIRED_SUPPORT
6542 if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged))
6543 showtags(tagged);
6544 #endif /* DIRED_SUPPORT */
6545
6546 /*
6547 * Check if there is more info below this page.
6548 */
6549 more_text = HText_canScrollDown();
6550
6551 if (newdoc.link < 0)
6552 goto_line(LYGetNewline());
6553 LYSetNewline(HText_getTopOfScreen() + 1);
6554 curdoc.line = LYGetNewline();
6555
6556 if (curdoc.title == NULL) {
6557 /*
6558 * If we don't yet have a title, try to get it, or set to that
6559 * for newdoc.title. - FM
6560 */
6561 if (HText_getTitle()) {
6562 StrAllocCopy(curdoc.title, HText_getTitle());
6563 } else {
6564 StrAllocCopy(curdoc.title, newdoc.title);
6565 }
6566 }
6567
6568 /*
6569 * If the request is to highlight a link which is counted from the
6570 * start of document, correct the link number:
6571 */
6572 if (newdoc_link_is_absolute) {
6573 newdoc_link_is_absolute = FALSE;
6574 if (curdoc.line > 1)
6575 newdoc.link -= HText_LinksInLines(HTMainText, 1,
6576 curdoc.line - 1);
6577 }
6578
6579 if (arrowup) {
6580 /*
6581 * arrowup is set if we just came up from a page below.
6582 */
6583 curdoc.link = nlinks - 1;
6584 arrowup = FALSE;
6585 } else {
6586 curdoc.link = newdoc.link;
6587 if (curdoc.link >= nlinks) {
6588 curdoc.link = nlinks - 1;
6589 } else if (curdoc.link < 0 && nlinks > 0) {
6590 /*
6591 * We may have popped a doc (possibly in local_dired) which
6592 * didn't have any links when it was pushed, but does have
6593 * links now (e.g., a file was created). Code below
6594 * assumes that curdoc.link is valid and that
6595 * (curdoc.link==-1) only occurs if (nlinks==0) is true. -
6596 * KW
6597 */
6598 curdoc.link = 0;
6599 }
6600 }
6601
6602 show_help = FALSE; /* reset */
6603 newdoc.line = 1;
6604 newdoc.link = 0;
6605 curdoc.line = LYGetNewline(); /* set */
6606 } else if (newdoc.link < 0) {
6607 newdoc.link = 0; /* ...just in case getfile set this */
6608 }
6609
6610 /*
6611 * Refresh the screen if necessary.
6612 */
6613 if (refresh_screen) {
6614 #if defined(FANCY_CURSES) || defined (USE_SLANG)
6615 if (enable_scrollback) {
6616 LYclear();
6617 } else {
6618 LYerase();
6619 }
6620 #else
6621 LYclear();
6622 #endif /* FANCY_CURSES || USE_SLANG */
6623 HText_pageDisplay(LYGetNewline(), prev_target->str);
6624
6625 #ifdef DIRED_SUPPORT
6626 if (lynx_edit_mode && nlinks > 0 && !HTList_isEmpty(tagged))
6627 showtags(tagged);
6628 #endif /* DIRED_SUPPORT */
6629
6630 /*
6631 * Check if there is more info below this page.
6632 */
6633 more_text = HText_canScrollDown();
6634
6635 /*
6636 * Adjust curdoc.link as above; nlinks may have changed, if the
6637 * refresh_screen flag was set as a result of a size change. Code
6638 * below assumes that curdoc.link is valid and that
6639 * (curdoc.link==-1) only occurs if (nlinks==0) is true. - kw
6640 */
6641 if (curdoc.link >= nlinks) {
6642 curdoc.link = nlinks - 1;
6643 } else if (curdoc.link < 0 && nlinks > 0) {
6644 curdoc.link = 0;
6645 }
6646
6647 if (user_mode == NOVICE_MODE)
6648 noviceline(more_text); /* print help message */
6649 refresh_screen = FALSE;
6650
6651 }
6652
6653 curlink_is_editable = (BOOLEAN)
6654 (nlinks > 0 &&
6655 LinkIsTextLike(curdoc.link));
6656
6657 use_last_tfpos = (BOOLEAN)
6658 (curlink_is_editable &&
6659 (real_cmd == LYK_LPOS_PREV_LINK ||
6660 real_cmd == LYK_LPOS_NEXT_LINK));
6661
6662 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
6663 if (!textfields_need_activation)
6664 textinput_activated = TRUE;
6665 #endif
6666
6667 #if defined(WIN_EX) /* 1997/10/08 (Wed) 14:52:06 */
6668 if (nlinks > 0) {
6669 char *p = "LYNX (unknown link type)";
6670
6671 /* Show the URL & kanji code . */
6672 if (strlen(links[curdoc.link].lname) == 0) {
6673
6674 if (links[curdoc.link].type == WWW_FORM_LINK_TYPE) {
6675
6676 switch (links[curdoc.link].l_form->type) {
6677 case F_TEXT_SUBMIT_TYPE:
6678 case F_SUBMIT_TYPE:
6679 case F_IMAGE_SUBMIT_TYPE:
6680 p = "[SUBMIT]";
6681 break;
6682 case F_PASSWORD_TYPE:
6683 p = "Password";
6684 break;
6685 case F_OPTION_LIST_TYPE:
6686 p = "Option list";
6687 break;
6688 case F_CHECKBOX_TYPE:
6689 p = "Check box";
6690 break;
6691 case F_RADIO_TYPE:
6692 p = "[Radio]";
6693 break;
6694 case F_RESET_TYPE:
6695 p = "[Reset]";
6696 break;
6697 case F_TEXT_TYPE:
6698 p = "Text input";
6699 break;
6700 case F_TEXTAREA_TYPE:
6701 p = "Text input lines";
6702 break;
6703 default:
6704 break;
6705 }
6706 set_ws_title(p);
6707 }
6708 } else {
6709 if (user_mode == ADVANCED_MODE) {
6710 p = curdoc.title;
6711 } else {
6712 p = links[curdoc.link].lname;
6713 }
6714
6715 if (strlen(p) < (sizeof(sjis_buff) / 10)) {
6716 strcpy(temp_buff, p);
6717 if (strchr(temp_buff, '%')) {
6718 HTUnEscape(temp_buff);
6719 }
6720 str_sjis(sjis_buff, temp_buff);
6721 set_ws_title(LYElideString(sjis_buff, 10));
6722 }
6723 }
6724 } else {
6725 if (strlen(curdoc.address) < sizeof(temp_buff) - 1) {
6726 if (user_mode == ADVANCED_MODE) {
6727 str_sjis(temp_buff, curdoc.title);
6728 } else {
6729 strcpy(temp_buff, curdoc.address);
6730 }
6731 set_ws_title(HTUnEscape(temp_buff));
6732 }
6733 }
6734 #endif /* WIN_EX */
6735
6736 /*
6737 * Report unread or new mail, if appropriate.
6738 */
6739 if (check_mail && !no_mail)
6740 LYCheckMail();
6741
6742 /*
6743 * If help is not on the screen, then put a message on the screen to
6744 * tell the user other misc info.
6745 */
6746 if (!show_help) {
6747 show_main_statusline(links[curdoc.link],
6748 ((curlink_is_editable &&
6749 textinput_activated)
6750 ? FOR_INPUT
6751 : FOR_PANEL));
6752 } else {
6753 show_help = FALSE;
6754 }
6755
6756 if (nlinks > 0) {
6757 /*
6758 * Highlight current link, unless it is an active text input field.
6759 */
6760 if (!curlink_is_editable) {
6761 LYhighlight(TRUE, curdoc.link, prev_target->str);
6762 #ifndef INACTIVE_INPUT_STYLE_VH
6763 } else if (!textinput_activated) {
6764 LYhighlight(TRUE, curdoc.link, prev_target->str);
6765 #endif
6766 }
6767 }
6768
6769 if (traversal) {
6770 /*
6771 * Don't go interactively into forms, or accept keystrokes from the
6772 * user
6773 */
6774 if (crawl && crawl_ok) {
6775 crawl_ok = FALSE;
6776 #ifdef FNAMES_8_3
6777 sprintf(cfile, "lnk%05d.dat", crawl_count);
6778 #else
6779 sprintf(cfile, "lnk%08d.dat", crawl_count);
6780 #endif /* FNAMES_8_3 */
6781 crawl_count = crawl_count + 1;
6782 if ((cfp = LYNewTxtFile(cfile)) != NULL) {
6783 print_crawl_to_fd(cfp, curdoc.address, curdoc.title);
6784 LYCloseOutput(cfp);
6785 } else {
6786 #ifdef UNIX
6787 FILE *fp = (dump_output_immediately
6788 ? stderr
6789 : stdout);
6790
6791 #else
6792 FILE *fp = stdout;
6793 #endif
6794 if (!dump_output_immediately)
6795 cleanup();
6796 fprintf(fp,
6797 gettext("Fatal error - could not open output file %s\n"),
6798 cfile);
6799 CleanupMainLoop();
6800 if (!dump_output_immediately) {
6801 exit_immediately(EXIT_FAILURE);
6802 }
6803 return (EXIT_FAILURE);
6804 }
6805 }
6806 } else {
6807 /*
6808 * Normal, non-traversal handling.
6809 */
6810 if (curlink_is_editable &&
6811 (textinput_activated || pending_form_c != -1)) {
6812 if (pending_form_c != -1) {
6813 real_c = pending_form_c;
6814 pending_form_c = -1;
6815 } else {
6816 /*
6817 * Replace novice lines if in NOVICE_MODE.
6818 */
6819 if (user_mode == NOVICE_MODE) {
6820 form_noviceline(FormIsReadonly(links[curdoc.link].l_form));
6821 }
6822 real_c = change_form_link(curdoc.link,
6823 &newdoc, &refresh_screen,
6824 use_last_tfpos, FALSE);
6825 }
6826 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
6827 if (textfields_need_activation)
6828 textinput_activated = FALSE;
6829 #ifdef INACTIVE_INPUT_STYLE_VH
6830 textinput_redrawn = FALSE;
6831 #endif
6832 #endif
6833
6834 c = (real_c == LKC_DONE) ? DO_NOTHING : LKC_TO_C(real_c);
6835 if (c != DO_NOTHING &&
6836 peek_mouse_link() != -1 && peek_mouse_link() != -2)
6837 old_c = 0;
6838 if (peek_mouse_link() >= 0 &&
6839 LKC_TO_LAC(keymap, real_c) != LYK_CHANGE_LINK) {
6840 do_change_link();
6841 if ((c == '\n' || c == '\r') &&
6842 LinkIsTextLike(curdoc.link) &&
6843 !textfields_need_activation) {
6844 c = DO_NOTHING;
6845 }
6846 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
6847 } else if (LinkIsTextarea(curdoc.link)
6848 && textfields_need_activation
6849 && !FormIsReadonly(links[curdoc.link].l_form)
6850 && peek_mouse_link() < 0 &&
6851 (((LKC_TO_LAC(keymap, real_c) == LYK_NEXT_LINK ||
6852 #ifdef TEXTAREA_AUTOGROW
6853 LKC_TO_LAC(keymap, real_c) == LYK_ACTIVATE ||
6854 #endif
6855 LKC_TO_LAC(keymap, real_c) == LYK_LPOS_NEXT_LINK ||
6856 LKC_TO_LAC(keymap, real_c) == LYK_DOWN_LINK) &&
6857 ((curdoc.link < nlinks - 1 &&
6858 LinkIsTextarea(curdoc.link + 1)
6859 && (links[curdoc.link].l_form->number ==
6860 links[curdoc.link + 1].l_form->number)
6861 && strcmp(links[curdoc.link].l_form->name,
6862 links[curdoc.link + 1].l_form->name)
6863 == 0) ||
6864 (curdoc.link == nlinks - 1 && more_text &&
6865 HText_TAHasMoreLines(curdoc.link, 1)))) ||
6866 ((LKC_TO_LAC(keymap, real_c) == LYK_PREV_LINK ||
6867 LKC_TO_LAC(keymap, real_c) == LYK_LPOS_PREV_LINK ||
6868 LKC_TO_LAC(keymap, real_c) == LYK_UP_LINK) &&
6869 ((curdoc.link > 0 &&
6870 LinkIsTextarea(curdoc.link - 1)
6871 && (links[curdoc.link].l_form->number ==
6872 links[curdoc.link - 1].l_form->number) &&
6873 strcmp(links[curdoc.link].l_form->name,
6874 links[curdoc.link - 1].l_form->name) == 0)
6875 || (curdoc.link == 0 && curdoc.line > 1 &&
6876 HText_TAHasMoreLines(curdoc.link, -1)))))) {
6877 textinput_activated = TRUE;
6878 #ifdef TEXTAREA_AUTOGROW
6879 if ((c == '\n' || c == '\r') &&
6880 LKC_TO_LAC(keymap, real_c) == LYK_ACTIVATE)
6881 c = LAC_TO_LKC0(LYK_NEXT_LINK);
6882 #endif /* TEXTAREA_AUTOGROW */
6883 #endif /* TEXTFIELDS_MAY_NEED_ACTIVATION */
6884 } else
6885 switch (c) {
6886 case '\n':
6887 case '\r':
6888 #ifdef TEXTAREA_AUTOGROW
6889 /*
6890 * If on the bottom line of a TEXTAREA, and the user
6891 * hit the ENTER key, we add a new line/anchor
6892 * automatically, positioning the cursor on it.
6893 *
6894 * If at the bottom of the screen, we effectively
6895 * perform an LYK_DOWN_HALF-like operation, then move
6896 * down to the new line we just added. --KED 02/14/99
6897 *
6898 * [There is some redundancy and non-standard
6899 * indentation in the monster-if() below. This is
6900 * intentional ... to try and improve the
6901 * "readability" (such as it is). Caveat emptor to
6902 * anyone trying to change it.]
6903 */
6904 if (LinkIsTextarea(curdoc.link)
6905 && ((curdoc.link == nlinks - 1 &&
6906 !(more_text &&
6907 HText_TAHasMoreLines(curdoc.link, 1)))
6908 ||
6909 ((curdoc.link < nlinks - 1) &&
6910 !LinkIsTextarea(curdoc.link + 1))
6911 ||
6912 ((curdoc.link < nlinks - 1) &&
6913 (LinkIsTextarea(curdoc.link + 1)
6914 && ((links[curdoc.link].l_form->number !=
6915 links[curdoc.link + 1].l_form->number) ||
6916 (strcmp(links[curdoc.link].l_form->name,
6917 links[curdoc.link + 1].l_form->name)
6918 != 0)))))) {
6919
6920 HText_ExpandTextarea(&links[curdoc.link], 1);
6921
6922 if (links[curdoc.link].ly < display_lines) {
6923 refresh_screen = TRUE;
6924 } else {
6925 LYChgNewline(display_lines / 2);
6926 if (nlinks > 0 && curdoc.link > -1 &&
6927 links[curdoc.link].ly > display_lines / 2) {
6928 newdoc.link = curdoc.link;
6929 for (i = 0;
6930 links[i].ly <= (display_lines / 2);
6931 i++)
6932 --newdoc.link;
6933 newdoc.link++;
6934 }
6935 }
6936 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
6937 if (textfields_need_activation) {
6938 textinput_activated = TRUE;
6939 textfields_need_activation = textfields_activation_option;
6940 #ifdef INACTIVE_INPUT_STYLE_VH
6941 textinput_redrawn = TRUE;
6942 #endif
6943 };
6944 #endif
6945
6946 }
6947 #endif /* TEXTAREA_AUTOGROW */
6948
6949 /*
6950 * Make return in input field (if it was returned by
6951 * change_form_link) act as LYK_NEXT_LINK, independent
6952 * of what key (if any) is mapped to LYK_NEXT_LINK. -
6953 * kw
6954 */
6955 c = LAC_TO_LKC0(LYK_NEXT_LINK);
6956 break;
6957 default:
6958
6959 if (old_c != c && old_c != real_c && c != real_c)
6960 real_c = c;
6961 }
6962 } else {
6963 #if defined(TEXTFIELDS_MAY_NEED_ACTIVATION) && defined(INACTIVE_INPUT_STYLE_VH)
6964 if (curlink_is_editable && !textinput_redrawn) {
6965 /*draw the text entry, but don't activate it */
6966 textinput_redrawn = TRUE;
6967 change_form_link_ex(curdoc.link,
6968 &newdoc, &refresh_screen,
6969 use_last_tfpos, FALSE, TRUE);
6970 if (LYShowCursor) {
6971 LYmove(links[curdoc.link].ly,
6972 ((links[curdoc.link].lx > 0) ?
6973 (links[curdoc.link].lx - 1) : 0));
6974 } else {
6975 LYHideCursor();
6976 }
6977 }
6978 #endif /* TEXTFIELDS_MAY_NEED_ACTIVATION && INACTIVE_INPUT_STYLE_VH */
6979 /*
6980 * Get a keystroke from the user. Save the last keystroke to
6981 * avoid redundant error reporting.
6982 */
6983 real_c = c = LYgetch(); /* get user input */
6984
6985 if (c != last_key)
6986 key_count = 0;
6987 key_count++;
6988 last_key = c;
6989 #ifndef VMS
6990 if (c == 3) { /* ^C */
6991 /*
6992 * This shouldn't happen. We'll try to deal with whatever
6993 * bug caused it. - FM
6994 */
6995 signal(SIGINT, cleanup_sig);
6996 old_c = 0;
6997 cmd = LYK_QUIT;
6998 goto new_cmd;
6999 }
7000 #endif /* !VMS */
7001 if (LKC_HAS_ESC_MOD(c) && EditBinding(c) != LYE_FORM_PASS) {
7002 /*
7003 * If ESC + <key> was read (and not recognized as a
7004 * terminal escape sequence for another key), ignore the
7005 * ESC modifier and act on <key> only if the line editor
7006 * binding would have passed the same ESC-modified
7007 * lynxkeycode back to us if it had been pressed in a text
7008 * input field. Otherwise set interesting part so that it
7009 * will map to 0, to prevent that ESC + <key> acts like
7010 * <key>, which might be unexpected. - kw
7011 */
7012 c = (c & ~LKC_MASK) | LAC_TO_LKC(0);
7013 }
7014 if (old_c != real_c) {
7015 old_c = 0;
7016 }
7017 }
7018 }
7019
7020 #ifdef VMS
7021 if (HadVMSInterrupt) {
7022 HadVMSInterrupt = FALSE;
7023 c = DO_NOTHING;
7024 }
7025 #else
7026 if (recent_sizechange) {
7027 if (c <= 0)
7028 c = DO_NOTHING;
7029 }
7030 #endif /* VMS */
7031
7032 new_keyboard_input:
7033 /*
7034 * A goto point for new input without going back through the getch()
7035 * loop.
7036 */
7037 if (traversal) {
7038 if ((c = DoTraversal(c, &crawl_ok)) < 0) {
7039 CleanupMainLoop();
7040 return (EXIT_FAILURE);
7041 }
7042 }
7043 /* traversal */
7044 #ifdef WIN_EX
7045 if (c == DO_NOTHING)
7046 cmd = LYK_DO_NOTHING;
7047 else
7048 #endif
7049 cmd = LKC_TO_LAC(keymap, c); /* adds 1 to map EOF to 0 */
7050
7051 #if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE)
7052 if (lynx_edit_mode && !no_dired_support && LKC_TO_LAC(key_override, c))
7053 cmd = LKC_TO_LAC(key_override, c);
7054 #endif /* DIRED_SUPPORT && OK_OVERRIDE */
7055
7056 real_cmd = cmd;
7057
7058 /*
7059 * A goto point for new input without going back through the getch()
7060 * loop.
7061 */
7062 new_cmd:
7063
7064 force_old_UCLYhndl_on_reload = FALSE;
7065 CTRACE_FLUSH(tfp);
7066
7067 if (cmd != LYK_UP_LINK && cmd != LYK_DOWN_LINK)
7068 follow_col = -1;
7069
7070 CTRACE((tfp, "Handling key as %s\n",
7071 ((LYKeycodeToKcmd((LYKeymapCode) cmd) != 0)
7072 ? LYKeycodeToKcmd((LYKeymapCode) cmd)->name
7073 : "unknown")));
7074 switch (cmd) {
7075 case -1:
7076 HTUserMsg(COMMAND_UNKNOWN);
7077 break;
7078 case 0: /* unmapped character */
7079 default:
7080 if (curdoc.link >= 0 && curdoc.link < nlinks &&
7081 LinkIsTextLike(curdoc.link)) {
7082
7083 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
7084 if (textfields_need_activation) {
7085 show_main_statusline(links[curdoc.link], FOR_PANEL);
7086 #ifdef INACTIVE_INPUT_STYLE_VH
7087 textinput_redrawn = FALSE;
7088 #endif
7089 } else
7090 #endif
7091 show_main_statusline(links[curdoc.link], FOR_INPUT);
7092 } else if (more_text) {
7093 HTInfoMsg(MOREHELP);
7094 } else {
7095 HTInfoMsg(HELP);
7096 }
7097 show_help = TRUE;
7098
7099 if (TRACE) {
7100 sprintf(cfile, "%d", c);
7101 LYaddstr(cfile); /* show the user input */
7102 cfile[0] = '\0';
7103 }
7104 break;
7105
7106 case LYK_COMMAND:
7107 cmd = handle_LYK_COMMAND(&user_input_buffer);
7108 goto new_cmd;
7109
7110 case LYK_INTERRUPT:
7111 /*
7112 * No network transmission to interrupt - 'til we multithread.
7113 */
7114 break;
7115
7116 case LYK_F_LINK_NUM:
7117 c = '\0';
7118 /* FALLTHRU */
7119 case LYK_1: /* FALLTHRU */
7120 case LYK_2: /* FALLTHRU */
7121 case LYK_3: /* FALLTHRU */
7122 case LYK_4: /* FALLTHRU */
7123 case LYK_5: /* FALLTHRU */
7124 case LYK_6: /* FALLTHRU */
7125 case LYK_7: /* FALLTHRU */
7126 case LYK_8: /* FALLTHRU */
7127 case LYK_9:
7128 handle_LYK_digit(c, &force_load, &old_c, real_c, &try_internal);
7129 break;
7130
7131 case LYK_SOURCE: /* toggle view source mode */
7132 handle_LYK_SOURCE(&ownerS_address);
7133 break;
7134
7135 case LYK_CHG_CENTER: /* ^Q */
7136
7137 if (no_table_center) {
7138 no_table_center = FALSE;
7139 HTInfoMsg(gettext("TABLE center enable."));
7140 } else {
7141 no_table_center = TRUE;
7142 HTInfoMsg(gettext("TABLE center disable."));
7143 }
7144 /* FALLTHRU */
7145
7146 case LYK_RELOAD: /* control-R to reload and refresh */
7147 handle_LYK_RELOAD(real_cmd);
7148 break;
7149
7150 case LYK_HISTORICAL: /* toggle 'historical' comments parsing */
7151 handle_LYK_HISTORICAL();
7152 break;
7153
7154 case LYK_MINIMAL: /* toggle 'minimal' comments parsing */
7155 handle_LYK_MINIMAL();
7156 break;
7157
7158 case LYK_SOFT_DQUOTES:
7159 handle_LYK_SOFT_DQUOTES();
7160 break;
7161
7162 case LYK_SWITCH_DTD:
7163 handle_LYK_SWITCH_DTD();
7164 break;
7165
7166 case LYK_QUIT: /* quit */
7167 if (handle_LYK_QUIT()) {
7168 CleanupMainLoop();
7169 return (EXIT_SUCCESS);
7170 }
7171 break;
7172
7173 case LYK_ABORT: /* don't ask the user about quitting */
7174 CleanupMainLoop();
7175 return (EXIT_SUCCESS);
7176
7177 case LYK_NEXT_PAGE: /* next page */
7178 handle_LYK_NEXT_PAGE(&old_c, real_c);
7179 break;
7180
7181 case LYK_PREV_PAGE: /* page up */
7182 handle_LYK_PREV_PAGE(&old_c, real_c);
7183 break;
7184
7185 case LYK_UP_TWO:
7186 handle_LYK_UP_TWO(&arrowup, &old_c, real_c);
7187 break;
7188
7189 case LYK_DOWN_TWO:
7190 handle_LYK_DOWN_TWO(&old_c, real_c);
7191 break;
7192
7193 case LYK_UP_HALF:
7194 handle_LYK_UP_HALF(&arrowup, &old_c, real_c);
7195 break;
7196
7197 case LYK_DOWN_HALF:
7198 handle_LYK_DOWN_HALF(&old_c, real_c);
7199 break;
7200
7201 #ifdef CAN_CUT_AND_PASTE
7202 case LYK_TO_CLIPBOARD: /* ^S */
7203 {
7204 char *s;
7205 int ch2;
7206
7207 /* The logic resembles one of ADD_BOOKMARK */
7208 if (nlinks > 0 && links[curdoc.link].lname
7209 && links[curdoc.link].type != WWW_FORM_LINK_TYPE) {
7210 /* Makes sense to copy a link */
7211 _statusline("Copy D)ocument's or L)ink's URL to clipboard or C)ancel?");
7212 ch2 = LYgetch_single();
7213 if (ch2 == 'D')
7214 s = curdoc.address;
7215 else if (ch2 == 'C')
7216 break;
7217 else
7218 s = links[curdoc.link].lname;
7219 } else
7220 s = curdoc.address;
7221 if (isEmpty(s))
7222 HTInfoMsg(gettext("Current URL is empty."));
7223 if (put_clip(s))
7224 HTInfoMsg(gettext("Copy to clipboard failed."));
7225 else if (s == curdoc.address)
7226 HTInfoMsg(gettext("Document URL put to clipboard."));
7227 else
7228 HTInfoMsg(gettext("Link URL put to clipboard."));
7229 }
7230 break;
7231
7232 case LYK_PASTE_URL:
7233 if (no_goto && !LYValidate) { /* Go to not allowed. - FM */
7234 HTUserMsg(GOTO_DISALLOWED);
7235 } else {
7236 unsigned char *s = (unsigned char *) get_clip_grab(), *e, *t;
7237 char *buf;
7238 int len2;
7239
7240 if (!s)
7241 break;
7242 len2 = (int) strlen((const char *) s);
7243 e = s + len2;
7244 while (s < e && strchr(" \t\n\r", *s))
7245 s++;
7246 while (s < e && strchr(" \t\n\r", e[-1]))
7247 e--;
7248 if (s[0] == '<' && e > s && e[-1] == '>') {
7249 s++;
7250 e--;
7251 if (!strncasecomp((const char *) s, "URL:", 4))
7252 s += 4;
7253 }
7254 if (s >= e) {
7255 HTInfoMsg(gettext("No URL in the clipboard."));
7256 break;
7257 }
7258 len = (unsigned) (e - s + 1);
7259 if (len < MAX_LINE)
7260 len = MAX_LINE; /* Required for do_check_goto_URL() */
7261 buf = typeMallocn(char, len);
7262
7263 LYStrNCpy(buf, (const char *) s, (e - s));
7264 t = (unsigned char *) buf;
7265
7266 while (s < e) {
7267 if (strchr(" \t\n\r", *s)) {
7268 int nl2 = 0; /* Keep whitespace without NL - file names! */
7269 unsigned char *s1 = s;
7270
7271 while (strchr(" \t\n\r", *s)) {
7272 if (!nl2 && *s == '\n')
7273 nl2 = 1;
7274 s++;
7275 }
7276 if (!nl2) {
7277 while (s1 < s) {
7278 if (*s1 != '\r' && *s1 != '\n')
7279 *t = *s1;
7280 t++, s1++;
7281 }
7282 }
7283 } else
7284 *t++ = *s++;
7285 }
7286 *t = '\0';
7287 get_clip_release();
7288 BStrCopy0(user_input_buffer, buf);
7289 do_check_goto_URL(&user_input_buffer, &temp, &force_load);
7290 free(buf);
7291 }
7292 break;
7293 #endif
7294
7295 #ifdef KANJI_CODE_OVERRIDE
7296 case LYK_CHG_KCODE:
7297 if (LYRawMode && (HTCJK == JAPANESE)) {
7298 switch (last_kcode) {
7299 case NOKANJI:
7300 last_kcode = SJIS;
7301 break;
7302 case SJIS:
7303 last_kcode = EUC;
7304 break;
7305 case EUC:
7306 last_kcode = NOKANJI;
7307 break;
7308 default:
7309 break;
7310 }
7311 }
7312 LYmove(0, 0);
7313 lynx_start_title_color();
7314 LYaddstr(str_kcode(last_kcode));
7315 lynx_stop_title_color();
7316
7317 break;
7318 #endif
7319
7320 case LYK_REFRESH:
7321 refresh_screen = TRUE;
7322 lynx_force_repaint();
7323 break;
7324
7325 case LYK_HOME:
7326 if (curdoc.line > 1) {
7327 LYSetNewline(1);
7328 } else {
7329 cmd = LYK_PREV_PAGE;
7330 goto new_cmd;
7331 }
7332 break;
7333
7334 case LYK_END:
7335 i = HText_getNumOfLines() - display_lines + 2;
7336 if (i >= 1 && LYGetNewline() != i) {
7337 LYSetNewline(i); /* go to end of file */
7338 arrowup = TRUE; /* position on last link */
7339 } else {
7340 cmd = LYK_NEXT_PAGE;
7341 goto new_cmd;
7342 }
7343 break;
7344
7345 case LYK_FIRST_LINK:
7346 handle_LYK_FIRST_LINK();
7347 break;
7348
7349 case LYK_LAST_LINK:
7350 handle_LYK_LAST_LINK();
7351 break;
7352
7353 case LYK_PREV_LINK:
7354 case LYK_LPOS_PREV_LINK:
7355 handle_LYK_PREV_LINK(&arrowup, &old_c, real_c);
7356 break;
7357
7358 case LYK_NEXT_LINK:
7359 case LYK_LPOS_NEXT_LINK:
7360 handle_LYK_NEXT_LINK(c, &old_c, real_c);
7361 break;
7362
7363 case LYK_FASTFORW_LINK:
7364 handle_LYK_FASTFORW_LINK(&old_c, real_c);
7365 break;
7366
7367 case LYK_FASTBACKW_LINK:
7368 if (handle_LYK_FASTBACKW_LINK(&cmd, &old_c, real_c))
7369 goto new_cmd;
7370 break;
7371
7372 case LYK_UP_LINK:
7373 handle_LYK_UP_LINK(&follow_col, &arrowup, &old_c, real_c);
7374 break;
7375
7376 case LYK_DOWN_LINK:
7377 handle_LYK_DOWN_LINK(&follow_col, &old_c, real_c);
7378 break;
7379
7380 case LYK_CHANGE_LINK:
7381 do_change_link();
7382 #if defined(TEXTFIELDS_MAY_NEED_ACTIVATION) && defined(INACTIVE_INPUT_STYLE_VH)
7383 if (textfields_need_activation)
7384 textinput_redrawn = FALSE;
7385 #endif /* TEXTFIELDS_MAY_NEED_ACTIVATION && INACTIVE_INPUT_STYLE_VH */
7386 break;
7387
7388 case LYK_RIGHT_LINK:
7389 handle_LYK_RIGHT_LINK();
7390 break;
7391
7392 case LYK_LEFT_LINK:
7393 handle_LYK_LEFT_LINK();
7394 break;
7395
7396 case LYK_COOKIE_JAR: /* show the cookie jar */
7397 if (handle_LYK_COOKIE_JAR(&cmd))
7398 goto new_cmd;
7399 break;
7400
7401 #ifdef USE_CACHEJAR
7402 case LYK_CACHE_JAR: /* show the cache jar */
7403 if (handle_LYK_CACHE_JAR(&cmd))
7404 goto new_cmd;
7405 break;
7406 #endif
7407
7408 case LYK_HISTORY: /* show the history page */
7409 if (handle_LYK_HISTORY(ForcePush))
7410 break;
7411
7412 /* FALLTHRU */
7413 case LYK_PREV_DOC: /* back up a level */
7414 switch (handle_PREV_DOC(&cmd, &old_c, real_c)) {
7415 case 1:
7416 CleanupMainLoop();
7417 return (EXIT_SUCCESS);
7418 case 2:
7419 goto new_cmd;
7420 }
7421 break;
7422
7423 case LYK_NEXT_DOC: /* undo back up a level */
7424 handle_NEXT_DOC();
7425 break;
7426
7427 case LYK_NOCACHE: /* Force submission of form or link with no-cache */
7428 if (!handle_LYK_NOCACHE(&old_c, real_c))
7429 break;
7430
7431 /* FALLTHRU */
7432 case LYK_ACTIVATE: /* follow a link */
7433 case LYK_MOUSE_SUBMIT: /* follow a link, submit TEXT_SUBMIT input */
7434 switch (handle_LYK_ACTIVATE(&c,
7435 cmd,
7436 &try_internal,
7437 &refresh_screen,
7438 &force_load,
7439 real_cmd)) {
7440 case 1:
7441 continue;
7442 case 2:
7443 goto new_keyboard_input;
7444 case 3:
7445 pending_form_c = c;
7446 break;
7447 }
7448 break;
7449
7450 case LYK_SUBMIT:
7451 handle_LYK_SUBMIT(curdoc.link, &newdoc, &refresh_screen);
7452 break;
7453
7454 case LYK_RESET:
7455 handle_LYK_RESET(curdoc.link, &refresh_screen);
7456 break;
7457
7458 case LYK_ELGOTO: /* edit URL of current link and go to it */
7459 if (handle_LYK_ELGOTO(&ch, &user_input_buffer, &temp, &old_c, real_c))
7460 do_check_goto_URL(&user_input_buffer, &temp, &force_load);
7461 break;
7462
7463 case LYK_ECGOTO: /* edit current URL and go to to it */
7464 if (handle_LYK_ECGOTO(&ch, &user_input_buffer, &temp, &old_c, real_c))
7465 do_check_goto_URL(&user_input_buffer, &temp, &force_load);
7466 break;
7467
7468 case LYK_GOTO: /* 'g' to goto a random URL */
7469 if (handle_LYK_GOTO(&ch, &user_input_buffer, &temp, &recall,
7470 &URLTotal, &URLNum, &FirstURLRecall, &old_c,
7471 real_c)) {
7472 if (do_check_recall(ch, &user_input_buffer, &temp, URLTotal,
7473 &URLNum, recall, &FirstURLRecall))
7474 do_check_goto_URL(&user_input_buffer, &temp, &force_load);
7475 }
7476 break;
7477
7478 case LYK_DWIMHELP: /* show context-dependent help file */
7479 handle_LYK_DWIMHELP(&cshelpfile);
7480 /* FALLTHRU */
7481
7482 case LYK_HELP: /* show help file */
7483 handle_LYK_HELP(&cshelpfile);
7484 break;
7485
7486 case LYK_INDEX: /* index file */
7487 handle_LYK_INDEX(&old_c, real_c);
7488 break;
7489
7490 case LYK_MAIN_MENU: /* return to main screen */
7491 handle_LYK_MAIN_MENU(&old_c, real_c);
7492 break;
7493
7494 #ifdef EXP_NESTED_TABLES
7495 case LYK_NESTED_TABLES:
7496 if (handle_LYK_NESTED_TABLES(&cmd))
7497 goto new_cmd;
7498 break;
7499 #endif
7500 case LYK_OPTIONS: /* options screen */
7501 if (handle_LYK_OPTIONS(&cmd, &refresh_screen))
7502 goto new_cmd;
7503 break;
7504
7505 case LYK_INDEX_SEARCH: /* search for a user string */
7506 handle_LYK_INDEX_SEARCH(&force_load, ForcePush, &old_c, real_c);
7507 break;
7508
7509 case LYK_WHEREIS: /* search within the document */
7510 case LYK_NEXT: /* find the next occurrence in the document */
7511 case LYK_PREV: /* find the previous occurrence in the document */
7512 handle_LYK_WHEREIS(cmd, &refresh_screen);
7513 break;
7514
7515 case LYK_COMMENT: /* reply by mail */
7516 handle_LYK_COMMENT(&refresh_screen, &owner_address, &old_c, real_c);
7517 break;
7518
7519 #ifdef DIRED_SUPPORT
7520 case LYK_TAG_LINK: /* tag or untag the current link */
7521 handle_LYK_TAG_LINK();
7522 break;
7523
7524 case LYK_MODIFY: /* rename a file or directory */
7525 handle_LYK_MODIFY(&refresh_screen);
7526 break;
7527
7528 case LYK_CREATE: /* create a new file or directory */
7529 handle_LYK_CREATE();
7530 break;
7531 #endif /* DIRED_SUPPORT */
7532
7533 case LYK_DWIMEDIT: /* context-dependent edit */
7534 switch (handle_LYK_DWIMEDIT(&cmd, &old_c, real_c)) {
7535 case 1:
7536 continue;
7537 case 2:
7538 goto new_cmd;
7539 }
7540 /* FALLTHRU */
7541
7542 case LYK_EDIT: /* edit */
7543 handle_LYK_EDIT(&old_c, real_c);
7544 break;
7545
7546 case LYK_DEL_BOOKMARK: /* remove a bookmark file link */
7547 handle_LYK_DEL_BOOKMARK(&refresh_screen, &old_c, real_c);
7548 break;
7549
7550 #ifdef DIRED_SUPPORT
7551 case LYK_REMOVE: /* remove files and directories */
7552 handle_LYK_REMOVE(&refresh_screen);
7553 break;
7554 #endif /* DIRED_SUPPORT */
7555
7556 #if defined(DIRED_SUPPORT) && defined(OK_INSTALL)
7557 case LYK_INSTALL: /* install a file into system area */
7558 handle_LYK_INSTALL();
7559 break;
7560 #endif /* DIRED_SUPPORT && OK_INSTALL */
7561
7562 case LYK_INFO: /* show document info */
7563 if (handle_LYK_INFO(&cmd))
7564 goto new_cmd;
7565 break;
7566
7567 case LYK_EDIT_TEXTAREA: /* use external editor on a TEXTAREA - KED */
7568 handle_LYK_EDIT_TEXTAREA(&refresh_screen, &old_c, real_c);
7569 break;
7570
7571 case LYK_GROW_TEXTAREA: /* add new lines to bottom of TEXTAREA - KED */
7572 handle_LYK_GROW_TEXTAREA(&refresh_screen);
7573 break;
7574
7575 case LYK_INSERT_FILE: /* insert file in TEXTAREA, above cursor - KED */
7576 handle_LYK_INSERT_FILE(&refresh_screen, &old_c, real_c);
7577 break;
7578
7579 case LYK_PRINT: /* print the file */
7580 handle_LYK_PRINT(&ForcePush, &old_c, real_c);
7581 break;
7582
7583 case LYK_LIST: /* list links in the current document */
7584 if (handle_LYK_LIST(&cmd))
7585 goto new_cmd;
7586 break;
7587
7588 #ifdef USE_ADDRLIST_PAGE
7589 case LYK_ADDRLIST: /* always list URLs (only) */
7590 if (handle_LYK_ADDRLIST(&cmd))
7591 goto new_cmd;
7592 break;
7593 #endif /* USE_ADDRLIST_PAGE */
7594
7595 case LYK_VLINKS: /* list links visited during the current session */
7596 if (handle_LYK_VLINKS(&cmd, &newdoc_link_is_absolute))
7597 goto new_cmd;
7598 break;
7599
7600 case LYK_TOOLBAR: /* go to Toolbar or Banner in current document */
7601 handle_LYK_TOOLBAR(&try_internal, &force_load, &old_c, real_c);
7602 break;
7603
7604 #if defined(DIRED_SUPPORT) || defined(VMS)
7605 case LYK_DIRED_MENU: /* provide full file management menu */
7606 handle_LYK_DIRED_MENU(&refresh_screen, &old_c, real_c);
7607 break;
7608 #endif /* DIRED_SUPPORT || VMS */
7609
7610 #ifdef USE_EXTERNALS
7611 case LYK_EXTERN_LINK: /* use external program on url */
7612 handle_LYK_EXTERN_LINK(&refresh_screen);
7613 break;
7614 case LYK_EXTERN_PAGE: /* use external program on current page */
7615 handle_LYK_EXTERN_PAGE(&refresh_screen);
7616 break;
7617 #endif /* USE_EXTERNALS */
7618
7619 case LYK_ADD_BOOKMARK: /* add link to bookmark file */
7620 handle_LYK_ADD_BOOKMARK(&refresh_screen, &old_c, real_c);
7621 break;
7622
7623 case LYK_VIEW_BOOKMARK: /* v to view home page */
7624 handle_LYK_VIEW_BOOKMARK(&refresh_screen, &old_c, real_c);
7625 break;
7626
7627 case LYK_SHELL: /* (!) shell escape */
7628 handle_LYK_SHELL(&refresh_screen, &old_c, real_c);
7629 break;
7630
7631 case LYK_DOWNLOAD:
7632 switch (handle_LYK_DOWNLOAD(&cmd, &old_c, real_c)) {
7633 case 1:
7634 continue;
7635 case 2:
7636 goto new_cmd;
7637 }
7638 break;
7639
7640 #ifdef DIRED_SUPPORT
7641 case LYK_UPLOAD:
7642 handle_LYK_UPLOAD();
7643 break;
7644 #endif /* DIRED_SUPPORT */
7645
7646 case LYK_TRACE_TOGGLE: /* Toggle TRACE mode. */
7647 handle_LYK_TRACE_TOGGLE();
7648 break;
7649
7650 case LYK_TRACE_LOG: /* View TRACE log. */
7651 handle_LYK_TRACE_LOG(&trace_mode_flag);
7652 break;
7653
7654 case LYK_IMAGE_TOGGLE:
7655 if (handle_LYK_IMAGE_TOGGLE(&cmd))
7656 goto new_cmd;
7657 break;
7658
7659 case LYK_INLINE_TOGGLE:
7660 if (handle_LYK_INLINE_TOGGLE(&cmd))
7661 goto new_cmd;
7662 break;
7663
7664 case LYK_RAW_TOGGLE:
7665 if (handle_LYK_RAW_TOGGLE(&cmd))
7666 goto new_cmd;
7667 break;
7668
7669 case LYK_HEAD:
7670 if (handle_LYK_HEAD(&cmd))
7671 goto new_cmd;
7672 break;
7673
7674 case LYK_TOGGLE_HELP:
7675 handle_LYK_TOGGLE_HELP();
7676 break;
7677
7678 case LYK_KEYMAP:
7679 handle_LYK_KEYMAP(&vi_keys_flag, &emacs_keys_flag, &old_c, real_c);
7680 break;
7681
7682 case LYK_JUMP:
7683 if (handle_LYK_JUMP(c, &user_input_buffer, &temp, &recall,
7684 &FirstURLRecall, &URLNum, &URLTotal, &ch,
7685 &old_c, real_c)) {
7686 if (do_check_recall(ch, &user_input_buffer, &temp, URLTotal,
7687 &URLNum, recall, &FirstURLRecall))
7688 do_check_goto_URL(&user_input_buffer, &temp, &force_load);
7689 }
7690 break;
7691
7692 case LYK_CLEAR_AUTH:
7693 handle_LYK_CLEAR_AUTH(&old_c, real_c);
7694 break;
7695
7696 case LYK_DO_NOTHING: /* pretty self explanatory */
7697 break;
7698 #ifdef SUPPORT_CHDIR
7699 case LYK_CHDIR:
7700 handle_LYK_CHDIR();
7701 break;
7702 case LYK_PWD:
7703 handle_LYK_PWD();
7704 break;
7705 #endif
7706 #ifdef USE_CURSES_PADS
7707 case LYK_SHIFT_LEFT:
7708 handle_LYK_SHIFT_LEFT(&refresh_screen, key_count);
7709 break;
7710 case LYK_SHIFT_RIGHT:
7711 handle_LYK_SHIFT_RIGHT(&refresh_screen, key_count);
7712 break;
7713 case LYK_LINEWRAP_TOGGLE:
7714 if (handle_LYK_LINEWRAP_TOGGLE(&cmd, &refresh_screen))
7715 goto new_cmd;
7716 break;
7717 #endif
7718
7719 #ifdef USE_MAXSCREEN_TOGGLE
7720 case LYK_MAXSCREEN_TOGGLE:
7721 if (handle_LYK_MAXSCREEN_TOGGLE(&cmd))
7722 goto new_cmd;
7723 break;
7724 #endif
7725 } /* end of BIG switch */
7726 }
7727 }
7728
are_different(DocInfo * doc1,DocInfo * doc2)7729 static int are_different(DocInfo *doc1, DocInfo *doc2)
7730 {
7731 char *cp1, *cp2;
7732
7733 /*
7734 * Do we have two addresses?
7735 */
7736 if (!doc1->address || !doc2->address)
7737 return (TRUE);
7738
7739 /*
7740 * Do they differ in the type of request?
7741 */
7742 if (doc1->isHEAD != doc2->isHEAD)
7743 return (TRUE);
7744
7745 /*
7746 * See if the addresses are different, making sure we're not tripped up by
7747 * multiple anchors in the the same document from a POST form. -- FM
7748 */
7749 cp1 = trimPoundSelector(doc1->address);
7750 cp2 = trimPoundSelector(doc2->address);
7751 /*
7752 * Are the base addresses different?
7753 */
7754 if (strcmp(doc1->address, doc2->address)) {
7755 restorePoundSelector(cp1);
7756 restorePoundSelector(cp2);
7757 return (TRUE);
7758 }
7759 restorePoundSelector(cp1);
7760 restorePoundSelector(cp2);
7761
7762 /*
7763 * Do the docs have different contents?
7764 */
7765 if (doc1->post_data) {
7766 if (doc2->post_data) {
7767 if (!BINEQ(doc1->post_data, doc2->post_data))
7768 return (TRUE);
7769 } else
7770 return (TRUE);
7771 } else if (doc2->post_data)
7772 return (TRUE);
7773
7774 /*
7775 * We'll assume the two documents in fact are the same.
7776 */
7777 return (FALSE);
7778 }
7779
7780 /* This determines whether two docs are _physically_ different,
7781 * meaning they are "from different files". - kw
7782 */
are_phys_different(DocInfo * doc1,DocInfo * doc2)7783 static int are_phys_different(DocInfo *doc1, DocInfo *doc2)
7784 {
7785 char *cp1, *cp2, *ap1 = doc1->address, *ap2 = doc2->address;
7786
7787 /*
7788 * Do we have two addresses?
7789 */
7790 if (!doc1->address || !doc2->address)
7791 return (TRUE);
7792
7793 /*
7794 * Do they differ in the type of request?
7795 */
7796 if (doc1->isHEAD != doc2->isHEAD)
7797 return (TRUE);
7798
7799 /*
7800 * Skip over possible LYNXIMGMAP parts. - kw
7801 */
7802 if (isLYNXIMGMAP(doc1->address))
7803 ap1 += LEN_LYNXIMGMAP;
7804 if (isLYNXIMGMAP(doc2->address))
7805 ap2 += LEN_LYNXIMGMAP;
7806 /*
7807 * If there isn't any real URL in doc2->address, but maybe just
7808 * a fragment, doc2 is assumed to be an internal reference in
7809 * the same physical document, so return FALSE. - kw
7810 */
7811 if (*ap2 == '\0' || *ap2 == '#')
7812 return (FALSE);
7813
7814 /*
7815 * See if the addresses are different, making sure we're not tripped up by
7816 * multiple anchors in the the same document from a POST form. -- FM
7817 */
7818 cp1 = trimPoundSelector(doc1->address);
7819 cp2 = trimPoundSelector(doc2->address);
7820 /*
7821 * Are the base addresses different?
7822 */
7823 if (strcmp(ap1, ap2)) {
7824 restorePoundSelector(cp1);
7825 restorePoundSelector(cp2);
7826 return (TRUE);
7827 }
7828 restorePoundSelector(cp1);
7829 restorePoundSelector(cp2);
7830
7831 /*
7832 * Do the docs have different contents?
7833 */
7834 if (doc1->post_data) {
7835 if (doc2->post_data) {
7836 if (!BINEQ(doc1->post_data, doc2->post_data))
7837 return (TRUE);
7838 } else
7839 return (TRUE);
7840 } else if (doc2->post_data)
7841 return (TRUE);
7842
7843 /*
7844 * We'll assume the two documents in fact are the same.
7845 */
7846 return (FALSE);
7847 }
7848
7849 /*
7850 * Utility for freeing the list of goto URLs. - FM
7851 */
7852 #ifdef LY_FIND_LEAKS
HTGotoURLs_free(void)7853 static void HTGotoURLs_free(void)
7854 {
7855 LYFreeStringList(Goto_URLs);
7856 Goto_URLs = NULL;
7857 }
7858 #endif
7859
7860 /*
7861 * Utility for listing Goto URLs, making any repeated URLs the most current in
7862 * the list. - FM
7863 */
HTAddGotoURL(char * url)7864 void HTAddGotoURL(char *url)
7865 {
7866 char *copy = NULL;
7867 char *old;
7868 HTList *cur;
7869
7870 if (isEmpty(url))
7871 return;
7872
7873 CTRACE((tfp, "HTAddGotoURL %s\n", url));
7874 StrAllocCopy(copy, url);
7875
7876 if (!Goto_URLs) {
7877 Goto_URLs = HTList_new();
7878 #ifdef LY_FIND_LEAKS
7879 atexit(HTGotoURLs_free);
7880 #endif
7881 HTList_addObject(Goto_URLs, copy);
7882 return;
7883 }
7884
7885 cur = Goto_URLs;
7886 while (NULL != (old = (char *) HTList_nextObject(cur))) {
7887 if (!strcmp(old, copy)) {
7888 HTList_removeObject(Goto_URLs, old);
7889 FREE(old);
7890 break;
7891 }
7892 }
7893 HTList_addObject(Goto_URLs, copy);
7894
7895 return;
7896 }
7897
7898 /*
7899 * When help is not on the screen, put a message on the screen to tell the user
7900 * other misc info.
7901 */
show_main_statusline(const LinkInfo curlink,int for_what)7902 static void show_main_statusline(const LinkInfo curlink,
7903 int for_what)
7904 {
7905 /*
7906 * Make sure form novice lines are replaced.
7907 */
7908 if (user_mode == NOVICE_MODE && for_what != FOR_INPUT) {
7909 noviceline(more_text);
7910 }
7911
7912 if (HTisDocumentSource()) {
7913 /*
7914 * Currently displaying HTML source.
7915 */
7916 _statusline(SOURCE_HELP);
7917
7918 /*
7919 * If we are in forms mode then explicitly tell the user what each kind
7920 * of link is.
7921 */
7922 #ifdef INDICATE_FORMS_MODE_FOR_ALL_LINKS_ON_PAGE
7923 } else if (lynx_mode == FORMS_LYNX_MODE && nlinks > 0) {
7924 #else
7925 #ifdef NORMAL_NON_FORM_LINK_STATUSLINES_FOR_ALL_USER_MODES
7926 } else if (lynx_mode == FORMS_LYNX_MODE && nlinks > 0 &&
7927 !(curlink.type & WWW_LINK_TYPE)) {
7928 #else
7929 } else if (lynx_mode == FORMS_LYNX_MODE && nlinks > 0 &&
7930 !(user_mode == ADVANCED_MODE &&
7931 (curlink.type & WWW_LINK_TYPE))) {
7932 #endif /* NORMAL_NON_FORM_LINK_STATUSLINES_FOR_ALL_USER_MODES */
7933 #endif /* INDICATE_FORMS_MODE_FOR_ALL_LINKS_ON_PAGE */
7934 if (curlink.type == WWW_FORM_LINK_TYPE) {
7935 show_formlink_statusline(curlink.l_form, for_what);
7936 } else {
7937 statusline(NORMAL_LINK_MESSAGE);
7938 }
7939
7940 /*
7941 * Let them know if it's an index -- very rare.
7942 */
7943 if (is_www_index) {
7944 const char *indx = gettext("-index-");
7945
7946 LYmove(LYlines - 1, LYcolLimit - (int) strlen(indx));
7947 lynx_start_reverse();
7948 LYaddstr(indx);
7949 lynx_stop_reverse();
7950 }
7951
7952 } else if (user_mode == ADVANCED_MODE && nlinks > 0) {
7953 /*
7954 * Show the URL or, for some internal links, the fragment
7955 */
7956 char *cp = NULL;
7957
7958 if (curlink.type == WWW_INTERN_LINK_TYPE &&
7959 !isLYNXIMGMAP(curlink.lname)) {
7960 cp = findPoundSelector(curlink.lname);
7961 }
7962 if (!cp)
7963 cp = curlink.lname;
7964 status_link(cp, more_text, is_www_index);
7965 } else if (is_www_index && more_text) {
7966 char buf[128];
7967
7968 sprintf(buf, WWW_INDEX_MORE_MESSAGE, key_for_func(LYK_INDEX_SEARCH));
7969 _statusline(buf);
7970 } else if (is_www_index) {
7971 char buf[128];
7972
7973 sprintf(buf, WWW_INDEX_MESSAGE, key_for_func(LYK_INDEX_SEARCH));
7974 _statusline(buf);
7975 } else if (more_text) {
7976 if (user_mode == NOVICE_MODE)
7977 _statusline(MORE);
7978 else
7979 _statusline(MOREHELP);
7980 } else {
7981 _statusline(HELP);
7982 }
7983
7984 /* turn off cursor since now it's probably on statusline -HV */
7985 /* But not if LYShowCursor is on. -show_cursor may be used as a
7986 * workaround to avoid putting the cursor in the last position, for
7987 * curses implementations or terminals that cannot deal with that
7988 * correctly. - kw */
7989 if (!LYShowCursor) {
7990 LYHideCursor();
7991 }
7992 }
7993
7994 /*
7995 * Public function for redrawing the statusline appropriate for the selected
7996 * link. It should only be called at times when curdoc.link, nlinks, and the
7997 * links[] array are valid. - kw
7998 */
repaint_main_statusline(int for_what)7999 void repaint_main_statusline(int for_what)
8000 {
8001 if (curdoc.link >= 0 && curdoc.link < nlinks)
8002 show_main_statusline(links[curdoc.link], for_what);
8003 }
8004
form_noviceline(int disabled)8005 static void form_noviceline(int disabled)
8006 {
8007 LYmove(LYlines - 2, 0);
8008 LYclrtoeol();
8009 if (!disabled) {
8010 LYaddstr(FORM_NOVICELINE_ONE);
8011 }
8012 LYmove(LYlines - 1, 0);
8013 LYclrtoeol();
8014 if (disabled)
8015 return;
8016 if (EditBinding(FROMASCII('\025')) == LYE_ERASE) {
8017 LYaddstr(FORM_NOVICELINE_TWO);
8018 } else if (EditBinding(FROMASCII('\025')) == LYE_DELBL) {
8019 LYaddstr(FORM_NOVICELINE_TWO_DELBL);
8020 } else {
8021 char *temp = NULL;
8022 char *erasekey = fmt_keys(LYKeyForEditAction(LYE_ERASE), -1);
8023
8024 if (erasekey) {
8025 HTSprintf0(&temp, FORM_NOVICELINE_TWO_VAR, erasekey);
8026 } else {
8027 erasekey = fmt_keys(LYKeyForEditAction(LYE_DELBL), -1);
8028 if (erasekey)
8029 HTSprintf0(&temp,
8030 FORM_NOVICELINE_TWO_DELBL_VAR, erasekey);
8031 }
8032 if (temp) {
8033 LYaddstr(temp);
8034 FREE(temp);
8035 }
8036 FREE(erasekey);
8037 }
8038 }
8039
exit_immediately_with_error_message(int state,int first_file)8040 static void exit_immediately_with_error_message(int state, int first_file)
8041 {
8042 char *buf = 0;
8043 char *buf2 = 0;
8044
8045 if (first_file) {
8046 /* print statusline messages as a hint, if any */
8047 LYstatusline_messages_on_exit(&buf2);
8048 }
8049
8050 if (state == NOT_FOUND) {
8051 HTSprintf0(&buf, "%s\n%s %s\n",
8052 NonNull(buf2),
8053 gettext("lynx: Can't access startfile"),
8054 /*
8055 * hack: if we fail in HTAccess.c
8056 * avoid duplicating URL, oh.
8057 */
8058 (buf2 && strstr(buf2, gettext("Can't Access"))) ?
8059 "" : startfile);
8060 }
8061
8062 if (state == NULLFILE) {
8063 HTSprintf0(&buf, "%s\n%s\n%s\n",
8064 NonNull(buf2),
8065 gettext("lynx: Start file could not be found or is not text/html or text/plain"),
8066 gettext(" Exiting..."));
8067 }
8068
8069 FREE(buf2);
8070
8071 if (!dump_output_immediately)
8072 cleanup();
8073
8074 if (buf != 0) {
8075 #ifdef UNIX
8076 if (dump_output_immediately) {
8077 fputs(buf, stderr);
8078 } else
8079 #endif /* UNIX */
8080 {
8081 SetOutputMode(O_TEXT);
8082 fputs(buf, stdout);
8083 SetOutputMode(O_BINARY);
8084 }
8085
8086 FREE(buf);
8087 }
8088
8089 if (!dump_output_immediately) {
8090 exit_immediately(EXIT_FAILURE);
8091 }
8092 /* else: return(EXIT_FAILURE) in mainloop */
8093 }
8094
status_link(char * curlink_name,int show_more,int show_indx)8095 static void status_link(char *curlink_name,
8096 int show_more,
8097 int show_indx)
8098 {
8099 #define MAX_STATUS (LYcolLimit - 1)
8100 #define MIN_STATUS 0
8101 char format[MAX_LINE];
8102 int prefix = 0;
8103 int length;
8104
8105 *format = 0;
8106 if (show_more && !nomore) {
8107 sprintf(format, "%.*s ",
8108 (int) (sizeof(format) - 2),
8109 gettext("-more-"));
8110 prefix = (int) strlen(format);
8111 }
8112 if (show_indx) {
8113 sprintf(format + prefix, "%.*s ",
8114 ((int) sizeof(format) - prefix - 2),
8115 gettext("-index-"));
8116 }
8117 prefix = (int) strlen(format);
8118 length = (int) strlen(curlink_name);
8119
8120 if (prefix > MAX_STATUS || prefix >= MAX_LINE - 1) {
8121 _user_message("%s", format); /* no room for url */
8122 } else {
8123 sprintf(format + prefix, "%%.%ds", MAX_STATUS - prefix);
8124
8125 if ((length + prefix > MAX_STATUS) && long_url_ok) {
8126 char *buf = NULL;
8127 int cut_from_pos;
8128 int cut_to_pos;
8129 int n;
8130
8131 StrAllocCopy(buf, curlink_name);
8132 /*
8133 * Scan to find the final leaf of the URL. Ignore trailing '/'.
8134 */
8135 for (cut_to_pos = length - 2;
8136 (cut_to_pos > 0) && (buf[cut_to_pos] != '/');
8137 cut_to_pos--) ;
8138 /*
8139 * Jump back to the next leaf to remove.
8140 */
8141 for (cut_from_pos = cut_to_pos - 4;
8142 (cut_from_pos > 0) && ((buf[cut_from_pos] != '/')
8143 || ((prefix + cut_from_pos
8144 + 4
8145 + (length - cut_to_pos)) >= MAX_STATUS));
8146 cut_from_pos--) ;
8147 /*
8148 * Replace some leaves to '...', if possible, and put the final
8149 * leaf at the end. We assume that one can recognize the link from
8150 * at least MIN_STATUS characters.
8151 */
8152 if (cut_from_pos > MIN_STATUS) {
8153 for (n = 1; n <= 3; n++)
8154 buf[cut_from_pos + n] = '.';
8155 for (n = 0; cut_to_pos + n <= length; n++)
8156 buf[cut_from_pos + 4 + n] = buf[cut_to_pos + n];
8157 }
8158 _user_message(format, buf);
8159 CTRACE((tfp, "lastline = %s\n", buf)); /* don't forget to erase me */
8160 FREE(buf);
8161 } else { /* show (possibly truncated) url */
8162 _user_message(format, curlink_name);
8163 }
8164 }
8165 }
8166
LYDownLoadAddress(void)8167 const char *LYDownLoadAddress(void)
8168 {
8169 return NonNull(newdoc.address);
8170 }
8171