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