Fixes for PC version.
[unix-history] / usr / src / usr.bin / tn3270 / distribution / utilities / tnrecv.c
CommitLineData
b6e18d58 1#include <stdio.h>
a0fc22ba 2
138011c0
GM
3#include <apilib/apilib.h>
4
b6e18d58
GM
5#include "tncomp.h"
6
7
8#include "../api/api.h"
9
10#include "../ctlr/function.h"
11#include "../ctlr/hostctlr.h"
12#include "../ctlr/oia.h"
13#include "../ctlr/screen.h"
14
55417bd3
GM
15#include "../apilib/disp_asc.h"
16#include "../apilib/astosc.h"
b6e18d58
GM
17
18#include "../general/general.h"
19
20ScreenImage Host[MAXSCREENSIZE];
21
22static char
85659f3c
GM
23 a_send_sequence[SEND_SEQUENCE_LENGTH+1],
24 a_ack_sequence[ACK_SEQUENCE_LENGTH+1],
25 a_checksum[CHECKSUM_LENGTH+1],
26 data_array[DATA_LENGTH+1];
b6e18d58
GM
27
28static int
29 verbose,
85659f3c 30 blocks,
b6e18d58
GM
31 enter_index,
32 clear_index,
33 ScreenSize,
34 session_id;
35
36static unsigned int
37 send_sequence,
85659f3c 38 ack_sequence = -1,
b6e18d58
GM
39 checksum;
40
41api_perror(string)
42char *string;
43{
44 fprintf(stderr, "Error: [0x%x/0x%x:0x%x/0x%x] from %s.\n",
45 api_sup_fcn_id, api_sup_errno,
46 api_fcn_fcn_id, api_fcn_errno, string);
47}
48
49
50char *
51session_type(type)
52int type;
53{
54 switch (type) {
55 case TYPE_WSCTL:
56 return "work station control";
57 case TYPE_DFT:
58 return "distributed function terminal";
59 case TYPE_CUT:
60 return "control unit terminal";
61 case TYPE_NOTEPAD:
62 return "notepad";
63 case TYPE_PC:
64 return "personal computer";
65 default:
66 return "(UNKNOWN)";
67 }
68}
69
85659f3c
GM
70static int
71wait_for_ps_or_oia()
72{
73#if defined(unix)
74 return api_ps_or_oia_modified();
75#endif /* defined(unix) */
76}
77
78
b6e18d58
GM
79static int
80wait_for_unlock()
81{
82 OIA oia;
83 ReadOiaGroupParms re;
85659f3c 84 static char zeroes[sizeof oia.input_inhibited] = { 0 };
b6e18d58
GM
85
86 do {
87 re.rc = re.function_id = 0;
88 re.session_id = session_id;
89 re.oia_buffer = (char far *) &oia;
90 re.oia_group_number = API_OIA_ALL_GROUPS;
91 if (api_read_oia_group(&re) == -1) {
92 api_perror("api_read_oia_group");
93 return -1;
94 } else if (verbose) {
95 if (IsOiaReady3274(&oia)) {
96 printf("3274 ready, ");
97 }
98 if (IsOiaMyJob(&oia)) {
99 printf("my job, ");
100 }
101 if (IsOiaInsert(&oia)) {
102 printf("insert mode, ");
103 }
104 if (IsOiaSystemLocked(&oia)) {
105 printf("system locked, ");
106 }
107 if (IsOiaTWait(&oia)) {
108 printf("terminal wait, ");
109 }
110 printf("are some bits from the OIA.\n");
111 }
85659f3c
GM
112 /* We turned this on, so turn it off now */
113 ResetOiaApiInhibit(&oia);
114 if (memcmp(zeroes, oia.input_inhibited, sizeof oia.input_inhibited)) {
115 if (wait_for_ps_or_oia() == -1) {
116 return -1;
117 }
118 }
119 } while (memcmp(zeroes, oia.input_inhibited, sizeof oia.input_inhibited));
b6e18d58
GM
120 return 0;
121}
122
123static int
124initialize()
125{
126 QuerySessionIdParms id;
127 QuerySessionParametersParms pa;
128 QuerySessionCursorParms cu;
129 ConnectToKeyboardParms conn;
130 DisableInputParms disable;
131 NameArray namearray;
132
133 if (api_init() == 0) {
134 fprintf(stderr, "API function not available.\n");
135 return -1;
136 }
137
138 id.rc = 0;
139 id.function_id = 0;
140 id.option_code = ID_OPTION_BY_NAME;
141 id.data_code = 'E';
142 id.name_array = &namearray;
143 namearray.length = sizeof namearray;
144 if (api_query_session_id(&id)) {
145 api_perror("api_query_session_id");
146 } else if (namearray.number_matching_session == 0) {
147 fprintf(stderr, "query_session_id: No matching sessions!\n");
148 return -1;
149 } else if (verbose) {
150 printf("Session short name 0x%x, type is ",
151 namearray.name_array_element.short_name);
152 printf("%s", session_type(namearray.name_array_element.type));
153 printf(", session ID is: 0x%x\n",
154 namearray.name_array_element.session_id);
155 }
156 session_id = namearray.name_array_element.session_id;
157
158 pa.rc = pa.function_id = 0;
159 pa.session_id = session_id;
160 if (api_query_session_parameters(&pa) == -1) {
161 api_perror("api_query_session_parameters");
162 return -1;
163 } else if (verbose) {
164 printf("Session type %s, ", session_type(pa.session_type));
165 if (pa.session_characteristics&CHARACTERISTIC_EAB) {
166 printf(" has EAB, ");
167 }
168 if (pa.session_characteristics&CHARACTERISTIC_PSS) {
169 printf(" has PSS, ");
170 }
171 printf("%d rows, %d columns ", pa.rows, pa.columns);
172 if (pa.presentation_space) {
173 printf("presentation space at 0x%x:0x%x.\n",
174 FP_SEG(pa.presentation_space), FP_OFF(pa.presentation_space));
175 } else {
176 printf("(no direct presentation space access).\n");
177 }
178 }
179 ScreenSize = pa.rows*pa.columns;
180 if (pa.session_characteristics&CHARACTERISTIC_EAB) {
181 fprintf(stderr,
182 "tncomp utilities not designed to work with extended attribute buffers.\n");
183 return -1;
184 }
185
186 if (verbose) {
187 cu.rc = cu.function_id = 0;
188 cu.session_id = session_id;
189 if (api_query_session_cursor(&cu) == -1) {
190 api_perror("api_query_session_cursor");
191 } else {
192 printf("cursor");
193 if (cu.cursor_type&CURSOR_INHIBITED_AUTOSCROLL) {
194 printf(" inhibited autoscroll");
195 }
196 if (cu.cursor_type&CURSOR_INHIBITED) {
197 printf(" inhibited");
198 }
199 if (cu.cursor_type&CURSOR_BLINKING) {
200 printf(" blinking");
201 } else {
202 printf(" not blinking");
203 }
204 if (cu.cursor_type&CURSOR_BOX) {
205 printf(" box ");
206 } else {
207 printf(" not box ");
208 }
209 printf("at row %d, column %d.\n",
210 cu.row_address, cu.column_address);
211 }
212 }
213
214 conn.rc = conn.function_id = 0;
215 conn.session_id = session_id;
216 conn.event_queue_id = conn.input_queue_id = 0;
217 conn.intercept_options = 0;
218 if (api_connect_to_keyboard(&conn) == -1) {
219 api_perror("api_connect_to_keyboard");
220 } else if (verbose) {
221 if (conn.first_connection_identifier) {
222 printf("First keyboard connection.\n");
223 } else {
224 printf("Not first keyboard connection.\n");
225 }
226 }
227
228 disable.rc = disable.function_id = 0;
229 disable.session_id = session_id;
230 disable.connectors_task_id = 0;
231 if (api_disable_input(&disable) == -1) {
232 api_perror("api_disable_input");
233 return -1;
234 } else if (verbose) {
235 printf("Disabled.\n");
236 }
237
238 if ((enter_index = ascii_to_index("ENTER")) == -1) {
239 return -1;
240 }
241 if ((clear_index = ascii_to_index("CLEAR")) == -1) {
242 return -1;
243 }
244
245 return 0; /* all ok */
246}
247
248static int
249send_key(index)
250int index;
251{
252 WriteKeystrokeParms wr;
253 extern struct astosc astosc[];
254
255 wait_for_unlock();
256
257 wr.rc = wr.function_id = 0;
258 wr.session_id = session_id;
259 wr.connectors_task_id = 0;
260 wr.options = OPTION_SINGLE_KEYSTROKE;
261 wr.number_of_keys_sent = 0;
262 wr.keystroke_specifier.keystroke_entry.scancode = astosc[index].scancode;
263 wr.keystroke_specifier.keystroke_entry.shift_state
264 = astosc[index].shiftstate;
265 if (api_write_keystroke(&wr) == -1) {
266 api_perror("api_write_keystroke");
267 return -1;
268 } else if (wr.number_of_keys_sent != 1) {
269 fprintf(stderr, "write_keystroke claims to have sent %d keystrokes.\n",
270 wr.number_of_keys_sent);
271 return -1;
272 } else if (verbose) {
273 printf("Keystroke sent.\n");
274 }
85659f3c
GM
275 if (wait_for_ps_or_oia() == -1) {
276 return -1;
277 }
b6e18d58
GM
278 return 0;
279}
280
281static int
282terminate()
283{
284 EnableInputParms enable;
285 DisconnectFromKeyboardParms disc;
286
287 enable.rc = enable.function_id = 0;
288 enable.session_id = session_id;
289 enable.connectors_task_id = 0;
290 if (api_enable_input(&enable) == -1) {
291 api_perror("api_enable");
292 return -1;
293 } else if (verbose) {
294 printf("Enabled.\n");
295 }
296
297 disc.rc = disc.function_id = 0;
298 disc.session_id = session_id;
299 disc.connectors_task_id = 0;
300 if (api_disconnect_from_keyboard(&disc) == -1) {
301 api_perror("api_disconnect_from_keyboard");
302 return -1;
303 } else if (verbose) {
304 printf("Disconnected from keyboard.\n");
305 }
306
307 (void) api_finish();
308
309 return 0;
310}
311
312
313static int
314get_screen()
315{
316 CopyStringParms copy;
317 /* Time copy services */
318
319 wait_for_unlock();
320
321 copy.copy_mode = 0;
322 copy.rc = copy.function_id = 0;
323 copy.source.session_id = session_id;
324 copy.source.buffer = 0;
325 copy.source.characteristics = 0;
326 copy.source.session_type = TYPE_DFT;
327 copy.source.begin = 0;
328
329 copy.source_end = ScreenSize;
330
331 copy.target.session_id = 0;
332 copy.target.buffer = (char *) &Host[0];
333 copy.target.characteristics = 0;
334 copy.target.session_type = TYPE_DFT;
335
336 if (api_copy_string(&copy) == -1) {
337 api_perror("api_copy_string");
338 return -1;
339 }
340 return 0;
341}
85659f3c
GM
342
343
344put_at(offset, from, length, attribute)
b6e18d58
GM
345int offset;
346char *from;
347int length;
348{
349 CopyStringParms copy;
b6e18d58
GM
350
351 wait_for_unlock();
352
353 copy.copy_mode = 0;
354 copy.rc = copy.function_id = 0;
355 copy.source.session_id = 0;
356 copy.source.buffer = from;
357 copy.source.characteristics = 0;
358 copy.source.session_type = TYPE_DFT;
359 copy.source.begin = 0;
360
361 copy.source_end = length-1;
362
363 copy.target.session_id = session_id;
364 copy.target.buffer = 0;
365 copy.target.characteristics = 0;
366 copy.target.session_type = TYPE_DFT;
367 copy.target.begin = offset;
368
369 if (api_copy_string(&copy) == -1) {
370 api_perror("api_copy_string");
371 return -1;
372 }
373 return 0;
374}
375
376static void
377translate(input, output, table, length)
378char *input, *output, table[];
379int length;
380{
381 unsigned char *indices = (unsigned char *) input;
382
383 while (length--) {
384 *output++ = table[*indices++];
385 }
386}
387
388static int
85659f3c
GM
389find_input_area(from)
390int from;
a0fc22ba 391{
55417bd3 392#define FieldDec(p) (0) /* We don't really use this */
b6e18d58
GM
393 register int i, attr;
394
85659f3c 395 for (i = from; i < MAXSCREENSIZE; ) {
b6e18d58
GM
396 if (IsStartField(i)) {
397 attr = FieldAttributes(i);
398 i++;
399 if (!IsProtectedAttr(i, attr)) {
400 return i;
401 }
402 } else {
403 i++;
a0fc22ba
GM
404 }
405 }
b6e18d58
GM
406 return -1;
407}
408
409
410static void
411getascii(offset, to, length)
412int offset; /* Where in screen */
413char *to; /* Where it goes to */
414int length; /* Where to put it */
415{
416 translate(Host+offset, to, disp_asc, length);
a0fc22ba
GM
417}
418
b6e18d58 419static int
85659f3c 420putascii(offset, from, length, before)
b6e18d58
GM
421int offset; /* Where in screen */
422char *from; /* Where it comes from */
423int length; /* Where to put it */
85659f3c 424int before; /* How much else should go */
b6e18d58
GM
425{
426 translate(from, Host+offset, asc_disp, length);
85659f3c
GM
427 if (put_at(offset-before,
428 (char *) Host+offset-before, length+before) == -1) {
b6e18d58
GM
429 return -1;
430 }
431 return 0;
432}
a0fc22ba 433
b6e18d58
GM
434static int
435ack()
436{
85659f3c
GM
437 static char ack_blanks[sizeof a_ack_sequence] = {0};
438
439 if (ack_blanks[0] == 0) {
440 int i;
441
442 for (i = 0; i < sizeof ack_blanks; i++) {
443 ack_blanks[i] = ' ';
444 }
445 }
446
447 memcpy(a_ack_sequence, ack_blanks, sizeof a_ack_sequence);
b6e18d58
GM
448 sprintf(a_ack_sequence, "%d", ack_sequence);
449 a_ack_sequence[strlen(a_ack_sequence)] = ' ';
85659f3c
GM
450 Host[ACK_SEQUENCE-1] |= ATTR_MDT;
451 if (putascii(ACK_SEQUENCE, a_ack_sequence, ACK_SEQUENCE_LENGTH, 1) == -1) {
b6e18d58
GM
452 return -1;
453 }
454 return 0;
455}
85659f3c
GM
456
457static int
458formatted_correct()
459{
460 if ((find_input_area(SEND_SEQUENCE-1) != SEND_SEQUENCE) ||
461 (find_input_area(SEND_SEQUENCE) != ACK_SEQUENCE) ||
462 (find_input_area(ACK_SEQUENCE) != CHECKSUM) ||
463 (find_input_area(CHECKSUM) != DATA)) {
464 return -1;
465 } else {
466 return 0;
467 }
468}
469
470
a0fc22ba
GM
471main(argc, argv)
472int argc;
473char *argv[];
474{
b6e18d58 475 register int i;
a0fc22ba
GM
476 int data_length, input_length;
477 char ascii[8]; /* Lots of room */
a0fc22ba 478 FILE *outfile;
b6e18d58
GM
479 char *data;
480 extern int optind;
481
482 /* Process any flags */
85659f3c 483 while ((i = getopt(argc, argv, "vb")) != EOF) {
b6e18d58
GM
484 switch (i) {
485 case 'v':
486 verbose = 1;
85659f3c
GM
487 break;
488 case 'b':
489 blocks = 1;
490 break;
b6e18d58
GM
491 }
492 }
a0fc22ba 493
b6e18d58 494 if ((argc-optind) < 2) {
a0fc22ba
GM
495 fprintf(stderr, "usage: %s local.file remote.file [remote.options]\n");
496 exit(1);
497 }
498
499 /* Open the local file */
b6e18d58 500 if ((outfile = fopen(argv[optind], "w")) == NULL) {
a0fc22ba
GM
501 perror("fopen");
502 exit(2);
503 }
504
b6e18d58
GM
505 optind++;
506
507 if (initialize() == -1) {
508 return -1;
509 }
510
a0fc22ba
GM
511 /* build the command line */
512 data = data_array;
b6e18d58 513 strcpy(data, "TNCOMP SEND");
a0fc22ba 514 data += strlen(data);
b6e18d58 515 for (; optind < argc; optind++) {
a0fc22ba 516 *data++ = ' ';
b6e18d58
GM
517 strcpy(data, argv[optind]);
518 data += strlen(argv[optind]);
a0fc22ba 519 }
b6e18d58
GM
520 if (verbose) {
521 printf("%s\n", data_array);
522 }
523 if (get_screen() == -1) {
524 return -1;
525 }
526 data_length = strlen(data_array);
527 if ((i = find_input_area()) == -1) { /* Get an input area */
528 if (send_key(clear_index) == -1) {
529 return -1;
530 }
85659f3c 531 if ((i = find_input_area(0)) == -1) { /* Try again */
b6e18d58
GM
532 fprintf(stderr, "Unable to enter command line.\n");
533 return -1;
534 }
535 }
85659f3c
GM
536 if (i == 0) {
537 Host[ScreenSize-1] |= ATTR_MDT;
538 } else {
539 Host[i-1] |= ATTR_MDT;
540 }
541 if (putascii(i, data_array, data_length, 1) == -1) {
b6e18d58
GM
542 return -1;
543 }
544 if (send_key(enter_index) == -1) {
545 return -1;
546 }
547 do {
548 if (get_screen() == -1) {
549 return -1;
550 }
85659f3c 551 } while (formatted_correct() == -1);
a0fc22ba 552
b6e18d58 553 do {
85659f3c
GM
554 if (get_screen() == -1) {
555 return -1;
556 }
b6e18d58 557 /* For each screen */
85659f3c
GM
558 if (formatted_correct() == -1) {
559 fprintf(stderr, "Bad screen written by host.\n");
560 return -1;
561 }
562 /* If MDT isn't reset in the sequence number, go around again */
563 if (Host[ACK_SEQUENCE-1]&ATTR_MDT) {
564 if (wait_for_ps_or_oia() == -1) {
565 return -1;
566 }
567 continue;
568 }
569 getascii(SEND_SEQUENCE, a_send_sequence, SEND_SEQUENCE_LENGTH);
b6e18d58 570 send_sequence = atoi(a_send_sequence);
85659f3c 571 getascii(CHECKSUM, a_checksum, CHECKSUM_LENGTH);
b6e18d58 572 checksum = atoi(a_checksum);
85659f3c 573 getascii(DATA, data_array, DATA_LENGTH);
b6e18d58
GM
574 data = data_array;
575 if (send_sequence != (ack_sequence+1)) {
85659f3c
GM
576 if (ack() == -1) {
577 return -1;
578 }
b6e18d58
GM
579 data = "1234"; /* Keep loop from failing */
580 if (send_key(enter_index) == -1) {
581 return -1;
582 }
583 if (get_screen() == -1) {
584 return -1;
585 }
586 continue;
a0fc22ba 587 }
b6e18d58 588
85659f3c
GM
589 data_length = DATA_LENGTH;
590 while (data_length && memcmp(data, " EOF", 4)
591 && memcmp(data, " ", 4)) {
b6e18d58 592 memcpy(ascii, data, 4);
85659f3c
GM
593 data += 4;
594 data_length -= 4;
b6e18d58
GM
595 ascii[4] = 0;
596 input_length = atoi(ascii);
85659f3c
GM
597 /* CMS can't live with zero length records */
598 if ((input_length > 1) ||
599 ((input_length == 1) && (data[0] != ' '))) {
b6e18d58 600 if (fwrite(data, sizeof (char),
85659f3c 601 input_length, outfile) == 0) {
b6e18d58
GM
602 perror("fwrite");
603 exit(9);
604 }
a0fc22ba 605 }
b6e18d58
GM
606 fprintf(outfile, "\n");
607 data += input_length;
608 data_length -= input_length;
609 }
85659f3c
GM
610
611 ack_sequence = send_sequence;
612 if (blocks) {
613 printf("#");
614 fflush(stdout);
615 }
616 if (ack() == -1) {
b6e18d58 617 return -1;
a0fc22ba 618 }
85659f3c 619 if (send_key(enter_index) == -1) {
b6e18d58
GM
620 return -1;
621 }
85659f3c 622 } while (memcmp(data, " EOF", 4));
b6e18d58 623
85659f3c
GM
624 if (blocks) {
625 printf("\n");
626 }
b6e18d58
GM
627 if (terminate() == -1) {
628 return -1;
a0fc22ba 629 }
b6e18d58 630 return 0;
a0fc22ba 631}