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