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