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