xref: /original-bsd/usr.bin/tn3270/ctlr/api.c (revision 183db9ee)
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 static char sccsid[] = "@(#)api.c	3.3 (Berkeley) 08/28/88";
20 #endif /* not lint */
21 
22 /*
23  * This file implements the API used in the PC version.
24  */
25 
26 #include <stdio.h>
27 
28 #include "api.h"
29 #include "../general/general.h"
30 
31 #include "../api/disp_asc.h"
32 
33 #include "screen.h"
34 #include "oia.h"
35 
36 #include "../general/globals.h"
37 
38 /*
39  * General utility routines.
40  */
41 
42 #if	defined(MSDOS)
43 
44 #if	defined(LINT_ARGS)
45 static void movetous(char *, int, int, int);
46 static void movetothem(int, int, char *, int);
47 #endif	/* defined(LINT_ARGS) */
48 
49 #define	access_api(foo,length,copyin)	(foo)
50 #define	unaccess_api(foo,goo,length,copyout)
51 
52 static void
53 movetous(parms, es, di, length)
54 char *parms;
55 int es, di;
56 int length;
57 {
58     char far *farparms = parms;
59 
60     movedata(es, di, FP_SEG(farparms), FP_OFF(farparms), length);
61 }
62 
63 static void
64 movetothem(es, di, parms, length)
65 int es, di;
66 char *parms;
67 int length;
68 {
69     char far *farparms = parms;
70 
71     movedata(FP_SEG(farparms), FP_OFF(farparms), es, di, length);
72 }
73 #endif	/* defined(MSDOS) */
74 
75 #if	defined(unix)
76 extern char *access_api();
77 extern void movetous(), movetothem(), unaccess_api();
78 #endif	/* defined(unix) */
79 
80 
81 /*
82  * Supervisor Services.
83  */
84 
85 static void
86 name_resolution(regs, sregs)
87 union REGS *regs;
88 struct SREGS *sregs;
89 {
90     NameResolveParms parms;
91 
92     movetous((char *) &parms, sregs->es, regs->x.di, sizeof parms);
93 
94     regs->h.cl = 0;
95     if (memcmp((char *)&parms, NAME_SESSMGR, sizeof parms.gate_name) == 0) {
96 	regs->x.dx = GATE_SESSMGR;
97     } else if (memcmp((char *)&parms, NAME_KEYBOARD,
98 					sizeof parms.gate_name) == 0) {
99 	regs->x.dx = GATE_KEYBOARD;
100     } else if (memcmp((char *)&parms, NAME_COPY, sizeof parms.gate_name) == 0) {
101 	regs->x.dx = GATE_COPY;
102     } else if (memcmp((char *)&parms, NAME_OIAM, sizeof parms.gate_name) == 0) {
103 	regs->x.dx = GATE_OIAM;
104     } else {
105 	regs->h.cl = 0x2e;	/* Name not found */
106     }
107     regs->h.ch = 0x12;
108     regs->h.bh = 7;
109 }
110 
111 /*
112  * Session Information Services.
113  */
114 
115 static void
116 query_session_id(regs, sregs)
117 union REGS *regs;
118 struct SREGS *sregs;
119 {
120     QuerySessionIdParms parms;
121 
122     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
123 
124     if ((parms.rc != 0) || (parms.function_id != 0)) {
125 	parms.rc = 0x0c;
126     } else if (parms.option_code != 0x01) {
127 	parms.rc = 0x0d;	/* Invalid option code */
128     } else if (parms.data_code != 0x45) {
129 	parms.rc = 0x0b;
130     } else {
131 	NameArray list;
132 
133 	movetous((char *)&list, FP_SEG(parms.name_array),
134 		    FP_OFF(parms.name_array), sizeof list);
135 	if ((list.length < 14) || (list.length > 170)) {
136 	    parms.rc = 0x12;
137 	} else {
138 	    list.number_matching_session = 1;
139 	    list.name_array_element.short_name = parms.data_code;
140 	    list.name_array_element.type = TYPE_DFT;
141 	    list.name_array_element.session_id = 23;
142 	    memcpy(list.name_array_element.long_name, "ONLYSESS",
143 			    sizeof list.name_array_element.long_name);
144 	    movetothem(FP_SEG(parms.name_array),
145 		FP_OFF(parms.name_array), (char *)&list, sizeof list);
146 	    parms.rc = 0;
147 	}
148     }
149     parms.function_id = 0x6b;
150     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
151 }
152 
153 static void
154 query_session_parameters(regs, sregs)
155 union REGS *regs;
156 struct SREGS *sregs;
157 {
158     QuerySessionParametersParms parms;
159 
160     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
161 
162     if ((parms.rc !=0) || (parms.function_id != 0)) {
163 	parms.rc = 0x0c;
164     } else if (parms.session_id != 23) {
165 	parms.rc = 0x02;
166     } else {
167 	parms.rc = 0;
168 	parms.session_type = TYPE_DFT;
169 	parms.session_characteristics = 0;	/* Neither EAB nor PSS */
170 	parms.rows = MaxNumberLines;
171 	parms.columns = MaxNumberColumns;
172 	parms.presentation_space = 0;
173     }
174     parms.function_id = 0x6b;
175     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
176 }
177 
178 static void
179 query_session_cursor(regs, sregs)
180 union REGS *regs;
181 struct SREGS *sregs;
182 {
183     QuerySessionCursorParms parms;
184 
185     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
186 
187     if ((parms.rc != 0) || (parms.function_id != 0)) {
188 	parms.rc = 0x0c;
189     } else if (parms.session_id != 23) {
190 	parms.rc = 0x02;
191     } else {
192 	parms.rc = 0;
193 	parms.cursor_type = CURSOR_BLINKING;	/* XXX what is inhibited? */
194 	parms.row_address = ScreenLine(CursorAddress);
195 	parms.column_address = ScreenLineOffset(CursorAddress);
196     }
197 
198     parms.function_id = 0x6b;
199     movetothem(sregs->es, regs->x.di, (char *) &parms, sizeof parms);
200 }
201 
202 /*
203  * Keyboard Services.
204  */
205 
206 
207 static void
208 connect_to_keyboard(regs, sregs)
209 union REGS *regs;
210 struct SREGS *sregs;
211 {
212     ConnectToKeyboardParms parms;
213 
214     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
215 
216     if ((parms.rc != 0) || (parms.function_id != 0)) {
217 	parms.rc = 0x0c;
218     } else if (parms.session_id != 23) {
219 	parms.rc = 0x02;
220     } else if (parms.intercept_options != 0) {
221 	parms.rc = 0x01;
222     } else {
223 	parms.rc = 0;
224 	parms.first_connection_identifier = 0;
225     }
226     parms.function_id = 0x62;
227 
228     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
229 }
230 
231 static void
232 disconnect_from_keyboard(regs, sregs)
233 union REGS *regs;
234 struct SREGS *sregs;
235 {
236     DisconnectFromKeyboardParms parms;
237 
238     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
239 
240     if ((parms.rc != 0) || (parms.function_id != 0)) {
241 	parms.rc = 0x0c;
242     } else if (parms.session_id != 23) {
243 	parms.rc = 0x02;
244     } else if (parms.connectors_task_id != 0) {
245 	parms.rc = 04;			/* XXX */
246     } else {
247 	parms.rc = 0;
248     }
249     parms.function_id = 0x62;
250 
251     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
252 }
253 
254 static void
255 write_keystroke(regs, sregs)
256 union REGS *regs;
257 struct SREGS *sregs;
258 {
259     WriteKeystrokeParms parms;
260 
261     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
262 
263     if ((parms.rc != 0) || (parms.function_id != 0)) {
264 	parms.rc = 0x0c;
265     } else if (parms.session_id != 23) {
266 	parms.rc = 0x02;
267     } else if (parms.connectors_task_id != 0) {
268 	parms.rc = 0x04;
269     } else {
270 	parms.number_of_keys_sent = 0;
271 	parms.rc = 0;
272 	if (parms.options == OPTION_SINGLE_KEYSTROKE) {
273 	    KeystrokeEntry *entry = &parms.keystroke_specifier.keystroke_entry;
274 
275 	    if (AcceptKeystroke(entry->scancode, entry->shift_state) == 0) {
276 		parms.rc = 0x10;		/* XXX needs 0x12 too! */
277 	    }
278 	    parms.number_of_keys_sent++;
279 	} else if (parms.options == OPTION_MULTIPLE_KEYSTROKES) {
280 	    KeystrokeList
281 		list,
282 		far *atlist = parms.keystroke_specifier.keystroke_list;
283 	    KeystrokeEntry
284 		entry[10],		/* 10 at a time */
285 		*ourentry,
286 		far *theirentry;
287 	    int
288 		todo;
289 
290 	    movetous((char *)&list, FP_SEG(atlist),
291 			FP_OFF(atlist), sizeof *atlist);
292 	    todo = list.length/2;
293 	    ourentry = entry+(highestof(entry)+1);
294 	    theirentry = &atlist->keystrokes;
295 
296 	    while (todo) {
297 		if (ourentry > &entry[highestof(entry)]) {
298 		    int thistime;
299 
300 		    thistime = todo;
301 		    if (thistime > numberof(entry)) {
302 			thistime = numberof(entry);
303 		    }
304 		    movetous((char *)entry, FP_SEG(theirentry),
305 			    FP_OFF(theirentry), thistime*sizeof *theirentry);
306 		    theirentry += thistime;
307 		    ourentry = entry;
308 		}
309 		if (AcceptKeystroke(ourentry->scancode,
310 						ourentry->shift_state) == 0) {
311 		    parms.rc = 0x10;		/* XXX needs 0x12 too! */
312 		    break;
313 		}
314 		parms.number_of_keys_sent++;
315 		ourentry++;
316 		todo--;
317 	    }
318 	} else {
319 	    parms.rc = 0x01;
320 	}
321     }
322     parms.function_id = 0x62;
323 
324     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
325 /* XXX */
326 }
327 
328 
329 static void
330 disable_input(regs, sregs)
331 union REGS *regs;
332 struct SREGS *sregs;
333 {
334     DisableInputParms parms;
335 
336     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
337 
338     if ((parms.rc != 0) || (parms.function_id != 0)) {
339 	parms.rc = 0x0c;
340     } else if (parms.session_id != 23) {
341 	parms.rc = 0x02;
342     } else if (parms.connectors_task_id != 0) {
343 	parms.rc = 0x04;
344     } else {
345 	SetOiaApiInhibit(&OperatorInformationArea);
346 	parms.rc = 0;
347     }
348     parms.function_id = 0x62;
349 
350     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
351 }
352 
353 static void
354 enable_input(regs, sregs)
355 union REGS *regs;
356 struct SREGS *sregs;
357 {
358     EnableInputParms parms;
359 
360     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
361 
362     if ((parms.rc != 0) || (parms.function_id != 0)) {
363 	parms.rc = 0x0c;
364     } else if (parms.session_id != 23) {
365 	parms.rc = 0x02;
366     } else if (parms.connectors_task_id != 0) {
367 	parms.rc = 0x04;
368     } else {
369 	ResetOiaApiInhibit(&OperatorInformationArea);
370 	parms.rc = 0;
371     }
372     parms.function_id = 0x62;
373 
374     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
375 }
376 
377 /*
378  * Copy Services.
379  */
380 
381 static
382 copy_subroutine(target, source, parms, what_is_user, length)
383 BufferDescriptor *target, *source;
384 CopyStringParms *parms;
385 int what_is_user;
386 #define	USER_IS_TARGET	0
387 #define	USER_IS_SOURCE	1
388 {
389 #define	TARGET_NO_EAB		1
390 #define	SOURCE_NO_EAB		2
391 #define	TARGET_PC		4
392 #define	SOURCE_PC		8
393 #define	NO_FIELD_ATTRIBUTES	16
394     int needtodo = 0;
395     int access_length;
396     char far *input;
397     char far *output;
398     char far *access_pointer;
399 
400     if ((target->characteristics^source->characteristics)
401 		    &CHARACTERISTIC_EAB) {
402 	if (target->characteristics&CHARACTERISTIC_EAB) {
403 	    needtodo |= TARGET_NO_EAB;	/* Need to bump for EAB in target */
404 	} else {
405 	    needtodo |= SOURCE_NO_EAB;	/* Need to bump for EAB in source */
406 	}
407     }
408     if (target->session_type != source->session_type) {
409 	if (target->session_type == TYPE_PC) {
410 	    needtodo |= TARGET_PC;	/* scan codes to PC */
411 	} else {
412 	    needtodo |= SOURCE_PC;	/* PC to scan codes */
413 	}
414     }
415     if ((parms->copy_mode&COPY_MODE_FIELD_ATTRIBUTES) == 0) {
416 	needtodo |= NO_FIELD_ATTRIBUTES;
417     }
418     access_length = length;
419     if (what_is_user == USER_IS_TARGET) {
420 	if (target->characteristics&CHARACTERISTIC_EAB) {
421 	    access_length *= 2;
422 	}
423 	input = (char far *) &Host[source->begin];
424 	access_pointer = target->buffer;
425 	output = access_api(target->buffer, access_length, 0);
426     } else {
427 	if (source->characteristics&CHARACTERISTIC_EAB) {
428 	    access_length *= 2;
429 	}
430 	access_pointer = source->buffer;
431 	input = access_api(source->buffer, access_length, 1);
432 	output = (char far *) &Host[target->begin];
433     }
434     while (length--) {
435 	if (needtodo&TARGET_PC) {
436 	    *output++ = disp_asc[*input++];
437 	} else if (needtodo&SOURCE_PC) {
438 	    *output++ = asc_disp[*input++];
439 	} else {
440 	    *output++ = *input++;
441 	}
442 	if (needtodo&TARGET_NO_EAB) {
443 	    input++;
444 	} else if (needtodo&SOURCE_NO_EAB) {
445 	    *output++ = 0;		/* Should figure out good EAB? */
446 	}
447     }
448     if (what_is_user == USER_IS_TARGET) {
449 	unaccess_api(target->buffer, access_pointer, access_length, 1);
450     } else {
451 	unaccess_api(source->buffer, access_pointer, access_length, 0);
452     }
453 }
454 
455 
456 static void
457 copy_string(regs, sregs)
458 union REGS *regs;
459 struct SREGS *sregs;
460 {
461     CopyStringParms parms;
462     BufferDescriptor *target = &parms.target, *source = &parms.source;
463     int length;
464 
465     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
466 
467     length = 1+parms.source_end-source->begin;
468     if ((parms.rc != 0) || (parms.function_id !=0)) {
469 	parms.rc = 0x0c;
470     } else if (target->session_id == 0) {	/* Target is buffer */
471 	if (source->session_id != 23) {		/* A no-no */
472 	    parms.rc = 0x2;
473 	} else {
474 	    if ((source->begin < 0) || (source->begin > highestof(Host))) {
475 		parms.rc = 0x06;		/* invalid source definition */
476 	    } else {
477 		if ((source->begin+length) > highestof(Host)) {
478 		    length = highestof(Host)-source->begin;
479 		    parms.rc = 0x0f;	/* Truncate */
480 		}
481 	        if ((source->characteristics == target->characteristics) &&
482 		    (source->session_type == target->session_type)) {
483 		    if (source->characteristics&CHARACTERISTIC_EAB) {
484 			length *= 2;
485 		    }
486 		    movetothem(FP_SEG(target->buffer),
487 			    FP_OFF(target->buffer),
488 			    (char *)&Host[source->begin], length);
489 		} else {
490 		    copy_subroutine(target, source, &parms,
491 							USER_IS_TARGET, length);
492 		}
493 	    }
494 	}
495     } else if (source->session_id != 0) {
496 	    parms.rc = 0xd;
497     } else {
498 	if ((target->begin < 0) || (source->begin > highestof(Host))) {
499 	    parms.rc = 0x07;		/* invalid source definition */
500 	} else {
501 	    if ((source->begin+length) > highestof(Host)) {
502 		length = highestof(Host)-source->begin;
503 		parms.rc = 0x0f;	/* Truncate */
504 	    }
505 	    if ((source->characteristics == target->characteristics) &&
506 		    (source->session_type == target->session_type)) {
507 		if (source->characteristics&CHARACTERISTIC_EAB) {
508 		    length *= 2;
509 		}
510 		movetous((char *)&Host[target->begin],
511 			    FP_SEG(source->buffer),
512 			    FP_OFF(source->buffer), length);
513 	    } else {
514 		copy_subroutine(target, source, &parms, USER_IS_SOURCE, length);
515 	    }
516 	}
517     }
518     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
519 }
520 /*
521  * Operator Information Area Services.
522  */
523 
524 static void
525 read_oia_group(regs, sregs)
526 union REGS *regs;
527 struct SREGS *sregs;
528 {
529     ReadOiaGroupParms parms;
530 
531     movetous((char *)&parms, sregs->es, regs->x.di, sizeof parms);
532 
533     if ((parms.rc != 0) || (parms.function_id != 0)) {
534 	parms.rc = 0x0c;
535     } else if (parms.session_id != 23) {
536 	parms.rc = 0x02;
537     } else {
538 	int group = parms.oia_group_number;
539 	char *from;
540 	int size;
541 
542 	if ((group != API_OIA_ALL_GROUPS) &&
543 		((group > API_OIA_LAST_LEGAL_GROUP) || (group < 0))) {
544 	} else {
545 	    if (group == API_OIA_ALL_GROUPS) {
546 		size = API_OIA_BYTES_ALL_GROUPS;
547 		from = (char *)&OperatorInformationArea;
548 	    } else if (group == API_OIA_INPUT_INHIBITED) {
549 		size = sizeof OperatorInformationArea.input_inhibited;
550 		from = (char *)&OperatorInformationArea.input_inhibited[0];
551 	    } else {
552 		size = 1;
553 		from = ((char *)&OperatorInformationArea)+group;
554 	    }
555 	    movetothem(FP_SEG(parms.oia_buffer), FP_OFF(parms.oia_buffer),
556 			from, size);
557 	}
558     }
559     parms.function_id = 0x6d;
560     movetothem(sregs->es, regs->x.di, (char *)&parms, sizeof parms);
561 }
562 
563 /*ARGSUSED*/
564 static void
565 unknown_op(regs, sregs)
566 union REGS *regs;
567 struct SREGS *sregs;
568 {
569     regs->h.ch = 0x12;
570     regs->h.cl = 0x05;
571 }
572 
573 
574 handle_api(regs, sregs)
575 union REGS *regs;
576 struct SREGS *sregs;
577 {
578     if (regs->h.ah == NAME_RESOLUTION) {
579 	name_resolution(regs, sregs);
580 #if	defined(unix)
581     } else if (regs->h.ah == PS_OR_OIA_MODIFIED) {
582 	while ((oia_modified == 0) && (ps_modified == 0)) {
583 	    (void) Scheduler(1);
584 	}
585 	oia_modified = ps_modified = 0;
586 #endif	/* defined(unix) */
587     } else if (regs->h.ah != 0x09) {
588 	regs->h.ch = 0x12;
589 	regs->h.cl = 0x0f;		/* XXX Invalid environmental access */
590     } else if (regs->x.bx != 0x8020) {
591 	regs->h.ch = 0x12;
592 	regs->h.cl = 0x08;		/* XXX Invalid wait specified */
593     } else if (regs->h.ch != 0) {
594 	regs->x.cx = 0x1206;		/* XXX Invalid priority */
595     } else {
596 	switch (regs->x.dx) {
597 	case GATE_SESSMGR:
598 	    switch (regs->h.al) {
599 	    case QUERY_SESSION_ID:
600 		if (regs->h.cl != 0) {
601 		    regs->x.cx = 0x1206;
602 		} else {
603 		    regs->x.cx = 0x1200;
604 		    query_session_id(regs, sregs);
605 		}
606 		break;
607 	    case QUERY_SESSION_PARAMETERS:
608 		if (regs->h.cl != 0) {
609 		    regs->x.cx = 0x1206;
610 		} else {
611 		    regs->x.cx = 0x1200;
612 		    query_session_parameters(regs, sregs);
613 		}
614 		break;
615 	    case QUERY_SESSION_CURSOR:
616 		if (regs->h.cl != 0xff) {
617 		    regs->x.cx = 0x1206;
618 		} else {
619 		    regs->x.cx = 0x1200;
620 		    query_session_cursor(regs, sregs);
621 		}
622 		break;
623 	    default:
624 		unknown_op(regs, sregs);
625 		break;
626 	    }
627 	    break;
628 	case GATE_KEYBOARD:
629 	    if (regs->h.cl != 00) {
630 		regs->x.cx = 0x1206;
631 	    } else {
632 		regs->x.cx = 0x1200;
633 		switch (regs->h.al) {
634 		case CONNECT_TO_KEYBOARD:
635 		    connect_to_keyboard(regs, sregs);
636 		    break;
637 		case DISABLE_INPUT:
638 		    disable_input(regs, sregs);
639 		    break;
640 		case WRITE_KEYSTROKE:
641 		    write_keystroke(regs, sregs);
642 		    break;
643 		case ENABLE_INPUT:
644 		    enable_input(regs, sregs);
645 		    break;
646 		case DISCONNECT_FROM_KEYBOARD:
647 		    disconnect_from_keyboard(regs, sregs);
648 		    break;
649 		default:
650 		    unknown_op(regs, sregs);
651 		    break;
652 		}
653 	    }
654 	    break;
655 	case GATE_COPY:
656 	    if (regs->h.cl != 0xff) {
657 		regs->x.cx = 0x1206;
658 	    } else {
659 		regs->x.cx = 0x1200;
660 		switch (regs->h.al) {
661 		case COPY_STRING:
662 		    copy_string(regs, sregs);
663 		    break;
664 		default:
665 		    unknown_op(regs, sregs);
666 		    break;
667 		}
668 	    }
669 	    break;
670 	case GATE_OIAM:
671 	    if (regs->h.cl != 0xff) {
672 		regs->x.cx = 0x1206;
673 	    } else {
674 		regs->x.cx = 0x1200;
675 		switch (regs->h.al) {
676 		case READ_OIA_GROUP:
677 		    read_oia_group(regs, sregs);
678 		    break;
679 		default:
680 		    unknown_op(regs, sregs);
681 		    break;
682 		}
683 	    }
684 	    break;
685 	default:
686 	    regs->h.ch = 0x12;
687 	    regs->h.cl = 0x34;		/* Invalid GATE entry */
688 	    break;
689 	}
690     }
691 }
692