1 /*
2 * Copyright (c) 2000-2009, 2013-2015, 2018, 2020 Paul Mattes.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the names of Paul Mattes nor the names of his contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY PAUL MATTES "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL PAUL MATTES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * Help.c
30 * Help information for c3270.
31 */
32
33 #include "globals.h"
34 #include "appres.h"
35 #include "resources.h"
36
37 #include "actions.h"
38 #include "c3270.h"
39 #include "glue.h"
40 #include "help.h"
41 #include "icmdc.h"
42 #include "names.h"
43 #include "popups.h"
44 #include "screen.h"
45 #include "utils.h"
46
47 #if defined(_WIN32) /*[*/
48 # include "wc3270.h"
49 #endif /*]*/
50
51 #define P_3270 0x0001 /* 3270 actions */
52 #define P_SCRIPTING 0x0002 /* scripting actions */
53 #define P_INTERACTIVE 0x0004 /* interactive (command-prompt) actions */
54 #define P_OPTIONS 0x0008 /* command-line options */
55 #define P_TRANSFER 0x0010 /* file transfer options */
56 #define P_HTML 0x0020 /* HTML help */
57
58 #if defined(WC3270) /*[*/
59 #define HELP_W "w"
60 #else /*][*/
61 #define HELP_W ""
62 #endif /*]*/
63
64 static struct {
65 const char *name;
66 const char *args;
67 int purpose;
68 const char *help;
69 } cmd_help[] = {
70 { AnAbort, NULL, P_SCRIPTING, "Abort pending scripts and macros" },
71 { AnAnsiText, NULL, P_SCRIPTING, "Dump pending NVT text" },
72 { AnAscii, NULL, P_SCRIPTING, "Screen contents in ASCII" },
73 { AnAscii, "<n>", P_SCRIPTING,
74 "<n> bytes of screen contents from cursor, in ASCII" },
75 { AnAscii, "<row>,<col>,<n>", P_SCRIPTING,
76 "<n> bytes of screen contents from <row>,<col> (0-origin), in ASCII" },
77 { AnAscii, "<row>,<col>,<rows>,<cols>", P_SCRIPTING,
78 "<rows>x<cols> of screen contents from <row>,<col> (0-origin), in ASCII" },
79 { AnAscii1, "<row>,<col>,<n>", P_SCRIPTING,
80 "<n> bytes of screen contents from <row>,<col> (1-origin), in ASCII" },
81 { AnAscii1, "<row>,<col>,<rows>,<cols>", P_SCRIPTING,
82 "<rows>x<cols> of screen contents from <row>,<col> (1-origin), in ASCII" },
83 { AnAsciiField, NULL, P_SCRIPTING,
84 "Contents of current field, in ASCII" },
85 { AnAttn, NULL, P_3270, "Send 3270 ATTN sequence (TELNET IP)" },
86 { AnBackSpace, NULL, P_3270, "Move cursor left" },
87 { AnBackTab, NULL, P_3270, "Move to previous field" },
88 { AnBell, NULL, P_SCRIPTING, "Ring the terminal bell" },
89 { AnCircumNot, NULL, P_3270,
90 "Send ~ in NVT mode, notsign (X'5F', U+00AC) in 3270 mode" },
91 { AnClear, NULL, P_3270, "Send CLEAR AID (clear screen)" },
92 { AnClose, NULL, P_INTERACTIVE, "Alias for " AnDisconnect "()" },
93 { AnCloseScript, NULL, P_SCRIPTING, "Exit peer script" },
94 { AnCompose, NULL, P_INTERACTIVE,
95 "Interpret next two keystrokes according to the compose map" },
96 { AnConnect, "[L:][Y:][A:][<lu>@]<host>[:<port>][=<accept>]",
97 P_INTERACTIVE, "Open connection to <host>" },
98 #if defined(LOCAL_PROCESS) /*[*/
99 { AnConnect, "-e,[<command>[,<arg>...]]", P_INTERACTIVE,
100 "Open connection to a local shell or command" },
101 #endif /*]*/
102 #if defined(WC3270) /*[*/
103 { AnCopy, NULL, P_3270, "Copy selected text to Windows clipboard" },
104 #endif /*]*/
105 { AnCursorSelect, NULL, P_3270,
106 "Light pen select at cursor location" },
107 #if defined(WC3270) /*[*/
108 { AnCut, NULL, P_3270,
109 "Copy selected text to Windows clipboard, then erase" },
110 #endif /*]*/
111 { AnDelete, NULL, P_3270, "Delete character at cursor" },
112 { AnDeleteField, NULL, P_3270, "Erase field at cursor location (^U)" },
113 { AnDeleteWord, NULL, P_3270,
114 "Erase word before cursor location (^W)" },
115 { AnDisconnect, NULL, P_INTERACTIVE, "Close connection to host" },
116 { AnDown, NULL, P_3270, "Move cursor down" },
117 { AnDup, NULL, P_3270, "3270 DUP key (X'1C')" },
118 { AnEbcdic, NULL, P_SCRIPTING, "Screen contents in EBCDIC" },
119 { AnEbcdic, "<n>", P_SCRIPTING,
120 "<n> bytes of screen contents from cursor, in EBCDIC" },
121 { AnEbcdic, "<row>,<col>,<n>", P_SCRIPTING,
122 "<n> bytes of screen contents from <row>,<col> (0-origin), in EBCDIC" },
123 { AnEbcdic, "<row>,<col>,<rows>,<cols>", P_SCRIPTING,
124 "<rows>x<cols> of screen contents from <row>,<col> (0-origin), in EBCDIC" },
125 { AnEbcdic1, "<row>,<col>,<n>", P_SCRIPTING,
126 "<n> bytes of screen contents from <row>,<col> (1-origin), in EBCDIC" },
127 { AnEbcdic1, "<row>,<col>,<rows>,<cols>", P_SCRIPTING,
128 "<rows>x<cols> of screen contents from <row>,<col> (1-origin), in EBCDIC" },
129 { AnEbcdicField, NULL, P_SCRIPTING,
130 "Contents of current field, in EBCDIC" },
131 { AnEnter, NULL, P_3270, "Send ENTER AID" },
132 { AnErase, NULL, P_3270, "Destructive backspace" },
133 { AnEraseEOF, NULL, P_3270, "Erase from cursor to end of field" },
134 { AnEraseInput, NULL, P_3270, "Erase all input fields" },
135 { AnEscape, NULL, P_INTERACTIVE,
136 "Escape to '" HELP_W "c3270>' prompt" },
137 { AnExecute, "<command>", P_SCRIPTING, "Execute a shell command" },
138 { "Exit", NULL, P_INTERACTIVE, "Exit " HELP_W "c3270" },
139 { AnExpect, "<pattern>", P_SCRIPTING, "Wait for NVT output" },
140 { AnFieldEnd, NULL, P_3270, "Move to end of field" },
141 { AnFieldMark, NULL, P_3270, "3270 FIELD MARK key (X'1E')" },
142 { AnFlip, NULL, P_3270, "Flip display left-to-right" },
143 { AnHelp, "all|interactive|3270|scripting|transfer|<action>",
144 P_INTERACTIVE, "Get help" },
145 { AnHexString, "<digits>", P_3270|P_SCRIPTING,
146 "Input field data in hex" },
147 { AnHome, NULL, P_3270, "Move cursor to first field" },
148 { Anignore, NULL, P_3270, "Do nothing" },
149 { "Info", "<text>", P_SCRIPTING|P_INTERACTIVE, "Display text in OIA" },
150 { AnInsert, NULL, P_3270, "Set 3270 insert mode" },
151 { AnInterrupt, NULL, P_3270, "In NVT mode, send IAC IP" },
152 { AnKey, "<symbol>|0x<nn>", P_3270, "Input one character" },
153 { AnKeyboardDisable, "[" ResTrue "|" ResFalse "|" KwForceEnable "]",
154 P_SCRIPTING|P_INTERACTIVE,
155 "Modify automatic script keyboard locking" },
156 { AnKeymap, "[<keymap-name>]", P_SCRIPTING|P_INTERACTIVE,
157 "Push temporary keymap, or pop if none specified" },
158 { AnKeypad, NULL, P_INTERACTIVE, "Pop up the 3270 keypad" },
159 { AnLeft, NULL, P_3270, "Move cursr left" },
160 { AnLeft2, NULL, P_3270, "Move cursor left 2 columns" },
161 { AnMacro, "<name>", P_SCRIPTING, "Execute a predefined macro" },
162 { AnMenu, NULL, P_INTERACTIVE, "Pop up the command menu" },
163 { AnMoveCursor, "<row>,<col>", P_3270|P_SCRIPTING,
164 "Move cursor to specific location (0-origin, deprecated)" },
165 { AnMoveCursor, "<offset>", P_3270|P_SCRIPTING,
166 "Move cursor to a buffer offset (0-origin)" },
167 { AnMoveCursor1, "<row>,<col>", P_3270|P_SCRIPTING,
168 "Move cursor to specific location (1-origin)" },
169 { AnNewline, NULL, P_3270, "Move cursor to first field in next row" },
170 { AnNextWord, NULL, P_3270, "Move cursor to next word" },
171 { AnOpen, NULL, P_INTERACTIVE, "Alias for " AnConnect "()" },
172 { AnPA, "<n>", P_3270, "Send 3270 Program Attention" },
173 #if defined(WC3270) /*[*/
174 { "Paste", NULL, P_3270, "Paste clipboard contents" },
175 #endif /*]*/
176 { AnPF, "<n>", P_3270, "Send 3270 PF AID" },
177 { AnPreviousWord, NULL, P_3270, "Move cursor to previous word" },
178 { AnPrinter, KwStart "[,lu]|" KwStop, P_3270|P_SCRIPTING|P_INTERACTIVE,
179 "Start or stop " HELP_W "pr3287 printer session" },
180 { AnPrintText,
181 "[" KwHtml "|" KwRtf ",][" KwModi ",][" KwCaption ",<caption>,][" KwReplace "|" KwAppend ",]" KwFile ",<filename>",
182 P_INTERACTIVE|P_SCRIPTING,
183 "Save screen image in a file" },
184 { AnPrintText,
185 "[" KwModi ",][" KwCaption ",<caption>],"
186 #if defined(WC3270) /*[*/
187 "[" KwDialog "|" KwNoDialog ",][<printer-name>]",
188 #else /*][*/
189 "[<print-command>]",
190 #endif /*]*/
191 P_INTERACTIVE|P_SCRIPTING,
192 "Print screen image" },
193 { AnPrompt, "[app-name]", P_SCRIPTING|P_INTERACTIVE,
194 "Start an external prompt" },
195 { AnQuery, "<keyword>", P_SCRIPTING|P_INTERACTIVE,
196 "Query operational parameters" },
197 { AnQuit, NULL, P_INTERACTIVE, "Exit " HELP_W "3270" },
198 { AnReadBuffer, "[" KwAscii "|" KwEbcdic "|" KwUnicode "]", P_SCRIPTING,
199 "Dump display buffer" },
200 { AnReadBuffer, "[" KwAscii "|" KwEbcdic "|" KwUnicode ",]" KwField, P_SCRIPTING,
201 "Dump display buffer for current field" },
202 { AnReconnect, NULL, P_INTERACTIVE, "Reconnect to previous host" },
203 { AnRedraw, NULL, P_INTERACTIVE|P_3270, "Redraw screen" },
204 { AnReset, NULL, P_3270, "Clear keyboard lock" },
205 { AnRight, NULL, P_3270, "Move cursor right" },
206 { AnRight2, NULL, P_3270, "Move cursor right 2 columns" },
207 { AnScreenTrace, KwOn "[[," KwFile "],<filename>]", P_INTERACTIVE,
208 "Save screen images to file" },
209 { AnScreenTrace,
210 # if defined(_WIN32) /*[*/
211 KwOn "," KwPrinter "[,<printer-name>]",
212 # else /*][*/
213 KwOn "," KwPrinter "[,<print-command>]",
214 # endif /*]*/
215 P_INTERACTIVE, "Save screen images to printer" },
216 { AnScreenTrace, KwOff, P_INTERACTIVE, "Stop saving screen images" },
217 { AnScript, "[" KwDashAsync ",][" KwDashNoLock ",][" KwDashSingle ",]"
218 #if defined(_WIN32) /*[*/
219 "[" KwDashShareConsole ",]"
220 #endif /*]*/
221 "<path>[,<arg>...]",
222 P_SCRIPTING, "Run a child script" },
223 { AnScroll, KwForward "|" KwBackward, P_INTERACTIVE, "Scroll screen" },
224 { AnSet, "[<setting-name>,value]", P_INTERACTIVE|P_SCRIPTING,
225 "Change a setting or display all settings" },
226 { AnShow, KwCopyright "|" KwStatus "|" KwKeymap, P_INTERACTIVE,
227 "Display status and settings" },
228 { AnSnap, "<args>", P_SCRIPTING, "Screen snapshot manipulation" },
229 { AnSource, "<file>", P_SCRIPTING|P_INTERACTIVE, "Read actions from file" },
230 { AnString, "<text>", P_3270|P_SCRIPTING, "Input a string" },
231 { AnSysReq, NULL, P_3270,
232 "Send 3270 Attention (TELNET ABORT or SYSREQ AID)" },
233 { AnTab, NULL, P_3270, "Move cursor to next field" },
234 { AnTemporaryComposeMap, "[<compose-map-name>]",
235 P_SCRIPTING|P_INTERACTIVE, "Set or clear temporary compose map" },
236 { AnTemporaryKeymap, "[<keymap-name>]", P_SCRIPTING|P_INTERACTIVE,
237 "Alias for " AnKeymap "()" },
238 #if defined(WC3270) /*[*/
239 { AnTitle, "<text>", P_SCRIPTING|P_INTERACTIVE, "Change window title" },
240 #endif /*]*/
241 { AnToggle, "[<toggle-name>[,value]]", P_INTERACTIVE|P_SCRIPTING,
242 "Change a toggle" },
243 { AnToggleInsert, NULL, P_3270, "Set or clear 3270 insert mode" },
244 { AnToggleReverse, NULL, P_3270, "Set or clear reverse-input mode" },
245 { AnTrace, KwOn "[,<file>]|" KwOff, P_INTERACTIVE, "Configure tracing" },
246 { AnTransfer, "[<args>]", P_INTERACTIVE,
247 "IND$FILE file transfer (see 'help file-transfer')" },
248 { AnUp, NULL, P_3270, "Move cursor up" },
249 { AnWait, "<args>", P_SCRIPTING, "Wait for host events" },
250 { NULL, NULL, 0, NULL }
251 };
252
253 #if defined(HAVE_START) || defined(WC3270) /*[*/
254 static void html_help(bool);
255 #endif /*]*/
256
257 static struct {
258 const char *name;
259 int flag;
260 const char *text;
261 const char **block;
262 void (*fn)(bool);
263 } help_subcommand[] = {
264 #if defined(HAVE_START) /*[*/
265 { "online", P_HTML, NULL, NULL, html_help },
266 #endif /*]*/
267 { "all", -1, NULL, NULL, NULL },
268 { "3270", P_3270, NULL, NULL, NULL },
269 { "interactive", P_INTERACTIVE, NULL, NULL, NULL },
270 { "options", P_OPTIONS, NULL, NULL, &cmdline_help },
271 { "scripting", P_SCRIPTING, NULL, NULL, NULL },
272 { "file-transfer", P_TRANSFER, NULL, NULL, ft_help },
273 #if defined(WC3270) /*[*/
274 { "html", P_HTML, NULL, NULL, html_help },
275 #endif /*]*/
276 { NULL, 0, NULL }
277 };
278
279 /* c3270-specific actions. */
280 static bool
Help_action(ia_t ia,unsigned argc,const char ** argv)281 Help_action(ia_t ia, unsigned argc, const char **argv)
282 {
283 int i;
284 int overall = -1;
285 int match = 0;
286 bool any = false;
287
288 action_debug(AnHelp, ia, argc, argv);
289 if (check_argc(AnHelp, argc, 0, 1) < 0) {
290 return false;
291 }
292
293 if (argc != 1) {
294 action_output(
295 #if defined(HAVE_START) /*[*/
296 " help online launch online help\n"
297 #endif /*]*/
298 " help all all actions\n"
299 " help 3270 3270 actions\n"
300 " help interactive interactive (command-prompt) actions\n"
301 " help <action> help for one <action>\n"
302 " help options command-line options\n"
303 " help scripting scripting actions\n"
304 " help file-transfer file transfer options\n"
305 #if defined(WC3270) /*[*/
306 " help html alias for 'help online'\n"
307 #endif /*]*/
308 );
309 return true;
310 }
311
312 /* The (hidden) verify option verifies the integrity of the help list. */
313 if (!strcmp(argv[0], "verify")) {
314 action_elt_t *e;
315 bool any = false;
316
317 for (i = 0; cmd_help[i].name; i++) {
318 bool found = false;
319
320 FOREACH_LLIST(&actions_list, e, action_elt_t *) {
321 if (!strcasecmp(cmd_help[i].name, e->t.name)) {
322 found = true;
323 break;
324 }
325 } FOREACH_LLIST_END(&actions_list, e, action_elt_t *);
326 if (!found) {
327 action_output("Help for nonexistent action: %s",
328 cmd_help[i].name);
329 any = true;
330 }
331 }
332 if (!any) {
333 action_output("No orphaned help messages.");
334 }
335 any = false;
336 FOREACH_LLIST(&actions_list, e, action_elt_t *) {
337 bool found = false;
338
339 for (i = 0; cmd_help[i].name; i++) {
340
341 if (!strcasecmp(cmd_help[i].name, e->t.name)) {
342 found = true;
343 break;
344 }
345 }
346 if (!found) {
347 action_output("No Help for %s", e->t.name);
348 any = true;
349 }
350 } FOREACH_LLIST_END(&actions_list, e, action_elt_t *);
351 if (!any) {
352 printf("No orphaned actions.\n");
353 }
354 return true;
355 }
356
357 /* Do a substring match on all of the actions. */
358 for (i = 0; cmd_help[i].name != NULL; i++) {
359 if (!strncasecmp(cmd_help[i].name, argv[0], strlen(argv[0]))) {
360 action_output(" %s(%s)\n %s",
361 cmd_help[i].name,
362 cmd_help[i].args? cmd_help[i].args: "",
363 cmd_help[i].help? cmd_help[i].help: "");
364 any = true;
365 }
366 }
367 if (any) {
368 return true;
369 }
370
371 /* Check for an exact match on one of the topics. */
372 for (i = 0; help_subcommand[i].name != NULL; i++) {
373 if (!strncasecmp(help_subcommand[i].name, argv[0], strlen(argv[0]))) {
374 match = help_subcommand[i].flag;
375 overall = i;
376 break;
377 }
378 }
379
380 if (!match) {
381 action_output("No such command: %s", argv[0]);
382 return false;
383 }
384
385 /* Matched on a topic. */
386 if (help_subcommand[overall].text != NULL) {
387 /* One-line topic. */
388 action_output("%s", help_subcommand[overall].text);
389 return true;
390 }
391 if (help_subcommand[overall].block != NULL) {
392 int j;
393
394 /* Multi-line topic. */
395 for (j = 0; help_subcommand[overall].block[j] != NULL; j++) {
396 action_output("%s", help_subcommand[overall].block[j]);
397 }
398 return true;
399 }
400 if (help_subcommand[overall].fn != NULL) {
401 /* Indirect output for topic. */
402 (*help_subcommand[overall].fn)(true);
403 return true;
404 }
405
406 /* Category. */
407 for (i = 0; cmd_help[i].name != NULL; i++) {
408 if (cmd_help[i].purpose & match) {
409 action_output(" %s(%s)\n %s",
410 cmd_help[i].name,
411 cmd_help[i].args? cmd_help[i].args: "",
412 cmd_help[i].help? cmd_help[i].help: "");
413 }
414 }
415
416 return true;
417 }
418
419 #if defined(HAVE_START) || defined(WC3270) /*[*/
420 static void
html_help(bool ignored _is_unused)421 html_help(bool ignored _is_unused)
422 {
423 start_html_help();
424 }
425 #endif /*]*/
426
427 /**
428 * Help module registration.
429 */
430 void
help_register(void)431 help_register(void)
432 {
433 static action_table_t help_actions[] = {
434 { AnHelp, Help_action, ACTION_KE }
435 };
436
437 /* Register the actions. */
438 register_actions(help_actions, array_count(help_actions));
439 }
440