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