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