1 /*
2 * Copyright (c) 1993-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 * query.c
30 * The Query() action.
31 */
32
33 #include "globals.h"
34
35 #include "appres.h"
36
37 #include "actions.h"
38 #include "codepage.h"
39 #include "copyright.h"
40 #include "ctlrc.h"
41 #include "host.h"
42 #include "lazya.h"
43 #include "names.h"
44 #include "popups.h"
45 #include "query.h"
46 #include "split_host.h"
47 #include "telnet.h"
48 #include "task.h"
49 #include "trace.h"
50 #include "screentrace.h"
51 #include "unicodec.h"
52 #include "utf8.h"
53 #include "utils.h"
54 #include "varbuf.h"
55
56 /* Globals */
57
58 /* Statics */
59
60 /* The current set of queries. */
61 static query_t *queries;
62 static size_t num_queries;
63
64 static const char *
query_terminal_name(void)65 query_terminal_name(void)
66 {
67 return termtype;
68 }
69
70 static const char *
query_build(void)71 query_build(void)
72 {
73 return build;
74 }
75
76 static const char *
get_connect_time(void)77 get_connect_time(void)
78 {
79 time_t t, td;
80 long dy, hr, mn, sc;
81
82 if (!CONNECTED) {
83 return NULL;
84 }
85
86 time(&t);
87
88 td = t - ns_time;
89 dy = (long)(td / (3600 * 24));
90 hr = (dy % (3600 * 24)) / 3600;
91 mn = (td % 3600) / 60;
92 sc = td % 60;
93
94 return (dy > 0)?
95 lazyaf("%ud%02u:%02u:%02u", dy, hr, mn, sc):
96 lazyaf("%02u:%02u:%02u", hr, mn, sc);
97 }
98
99 static const char *
get_codepage(void)100 get_codepage(void)
101 {
102 char *sbcs = lazyaf("%s sbcs gcsgid %u cpgid %u",
103 get_canonical_codepage(),
104 (unsigned short)((cgcsgid >> 16) & 0xffff),
105 (unsigned short)(cgcsgid & 0xffff));
106 return dbcs? lazyaf("%s dbcs gcsgid %u cpgid %u",
107 sbcs,
108 (unsigned short)((cgcsgid_dbcs >> 16) & 0xffff),
109 (unsigned short)(cgcsgid_dbcs & 0xffff)):
110 sbcs;
111 }
112
113 static const char *
get_codepages(void)114 get_codepages(void)
115 {
116 cpname_t *c = get_cpnames();
117 varbuf_t r;
118 int i, j;
119 char *sep = "";
120
121 vb_init(&r);
122 for (i = 0; c[i].name != NULL; i++) {
123 vb_appendf(&r, "%s%s %cbcs", sep, c[i].name, c[i].dbcs? 'd': 's');
124 sep = "\n";
125 for (j = 0; j < c[i].num_aliases; j++) {
126 vb_appendf(&r, " %s", c[i].aliases[j]);
127 }
128 }
129
130 free_cpnames(c);
131 return lazya(vb_consume(&r));
132 }
133
134 static const char *
get_proxy(void)135 get_proxy(void)
136 {
137 const char *ptype = net_proxy_type();
138 const char *user = net_proxy_user();
139
140 return (ptype != NULL)?
141 lazyaf("%s %s %s%s%s",
142 ptype,
143 net_proxy_host(),
144 net_proxy_port(),
145 (user != NULL)? " ": "",
146 (user != NULL)? user: ""):
147 NULL;
148 }
149
150 static const char *
get_rx(void)151 get_rx(void)
152 {
153 if (!CONNECTED) {
154 return NULL;
155 }
156
157 return IN_3270?
158 lazyaf("records %u bytes %u", ns_rrcvd, ns_brcvd):
159 lazyaf("bytes %u", ns_brcvd);
160 }
161
162 static const char *
get_screentracefile(void)163 get_screentracefile(void)
164 {
165 if (!toggled(SCREEN_TRACE)) {
166 return NULL;
167 }
168 return trace_get_screentrace_name();
169 }
170
171 static const char *
get_tasks(void)172 get_tasks(void)
173 {
174 char *r = task_get_tasks();
175 size_t sl = strlen(r);
176
177 if (sl > 0 && r[sl - 1] == '\n') {
178 r[sl - 1] = '\0';
179 }
180 return lazya(r);
181 }
182
183 static const char *
get_tracefile(void)184 get_tracefile(void)
185 {
186 if (!toggled(TRACING)) {
187 return NULL;
188 }
189 return tracefile_name;
190 }
191
192 static const char *
get_tx(void)193 get_tx(void)
194 {
195 if (!CONNECTED) {
196 return NULL;
197 }
198
199 return IN_3270?
200 lazyaf("records %u bytes %u", ns_rsent, ns_bsent):
201 lazyaf("bytes %u", ns_bsent);
202 }
203
204 const char *
get_about(void)205 get_about(void)
206 {
207 return lazyaf("%s\nCopyright 1989-%s by Paul Mattes, GTRC and others.",
208 build, cyear);
209 }
210
211 /* Common code for Query() and Show() actions. */
212 bool
query_common(const char * name,ia_t ia,unsigned argc,const char ** argv)213 query_common(const char *name, ia_t ia, unsigned argc, const char **argv)
214 {
215 size_t i;
216 size_t sl;
217
218 action_debug(name, ia, argc, argv);
219 if (check_argc(name, argc, 0, 1) < 0) {
220 return false;
221 }
222
223 switch (argc) {
224 case 0:
225 for (i = 0; i < num_queries; i++) {
226 if (!queries[i].hidden) {
227 const char *s = (queries[i].fn? (*queries[i].fn)():
228 queries[i].string);
229
230 if (s == NULL) {
231 s = "";
232 }
233 if (queries[i].specific && strcmp(s, "")) {
234 s = "...";
235 }
236 action_output("%s:%s%s", queries[i].name, *s? " ": "", s);
237 }
238 }
239 break;
240 case 1:
241 sl = strlen(argv[0]);
242 for (i = 0; i < num_queries; i++) {
243 if (!strncasecmp(argv[0], queries[i].name, sl)) {
244 const char *s;
245
246 if (strlen(queries[i].name) > sl &&
247 queries[i + 1].name != NULL &&
248 !strncasecmp(argv[0], queries[i + 1].name, sl)) {
249 popup_an_error("%s: Ambiguous parameter", name);
250 return false;
251 }
252
253 if (queries[i].fn) {
254 s = (*queries[i].fn)();
255 } else {
256 s = queries[i].string;
257 }
258 if (s == NULL) {
259 s = "";
260 }
261 action_output("%s\n", s);
262 return true;
263 }
264 }
265 popup_an_error("%s: Unknown parameter", name);
266 return false;
267 }
268 return true;
269 }
270
271 /* Compare two queries by name. */
272 static int
query_compare(const void * a,const void * b)273 query_compare(const void *a, const void *b)
274 {
275 const query_t *qa = (query_t *)a;
276 const query_t *qb = (query_t *)b;
277
278 return strcmp(qa->name, qb->name);
279 }
280
281 bool
Query_action(ia_t ia,unsigned argc,const char ** argv)282 Query_action(ia_t ia, unsigned argc, const char **argv)
283 {
284 return query_common(AnQuery, ia, argc, argv);
285 }
286
287 bool
Show_action(ia_t ia,unsigned argc,const char ** argv)288 Show_action(ia_t ia, unsigned argc, const char **argv)
289 {
290 return query_common(AnShow, ia, argc, argv);
291 }
292
293 /**
294 * Register a set of queries.
295 */
296 void
register_queries(query_t new_queries[],size_t count)297 register_queries(query_t new_queries[], size_t count)
298 {
299 query_t *q = Malloc(sizeof(query_t) * (num_queries + count));
300
301 memcpy(q, queries, sizeof(query_t) * num_queries);
302 memcpy(q + num_queries, new_queries, sizeof(query_t) * count);
303 qsort(q, num_queries + count, sizeof(query_t), query_compare);
304 Free(queries);
305 queries = q;
306 num_queries += count;
307 }
308
309 /**
310 * Query module registration.
311 */
312 void
query_register(void)313 query_register(void)
314 {
315 static action_table_t actions[] = {
316 { AnQuery, Query_action, 0 },
317 { AnShow, Show_action, 0 }
318 };
319 static query_t base_queries[] = {
320 { KwAbout, get_about, NULL, false, true },
321 { KwActions, all_actions, NULL, false, true },
322 { KwBindPluName, net_query_bind_plu_name, NULL, false, false },
323 { KwBuildOptions, build_options, NULL, false, false },
324 { KwConnectionState, net_query_connection_state, NULL, false, false },
325 { KwConnectTime, get_connect_time, NULL, false, false },
326 { KwCodePage, get_codepage, NULL, false, false },
327 { KwCodePages, get_codepages, NULL, false, true },
328 { KwCopyright, show_copyright, NULL, false, true },
329 { KwCursor, ctlr_query_cursor, NULL, true, false },
330 { KwCursor1, ctlr_query_cursor1, NULL, false, false },
331 { KwFormatted, ctlr_query_formatted, NULL, false, false },
332 { KwHost, net_query_host, NULL, false, false },
333 { KwLocalEncoding, get_codeset, NULL, false, false },
334 { KwLuName, net_query_lu_name, NULL, false, false },
335 { KwModel, NULL, full_model_name, true, false },
336 { KwPrefixes, host_prefixes, NULL, false, false },
337 { KwProxy, get_proxy, NULL, false, false },
338 { KwScreenCurSize, ctlr_query_cur_size_old, NULL, true, false },
339 { KwScreenMaxSize, ctlr_query_max_size_old, NULL, true, false },
340 { KwScreenSizeCurrent, ctlr_query_cur_size, NULL, false, false },
341 { KwScreenSizeMax, ctlr_query_max_size, NULL, false, false },
342 { KwScreenTraceFile, get_screentracefile, NULL, false, false },
343 { KwSsl, net_query_tls, NULL, true, false },
344 { KwStatsRx, get_rx, NULL, false, false },
345 { KwStatsTx, get_tx, NULL, false, false },
346 { KwTasks, get_tasks, NULL, false, true },
347 { KwTelnetMyOptions, net_myopts, NULL, false, false },
348 { KwTelnetHostOptions, net_hisopts, NULL, false, false },
349 { KwTerminalName, query_terminal_name, NULL, false, false },
350 { KwTraceFile, get_tracefile, NULL, false, false },
351 { KwTls, net_query_tls, NULL, false, false },
352 { KwTlsCertInfo, net_server_cert_info, NULL, false, true },
353 { KwTlsProvider, net_sio_provider, NULL, false, false },
354 { KwTlsSessionInfo, net_session_info, NULL, false, true },
355 { KwTn3270eOptions, tn3270e_current_opts, NULL, false, false },
356 { KwVersion, query_build, NULL, false, false }
357 };
358
359 /* Register actions.*/
360 register_actions(actions, array_count(actions));
361
362 /* Register queries. */
363 register_queries(base_queries, array_count(base_queries));
364 }
365