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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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