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.1 (Berkeley) 12/04/88"; 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 c = buffer[2]; 396 if (c == ORDER_GE) { 397 Ensure(4); 398 c = buffer[3]; 399 buffer += 4; 400 count -= 4; 401 } else { 402 buffer += 3; 403 count -= 3; 404 } 405 do { 406 AddHost(BufferAddress, ebc_disp[c]); 407 BufferAddress = ScreenInc(BufferAddress); 408 } while (BufferAddress != i); 409 break; 410 case ORDER_EUA: /* (from [here,there), ie: half open interval] */ 411 Ensure(2); 412 /* 413 * Compiler error - msc version 4.0: 414 * "expression too complicated". 415 */ 416 i = WhereAttrByte(BufferAddress); 417 c = FieldAttributes(i); 418 i = Addr3270(buffer[0], buffer[1]); 419 do { 420 if (IsStartField(BufferAddress)) { 421 c = FieldAttributes(BufferAddress); 422 } else if (!IsProtectedAttr(BufferAddress, c)) { 423 AddHost(BufferAddress, 0); 424 } 425 BufferAddress = ScreenInc(BufferAddress); 426 } while (i != BufferAddress); 427 buffer += 2; 428 count -= 2; 429 break; 430 case ORDER_GE: 431 Ensure(2); 432 /* XXX Should do SOMETHING! */ 433 /* XXX buffer += 0; */ 434 /* XXX count -= 0; *//* For now, just use this character */ 435 break; 436 case ORDER_YALE: /* special YALE defined order */ 437 Ensure(2); /* need at least two characters */ 438 if (*buffer == 0x5b) { 439 i = OptOrder(buffer+1, count-1, control); 440 if (i == 0) { 441 return(origCount-(count+1)); /* come here again */ 442 } else { 443 buffer += 1 + i; 444 count -= (1 + i); 445 } 446 } 447 break; 448 default: 449 { 450 char s_buffer[100]; 451 static struct orders_def unk_order 452 = { 0, "??", "(unknown)" }; 453 struct orders_def *porder = &unk_order; 454 int s_i; 455 456 for (s_i = 0; s_i <= highestof(orders_def); s_i++) { 457 if (orders_def[s_i].code == c) { 458 porder = &orders_def[s_i]; 459 break; 460 } 461 } 462 sprintf(s_buffer, 463 "Unsupported order '%s' (%s, 0x%x) received.\n", 464 porder->long_name, porder->short_name, c); 465 ExitString(s_buffer, 1); 466 /*NOTREACHED*/ 467 } 468 } 469 if (count < 0) { 470 count = 0; 471 } 472 } else { 473 /* Data comes in large clumps - take it all */ 474 i = BufferAddress; 475 AddHostA(i, ebc_disp[c]); 476 SetHighestLowest(i); 477 i = ScreenInc(i); 478 c = *buffer; 479 while (count && !IsOrder(c)) { 480 AddHostA(i, ebc_disp[c]); 481 i = ScreenInc(i); 482 if (i == LowestScreen()) { 483 SetHighestLowest(HighestScreen()); 484 } 485 count--; 486 buffer++; 487 c = *buffer; 488 } 489 SetHighestLowest(i); 490 BufferAddress = i; 491 } 492 } 493 if (count == 0) { 494 if (control) { 495 #if !defined(PURE3274) 496 OutputClock++; /* time rolls on */ 497 #endif /* !defined(PURE3274) */ 498 if (Wcc & WCC_RESTORE) { 499 #if !defined(PURE3274) 500 if (TransparentClock != OutputClock) { 501 AidByte = 0; 502 } 503 #else /* !defined(PURE3274) */ 504 AidByte = 0; 505 #endif /* !defined(PURE3274) */ 506 UnLocked = 1; 507 ResetOiaSystemLocked(&OperatorInformationArea); 508 SetOiaModified(); 509 SetPsModified(); 510 TerminalIn(); 511 } 512 if (Wcc & WCC_ALARM) { 513 RingBell((char *)0); 514 } 515 } 516 LastWasTerminated = control; /* state for next time */ 517 return(origCount); 518 } else { 519 return(origCount-count); 520 } 521 } 522 523 /* 524 * Init3270() 525 * 526 * Initialize any 3270 (controller) variables to an initial state 527 * in preparation for accepting a connection. 528 */ 529 530 void 531 Init3270() 532 { 533 int i; 534 535 OptInit(); /* initialize mappings */ 536 537 ClearArray(Host); 538 539 ClearArray(Orders); 540 for (i = 0; i <= highestof(orders_def); i++) { 541 Orders[orders_def[i].code] = 1; 542 } 543 544 DeleteAllFields(); /* Clear screen */ 545 Lowest = HighestScreen()+1; 546 Highest = LowestScreen()-1; 547 CursorAddress = BufferAddress = SetBufferAddress(0,0); 548 UnLocked = 1; 549 #if !defined(PURE3274) 550 OutputClock = 1; 551 TransparentClock = -1; 552 #endif /* !defined(PURE3274) */ 553 SetOiaReady3274(&OperatorInformationArea); 554 } 555 556 557 void 558 Stop3270() 559 { 560 ResetOiaReady3274(&OperatorInformationArea); 561 } 562