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