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