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