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