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