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