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