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	3.3 (Berkeley) 06/29/88";
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     Host[ACK_SEQUENCE-1] |= ATTR_MDT;
477     if (putascii(ACK_SEQUENCE, a_ack_sequence, ACK_SEQUENCE_LENGTH, 1) == -1) {
478 	return -1;
479     }
480     return 0;
481 }
482 
483 static int
484 formatted_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 
497 main(argc, argv)
498 int	argc;
499 char	*argv[];
500 {
501     register int i;
502     int data_length, input_length;
503     char ascii[8];			/* Lots of room */
504     FILE *outfile;
505     char *data;
506     char *argv0 = argv[0];
507 
508     argc--;
509     argv++;
510     /* Process any flags */
511     while (argc && (argv[0][0] == '-')) {
512 	switch (argv[0][1]) {
513 	case 'v':
514 	    verbose = 1;
515 	    break;
516 	case 'b':
517 	    blocks = 1;
518 	    break;
519 	}
520 	argc--;
521 	argv++;
522     }
523 
524     if ((argc) < 2) {
525 	fprintf(stderr,
526 		"usage: %s [-b] [-v] local.file remote.file [remote.options]\n",
527 			argv0);
528 	exit(1);
529     }
530 
531     /* Open the local file */
532     if ((outfile = fopen(argv[0], "w")) == NULL) {
533 	perror("fopen");
534 	exit(2);
535     }
536     argc--;
537     argv++;
538 
539     if (initialize() == -1) {
540 	return -1;
541     }
542 
543     /* build the command line */
544     data = data_array;
545     strcpy(data, "TNCOMP SEND");
546     data += strlen(data);
547     while (argc--) {
548 	*data++ = ' ';
549 	strcpy(data, argv[0]);
550 	data += strlen(argv[0]);
551 	argv++;
552     }
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);
560     if ((i = find_input_area(0)) == -1) {		/* Get an input area */
561 	if (send_key(clear_index) == -1) {
562 	    return -1;
563 	}
564 	if ((i = find_input_area(0)) == -1) {		/* Try again */
565 	    fprintf(stderr, "Unable to enter command line.\n");
566 	    return -1;
567 	}
568     }
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) {
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 	}
584     } while (formatted_correct() == -1);
585 
586     do {
587 	if (get_screen() == -1) {
588 	    return -1;
589 	}
590 	/* For each screen */
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);
603 	send_sequence = atoi(a_send_sequence);
604 	getascii(CHECKSUM, a_checksum, CHECKSUM_LENGTH);
605 	checksum = atoi(a_checksum);
606 	getascii(DATA, data_array, DATA_LENGTH);
607 	data = data_array;
608 	if (send_sequence != (ack_sequence+1)) {
609 	    if (ack() == -1) {
610 		return -1;
611 	    }
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;
620 	}
621 
622 	data_length = DATA_LENGTH;
623 	while (data_length && memcmp(data, " EOF", 4)
624 						&& memcmp(data, "    ", 4)) {
625 	    memcpy(ascii, data, 4);
626 	    data += 4;
627 	    data_length -= 4;
628 	    ascii[4] = 0;
629 	    input_length = atoi(ascii);
630 	    /* CMS can't live with zero length records */
631 	    if ((input_length > 1) ||
632 			((input_length == 1) && (data[0] != ' '))) {
633 		if (fwrite(data, sizeof (char),
634 					input_length, outfile) == 0) {
635 		    perror("fwrite");
636 		    exit(9);
637 		}
638 	    }
639 	    fprintf(outfile, "\n");
640 	    data += input_length;
641 	    data_length -= input_length;
642 	}
643 
644 	ack_sequence = send_sequence;
645 	if (blocks) {
646 	    printf("#");
647 	    fflush(stdout);
648 	}
649 	if (ack() == -1) {
650 	    return -1;
651 	}
652 	if (send_key(enter_index) == -1) {
653 	    return -1;
654 	}
655     } while (memcmp(data, " EOF", 4));
656 
657     if (blocks) {
658 	printf("\n");
659     }
660     if (terminate() == -1) {
661 	return -1;
662     }
663     return 0;
664 }
665