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 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.
16  */
17 
18 #ifndef lint
19 char 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
25 static char sccsid[] = "@(#)tnrecv.c	4.2 (Berkeley) 05/30/89";
26 #endif /* not lint */
27 
28 #include <stdio.h>
29 
30 #include <api/apilib.h>
31 
32 #include "tncomp.h"
33 
34 
35 #include "../ctlr/api.h"
36 #include "../ctlr/function.h"
37 #include "../ctlr/hostctlr.h"
38 #include "../ctlr/oia.h"
39 #include "../ctlr/screen.h"
40 
41 #include "../api/disp_asc.h"
42 #include "../api/astosc.h"
43 
44 #include "../general/general.h"
45 
46 ScreenImage Host[MAXSCREENSIZE];
47 
48 static char
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];
53 
54 static int
55     verbose,
56     blocks,
57     enter_index,
58     clear_index,
59     ScreenSize,
60     session_id;
61 
62 static unsigned int
63     send_sequence,
64     ack_sequence = -1,
65     checksum;
66 
67 api_perror(string)
68 char *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 
76 char *
77 session_type(type)
78 int	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 
96 static int
97 wait_for_ps_or_oia()
98 {
99 #if	defined(unix)
100     return api_ps_or_oia_modified();
101 #endif	/* defined(unix) */
102 }
103 
104 
105 static int
106 wait_for_unlock()
107 {
108     OIA oia;
109     ReadOiaGroupParms re;
110     static char zeroes[sizeof oia.input_inhibited] = { 0 };
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 	}
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));
146     return 0;
147 }
148 
149 static int
150 initialize()
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 
274 static int
275 send_key(index)
276 int	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     }
301     if (wait_for_ps_or_oia() == -1) {
302 	return -1;
303     }
304     return 0;
305 }
306 
307 static int
308 terminate()
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 
339 static int
340 get_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 }
368 
369 
370 put_at(offset, from, length, attribute)
371 int	offset;
372 char	*from;
373 int	length;
374 {
375     CopyStringParms copy;
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 
402 static void
403 translate(input, output, table, length)
404 char *input, *output, table[];
405 int length;
406 {
407     unsigned char *indices = (unsigned char *) input;
408 
409     while (length--) {
410 	*output++ = table[*indices++];
411     }
412 }
413 
414 static int
415 find_input_area(from)
416 int	from;
417 {
418 #define	FieldDec(p)	(0)		/* We don't really use this */
419     register int i, attr;
420 
421     for (i = from; i < MAXSCREENSIZE; ) {
422 	if (IsStartField(i)) {
423 	    attr = FieldAttributes(i);
424 	    i++;
425 	    if (!IsProtectedAttr(i, attr)) {
426 		return i;
427 	    }
428 	} else {
429 	    i++;
430 	}
431     }
432     return -1;
433 }
434 
435 
436 static void
437 getascii(offset, to, length)
438 int	offset;				/* Where in screen */
439 char	*to;				/* Where it goes to */
440 int	length;				/* Where to put it */
441 {
442     translate(Host+offset, to, disp_asc, length);
443 }
444 
445 static int
446 putascii(offset, from, length, before)
447 int	offset;				/* Where in screen */
448 char	*from;				/* Where it comes from */
449 int	length;				/* Where to put it */
450 int	before;				/* How much else should go */
451 {
452     translate(from, Host+offset, asc_disp, length);
453     if (put_at(offset-before,
454 			(char *) Host+offset-before, length+before) == -1) {
455 	return -1;
456     }
457     return 0;
458 }
459 
460 static int
461 ack()
462 {
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);
474     sprintf(a_ack_sequence, "%d", ack_sequence);
475     a_ack_sequence[strlen(a_ack_sequence)] = ' ';
476     if (putascii(ACK_SEQUENCE, a_ack_sequence, ACK_SEQUENCE_LENGTH, 0) == -1) {
477 	return -1;
478     }
479     return 0;
480 }
481 
482 static int
483 formatted_correct()
484 {
485     if ((find_input_area(SEND_SEQUENCE-1) != SEND_SEQUENCE) ||
486 	    (find_input_area(SEND_SEQUENCE) != ACK_SEQUENCE) ||
487 	    (find_input_area(ACK_SEQUENCE) != CHECKSUM) ||
488 	    (find_input_area(CHECKSUM) != DATA)) {
489 	return -1;
490     } else {
491 	return 0;
492     }
493 }
494 
495 
496 main(argc, argv)
497 int	argc;
498 char	*argv[];
499 {
500     register int i;
501     int data_length, input_length;
502     char ascii[8];			/* Lots of room */
503     FILE *outfile;
504     char *data;
505     char *argv0 = argv[0];
506 
507     argc--;
508     argv++;
509     /* Process any flags */
510     while (argc && (argv[0][0] == '-')) {
511 	switch (argv[0][1]) {
512 	case 'v':
513 	    verbose = 1;
514 	    break;
515 	case 'b':
516 	    blocks = 1;
517 	    break;
518 	}
519 	argc--;
520 	argv++;
521     }
522 
523     if ((argc) < 2) {
524 	fprintf(stderr,
525 		"usage: %s [-b] [-v] local.file remote.file [remote.options]\n",
526 			argv0);
527 	exit(1);
528     }
529 
530     /* Open the local file */
531     if ((outfile = fopen(argv[0], "w")) == NULL) {
532 	perror("fopen");
533 	exit(2);
534     }
535     argc--;
536     argv++;
537 
538     if (initialize() == -1) {
539 	return -1;
540     }
541 
542     /* build the command line */
543     data = data_array;
544     strcpy(data, "TNCOMP SEND");
545     data += strlen(data);
546     while (argc--) {
547 	*data++ = ' ';
548 	strcpy(data, argv[0]);
549 	data += strlen(argv[0]);
550 	argv++;
551     }
552     if (verbose) {
553 	printf("%s\n", data_array);
554     }
555     if (get_screen() == -1) {
556 	return -1;
557     }
558     data_length = strlen(data_array);
559     if ((i = find_input_area(0)) == -1) {		/* Get an input area */
560 	if (send_key(clear_index) == -1) {
561 	    return -1;
562 	}
563 	if ((i = find_input_area(0)) == -1) {		/* Try again */
564 	    fprintf(stderr, "Unable to enter command line.\n");
565 	    return -1;
566 	}
567     }
568     if (putascii(i, data_array, data_length, 0) == -1) {
569 	return -1;
570     }
571     if (send_key(enter_index) == -1) {
572 	return -1;
573     }
574     do {
575 	if (get_screen() == -1) {
576 	    return -1;
577 	}
578     } while (formatted_correct() == -1);
579 
580     do {
581 	if (get_screen() == -1) {
582 	    return -1;
583 	}
584 	/* For each screen */
585 	if (formatted_correct() == -1) {
586 	    fprintf(stderr, "Bad screen written by host.\n");
587 	    return -1;
588 	}
589 	/* If MDT isn't reset in the sequence number, go around again */
590 	if (Host[ACK_SEQUENCE-1]&ATTR_MDT) {
591 	    if (wait_for_ps_or_oia() == -1) {
592 		return -1;
593 	    }
594 	    continue;
595 	}
596 	getascii(SEND_SEQUENCE, a_send_sequence, SEND_SEQUENCE_LENGTH);
597 	send_sequence = atoi(a_send_sequence);
598 	getascii(CHECKSUM, a_checksum, CHECKSUM_LENGTH);
599 	checksum = atoi(a_checksum);
600 	getascii(DATA, data_array, DATA_LENGTH);
601 	data = data_array;
602 	if (send_sequence != (ack_sequence+1)) {
603 	    if (ack() == -1) {
604 		return -1;
605 	    }
606 	    data = "1234";		/* Keep loop from failing */
607 	    if (send_key(enter_index) == -1) {
608 		return -1;
609 	    }
610 	    if (get_screen() == -1) {
611 		return -1;
612 	    }
613 	    continue;
614 	}
615 
616 	data_length = DATA_LENGTH;
617 	while (data_length && memcmp(data, " EOF", 4)
618 						&& memcmp(data, "    ", 4)) {
619 	    memcpy(ascii, data, 4);
620 	    data += 4;
621 	    data_length -= 4;
622 	    ascii[4] = 0;
623 	    input_length = atoi(ascii);
624 	    /* CMS can't live with zero length records */
625 	    if ((input_length > 1) ||
626 			((input_length == 1) && (data[0] != ' '))) {
627 		if (fwrite(data, sizeof (char),
628 					input_length, outfile) == 0) {
629 		    perror("fwrite");
630 		    exit(9);
631 		}
632 	    }
633 	    fprintf(outfile, "\n");
634 	    data += input_length;
635 	    data_length -= input_length;
636 	}
637 
638 	ack_sequence = send_sequence;
639 	if (blocks) {
640 	    printf("#");
641 	    fflush(stdout);
642 	}
643 	if (ack() == -1) {
644 	    return -1;
645 	}
646 	if (send_key(enter_index) == -1) {
647 	    return -1;
648 	}
649     } while (memcmp(data, " EOF", 4));
650 
651     if (blocks) {
652 	printf("\n");
653     }
654     if (terminate() == -1) {
655 	return -1;
656     }
657     return 0;
658 }
659