1 /* 2 * Copyright (c) 1984, 1985, 1986 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[] = "@(#)outbound.c 3.1 10/29/86"; 24 #endif /* lint */ 25 26 27 #include <stdio.h> 28 29 #include "../general/general.h" 30 31 #include "hostctlr.h" 32 #include "oia.h" 33 #include "screen.h" 34 #include "ebc_disp.h" 35 36 #include "../general/globals.h" 37 #include "options.ext" 38 #include "../telnet.ext" 39 #include "inbound.ext" 40 #include "outbound.ext" 41 #include "../general/bsubs.ext" 42 43 #define SetHighestLowest(position) { \ 44 if (position < Lowest) { \ 45 Lowest = position; \ 46 } \ 47 if (position > Highest) { \ 48 Highest = position; \ 49 } \ 50 } 51 52 53 static int LastWasTerminated = 1; /* was "control" = 1 last time? */ 54 55 /* some globals */ 56 57 #if !defined(PURE3274) 58 int OutputClock; /* what time it is */ 59 int TransparentClock; /* time we were last in transparent */ 60 #endif /* !defined(PURE3274) */ 61 62 char CIABuffer[64] = { 63 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 64 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 65 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 66 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 67 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 68 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 69 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 70 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f 71 }; 72 73 static struct orders_def orders_def[] = ORDERS_DEF; 74 75 /* 76 * init_ctlr() 77 * 78 * Initialize all data from the 'data' portion to their startup values. 79 */ 80 81 void 82 init_ctlr() 83 { 84 LastWasTerminated = 1; 85 #if !defined(PURE3274) 86 OutputClock = TransparentClock = 0; 87 #endif /* !defined(PURE3274) */ 88 init_inbound(); 89 init_oia(); 90 } 91 92 93 FieldInc(position) 94 register int position; /* Position in previous field */ 95 { 96 register ScreenImage *ptr; 97 98 ptr = (ScreenImage *)memNSchr((char *)Host+position+1, ATTR_MASK, 99 HighestScreen()-position, ATTR_MASK, sizeof Host[0]); 100 if (ptr == 0) { 101 ptr = (ScreenImage *)memNSchr((char *)Host+LowestScreen(), ATTR_MASK, 102 position-LowestScreen(), ATTR_MASK, sizeof Host[0]); 103 if (ptr == 0) { 104 return LowestScreen(); 105 } 106 } 107 return ptr-Host; 108 } 109 110 FieldDec(position) 111 int position; 112 { 113 register ScreenImage *ptr; 114 115 ptr = (ScreenImage *)memNSchr((char *)(Host+position)-1, ATTR_MASK, 116 position-LowestScreen(), ATTR_MASK, -sizeof Host[0]); 117 if (ptr == 0) { 118 ptr = (ScreenImage *)memNSchr((char *)Host+HighestScreen(), ATTR_MASK, 119 HighestScreen()-position, ATTR_MASK, -sizeof Host[0]); 120 if (ptr == 0) { 121 return LowestScreen(); 122 } 123 } 124 return ptr-Host; 125 } 126 127 /* Clear3270 - called to clear the screen */ 128 129 void 130 Clear3270() 131 { 132 ClearArray(Host); 133 DeleteAllFields(); /* get rid of all fields */ 134 BufferAddress = SetBufferAddress(0,0); 135 CursorAddress = SetBufferAddress(0,0); 136 Lowest = LowestScreen(); 137 Highest = HighestScreen(); 138 } 139 140 /* AddHost - called to add a character to the buffer. 141 * We use a macro in this module, since we call it so 142 * often from loops. 143 * 144 * NOTE: It is a macro, so don't go around using AddHost(p, *c++), or 145 * anything similar. (I don't define any temporary variables, again 146 * just for the speed.) 147 */ 148 void 149 AddHost(position, character) 150 int position; 151 char character; 152 { 153 #if defined(SLOWSCREEN) 154 # define AddHostA(p,c) \ 155 { \ 156 if (IsStartField(p)) { \ 157 DeleteField(p); \ 158 Highest = HighestScreen(); \ 159 Lowest = LowestScreen(); \ 160 SetHighestLowest(p); \ 161 } \ 162 SetHost(p, c); \ 163 } 164 # define AddHost(p,c) \ 165 { \ 166 if (c != GetHost(p)) { \ 167 SetHighestLowest(p); \ 168 } \ 169 AddHostA(p,c); \ 170 } /* end of macro of AddHost */ 171 #else /* defined(SLOWSCREEN) */ 172 # define AddHost(p,c) \ 173 { \ 174 if (IsStartField(p)) { \ 175 DeleteField(p); \ 176 Highest = HighestScreen(); \ 177 Lowest = LowestScreen(); \ 178 SetHost(p, c); \ 179 } else { \ 180 SetHost(p, c); \ 181 SetHighestLowest(p); \ 182 } \ 183 } /* end of macro of AddHost */ 184 #endif /* defined(SLOWSCREEN) */ 185 186 AddHost(position, character); 187 } 188 189 /* returns the number of characters consumed */ 190 int 191 DataFromNetwork(buffer, count, control) 192 register unsigned char *buffer; /* what the data is */ 193 register int count; /* and how much there is */ 194 int control; /* this buffer ended block? */ 195 { 196 int origCount; 197 register int c; 198 register int i; 199 static int Command; 200 static int Wcc; 201 202 origCount = count; 203 204 if (LastWasTerminated) { 205 206 if (count < 2) { 207 if (count == 0) { 208 ExitString(stderr, "Short count received from host!\n", 1); 209 return(count); 210 } 211 Command = buffer[0]; 212 switch (Command) { /* This had better be a read command */ 213 case CMD_READ_MODIFIED: 214 case CMD_SNA_READ_MODIFIED: 215 case CMD_SNA_READ_MODIFIED_ALL: 216 SetOiaOnlineA(&OperatorInformationArea); 217 SetOiaModified(); 218 DoReadModified(Command); 219 break; 220 case CMD_READ_BUFFER: 221 case CMD_SNA_READ_BUFFER: 222 SetOiaOnlineA(&OperatorInformationArea); 223 SetOiaModified(); 224 DoReadBuffer(); 225 break; 226 default: 227 { 228 char buffer[100]; 229 230 sprintf(buffer, 231 "Unexpected read command code 0x%x received.\n", 232 Command); 233 ExitString(stderr, buffer, 1); 234 break; 235 } 236 } 237 return(1); /* We consumed everything */ 238 } 239 Command = buffer[0]; 240 Wcc = buffer[1]; 241 if (Wcc & WCC_RESET_MDT) { 242 i = c = WhereAttrByte(LowestScreen()); 243 do { 244 if (HasMdt(i)) { 245 TurnOffMdt(i); 246 } 247 i = FieldInc(i); 248 } while (i != c); 249 } 250 251 switch (Command) { 252 case CMD_ERASE_WRITE: 253 case CMD_ERASE_WRITE_ALTERNATE: 254 case CMD_SNA_ERASE_WRITE: 255 case CMD_SNA_ERASE_WRITE_ALTERNATE: 256 { 257 int newlines, newcolumns; 258 259 SetOiaOnlineA(&OperatorInformationArea); 260 ResetOiaTWait(&OperatorInformationArea); 261 SetOiaModified(); 262 if ((Command == CMD_ERASE_WRITE) 263 || (Command == CMD_SNA_ERASE_WRITE)) { 264 newlines = 24; 265 newcolumns = 80; 266 } else { 267 newlines = MaxNumberLines; 268 newcolumns = MaxNumberColumns; 269 } 270 if ((newlines != NumberLines) 271 || (newcolumns != NumberColumns)) { 272 /* 273 * The LocalClearScreen() is really for when we 274 * are going from a larger screen to a smaller 275 * screen, and we need to clear off the stuff 276 * at the end of the lines, or the lines at 277 * the end of the screen. 278 */ 279 LocalClearScreen(); 280 NumberLines = newlines; 281 NumberColumns = newcolumns; 282 ScreenSize = NumberLines * NumberColumns; 283 } 284 Clear3270(); 285 #if !defined(PURE3274) 286 if (TransparentClock == OutputClock) { 287 TransStop(); 288 } 289 #endif /* !defined(PURE3274) */ 290 break; 291 } 292 293 case CMD_ERASE_ALL_UNPROTECTED: 294 case CMD_SNA_ERASE_ALL_UNPROTECTED: 295 SetOiaOnlineA(&OperatorInformationArea); 296 ResetOiaTWait(&OperatorInformationArea); 297 SetOiaModified(); 298 CursorAddress = HighestScreen()+1; 299 for (i = LowestScreen(); i <= HighestScreen(); i = ScreenInc(i)) { 300 if (IsUnProtected(i)) { 301 if (CursorAddress > i) { 302 CursorAddress = i; 303 } 304 AddHost(i, '\0'); 305 } 306 if (HasMdt(i)) { 307 TurnOffMdt(i); 308 } 309 } 310 if (CursorAddress == HighestScreen()+1) { 311 CursorAddress = SetBufferAddress(0,0); 312 } 313 UnLocked = 1; 314 AidByte = 0; 315 ResetOiaSystemLocked(&OperatorInformationArea); 316 SetOiaModified(); 317 TerminalIn(); 318 break; 319 case CMD_WRITE: 320 case CMD_SNA_WRITE: 321 SetOiaOnlineA(&OperatorInformationArea); 322 ResetOiaTWait(&OperatorInformationArea); 323 SetOiaModified(); 324 break; 325 default: 326 { 327 char buffer[100]; 328 329 sprintf(buffer, 330 "Unexpected write command code 0x%x received.\n", 331 Command); 332 ExitString(stderr, buffer, 1); 333 break; 334 } 335 } 336 337 count -= 2; /* strip off command and wcc */ 338 buffer += 2; 339 340 } 341 LastWasTerminated = 0; /* then, reset at end... */ 342 343 while (count) { 344 count--; 345 c = *buffer++; 346 if (IsOrder(c)) { 347 /* handle an order */ 348 switch (c) { 349 # define Ensure(x) if (count < x) { \ 350 if (!control) { \ 351 return(origCount-(count+1)); \ 352 } else { \ 353 /* XXX - should not occur */ \ 354 count = 0; \ 355 break; \ 356 } \ 357 } 358 case ORDER_SF: 359 Ensure(1); 360 c = *buffer++; 361 count--; 362 if ( ! (IsStartField(BufferAddress) && 363 FieldAttributes(BufferAddress) == c)) { 364 SetHighestLowest(BufferAddress); 365 NewField(BufferAddress,c); 366 } 367 BufferAddress = ScreenInc(BufferAddress); 368 break; 369 case ORDER_SBA: 370 Ensure(2); 371 i = buffer[0]; 372 c = buffer[1]; 373 #if !defined(PURE3274) 374 if (!i && !c) { /* transparent write */ 375 if (!control) { 376 return(origCount-(count+1)); 377 } else { 378 TransparentClock = OutputClock; /* clock next */ 379 TransOut(buffer+2, count-2); /* output */ 380 SendToIBM(); /* ack block */ 381 TransparentClock = OutputClock+1; /* clock next */ 382 buffer += count; 383 count -= count; 384 } 385 break; 386 } 387 #endif /* !defined(PURE3274) */ 388 BufferAddress = Addr3270(i, c); 389 buffer += 2; 390 count -= 2; 391 break; 392 case ORDER_IC: 393 CursorAddress = BufferAddress; 394 break; 395 /* 396 * XXX - PT is supposed to null fill the screen buffer 397 * under certain draconian conditions. 398 */ 399 case ORDER_PT: 400 i = BufferAddress; 401 do { 402 if (IsStartField(i)) { 403 if (!IsProtected(ScreenInc(i))) { 404 break; 405 } 406 } 407 i = ScreenInc(i); 408 } while (i != HighestScreen()); 409 BufferAddress = ScreenInc(i); 410 break; 411 case ORDER_RA: 412 Ensure(3); 413 i = Addr3270(buffer[0], buffer[1]); 414 c = buffer[2]; 415 if (c == ORDER_GE) { 416 Ensure(4); 417 c = buffer[3]; 418 buffer += 4; 419 count -= 4; 420 } else { 421 buffer += 3; 422 count -= 3; 423 } 424 do { 425 AddHost(BufferAddress, ebc_disp[c]); 426 BufferAddress = ScreenInc(BufferAddress); 427 } while (BufferAddress != i); 428 break; 429 case ORDER_EUA: /* (from [here,there), ie: half open interval] */ 430 Ensure(2); 431 /* 432 * Compiler error - msc version 4.0: 433 * "expression too complicated". 434 */ 435 i = WhereAttrByte(BufferAddress); 436 c = FieldAttributes(i); 437 for (i = Addr3270(buffer[0], buffer[1]); i != BufferAddress; 438 BufferAddress = ScreenInc(BufferAddress)) { 439 if (IsStartField(BufferAddress)) { 440 c = FieldAttributes(BufferAddress); 441 } else if (!IsProtectedAttr(BufferAddress, c)) { 442 AddHost(BufferAddress, 0); 443 } 444 } 445 buffer += 2; 446 count -= 2; 447 break; 448 case ORDER_GE: 449 Ensure(2); 450 /* XXX Should do SOMETHING! */ 451 buffer += 0; 452 count -= 0; /* For now, just use this character */ 453 break; 454 case ORDER_YALE: /* special YALE defined order */ 455 Ensure(2); /* need at least two characters */ 456 if (*buffer == 0x5b) { 457 i = OptOrder(buffer+1, count-1, control); 458 if (i == 0) { 459 return(origCount-(count+1)); /* come here again */ 460 } else { 461 buffer += 1 + i; 462 count -= (1 + i); 463 } 464 } 465 break; 466 default: 467 { 468 char buffer[100]; 469 static struct orders_def unk_order 470 = { 0, "??", "(unknown)" }; 471 struct orders_def *porder = &unk_order; 472 int i; 473 474 for (i = 0; i <= highestof(orders_def); i++) { 475 if (orders_def[i].code == c) { 476 porder = &orders_def[i]; 477 break; 478 } 479 } 480 sprintf(buffer, 481 "Unsupported order '%s' (%s, 0x%x) received.\n", 482 porder->long_name, porder->short_name, c); 483 ExitString(stderr, buffer, 1); 484 /*NOTREACHED*/ 485 } 486 } 487 if (count < 0) { 488 count = 0; 489 } 490 } else { 491 /* Data comes in large clumps - take it all */ 492 i = BufferAddress; 493 #if !defined(SLOWSCREEN) 494 AddHost(i, ebc_disp[c]); 495 #else /* !defined(SLOWSCREEN) */ 496 AddHostA(i, ebc_disp[c]); 497 SetHighestLowest(i); 498 #endif /* !defined(SLOWSCREEN) */ 499 i = ScreenInc(i); 500 c = *buffer; 501 while (count && !IsOrder(c)) { 502 #if !defined(SLOWSCREEN) 503 AddHost(i, ebc_disp[c]); 504 #else /* !defined(SLOWSCREEN) */ 505 AddHostA(i, ebc_disp[c]); 506 #endif /* !defined(SLOWSCREEN) */ 507 i = ScreenInc(i); 508 #if defined(SLOWSCREEN) 509 if (i == LowestScreen()) { 510 SetHighestLowest(HighestScreen()); 511 } 512 #endif /* defined(SLOWSCREEN) */ 513 count--; 514 buffer++; 515 c = *buffer; 516 } 517 #if defined(SLOWSCREEN) 518 SetHighestLowest(i); 519 #endif /* defined(SLOWSCREEN) */ 520 BufferAddress = i; 521 } 522 } 523 if (count == 0) { 524 #if !defined(PURE3274) 525 OutputClock++; /* time rolls on */ 526 #endif /* !defined(PURE3274) */ 527 if (control) { 528 if (Wcc & WCC_RESTORE) { 529 #if !defined(PURE3274) 530 if (TransparentClock != OutputClock) { 531 AidByte = 0; 532 } 533 #else /* !defined(PURE3274) */ 534 AidByte = 0; 535 #endif /* !defined(PURE3274) */ 536 UnLocked = 1; 537 ResetOiaSystemLocked(&OperatorInformationArea); 538 SetOiaModified(); 539 SetPsModified(); 540 TerminalIn(); 541 } 542 if (Wcc & WCC_ALARM) { 543 RingBell(0); 544 } 545 } 546 LastWasTerminated = control; /* state for next time */ 547 return(origCount); 548 } else { 549 return(origCount-count); 550 } 551 } 552 553 /* 554 * Init3270() 555 * 556 * Initialize any 3270 (controller) variables to an initial state 557 * in preparation for accepting a connection. 558 */ 559 560 void 561 Init3270() 562 { 563 int i; 564 565 OptInit(); /* initialize mappings */ 566 567 ClearArray(Host); 568 569 ClearArray(Orders); 570 for (i = 0; i <= highestof(orders_def); i++) { 571 Orders[orders_def[i].code] = 1; 572 } 573 574 DeleteAllFields(); /* Clear screen */ 575 Lowest = HighestScreen()+1; 576 Highest = LowestScreen()-1; 577 CursorAddress = BufferAddress = SetBufferAddress(0,0); 578 UnLocked = 1; 579 OutputClock = 1; 580 TransparentClock = -1; 581 SetOiaReady3274(&OperatorInformationArea); 582 } 583 584 585 void 586 Stop3270() 587 { 588 ResetOiaReady3274(&OperatorInformationArea); 589 } 590