1 /* $LynxId: LYForms.c,v 1.103 2013/05/04 12:58:54 tom Exp $ */
2 #include <HTUtils.h>
3 #include <HTCJK.h>
4 #include <HTTP.h>
5 #include <HTAlert.h>
6 #include <LYCurses.h>
7 #include <GridText.h>
8 #include <LYCharSets.h>
9 #include <UCAux.h>
10 #include <LYGlobalDefs.h>
11 #include <LYUtils.h>
12 #include <LYStrings.h>
13 #include <LYKeymap.h>
14 #include <LYClean.h>
15 
16 #include <LYLeaks.h>
17 
18 #ifdef USE_COLOR_STYLE
19 #include <AttrList.h>
20 #include <LYHash.h>
21 #endif
22 
23 #if defined(VMS) && !defined(USE_SLANG)
24 #define CTRL_W_HACK DO_NOTHING
25 #else
26 #define CTRL_W_HACK 23		/* CTRL-W refresh without clearok */
27 #endif /* VMS && !USE_SLANG */
28 
29 static int form_getstr(int cur,
30 		       int use_last_tfpos,
31 		       int redraw_only);
32 
33 /*
34  * Returns an array of pointers to the given list
35  */
options_list(OptionType * opt_ptr)36 static char **options_list(OptionType * opt_ptr)
37 {
38     char **result = 0;
39     size_t len;
40     int pass;
41     OptionType *tmp_ptr;
42 
43     for (pass = 0; pass < 2; pass++) {
44 	for (tmp_ptr = opt_ptr, len = 0; tmp_ptr != 0; tmp_ptr = tmp_ptr->next) {
45 	    if (pass != 0)
46 		result[len] = tmp_ptr->name;
47 	    len++;
48 	}
49 	if (pass == 0) {
50 	    len++;
51 	    result = typecallocn(char *, len);
52 
53 	    if (result == 0)
54 		outofmem(__FILE__, "options_list");
55 	} else {
56 	    result[len] = 0;
57 	}
58     }
59 
60     return result;
61 }
62 
change_form_link_ex(int cur,DocInfo * newdoc,BOOLEAN * refresh_screen,int use_last_tfpos,int immediate_submit,int redraw_only)63 int change_form_link_ex(int cur,
64 			DocInfo *newdoc,
65 			BOOLEAN *refresh_screen,
66 			int use_last_tfpos,
67 			int immediate_submit,
68 			int redraw_only)
69 {
70     FormInfo *form = links[cur].l_form;
71     char *link_name;
72     char *link_value;
73     int newdoc_changed = 0;
74     int c = DO_NOTHING;
75     int title_adjust = (no_title ? -TITLE_LINES : 0);
76     char **my_data = 0;
77 
78     /*
79      * If there is no form to perform action on, don't do anything.
80      */
81     if (form == NULL) {
82 	return (c);
83     }
84     link_name = form->name;
85     link_value = form->value;
86     my_data = options_list(form->select_list);
87 
88     /*
89      * Move to the link position.
90      */
91     LYmove(links[cur].ly + title_adjust, links[cur].lx);
92 
93     switch (form->type) {
94     case F_CHECKBOX_TYPE:
95 	if (FormIsReadonly(form))
96 	    break;
97 	LYSetHilite(cur, form->num_value ? unchecked_box : checked_box);
98 	form->num_value = !form->num_value;
99 	break;
100 
101     case F_OPTION_LIST_TYPE:
102 	if (form->select_list == 0) {
103 	    HTAlert(BAD_HTML_NO_POPUP);
104 	    c = DO_NOTHING;
105 	    break;
106 	}
107 
108 	if (FormIsReadonly(form)) {
109 	    (void) LYhandlePopupList(form->num_value,
110 				     links[cur].ly,
111 				     links[cur].lx,
112 				     (STRING2PTR) my_data,
113 				     form->size,
114 				     form->size_l,
115 				     FormIsReadonly(form),
116 				     FALSE);
117 #if CTRL_W_HACK != DO_NOTHING
118 	    if (!enable_scrollback)
119 		c = CTRL_W_HACK;	/* CTRL-W refresh without clearok */
120 	    else
121 #endif
122 		c = 12;		/* CTRL-L for repaint */
123 	    break;
124 	}
125 	form->num_value = LYhandlePopupList(form->num_value,
126 					    links[cur].ly,
127 					    links[cur].lx,
128 					    (STRING2PTR) my_data,
129 					    form->size,
130 					    form->size_l,
131 					    FormIsReadonly(form),
132 					    FALSE);
133 	{
134 	    OptionType *opt_ptr = form->select_list;
135 	    int i;
136 
137 	    for (i = 0; i < form->num_value; i++, opt_ptr = opt_ptr->next) ;	/* null body */
138 	    /*
139 	     * Set the name.
140 	     */
141 	    form->value = opt_ptr->name;
142 	    /*
143 	     * Set the value.
144 	     */
145 	    form->cp_submit_value = opt_ptr->cp_submit_value;
146 	    /*
147 	     * Set charset in which we have the submit value.  - kw
148 	     */
149 	    form->value_cs = opt_ptr->value_cs;
150 	}
151 #if CTRL_W_HACK != DO_NOTHING
152 	if (!enable_scrollback)
153 	    c = CTRL_W_HACK;	/* CTRL-W refresh without clearok */
154 	else
155 #endif
156 	    c = 12;		/* CTRL-L for repaint */
157 	break;
158 
159     case F_RADIO_TYPE:
160 	if (FormIsReadonly(form))
161 	    break;
162 	/*
163 	 * Radio buttons must have one and only one down at a time!
164 	 */
165 	if (form->num_value) {
166 	    if (user_mode == NOVICE_MODE) {
167 		HTUserMsg(NEED_CHECKED_RADIO_BUTTON);
168 	    }
169 	} else {
170 	    int i;
171 
172 	    /*
173 	     * Run though list of the links on the screen and unselect any that
174 	     * are selected.  :)
175 	     */
176 	    lynx_start_radio_color();
177 	    for (i = 0; i < nlinks; i++) {
178 		if (links[i].type == WWW_FORM_LINK_TYPE
179 		    && links[i].l_form->type == F_RADIO_TYPE
180 		    && links[i].l_form->number == form->number
181 		/*
182 		 * If it has the same name and its on...
183 		 */
184 		    && !strcmp(links[i].l_form->name, form->name)
185 		    && links[i].l_form->num_value) {
186 		    LYmove(links[i].ly, links[i].lx);
187 		    LYaddstr(unchecked_radio);
188 		    LYSetHilite(i, unchecked_radio);
189 		}
190 	    }
191 	    lynx_stop_radio_color();
192 	    /*
193 	     * Will unselect other button and select this one.
194 	     */
195 	    HText_activateRadioButton(form);
196 	    /*
197 	     * Now highlight this one.
198 	     */
199 	    LYSetHilite(cur, checked_radio);
200 	}
201 	break;
202 
203     case F_FILE_TYPE:
204     case F_TEXT_TYPE:
205     case F_TEXTAREA_TYPE:
206     case F_PASSWORD_TYPE:
207 	c = form_getstr(cur, use_last_tfpos, redraw_only);
208 	LYSetHilite(cur, ((form->type == F_PASSWORD_TYPE)
209 			  ? STARS(LYstrCells(form->value))
210 			  : form->value));
211 	break;
212 
213     case F_RESET_TYPE:
214 	if (FormIsReadonly(form))
215 	    break;
216 	HText_ResetForm(form);
217 	*refresh_screen = TRUE;
218 	break;
219 
220     case F_TEXT_SUBMIT_TYPE:
221 	if (redraw_only) {
222 	    c = form_getstr(cur, use_last_tfpos, TRUE);
223 	    break;
224 	}
225 	if (!immediate_submit)
226 	    c = form_getstr(cur, use_last_tfpos, FALSE);
227 	if (FormIsReadonly(form) &&
228 	    (c == '\r' || c == '\n' || immediate_submit)) {
229 	    if (peek_mouse_link() >= 0)
230 		c = LAC_TO_LKC0(LYK_ACTIVATE);
231 	    else
232 		c = '\t';
233 	    break;
234 	}
235 	/*
236 	 * If immediate_submit is set, we didn't enter the line editor above,
237 	 * and will now try to call HText_SubmitForm() directly.  If
238 	 * immediate_submit is not set, c is the lynxkeycode returned from line
239 	 * editing.  Then if c indicates that a key was pressed that means we
240 	 * should submit, but with some extra considerations (i.e.  NOCACHE,
241 	 * DOWNLOAD, different from simple Enter), or if we should act on some
242 	 * *other* link selected with the mouse, we'll just return c and leave
243 	 * it to mainloop() to do the right thing; if everything checks out, it
244 	 * should call this function again, with immediate_submit set.
245 	 *
246 	 * If c indicates that line editing ended with Enter, we still defer to
247 	 * mainloop() for further checking if the submit action URL could
248 	 * require more checks than we do here.  Only in the remaining cases do
249 	 * we proceed to call HText_SubmitForm() directly before returning.  -
250 	 * kw
251 	 */
252 	if (immediate_submit ||
253 	    ((c == '\r' ||
254 	      c == '\n' ||
255 	      c == LAC_TO_LKC0(LYK_MOUSE_SUBMIT)) &&
256 	     peek_mouse_link() == -1)) {
257 	    LYSetHilite(cur, form->value);
258 #ifdef TEXT_SUBMIT_CONFIRM_WANTED
259 	    if (!immediate_submit && (c == '\r' || c == '\n') &&
260 		!HTConfirmDefault(NO_SUBMIT_BUTTON_QUERY, YES)) {
261 		/* User was prompted and declined; if canceled with ^G
262 		 * let mainloop stay on this field, otherwise move on to
263 		 * the next field or link. - kw
264 		 */
265 		if (HTLastConfirmCancelled())
266 		    c = DO_NOTHING;
267 		else
268 		    c = LAC_TO_LKC(LYK_NEXT_LINK);
269 		break;
270 	    }
271 #endif
272 	    if (isEmpty(form->submit_action)) {
273 		HTUserMsg(NO_FORM_ACTION);
274 		c = DO_NOTHING;
275 		break;
276 	    } else if (form->submit_method == URL_MAIL_METHOD && no_mail) {
277 		HTAlert(FORM_MAILTO_DISALLOWED);
278 		c = DO_NOTHING;
279 		break;
280 	    } else if (!immediate_submit &&
281 		       ((no_file_url &&
282 			 isFILE_URL(form->submit_action)) ||
283 			!strncasecomp(form->submit_action, "lynx", 4))) {
284 		c = LAC_TO_LKC0(LYK_MOUSE_SUBMIT);
285 		break;
286 	    } else {
287 		if (form->no_cache &&
288 		    form->submit_method != URL_MAIL_METHOD) {
289 		    LYforce_no_cache = TRUE;
290 		    reloading = TRUE;
291 		}
292 		newdoc_changed =
293 		    HText_SubmitForm(form, newdoc, link_name, form->value);
294 	    }
295 	    if (form->submit_method == URL_MAIL_METHOD) {
296 		*refresh_screen = TRUE;
297 	    } else {
298 		/*
299 		 * Returns new document URL.
300 		 */
301 		newdoc->link = 0;
302 		newdoc->internal_link = FALSE;
303 	    }
304 	    c = DO_NOTHING;
305 	    break;
306 	} else {
307 	    LYSetHilite(cur, form->value);
308 	}
309 	break;
310 
311     case F_SUBMIT_TYPE:
312     case F_IMAGE_SUBMIT_TYPE:
313 	if (FormIsReadonly(form))
314 	    break;
315 	if (form->no_cache &&
316 	    form->submit_method != URL_MAIL_METHOD) {
317 	    LYforce_no_cache = TRUE;
318 	    reloading = TRUE;
319 	}
320 	newdoc_changed =
321 	    HText_SubmitForm(form, newdoc, link_name, link_value);
322 	if (form->submit_method == URL_MAIL_METHOD)
323 	    *refresh_screen = TRUE;
324 	else {
325 	    /* returns new document URL */
326 	    newdoc->link = 0;
327 	    newdoc->internal_link = FALSE;
328 	}
329 	break;
330 
331     }
332 
333     if (newdoc_changed) {
334 	c = LKC_DONE;
335     } else {
336 	/*
337 	 * These flags may have been set in mainloop, anticipating that a
338 	 * request will be submitted.  But if we haven't filled in newdoc, that
339 	 * won't actually be the case, so unset them.  - kw
340 	 */
341 	LYforce_no_cache = FALSE;
342 	reloading = FALSE;
343     }
344     FREE(my_data);
345     return (c);
346 }
347 
change_form_link(int cur,DocInfo * newdoc,BOOLEAN * refresh_screen,int use_last_tfpos,int immediate_submit)348 int change_form_link(int cur,
349 		     DocInfo *newdoc,
350 		     BOOLEAN *refresh_screen,
351 		     int use_last_tfpos,
352 		     int immediate_submit)
353 {
354     /*pass all our args and FALSE as last arg */
355     return change_form_link_ex(cur,
356 			       newdoc,
357 			       refresh_screen,
358 			       use_last_tfpos,
359 			       immediate_submit,
360 			       FALSE /*redraw_only */ );
361 }
362 
363 static int LastTFPos = -1;	/* remember last text field position */
364 
LYSetLastTFPos(int pos)365 static void LYSetLastTFPos(int pos)
366 {
367     LastTFPos = pos;
368 }
369 
form_getstr(int cur,int use_last_tfpos,int redraw_only)370 static int form_getstr(int cur,
371 		       int use_last_tfpos,
372 		       int redraw_only)
373 {
374     FormInfo *form = links[cur].l_form;
375     char *link_value = form->value;
376     int ch;
377     int far_col;
378     int startcol, startline;
379     int action, repeat;
380     int last_xlkc = -1;
381 
382 #ifdef SUPPORT_MULTIBYTE_EDIT
383     BOOL refresh_mb = TRUE;
384 #endif
385 
386     EditFieldData MyEdit, *edit = &MyEdit;
387     BOOLEAN Edited = FALSE;	/* Value might be updated? */
388 
389     /*
390      * Get the initial position of the cursor.
391      */
392     LYGetYX(startline, startcol);
393     if (startline < 0)
394 	startline = 0;
395     if (startcol < 0)
396 	startcol = 0;
397     if ((startcol + form->size) > LYcolLimit)
398 	far_col = LYcolLimit;
399     else
400 	far_col = (startcol + form->size);
401 
402     /*
403      * Make sure the form field value does not exceed our buffer.  - FM
404      */
405     if (form->maxlength != 0 &&
406 	strlen(form->value) > form->maxlength) {
407 	/*
408 	 * We can't fit the entire value into the editing buffer, so enter as
409 	 * much of the tail as fits.  - FM
410 	 */
411 	link_value += (strlen(form->value) - form->maxlength);
412 	if (!FormIsReadonly(form) &&
413 	    !(form->submit_method == URL_MAIL_METHOD && no_mail)) {
414 	    /*
415 	     * If we can edit it, report that we are using the tail.  - FM
416 	     */
417 	    HTUserMsg(FORM_VALUE_TOO_LONG);
418 	    show_formlink_statusline(form, redraw_only ? FOR_PANEL : FOR_INPUT);
419 	    LYmove(startline, startcol);
420 	}
421     }
422 
423     /*
424      * Print panned line
425      */
426     LYSetupEdit(edit, link_value, form->maxlength, (far_col - startcol));
427     edit->pad = '_';
428     edit->hidden = (BOOL) (form->type == F_PASSWORD_TYPE);
429     if (use_last_tfpos &&
430 	LastTFPos >= 0 &&
431 	LastTFPos < (int) edit->buffer_used) {
432 #if defined(TEXTFIELDS_MAY_NEED_ACTIVATION) && defined(INACTIVE_INPUT_STYLE_VH)
433 	if (redraw_only) {
434 	    if (!(edit->buffer_used >= edit->dspwdth &&
435 		  LastTFPos >= edit->dspwdth - edit->margin)) {
436 		edit->pos = LastTFPos;
437 		if (edit->buffer_used >= edit->dspwdth)
438 		    textinput_redrawn = FALSE;
439 	    }
440 	} else
441 #endif /* TEXTFIELDS_MAY_NEED_ACTIVATION && INACTIVE_INPUT_STYLE_VH */
442 	    edit->pos = LastTFPos;
443 #ifdef ENHANCED_LINEEDIT
444 	if (edit->pos == 0)
445 	    /* Do not show the region. */
446 	    edit->mark = -(int) (1 + edit->buffer_used);
447 #endif
448     }
449     /* Try to prepare for setting position based on the last mouse event */
450 #if defined(TEXTFIELDS_MAY_NEED_ACTIVATION) && defined(INACTIVE_INPUT_STYLE_VH)
451     if (!redraw_only) {
452 	if (peek_mouse_levent()) {
453 	    if (!use_last_tfpos && !textinput_redrawn) {
454 		edit->pos = 0;
455 	    }
456 	}
457 	textinput_redrawn = FALSE;
458     }
459 #else
460     if (peek_mouse_levent()) {
461 	if (!use_last_tfpos)
462 	    edit->pos = 0;
463     }
464 #endif /* TEXTFIELDS_MAY_NEED_ACTIVATION && INACTIVE_INPUT_STYLE_VH */
465     LYRefreshEdit(edit);
466     if (redraw_only) {
467 	LYFinishEdit(edit);
468 	return 0;		/*return value won't be analysed */
469     }
470 #ifdef FEPCTRL
471     fep_on();
472 #endif
473     /*
474      * And go for it!
475      */
476     for (;;) {
477       again:
478 	repeat = -1;
479 	get_mouse_link();	/* Reset mouse_link. */
480 
481 	ch = LYgetch_input();
482 #ifdef SUPPORT_MULTIBYTE_EDIT
483 	if (!refresh_mb
484 	    && (EditBinding(ch) != LYE_CHAR)
485 #ifndef WIN_EX
486 	    && (EditBinding(ch) != LYE_AIX)
487 #endif
488 	    )
489 	    goto again;
490 #endif /* SUPPORT_MULTIBYTE_EDIT */
491 #ifdef VMS
492 	if (HadVMSInterrupt) {
493 	    HadVMSInterrupt = FALSE;
494 	    ch = LYCharINTERRUPT2;
495 	}
496 #endif /* VMS */
497 
498 	action = 0;
499 #ifdef USE_MOUSE
500 #  if defined(NCURSES) || defined(PDCURSES)
501 	if (ch != -1 && (ch & LKC_ISLAC) && !(ch & LKC_ISLECLAC))	/* already lynxactioncode? */
502 	    break;		/* @@@ maybe move these 2 lines outside ifdef -kw */
503 	if (ch == MOUSE_KEY) {	/* Need to process ourselves */
504 #if defined(PDCURSES)
505 	    int curx, cury;
506 
507 	    request_mouse_pos();
508 	    LYGetYX(cury, curx);
509 	    if (MOUSE_Y_POS == cury) {
510 		repeat = MOUSE_X_POS - curx;
511 		if (repeat < 0) {
512 		    action = LYE_BACK;
513 		    repeat = -repeat;
514 		} else
515 		    action = LYE_FORW;
516 	    }
517 #else
518 	    MEVENT event;
519 	    int curx, cury;
520 
521 	    getmouse(&event);
522 	    LYGetYX(cury, curx);
523 	    if (event.y == cury) {
524 		repeat = event.x - curx;
525 		if (repeat < 0) {
526 		    action = LYE_BACK;
527 		    repeat = -repeat;
528 		} else
529 		    action = LYE_FORW;
530 	    }
531 #endif /* PDCURSES */
532 	    else {
533 		/* Mouse event passed to us as MOUSE_KEY, and apparently not on
534 		 * this field's line?  Something is not as it should be...
535 		 *
536 		 * A call to statusline() may have happened, possibly from
537 		 * within a mouse menu.  Let's at least make sure here that the
538 		 * cursor position gets restored.  - kw
539 		 */
540 		edit->dirty = TRUE;
541 	    }
542 	} else
543 #  endif /* NCURSES || PDCURSES */
544 #endif /* USE_MOUSE */
545 
546 	{
547 	    if (!(ch & LKC_ISLECLAC))
548 		ch |= edit->current_modifiers;
549 	    edit->current_modifiers = 0;
550 	    if (last_xlkc != -1) {
551 		if (ch == last_xlkc)
552 		    ch |= LKC_MOD3;
553 	    }
554 	}
555 	if (peek_mouse_link() != -1)
556 	    break;
557 
558 	if (!action)
559 	    action = EditBinding(ch);
560 	if ((action & LYE_DF) && !(action & LYE_FORM_LAC)) {
561 	    last_xlkc = ch;
562 	    action &= ~LYE_DF;
563 	} else {
564 	    last_xlkc = -1;
565 	}
566 
567 	if (action == LYE_SETM1) {
568 	    /*
569 	     * Set flag for modifier 1.
570 	     */
571 	    edit->current_modifiers |= LKC_MOD1;
572 	    continue;
573 	}
574 	if (action == LYE_SETM2) {
575 	    /*
576 	     * Set flag for modifier 2.
577 	     */
578 	    edit->current_modifiers |= LKC_MOD2;
579 	    continue;
580 	}
581 	/*
582 	 * Filter out global navigation keys that should not be passed to line
583 	 * editor, and LYK_REFRESH.
584 	 */
585 	if (action == LYE_ENTER)
586 	    break;
587 	if (action == LYE_FORM_PASS)
588 	    break;
589 	if (action & LYE_FORM_LAC) {
590 	    ch = (action & LAC_MASK) | LKC_ISLAC;
591 	    break;
592 	}
593 	if (action == LYE_LKCMD) {
594 	    _statusline(ENTER_LYNX_COMMAND);
595 	    ch = LYgetch();
596 #ifdef VMS
597 	    if (HadVMSInterrupt) {
598 		HadVMSInterrupt = FALSE;
599 		ch = LYCharINTERRUPT2;
600 	    }
601 #endif /* VMS */
602 	    break;
603 	}
604 #ifdef CAN_CUT_AND_PASTE	/* 1998/10/01 (Thu) 19:19:22 */
605 	if (action == LYE_PASTE) {
606 	    unsigned char *s = (unsigned char *) get_clip_grab(), *e;
607 	    char *buf = NULL;
608 	    int len;
609 
610 	    if (!s)
611 		break;
612 	    len = (int) strlen((const char *) s);
613 	    e = s + len;
614 
615 	    if (len > 0) {
616 		unsigned char *e1 = s;
617 
618 		while (e1 < e) {
619 		    if (*e1 < ' ') {	/* Stop here? */
620 			if (e1 > s)
621 			    LYEditInsert(edit, s, (int) (e1 - s), -1, TRUE);
622 			s = e1;
623 			if (*e1 == '\t') {	/* Replace by space */
624 			    LYEditInsert(edit, (unsigned const char *) " ", 1,
625 					 -1, TRUE);
626 			    s = ++e1;
627 			} else
628 			    break;
629 		    } else
630 			++e1;
631 		}
632 		if (e1 > s)
633 		    LYEditInsert(edit, s, (int) (e1 - s), -1, TRUE);
634 		while (e1 < e && *e1 == '\r')
635 		    e1++;
636 		if (e1 + 1 < e && *e1 == '\n')
637 		    StrAllocCopy(buf, (char *) e1 + 1);		/* Survive _release() */
638 		get_clip_release();
639 		_statusline(ENTER_TEXT_ARROWS_OR_TAB);
640 		if (strcmp(link_value, edit->buffer) != 0) {
641 		    Edited = TRUE;
642 		}
643 		if (buf) {
644 		    put_clip(buf);
645 		    FREE(buf);
646 		    ch = '\n';	/* Sometimes moves to the next line */
647 		    break;
648 		}
649 		LYRefreshEdit(edit);
650 	    } else {
651 		HTInfoMsg(gettext("Clipboard empty or Not text data."));
652 #ifdef FEPCTRL
653 		fep_off();
654 #endif
655 		continue;
656 	    }
657 	}
658 #endif
659 #ifndef WIN_EX
660 	if (action == LYE_AIX &&
661 	    (!IS_CJK_TTY && LYlowest_eightbit[current_char_set] > 0x97))
662 	    break;
663 #endif
664 	if (action == LYE_TAB) {
665 	    ch = (int) ('\t');
666 	    break;
667 	}
668 	if (action == LYE_ABORT) {
669 #ifdef FEPCTRL
670 	    fep_off();
671 #endif
672 	    LYFinishEdit(edit);
673 	    return (DO_NOTHING);
674 	}
675 	if (action == LYE_STOP) {
676 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
677 	    textfields_need_activation = TRUE;
678 	    break;
679 #else
680 #ifdef ENHANCED_LINEEDIT
681 	    if (edit->mark >= 0)
682 		/* Disable. */
683 		edit->mark = -(int) (1 + edit->buffer_used);
684 #endif
685 #endif
686 	}
687 	if (action == LYE_NOP && LKC_TO_LAC(keymap, ch) == LYK_REFRESH)
688 	    break;
689 #ifdef SH_EX
690 /* ASATAKU emacskey hack 1997/08/26 (Tue) 09:19:23 */
691 	if (emacs_keys &&
692 	    (EditBinding(ch) == LYE_FORWW || EditBinding(ch) == LYE_BACKW))
693 	    goto breakfor;
694 /* ASATAKU emacskey hack */
695 #endif
696 	switch (ch) {
697 	default:
698 	    /* [ 1999/04/14 (Wed) 15:01:33 ]
699 	     * Left arrow in column 0 deserves special treatment here, else
700 	     * you can get trapped in a form without submit button!
701 	     */
702 	    if (action == LYE_BACK && edit->pos == 0 && repeat == -1) {
703 		int c = YES;	/* Go back immediately if no changes */
704 
705 		if (textfield_prompt_at_left_edge) {
706 		    c = HTConfirmDefault(PREV_DOC_QUERY, NO);
707 		} else if (strcmp(edit->buffer, link_value)) {
708 		    c = HTConfirmDefault(PREV_DOC_QUERY, NO);
709 		}
710 		if (c == YES) {
711 #ifdef FEPCTRL
712 		    fep_off();
713 #endif
714 		    LYFinishEdit(edit);
715 		    return (ch);
716 		} else {
717 		    if (FormIsReadonly(form))
718 			_statusline(ARROWS_OR_TAB_TO_MOVE);
719 		    else
720 			_statusline(ENTER_TEXT_ARROWS_OR_TAB);
721 		}
722 	    }
723 	    if (FormIsReadonly(form)) {
724 		/*
725 		 * Allow actions that don't modify the contents even in
726 		 * disabled form fields, so the user can scroll through the
727 		 * line for reading if necessary.  - kw
728 		 */
729 		switch (action) {
730 		case LYE_BOL:
731 		case LYE_EOL:
732 		case LYE_FORW:
733 		case LYE_FORW_RL:
734 		case LYE_BACK:
735 		case LYE_BACK_LL:
736 		case LYE_FORWW:
737 		case LYE_BACKW:
738 #ifdef EXP_KEYBOARD_LAYOUT
739 		case LYE_SWMAP:
740 #endif
741 #ifdef ENHANCED_LINEEDIT
742 		case LYE_SETMARK:
743 		case LYE_XPMARK:
744 #endif
745 		    break;
746 		default:
747 		    goto again;
748 		}
749 	    }
750 	    /*
751 	     * Make sure the statusline uses editmode help.
752 	     */
753 	    if (repeat < 0)
754 		repeat = 1;
755 	    while (repeat--) {
756 		int rc = LYEdit1(edit, ch, action & ~LYE_DF, TRUE);
757 
758 		if (rc < 0) {
759 		    ch = -rc;
760 		    /* FORW_RL and BACK_LL may require special attention.
761 		       BACK_LL wanted to switch to the previous link on
762 		       the same line.  However, if there is no such link,
763 		       then we would either disactivate the form
764 		       (with -tna), or will reenter the form, thus we jump
765 		       to the end of the line; both are counterintuitive.
766 		       Unfortunately, we do not have access to curdoc.link,
767 		       so we deduce it ourselves.  We don't have the info
768 		       to do it inside LYLineEdit().
769 		       This should work for prompts too.  */
770 		    switch (action) {
771 		    case LYE_BACK_LL:
772 			if (cur > 0
773 			    && links[cur - 1].ly == links[cur].ly) {
774 			    goto breakfor;
775 			}
776 			break;
777 		    case LYE_FORW_RL:
778 			if (cur >= 0
779 			    && cur < nlinks - 1
780 			    && links[cur + 1].ly == links[cur].ly) {
781 			    goto breakfor;
782 			}
783 			break;
784 		    default:
785 			goto breakfor;
786 		    }
787 		}
788 #ifdef SUPPORT_MULTIBYTE_EDIT
789 		if (rc == 0) {
790 		    if (IS_CJK_TTY && (0x80 <= ch)
791 			&& (ch <= 0xfe) && refresh_mb)
792 			refresh_mb = FALSE;
793 		    else
794 			refresh_mb = TRUE;
795 		} else {
796 		    if (!refresh_mb) {
797 			LYEdit1(edit, 0, LYE_DELP, TRUE);
798 		    }
799 		}
800 #endif /* SUPPORT_MULTIBYTE_EDIT */
801 	    }
802 	    _statusline(ENTER_TEXT_ARROWS_OR_TAB);
803 	    if (strcmp(link_value, edit->buffer)) {
804 		Edited = TRUE;
805 	    }
806 #ifdef SUPPORT_MULTIBYTE_EDIT
807 	    if (refresh_mb)
808 #endif
809 		LYRefreshEdit(edit);
810 	    LYSetLastTFPos(edit->pos);
811 	}
812     }
813   breakfor:
814     if (Edited) {
815 
816 	/*
817 	 * Load the new value.
818 	 */
819 	if (link_value == form->value) {
820 	    /*
821 	     * The previous value did fit in the line buffer, so replace it
822 	     * with the new value.  - FM
823 	     */
824 	    StrAllocCopy(form->value, edit->buffer);
825 	} else {
826 	    int old_len = (int) strlen(form->value);
827 	    int new_len = (int) strlen(link_value);
828 
829 	    /*
830 	     * Combine the modified tail with the unmodified head.  - FM
831 	     */
832 	    form->value[(old_len > new_len) ? (old_len - new_len) : 0] = '\0';
833 	    StrAllocCat(form->value, edit->buffer);
834 	    HTUserMsg(FORM_TAIL_COMBINED_WITH_HEAD);
835 	}
836 
837 	/* 2.8.4pre.3 - most browsers appear to preserve trailing spaces -VH */
838 	/*
839 	 * Remove trailing spaces
840 	 *
841 	 * Do we really need to do that here?  Trailing spaces will only be
842 	 * there if user keyed them in.  Rather rude to throw away their hard
843 	 * earned spaces.  Better deal with trailing spaces when submitting the
844 	 * form????
845 	 */
846 	if (LYtrimInputFields) {
847 	    LYTrimTrailing(form->value);
848 	}
849 
850 	/*
851 	 * If the field has been changed, assume that it is now in current
852 	 * display character set, even if for some reason it wasn't!  Hopefully
853 	 * a user will only submit the form if the non-ASCII characters are
854 	 * displayed correctly, which means (assuming that the display
855 	 * character set has been set truthfully) the user confirms by changing
856 	 * the field that the character encoding is right.  - kw
857 	 */
858 	if (non_empty(form->value))
859 	    form->value_cs = current_char_set;
860     }
861 #ifdef FEPCTRL
862     fep_off();
863 #endif
864     LYFinishEdit(edit);
865     return (ch);
866 }
867 
868 /*
869  * Display statusline info tailored for the current form field.
870  */
show_formlink_statusline(const FormInfo * form,int for_what)871 void show_formlink_statusline(const FormInfo * form,
872 			      int for_what)
873 {
874     switch (form->type) {
875     case F_PASSWORD_TYPE:
876 	if (FormIsReadonly(form))
877 	    statusline(FORM_LINK_PASSWORD_UNM_MSG);
878 	else
879 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
880 	if (for_what == FOR_PANEL)
881 	    statusline(FORM_LINK_PASSWORD_MESSAGE_INA);
882 	else
883 #endif
884 	    statusline(FORM_LINK_PASSWORD_MESSAGE);
885 	break;
886     case F_OPTION_LIST_TYPE:
887 	if (FormIsReadonly(form))
888 	    statusline(FORM_LINK_OPTION_LIST_UNM_MSG);
889 	else
890 	    statusline(FORM_LINK_OPTION_LIST_MESSAGE);
891 	break;
892     case F_CHECKBOX_TYPE:
893 	if (FormIsReadonly(form))
894 	    statusline(FORM_LINK_CHECKBOX_UNM_MSG);
895 	else
896 	    statusline(FORM_LINK_CHECKBOX_MESSAGE);
897 	break;
898     case F_RADIO_TYPE:
899 	if (FormIsReadonly(form))
900 	    statusline(FORM_LINK_RADIO_UNM_MSG);
901 	else
902 	    statusline(FORM_LINK_RADIO_MESSAGE);
903 	break;
904     case F_TEXT_SUBMIT_TYPE:
905 	if (FormIsReadonly(form)) {
906 	    statusline(FORM_LINK_TEXT_SUBMIT_UNM_MSG);
907 	} else if (form->submit_method ==
908 		   URL_MAIL_METHOD) {
909 	    if (no_mail)
910 		statusline(FORM_LINK_TEXT_SUBMIT_MAILTO_DIS_MSG);
911 	    else
912 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
913 	    if (for_what == FOR_PANEL)
914 		statusline(FORM_TEXT_SUBMIT_MAILTO_MSG_INA);
915 	    else
916 #endif
917 		statusline(FORM_LINK_TEXT_SUBMIT_MAILTO_MSG);
918 	} else if (form->no_cache) {
919 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
920 	    if (for_what == FOR_PANEL)
921 		statusline(FORM_TEXT_RESUBMIT_MESSAGE_INA);
922 	    else
923 #endif
924 		statusline(FORM_LINK_TEXT_RESUBMIT_MESSAGE);
925 	} else {
926 	    char *submit_str = NULL;
927 	    char *xkey_info = key_for_func_ext(LYK_NOCACHE, for_what);
928 
929 	    if (non_empty(xkey_info)) {
930 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
931 		if (for_what == FOR_PANEL)
932 		    HTSprintf0(&submit_str, FORM_TEXT_SUBMIT_MESSAGE_INA_X,
933 			       xkey_info);
934 		else
935 #endif
936 		    HTSprintf0(&submit_str, FORM_LINK_TEXT_SUBMIT_MESSAGE_X,
937 			       xkey_info);
938 		statusline(submit_str);
939 		FREE(submit_str);
940 	    } else {
941 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
942 		if (for_what == FOR_PANEL)
943 		    statusline(FORM_LINK_TEXT_SUBMIT_MESSAGE_INA);
944 		else
945 #endif
946 		    statusline(FORM_LINK_TEXT_SUBMIT_MESSAGE);
947 	    }
948 	    FREE(xkey_info);
949 	}
950 	break;
951     case F_SUBMIT_TYPE:
952     case F_IMAGE_SUBMIT_TYPE:
953 	if (FormIsReadonly(form)) {
954 	    statusline(FORM_LINK_SUBMIT_DIS_MSG);
955 	} else if (form->submit_method ==
956 		   URL_MAIL_METHOD) {
957 	    if (no_mail) {
958 		statusline(FORM_LINK_SUBMIT_MAILTO_DIS_MSG);
959 	    } else {
960 		if (user_mode == ADVANCED_MODE) {
961 		    char *submit_str = NULL;
962 
963 		    StrAllocCopy(submit_str, FORM_LINK_SUBMIT_MAILTO_PREFIX);
964 		    StrAllocCat(submit_str, form->submit_action);
965 		    statusline(submit_str);
966 		    FREE(submit_str);
967 		} else {
968 		    statusline(FORM_LINK_SUBMIT_MAILTO_MSG);
969 		}
970 	    }
971 	} else if (form->no_cache) {
972 	    if (user_mode == ADVANCED_MODE) {
973 		char *submit_str = NULL;
974 
975 		StrAllocCopy(submit_str, FORM_LINK_RESUBMIT_PREFIX);
976 		StrAllocCat(submit_str, form->submit_action);
977 		statusline(submit_str);
978 		FREE(submit_str);
979 	    } else {
980 		statusline(FORM_LINK_RESUBMIT_MESSAGE);
981 	    }
982 	} else {
983 	    if (user_mode == ADVANCED_MODE) {
984 		char *submit_str = NULL;
985 
986 		StrAllocCopy(submit_str, FORM_LINK_SUBMIT_PREFIX);
987 		StrAllocCat(submit_str, form->submit_action);
988 		statusline(submit_str);
989 		FREE(submit_str);
990 	    } else {
991 		statusline(FORM_LINK_SUBMIT_MESSAGE);
992 	    }
993 	}
994 	break;
995     case F_RESET_TYPE:
996 	if (FormIsReadonly(form))
997 	    statusline(FORM_LINK_RESET_DIS_MSG);
998 	else
999 	    statusline(FORM_LINK_RESET_MESSAGE);
1000 	break;
1001     case F_BUTTON_TYPE:
1002 	if (FormIsReadonly(form))
1003 	    statusline(FORM_LINK_BUTTON_DIS_MSG);
1004 	else
1005 	    statusline(FORM_LINK_BUTTON_MESSAGE);
1006 	break;
1007     case F_FILE_TYPE:
1008 	if (FormIsReadonly(form))
1009 	    statusline(FORM_LINK_FILE_UNM_MSG);
1010 	else
1011 	    statusline(FORM_LINK_FILE_MESSAGE);
1012 	break;
1013     case F_TEXT_TYPE:
1014 	if (FormIsReadonly(form))
1015 	    statusline(FORM_LINK_TEXT_UNM_MSG);
1016 	else
1017 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
1018 	if (for_what == FOR_PANEL)
1019 	    statusline(FORM_LINK_TEXT_MESSAGE_INA);
1020 	else
1021 #endif
1022 	    statusline(FORM_LINK_TEXT_MESSAGE);
1023 	break;
1024     case F_TEXTAREA_TYPE:
1025 	if (FormIsReadonly(form)) {
1026 	    statusline(FORM_LINK_TEXT_UNM_MSG);
1027 	} else {
1028 	    char *submit_str = NULL;
1029 	    char *xkey_info = NULL;
1030 
1031 	    if (!no_editor && non_empty(editor)) {
1032 		xkey_info = key_for_func_ext(LYK_EDIT_TEXTAREA, for_what);
1033 #ifdef TEXTAREA_AUTOEXTEDIT
1034 		if (!xkey_info)
1035 		    xkey_info = key_for_func_ext(LYK_DWIMEDIT, for_what);
1036 #endif
1037 	    }
1038 	    if (non_empty(xkey_info)) {
1039 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
1040 		if (for_what == FOR_PANEL)
1041 		    HTSprintf0(&submit_str, FORM_LINK_TEXTAREA_MESSAGE_INA_E,
1042 			       xkey_info);
1043 		else
1044 #endif
1045 		    HTSprintf0(&submit_str, FORM_LINK_TEXTAREA_MESSAGE_E,
1046 			       xkey_info);
1047 		statusline(submit_str);
1048 		FREE(submit_str);
1049 	    } else {
1050 #ifdef TEXTFIELDS_MAY_NEED_ACTIVATION
1051 		if (for_what == FOR_PANEL)
1052 		    statusline(FORM_LINK_TEXTAREA_MESSAGE_INA);
1053 		else
1054 #endif
1055 		    statusline(FORM_LINK_TEXTAREA_MESSAGE);
1056 	    }
1057 	    FREE(xkey_info);
1058 	}
1059 	break;
1060     }
1061 }
1062