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