1/* Copyright (c) 1993-2002 2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) 3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) 4 * Copyright (c) 1987 Oliver Laumann 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program (see the file COPYING); if not, write to the 18 * Free Software Foundation, Inc., 19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 20 * 21 **************************************************************** 22 */ 23 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <signal.h> 27#include <fcntl.h> 28#if !defined(sun) && !defined(B43) && !defined(ISC) && !defined(pyr) && !defined(_CX_UX) 29# include <time.h> 30#endif 31#include <sys/time.h> 32#ifndef sun 33#include <sys/ioctl.h> 34#endif 35 36 37#include "config.h" 38 39/* for solaris 2.1, Unixware (SVR4.2) and possibly others: */ 40#ifdef SVR4 41# include <sys/stropts.h> 42#endif 43 44#include "screen.h" 45#include "extern.h" 46#include "logfile.h" 47 48extern struct comm comms[]; 49extern char *rc_name; 50extern char *RcFileName, *home; 51extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[]; 52extern char *hstatusstring, *captionstring, *timestring; 53extern char *wliststr, *wlisttit; 54extern int captionalways; 55extern char *hardcopydir, *screenlogfile, *logtstamp_string; 56extern int log_flush, logtstamp_on, logtstamp_after; 57extern char *VisualBellString; 58extern int VBellWait, MsgWait, MsgMinWait, SilenceWait; 59extern char SockPath[], *SockName; 60extern int TtyMode, auto_detach, use_altscreen; 61extern int iflag, maxwin; 62extern int use_hardstatus, visual_bell; 63#ifdef COLOR 64extern int attr2color[][4]; 65extern int nattr2color; 66#endif 67extern int hardstatusemu; 68extern char *printcmd; 69extern int default_startup; 70extern int defobuflimit; 71extern int defnonblock; 72extern int ZombieKey_destroy; 73extern int ZombieKey_resurrect; 74#ifdef AUTO_NUKE 75extern int defautonuke; 76#endif 77extern int separate_sids; 78extern struct NewWindow nwin_default, nwin_undef; 79#ifdef COPY_PASTE 80extern int join_with_cr; 81extern int compacthist; 82extern int search_ic; 83# ifdef FONT 84extern int pastefont; 85# endif 86extern unsigned char mark_key_tab[]; 87extern char *BufferFile; 88#endif 89#ifdef POW_DETACH 90extern char *BufferFile, *PowDetachString; 91#endif 92#ifdef MULTIUSER 93extern struct acluser *EffectiveAclUser; /* acl.c */ 94#endif 95extern struct term term[]; /* terminal capabilities */ 96#ifdef MAPKEYS 97extern char *kmapdef[]; 98extern char *kmapadef[]; 99extern char *kmapmdef[]; 100#endif 101extern struct mchar mchar_so, mchar_null; 102extern int VerboseCreate; 103#ifdef UTF8 104extern char *screenencodings; 105#endif 106 107static int CheckArgNum __P((int, char **)); 108static void ClearAction __P((struct action *)); 109static void SaveAction __P((struct action *, int, char **, int *)); 110static int NextWindow __P((void)); 111static int PreviousWindow __P((void)); 112static int MoreWindows __P((void)); 113static void LogToggle __P((int)); 114static void ShowInfo __P((void)); 115static void ShowDInfo __P((void)); 116static struct win *WindowByName __P((char *)); 117static int WindowByNumber __P((char *)); 118static int ParseOnOff __P((struct action *, int *)); 119static int ParseWinNum __P((struct action *, int *)); 120static int ParseBase __P((struct action *, char *, int *, int, char *)); 121static int ParseNum1000 __P((struct action *, int *)); 122static char **SaveArgs __P((char **)); 123static int IsNum __P((char *, int)); 124static void Colonfin __P((char *, int, char *)); 125static void InputSelect __P((void)); 126static void InputSetenv __P((char *)); 127static void InputAKA __P((void)); 128#ifdef MULTIUSER 129static int InputSu __P((struct win *, struct acluser **, char *)); 130static void su_fin __P((char *, int, char *)); 131#endif 132static void AKAfin __P((char *, int, char *)); 133#ifdef COPY_PASTE 134static void copy_reg_fn __P((char *, int, char *)); 135static void ins_reg_fn __P((char *, int, char *)); 136#endif 137static void process_fn __P((char *, int, char *)); 138#ifdef PASSWORD 139static void pass1 __P((char *, int, char *)); 140static void pass2 __P((char *, int, char *)); 141#endif 142#ifdef POW_DETACH 143static void pow_detach_fn __P((char *, int, char *)); 144#endif 145static void digraph_fn __P((char *, int, char *)); 146static void confirm_fn __P((char *, int, char *)); 147static int IsOnDisplay __P((struct win *)); 148static void ResizeRegions __P((char*)); 149static void ResizeFin __P((char *, int, char *)); 150static struct action *FindKtab __P((char *, int)); 151 152 153extern struct layer *flayer; 154extern struct display *display, *displays; 155extern struct win *fore, *console_window, *windows; 156extern struct acluser *users; 157 158extern char screenterm[], HostName[], version[]; 159extern struct NewWindow nwin_undef, nwin_default; 160extern struct LayFuncs WinLf; 161 162extern int Z0width, Z1width; 163extern int real_uid, real_gid; 164 165#ifdef NETHACK 166extern int nethackflag; 167#endif 168 169 170struct win *wtab[MAXWIN]; /* window table, should be dynamic */ 171 172#ifdef MULTIUSER 173extern char *multi; 174extern int maxusercount; 175#endif 176char NullStr[] = ""; 177 178struct plop plop_tab[MAX_PLOP_DEFS]; 179 180#ifndef PTYMODE 181# define PTYMODE 0622 182#endif 183 184int TtyMode = PTYMODE; 185int hardcopy_append = 0; 186int all_norefresh = 0; 187#ifdef ZMODEM 188int zmodem_mode = 0; 189char *zmodem_sendcmd; 190char *zmodem_recvcmd; 191static char *zmodes[4] = {"off", "auto", "catch", "pass"}; 192#endif 193 194int idletimo; 195struct action idleaction; 196#ifdef BLANKER_PRG 197char **blankerprg; 198#endif 199 200struct action ktab[256]; /* command key translation table */ 201struct kclass { 202 struct kclass *next; 203 char *name; 204 struct action ktab[256]; 205}; 206struct kclass *kclasses; 207 208#ifdef MAPKEYS 209struct action umtab[KMAP_KEYS+KMAP_AKEYS]; 210struct action dmtab[KMAP_KEYS+KMAP_AKEYS]; 211struct action mmtab[KMAP_KEYS+KMAP_AKEYS]; 212struct kmap_ext *kmap_exts; 213int kmap_extn; 214static int maptimeout = 300; 215#endif 216 217 218/* digraph table taken from old vim and rfc1345 */ 219static const unsigned char digraphs[][3] = { 220 {' ', ' ', 160}, /* � */ 221 {'N', 'S', 160}, /* � */ 222 {'~', '!', 161}, /* � */ 223 {'!', '!', 161}, /* � */ 224 {'!', 'I', 161}, /* � */ 225 {'c', '|', 162}, /* � */ 226 {'c', 't', 162}, /* � */ 227 {'$', '$', 163}, /* � */ 228 {'P', 'd', 163}, /* � */ 229 {'o', 'x', 164}, /* � */ 230 {'C', 'u', 164}, /* � */ 231 {'C', 'u', 164}, /* � */ 232 {'E', 'u', 164}, /* � */ 233 {'Y', '-', 165}, /* � */ 234 {'Y', 'e', 165}, /* � */ 235 {'|', '|', 166}, /* � */ 236 {'B', 'B', 166}, /* � */ 237 {'p', 'a', 167}, /* � */ 238 {'S', 'E', 167}, /* � */ 239 {'"', '"', 168}, /* � */ 240 {'\'', ':', 168}, /* � */ 241 {'c', 'O', 169}, /* � */ 242 {'C', 'o', 169}, /* � */ 243 {'a', '-', 170}, /* � */ 244 {'<', '<', 171}, /* � */ 245 {'-', ',', 172}, /* � */ 246 {'N', 'O', 172}, /* � */ 247 {'-', '-', 173}, /* � */ 248 {'r', 'O', 174}, /* � */ 249 {'R', 'g', 174}, /* � */ 250 {'-', '=', 175}, /* � */ 251 {'\'', 'm', 175}, /* � */ 252 {'~', 'o', 176}, /* � */ 253 {'D', 'G', 176}, /* � */ 254 {'+', '-', 177}, /* � */ 255 {'2', '2', 178}, /* � */ 256 {'2', 'S', 178}, /* � */ 257 {'3', '3', 179}, /* � */ 258 {'3', 'S', 179}, /* � */ 259 {'\'', '\'', 180}, /* � */ 260 {'j', 'u', 181}, /* � */ 261 {'M', 'y', 181}, /* � */ 262 {'p', 'p', 182}, /* � */ 263 {'P', 'I', 182}, /* � */ 264 {'~', '.', 183}, /* � */ 265 {'.', 'M', 183}, /* � */ 266 {',', ',', 184}, /* � */ 267 {'\'', ',', 184}, /* � */ 268 {'1', '1', 185}, /* � */ 269 {'1', 'S', 185}, /* � */ 270 {'o', '-', 186}, /* � */ 271 {'>', '>', 187}, /* � */ 272 {'1', '4', 188}, /* � */ 273 {'1', '2', 189}, /* � */ 274 {'3', '4', 190}, /* � */ 275 {'~', '?', 191}, /* � */ 276 {'?', '?', 191}, /* � */ 277 {'?', 'I', 191}, /* � */ 278 {'A', '`', 192}, /* � */ 279 {'A', '!', 192}, /* � */ 280 {'A', '\'', 193}, /* � */ 281 {'A', '^', 194}, /* � */ 282 {'A', '>', 194}, /* � */ 283 {'A', '~', 195}, /* � */ 284 {'A', '?', 195}, /* � */ 285 {'A', '"', 196}, /* � */ 286 {'A', ':', 196}, /* � */ 287 {'A', '@', 197}, /* � */ 288 {'A', 'A', 197}, /* � */ 289 {'A', 'E', 198}, /* � */ 290 {'C', ',', 199}, /* � */ 291 {'E', '`', 200}, /* � */ 292 {'E', '!', 200}, /* � */ 293 {'E', '\'', 201}, /* � */ 294 {'E', '^', 202}, /* � */ 295 {'E', '>', 202}, /* � */ 296 {'E', '"', 203}, /* � */ 297 {'E', ':', 203}, /* � */ 298 {'I', '`', 204}, /* � */ 299 {'I', '!', 204}, /* � */ 300 {'I', '\'', 205}, /* � */ 301 {'I', '^', 206}, /* � */ 302 {'I', '>', 206}, /* � */ 303 {'I', '"', 207}, /* � */ 304 {'I', ':', 207}, /* � */ 305 {'D', '-', 208}, /* � */ 306 {'N', '~', 209}, /* � */ 307 {'N', '?', 209}, /* � */ 308 {'O', '`', 210}, /* � */ 309 {'O', '!', 210}, /* � */ 310 {'O', '\'', 211}, /* � */ 311 {'O', '^', 212}, /* � */ 312 {'O', '>', 212}, /* � */ 313 {'O', '~', 213}, /* � */ 314 {'O', '?', 213}, /* � */ 315 {'O', '"', 214}, /* � */ 316 {'O', ':', 214}, /* � */ 317 {'/', '\\', 215}, /* � */ 318 {'*', 'x', 215}, /* � */ 319 {'O', '/', 216}, /* � */ 320 {'U', '`', 217}, /* � */ 321 {'U', '!', 217}, /* � */ 322 {'U', '\'', 218}, /* � */ 323 {'U', '^', 219}, /* � */ 324 {'U', '>', 219}, /* � */ 325 {'U', '"', 220}, /* � */ 326 {'U', ':', 220}, /* � */ 327 {'Y', '\'', 221}, /* � */ 328 {'I', 'p', 222}, /* � */ 329 {'T', 'H', 222}, /* � */ 330 {'s', 's', 223}, /* � */ 331 {'s', '"', 223}, /* � */ 332 {'a', '`', 224}, /* � */ 333 {'a', '!', 224}, /* � */ 334 {'a', '\'', 225}, /* � */ 335 {'a', '^', 226}, /* � */ 336 {'a', '>', 226}, /* � */ 337 {'a', '~', 227}, /* � */ 338 {'a', '?', 227}, /* � */ 339 {'a', '"', 228}, /* � */ 340 {'a', ':', 228}, /* � */ 341 {'a', 'a', 229}, /* � */ 342 {'a', 'e', 230}, /* � */ 343 {'c', ',', 231}, /* � */ 344 {'e', '`', 232}, /* � */ 345 {'e', '!', 232}, /* � */ 346 {'e', '\'', 233}, /* � */ 347 {'e', '^', 234}, /* � */ 348 {'e', '>', 234}, /* � */ 349 {'e', '"', 235}, /* � */ 350 {'e', ':', 235}, /* � */ 351 {'i', '`', 236}, /* � */ 352 {'i', '!', 236}, /* � */ 353 {'i', '\'', 237}, /* � */ 354 {'i', '^', 238}, /* � */ 355 {'i', '>', 238}, /* � */ 356 {'i', '"', 239}, /* � */ 357 {'i', ':', 239}, /* � */ 358 {'d', '-', 240}, /* � */ 359 {'n', '~', 241}, /* � */ 360 {'n', '?', 241}, /* � */ 361 {'o', '`', 242}, /* � */ 362 {'o', '!', 242}, /* � */ 363 {'o', '\'', 243}, /* � */ 364 {'o', '^', 244}, /* � */ 365 {'o', '>', 244}, /* � */ 366 {'o', '~', 245}, /* � */ 367 {'o', '?', 245}, /* � */ 368 {'o', '"', 246}, /* � */ 369 {'o', ':', 246}, /* � */ 370 {':', '-', 247}, /* � */ 371 {'o', '/', 248}, /* � */ 372 {'u', '`', 249}, /* � */ 373 {'u', '!', 249}, /* � */ 374 {'u', '\'', 250}, /* � */ 375 {'u', '^', 251}, /* � */ 376 {'u', '>', 251}, /* � */ 377 {'u', '"', 252}, /* � */ 378 {'u', ':', 252}, /* � */ 379 {'y', '\'', 253}, /* � */ 380 {'i', 'p', 254}, /* � */ 381 {'t', 'h', 254}, /* � */ 382 {'y', '"', 255}, /* � */ 383 {'y', ':', 255}, /* � */ 384 {'"', '[', 196}, /* � */ 385 {'"', '\\', 214}, /* � */ 386 {'"', ']', 220}, /* � */ 387 {'"', '{', 228}, /* � */ 388 {'"', '|', 246}, /* � */ 389 {'"', '}', 252}, /* � */ 390 {'"', '~', 223} /* � */ 391}; 392 393 394char *noargs[1]; 395 396void 397InitKeytab() 398{ 399 register unsigned int i; 400#ifdef MAPKEYS 401 char *argarr[2]; 402#endif 403 404 for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++) 405 { 406 ktab[i].nr = RC_ILLEGAL; 407 ktab[i].args = noargs; 408 ktab[i].argl = 0; 409 } 410#ifdef MAPKEYS 411 for (i = 0; i < KMAP_KEYS+KMAP_AKEYS; i++) 412 { 413 umtab[i].nr = RC_ILLEGAL; 414 umtab[i].args = noargs; 415 umtab[i].argl = 0; 416 dmtab[i].nr = RC_ILLEGAL; 417 dmtab[i].args = noargs; 418 dmtab[i].argl = 0; 419 mmtab[i].nr = RC_ILLEGAL; 420 mmtab[i].args = noargs; 421 mmtab[i].argl = 0; 422 } 423 argarr[1] = 0; 424 for (i = 0; i < NKMAPDEF; i++) 425 { 426 if (i + KMAPDEFSTART < T_CAPS) 427 continue; 428 if (i + KMAPDEFSTART >= T_CAPS + KMAP_KEYS) 429 continue; 430 if (kmapdef[i] == 0) 431 continue; 432 argarr[0] = kmapdef[i]; 433 SaveAction(dmtab + i + (KMAPDEFSTART - T_CAPS), RC_STUFF, argarr, 0); 434 } 435 for (i = 0; i < NKMAPADEF; i++) 436 { 437 if (i + KMAPADEFSTART < T_CURSOR) 438 continue; 439 if (i + KMAPADEFSTART >= T_CURSOR + KMAP_AKEYS) 440 continue; 441 if (kmapadef[i] == 0) 442 continue; 443 argarr[0] = kmapadef[i]; 444 SaveAction(dmtab + i + (KMAPADEFSTART - T_CURSOR + KMAP_KEYS), RC_STUFF, argarr, 0); 445 } 446 for (i = 0; i < NKMAPMDEF; i++) 447 { 448 if (i + KMAPMDEFSTART < T_CAPS) 449 continue; 450 if (i + KMAPMDEFSTART >= T_CAPS + KMAP_KEYS) 451 continue; 452 if (kmapmdef[i] == 0) 453 continue; 454 argarr[0] = kmapmdef[i]; 455 argarr[1] = 0; 456 SaveAction(mmtab + i + (KMAPMDEFSTART - T_CAPS), RC_STUFF, argarr, 0); 457 } 458#endif 459 460 ktab['h'].nr = RC_HARDCOPY; 461#ifdef BSDJOBS 462 ktab['z'].nr = ktab[Ctrl('z')].nr = RC_SUSPEND; 463#endif 464 ktab['c'].nr = ktab[Ctrl('c')].nr = RC_SCREEN; 465 ktab[' '].nr = ktab[Ctrl(' ')].nr = 466 ktab['n'].nr = ktab[Ctrl('n')].nr = RC_NEXT; 467 ktab['N'].nr = RC_NUMBER; 468 ktab[Ctrl('h')].nr = ktab[0177].nr = ktab['p'].nr = ktab[Ctrl('p')].nr = RC_PREV; 469 ktab['k'].nr = ktab[Ctrl('k')].nr = RC_KILL; 470 ktab['l'].nr = ktab[Ctrl('l')].nr = RC_REDISPLAY; 471 ktab['w'].nr = ktab[Ctrl('w')].nr = RC_WINDOWS; 472 ktab['v'].nr = RC_VERSION; 473 ktab[Ctrl('v')].nr = RC_DIGRAPH; 474 ktab['q'].nr = ktab[Ctrl('q')].nr = RC_XON; 475 ktab['s'].nr = ktab[Ctrl('s')].nr = RC_XOFF; 476 ktab['t'].nr = ktab[Ctrl('t')].nr = RC_TIME; 477 ktab['i'].nr = ktab[Ctrl('i')].nr = RC_INFO; 478 ktab['m'].nr = ktab[Ctrl('m')].nr = RC_LASTMSG; 479 ktab['A'].nr = RC_TITLE; 480#if defined(UTMPOK) && defined(LOGOUTOK) 481 ktab['L'].nr = RC_LOGIN; 482#endif 483 ktab[','].nr = RC_LICENSE; 484 ktab['W'].nr = RC_WIDTH; 485 ktab['.'].nr = RC_DUMPTERMCAP; 486 ktab[Ctrl('\\')].nr = RC_QUIT; 487#ifdef DETACH 488 ktab['d'].nr = ktab[Ctrl('d')].nr = RC_DETACH; 489# ifdef POW_DETACH 490 ktab['D'].nr = RC_POW_DETACH; 491# endif 492#endif 493 ktab['r'].nr = ktab[Ctrl('r')].nr = RC_WRAP; 494 ktab['f'].nr = ktab[Ctrl('f')].nr = RC_FLOW; 495 ktab['C'].nr = RC_CLEAR; 496 ktab['Z'].nr = RC_RESET; 497 ktab['H'].nr = RC_LOG; 498 ktab['M'].nr = RC_MONITOR; 499 ktab['?'].nr = RC_HELP; 500#ifdef MULTI 501 ktab['*'].nr = RC_DISPLAYS; 502#endif 503 { 504 char *args[2]; 505 args[0] = "-"; 506 args[1] = NULL; 507 SaveAction(ktab + '-', RC_SELECT, args, 0); 508 } 509 for (i = 0; i < ((MAXWIN < 10) ? MAXWIN : 10); i++) 510 { 511 char *args[2], arg1[10]; 512 args[0] = arg1; 513 args[1] = 0; 514 sprintf(arg1, "%d", i); 515 SaveAction(ktab + '0' + i, RC_SELECT, args, 0); 516 } 517 ktab['\''].nr = RC_SELECT; /* calling a window by name */ 518 { 519 char *args[2]; 520 args[0] = "-b"; 521 args[1] = 0; 522 SaveAction(ktab + '"', RC_WINDOWLIST, args, 0); 523 } 524 ktab[Ctrl('G')].nr = RC_VBELL; 525 ktab[':'].nr = RC_COLON; 526#ifdef COPY_PASTE 527 ktab['['].nr = ktab[Ctrl('[')].nr = RC_COPY; 528 { 529 char *args[2]; 530 args[0] = "."; 531 args[1] = 0; 532 SaveAction(ktab + ']', RC_PASTE, args, 0); 533 SaveAction(ktab + Ctrl(']'), RC_PASTE, args, 0); 534 } 535 ktab['{'].nr = RC_HISTORY; 536 ktab['}'].nr = RC_HISTORY; 537 ktab['>'].nr = RC_WRITEBUF; 538 ktab['<'].nr = RC_READBUF; 539 ktab['='].nr = RC_REMOVEBUF; 540#endif 541#ifdef POW_DETACH 542 ktab['D'].nr = RC_POW_DETACH; 543#endif 544#ifdef LOCK 545 ktab['x'].nr = ktab[Ctrl('x')].nr = RC_LOCKSCREEN; 546#endif 547 ktab['b'].nr = ktab[Ctrl('b')].nr = RC_BREAK; 548 ktab['B'].nr = RC_POW_BREAK; 549 ktab['_'].nr = RC_SILENCE; 550 ktab['S'].nr = RC_SPLIT; 551 ktab['Q'].nr = RC_ONLY; 552 ktab['X'].nr = RC_REMOVE; 553 ktab['F'].nr = RC_FIT; 554 ktab['\t'].nr = RC_FOCUS; 555 /* These come last; they may want overwrite others: */ 556 if (DefaultEsc >= 0) 557 { 558 ClearAction(&ktab[DefaultEsc]); 559 ktab[DefaultEsc].nr = RC_OTHER; 560 } 561 if (DefaultMetaEsc >= 0) 562 { 563 ClearAction(&ktab[DefaultMetaEsc]); 564 ktab[DefaultMetaEsc].nr = RC_META; 565 } 566 567 idleaction.nr = RC_BLANKER; 568 idleaction.args = noargs; 569 idleaction.argl = 0; 570} 571 572static struct action * 573FindKtab(class, create) 574char *class; 575int create; 576{ 577 struct kclass *kp, **kpp; 578 int i; 579 580 if (class == 0) 581 return ktab; 582 for (kpp = &kclasses; (kp = *kpp) != 0; kpp = &kp->next) 583 if (!strcmp(kp->name, class)) 584 break; 585 if (kp == 0) 586 { 587 if (!create) 588 return 0; 589 if (strlen(class) > 80) 590 { 591 Msg(0, "Command class name too long."); 592 return 0; 593 } 594 kp = malloc(sizeof(*kp)); 595 if (kp == 0) 596 { 597 Msg(0, strnomem); 598 return 0; 599 } 600 kp->name = SaveStr(class); 601 for (i = 0; i < (int)(sizeof(kp->ktab)/sizeof(*kp->ktab)); i++) 602 { 603 kp->ktab[i].nr = RC_ILLEGAL; 604 kp->ktab[i].args = noargs; 605 } 606 kp->next = 0; 607 *kpp = kp; 608 } 609 return kp->ktab; 610} 611 612static void 613ClearAction(act) 614struct action *act; 615{ 616 char **p; 617 618 if (act->nr == RC_ILLEGAL) 619 return; 620 act->nr = RC_ILLEGAL; 621 if (act->args == noargs) 622 return; 623 for (p = act->args; *p; p++) 624 free(*p); 625 free((char *)act->args); 626 act->args = noargs; 627 act->argl = 0; 628} 629 630/* 631 * ProcessInput: process input from display and feed it into 632 * the layer on canvas D_forecv. 633 */ 634 635#ifdef MAPKEYS 636 637/* 638 * This ProcessInput just does the keybindings and passes 639 * everything else on to ProcessInput2. 640 */ 641 642void 643ProcessInput(ibuf, ilen) 644char *ibuf; 645int ilen; 646{ 647 int ch, slen; 648 unsigned char *s, *q; 649 int i, l; 650 char *p; 651 652 debug1("ProcessInput: %d bytes\n", ilen); 653 if (display == 0 || ilen == 0) 654 return; 655 if (D_seql) 656 evdeq(&D_mapev); 657 slen = ilen; 658 s = (unsigned char *)ibuf; 659 while (ilen-- > 0) 660 { 661 ch = *s++; 662 if (D_dontmap || !D_nseqs) 663 { 664 D_dontmap = 0; 665 continue; 666 } 667 for (;;) 668 { 669 debug3("cmp %c %c[%d]\n", ch, *D_seqp, D_seqp - D_kmaps); 670 if (*D_seqp != ch) 671 { 672 l = D_seqp[D_seqp[-D_seql-1] + 1]; 673 if (l) 674 { 675 D_seqp += l * 2 + 4; 676 debug1("miss %d\n", D_seqp - D_kmaps); 677 continue; 678 } 679 debug("complete miss\n"); 680 D_mapdefault = 0; 681 l = D_seql; 682 p = (char *)D_seqp - l; 683 D_seql = 0; 684 D_seqp = D_kmaps + 3; 685 if (l == 0) 686 break; 687 if ((q = D_seqh) != 0) 688 { 689 D_seqh = 0; 690 i = q[0] << 8 | q[1]; 691 i &= ~KMAP_NOTIMEOUT; 692 debug1("Mapping former hit #%d - ", i); 693 debug2("%d(%s) - ", q[2], q + 3); 694 if (StuffKey(i)) 695 ProcessInput2((char *)q + 3, q[2]); 696 if (display == 0) 697 return; 698 l -= q[2]; 699 p += q[2]; 700 } 701 else 702 D_dontmap = 1; 703 debug1("flush old %d\n", l); 704 ProcessInput(p, l); 705 if (display == 0) 706 return; 707 evdeq(&D_mapev); 708 continue; 709 } 710 if (D_seql++ == 0) 711 { 712 /* Finish old stuff */ 713 slen -= ilen + 1; 714 debug1("finish old %d\n", slen); 715 if (slen) 716 ProcessInput2(ibuf, slen); 717 if (display == 0) 718 return; 719 D_seqh = 0; 720 } 721 ibuf = (char *)s; 722 slen = ilen; 723 D_seqp++; 724 l = D_seql; 725 debug2("length am %d, want %d\n", l, D_seqp[-l - 1]); 726 if (l == D_seqp[-l - 1]) 727 { 728 if (D_seqp[l] != l) 729 { 730 q = D_seqp + 1 + l; 731 if (D_kmaps + D_nseqs > q && q[2] > l && !bcmp(D_seqp - l, q + 3, l)) 732 { 733 debug1("have another mapping (%s), delay execution\n", q + 3); 734 D_seqh = D_seqp - 3 - l; 735 D_seqp = q + 3 + l; 736 break; 737 } 738 } 739 i = D_seqp[-l - 3] << 8 | D_seqp[-l - 2]; 740 i &= ~KMAP_NOTIMEOUT; 741 debug1("Mapping #%d - ", i); 742 p = (char *)D_seqp - l; 743 debug2("%d(%s) - ", l, p); 744 D_seql = 0; 745 D_seqp = D_kmaps + 3; 746 D_seqh = 0; 747 if (StuffKey(i)) 748 ProcessInput2(p, l); 749 if (display == 0) 750 return; 751 } 752 break; 753 } 754 } 755 if (D_seql) 756 { 757 debug("am in sequence -> check for timeout\n"); 758 l = D_seql; 759 for (s = D_seqp; ; s += i * 2 + 4) 760 { 761 if (s[-l-3] & KMAP_NOTIMEOUT >> 8) 762 break; 763 if ((i = s[s[-l-1] + 1]) == 0) 764 { 765 SetTimeout(&D_mapev, maptimeout); 766 evenq(&D_mapev); 767 break; 768 } 769 } 770 } 771 ProcessInput2(ibuf, slen); 772} 773 774#else 775# define ProcessInput2 ProcessInput 776#endif 777 778 779/* 780 * Here only the screen escape commands are handled. 781 */ 782 783void 784ProcessInput2(ibuf, ilen) 785char *ibuf; 786int ilen; 787{ 788 char *s; 789 int ch, slen; 790 struct action *ktabp; 791 792 debug1("ProcessInput2: %d bytes\n", ilen); 793 while (ilen && display) 794 { 795 debug1(" - ilen now %d bytes\n", ilen); 796 flayer = D_forecv->c_layer; 797 fore = D_fore; 798 slen = ilen; 799 s = ibuf; 800 if (!D_ESCseen) 801 { 802 while (ilen > 0) 803 { 804 if ((unsigned char)*s++ == D_user->u_Esc) 805 break; 806 ilen--; 807 } 808 slen -= ilen; 809 if (slen) 810 DoProcess(fore, &ibuf, &slen, 0); 811 if (--ilen == 0) 812 D_ESCseen = ktab; 813 } 814 if (ilen <= 0) 815 return; 816 ktabp = D_ESCseen ? D_ESCseen : ktab; 817 D_ESCseen = 0; 818 ch = (unsigned char)*s; 819 820 /* 821 * As users have different esc characters, but a common ktab[], 822 * we fold back the users esc and meta-esc key to the Default keys 823 * that can be looked up in the ktab[]. grmbl. jw. 824 * XXX: make ktab[] a per user thing. 825 */ 826 if (ch == D_user->u_Esc) 827 ch = DefaultEsc; 828 else if (ch == D_user->u_MetaEsc) 829 ch = DefaultMetaEsc; 830 831 if (ch >= 0) 832 DoAction(&ktabp[ch], ch); 833 ibuf = (char *)(s + 1); 834 ilen--; 835 } 836} 837 838void 839DoProcess(p, bufp, lenp, pa) 840struct win *p; 841char **bufp; 842int *lenp; 843struct paster *pa; 844{ 845 int oldlen; 846 struct display *d = display; 847 848#ifdef COPY_PASTE 849 /* XXX -> PasteStart */ 850 if (pa && *lenp > 1 && p && p->w_slowpaste) 851 { 852 /* schedule slowpaste event */ 853 SetTimeout(&p->w_paster.pa_slowev, p->w_slowpaste); 854 evenq(&p->w_paster.pa_slowev); 855 return; 856 } 857#endif 858 while (flayer && *lenp) 859 { 860#ifdef COPY_PASTE 861 if (!pa && p && p->w_paster.pa_pastelen && flayer == p->w_paster.pa_pastelayer) 862 { 863 debug("layer is busy - beep!\n"); 864 WBell(p, visual_bell); 865 *bufp += *lenp; 866 *lenp = 0; 867 display = d; 868 return; 869 } 870#endif 871 oldlen = *lenp; 872 LayProcess(bufp, lenp); 873#ifdef COPY_PASTE 874 if (pa && !pa->pa_pastelayer) 875 break; /* flush rest of paste */ 876#endif 877 if (*lenp == oldlen) 878 { 879 if (pa) 880 { 881 display = d; 882 return; 883 } 884 /* We're full, let's beep */ 885 debug("layer is full - beep!\n"); 886 WBell(p, visual_bell); 887 break; 888 } 889 } 890 *bufp += *lenp; 891 *lenp = 0; 892 display = d; 893#ifdef COPY_PASTE 894 if (pa && pa->pa_pastelen == 0) 895 FreePaster(pa); 896#endif 897} 898 899int 900FindCommnr(str) 901char *str; 902{ 903 int x, m, l = 0, r = RC_LAST; 904 while (l <= r) 905 { 906 m = (l + r) / 2; 907 x = strcmp(str, comms[m].name); 908 if (x > 0) 909 l = m + 1; 910 else if (x < 0) 911 r = m - 1; 912 else 913 return m; 914 } 915 return RC_ILLEGAL; 916} 917 918static int 919CheckArgNum(nr, args) 920int nr; 921char **args; 922{ 923 int i, n; 924 static char *argss[] = {"no", "one", "two", "three", "four", "OOPS"}; 925 static char *orformat[] = 926 { 927 "%s: %s: %s argument%s required", 928 "%s: %s: %s or %s argument%s required", 929 "%s: %s: %s, %s or %s argument%s required", 930 "%s: %s: %s, %s, %s or %s argument%s required" 931 }; 932 933 n = comms[nr].flags & ARGS_MASK; 934 for (i = 0; args[i]; i++) 935 ; 936 if (comms[nr].flags & ARGS_ORMORE) 937 { 938 if (i < n) 939 { 940 Msg(0, "%s: %s: at least %s argument%s required", 941 rc_name, comms[nr].name, argss[n], n != 1 ? "s" : ""); 942 return -1; 943 } 944 } 945 else if ((comms[nr].flags & ARGS_PLUS1) && 946 (comms[nr].flags & ARGS_PLUS2) && 947 (comms[nr].flags & ARGS_PLUS3)) 948 { 949 if (i != n && i != n + 1 && i != n + 2 && i != n + 3) 950 { 951 Msg(0, orformat[3], rc_name, comms[nr].name, argss[n], 952 argss[n + 1], argss[n + 2], argss[n + 3], ""); 953 return -1; 954 } 955 } 956 else if ((comms[nr].flags & ARGS_PLUS1) && 957 (comms[nr].flags & ARGS_PLUS2)) 958 { 959 if (i != n && i != n + 1 && i != n + 2) 960 { 961 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n], 962 argss[n + 1], argss[n + 2], ""); 963 return -1; 964 } 965 } 966 else if ((comms[nr].flags & ARGS_PLUS1) && 967 (comms[nr].flags & ARGS_PLUS3)) 968 { 969 if (i != n && i != n + 1 && i != n + 3) 970 { 971 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n], 972 argss[n + 1], argss[n + 3], ""); 973 return -1; 974 } 975 } 976 else if ((comms[nr].flags & ARGS_PLUS2) && 977 (comms[nr].flags & ARGS_PLUS3)) 978 { 979 if (i != n && i != n + 2 && i != n + 3) 980 { 981 Msg(0, orformat[2], rc_name, comms[nr].name, argss[n], 982 argss[n + 2], argss[n + 3], ""); 983 return -1; 984 } 985 } 986 else if (comms[nr].flags & ARGS_PLUS1) 987 { 988 if (i != n && i != n + 1) 989 { 990 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n], 991 argss[n + 1], n != 0 ? "s" : ""); 992 return -1; 993 } 994 } 995 else if (comms[nr].flags & ARGS_PLUS2) 996 { 997 if (i != n && i != n + 2) 998 { 999 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n], 1000 argss[n + 2], "s"); 1001 return -1; 1002 } 1003 } 1004 else if (comms[nr].flags & ARGS_PLUS3) 1005 { 1006 if (i != n && i != n + 3) 1007 { 1008 Msg(0, orformat[1], rc_name, comms[nr].name, argss[n], 1009 argss[n + 3], ""); 1010 return -1; 1011 } 1012 } 1013 else if (i != n) 1014 { 1015 Msg(0, orformat[0], rc_name, comms[nr].name, argss[n], n != 1 ? "s" : ""); 1016 return -1; 1017 } 1018 return i; 1019} 1020 1021/*ARGSUSED*/ 1022void 1023DoAction(act, key) 1024struct action *act; 1025int key; 1026{ 1027 int nr = act->nr; 1028 char **args = act->args; 1029 int *argl = act->argl; 1030 struct win *p; 1031 int argc, i, n, msgok; 1032 char *s; 1033 char ch; 1034 struct display *odisplay = display; 1035 struct acluser *user; 1036 1037 user = display ? D_user : users; 1038 if (nr == RC_ILLEGAL) 1039 { 1040 debug1("key '%c': No action\n", key); 1041 return; 1042 } 1043 n = comms[nr].flags; 1044 if ((n & NEED_DISPLAY) && display == 0) 1045 { 1046 Msg(0, "%s: %s: display required", rc_name, comms[nr].name); 1047 return; 1048 } 1049 if ((n & NEED_FORE) && fore == 0) 1050 { 1051 Msg(0, "%s: %s: window required", rc_name, comms[nr].name); 1052 return; 1053 } 1054 if ((n & NEED_LAYER) && flayer == 0) 1055 { 1056 Msg(0, "%s: %s: display or window required", rc_name, comms[nr].name); 1057 return; 1058 } 1059 if ((argc = CheckArgNum(nr, args)) < 0) 1060 return; 1061#ifdef MULTIUSER 1062 if (display) 1063 { 1064 if (AclCheckPermCmd(D_user, ACL_EXEC, &comms[nr])) 1065 { 1066 Msg(0, "%s: %s: permission denied (user %s)", 1067 rc_name, comms[nr].name, (EffectiveAclUser ? EffectiveAclUser : D_user)->u_name); 1068 return; 1069 } 1070 } 1071#endif /* MULTIUSER */ 1072 1073 msgok = display && !*rc_name; 1074 switch(nr) 1075 { 1076 case RC_SELECT: 1077 if (!*args) 1078 InputSelect(); 1079 else if (args[0][0] == '-' && !args[0][1]) 1080 { 1081 SetForeWindow((struct win *)0); 1082 Activate(0); 1083 } 1084 else if (args[0][0] == '.' && !args[0][1]) 1085 { 1086 if (!fore) 1087 Msg(0, "select . needs a window"); 1088 else 1089 { 1090 SetForeWindow(fore); 1091 Activate(0); 1092 } 1093 } 1094 else if (ParseWinNum(act, &n) == 0) 1095 SwitchWindow(n); 1096 break; 1097#ifdef AUTO_NUKE 1098 case RC_DEFAUTONUKE: 1099 if (ParseOnOff(act, &defautonuke) == 0 && msgok) 1100 Msg(0, "Default autonuke turned %s", defautonuke ? "on" : "off"); 1101 if (display && *rc_name) 1102 D_auto_nuke = defautonuke; 1103 break; 1104 case RC_AUTONUKE: 1105 if (ParseOnOff(act, &D_auto_nuke) == 0 && msgok) 1106 Msg(0, "Autonuke turned %s", D_auto_nuke ? "on" : "off"); 1107 break; 1108#endif 1109 case RC_DEFOBUFLIMIT: 1110 if (ParseNum(act, &defobuflimit) == 0 && msgok) 1111 Msg(0, "Default limit set to %d", defobuflimit); 1112 if (display && *rc_name) 1113 { 1114 D_obufmax = defobuflimit; 1115 D_obuflenmax = D_obuflen - D_obufmax; 1116 } 1117 break; 1118 case RC_OBUFLIMIT: 1119 if (*args == 0) 1120 Msg(0, "Limit is %d, current buffer size is %d", D_obufmax, D_obuflen); 1121 else if (ParseNum(act, &D_obufmax) == 0 && msgok) 1122 Msg(0, "Limit set to %d", D_obufmax); 1123 D_obuflenmax = D_obuflen - D_obufmax; 1124 break; 1125 case RC_DUMPTERMCAP: 1126 WriteFile(user, (char *)0, DUMP_TERMCAP); 1127 break; 1128 case RC_HARDCOPY: 1129 { 1130 int mode = DUMP_HARDCOPY; 1131 1132 if (argc > 1 && !strcmp(*args, "-h")) 1133 { 1134 mode = DUMP_SCROLLBACK; 1135 args++; 1136 argc--; 1137 } 1138 if (*args && args[1]) 1139 { 1140 Msg(0, "%s: hardcopy: too many arguments", rc_name); 1141 break; 1142 } 1143 if (fore == 0 && *args == 0) 1144 Msg(0, "%s: hardcopy: window required", rc_name); 1145 else 1146 WriteFile(user, *args, mode); 1147 } 1148 break; 1149 case RC_DEFLOG: 1150 (void)ParseOnOff(act, &nwin_default.Lflag); 1151 break; 1152 case RC_LOG: 1153 n = fore->w_log ? 1 : 0; 1154 ParseSwitch(act, &n); 1155 LogToggle(n); 1156 break; 1157#ifdef BSDJOBS 1158 case RC_SUSPEND: 1159 Detach(D_STOP); 1160 break; 1161#endif 1162 case RC_NEXT: 1163 if (MoreWindows()) 1164 SwitchWindow(NextWindow()); 1165 break; 1166 case RC_PREV: 1167 if (MoreWindows()) 1168 SwitchWindow(PreviousWindow()); 1169 break; 1170 case RC_KILL: 1171 { 1172 char *name; 1173 1174 if (key >= 0) 1175 { 1176#ifdef PSEUDOS 1177 Input(fore->w_pwin ? "Really kill this filter [y/n]" : "Really kill this window [y/n]", 1, INP_RAW, confirm_fn, (char *)RC_KILL); 1178#else 1179 Input("Really kill this window [y/n]", 1, INP_RAW, confirm_fn, (char *)RC_KILL); 1180#endif 1181 break; 1182 } 1183 n = fore->w_number; 1184#ifdef PSEUDOS 1185 if (fore->w_pwin) 1186 { 1187 FreePseudowin(fore); 1188 Msg(0, "Filter removed."); 1189 break; 1190 } 1191#endif 1192 name = SaveStr(fore->w_title); 1193 KillWindow(fore); 1194 Msg(0, "Window %d (%s) killed.", n, name); 1195 if (name) 1196 free(name); 1197 break; 1198 } 1199 case RC_QUIT: 1200 if (key >= 0) 1201 { 1202 Input("Really quit and kill all your windows [y/n]", 1, INP_RAW, confirm_fn, (char *)RC_QUIT); 1203 break; 1204 } 1205 Finit(0); 1206 /* NOTREACHED */ 1207#ifdef DETACH 1208 case RC_DETACH: 1209 if (*args && !strcmp(*args, "-h")) 1210 Hangup(); 1211 else 1212 Detach(D_DETACH); 1213 break; 1214# ifdef POW_DETACH 1215 case RC_POW_DETACH: 1216 if (key >= 0) 1217 { 1218 static char buf[2]; 1219 1220 buf[0] = key; 1221 Input(buf, 1, INP_RAW, pow_detach_fn, NULL); 1222 } 1223 else 1224 Detach(D_POWER); /* detach and kill Attacher's parent */ 1225 break; 1226# endif 1227#endif 1228 case RC_DEBUG: 1229#ifdef DEBUG 1230 if (!*args) 1231 { 1232 if (dfp) 1233 Msg(0, "debugging info is written to %s/", DEBUGDIR); 1234 else 1235 Msg(0, "debugging is currently off. Use 'debug on' to enable."); 1236 break; 1237 } 1238 if (dfp) 1239 { 1240 debug("debug: closing debug file.\n"); 1241 fflush(dfp); 1242 fclose(dfp); 1243 dfp = NULL; 1244 } 1245 if (strcmp("off", *args)) 1246 opendebug(0, 1); 1247# ifdef SIG_NODEBUG 1248 else if (display) 1249 kill(D_userpid, SIG_NODEBUG); /* a one shot item, but hey... */ 1250# endif /* SIG_NODEBUG */ 1251#else 1252 if (*args == 0 || strcmp("off", *args)) 1253 Msg(0, "Sorry, screen was compiled without -DDEBUG option."); 1254#endif 1255 break; 1256#ifdef ZMODEM 1257 case RC_ZMODEM: 1258 if (*args && !strcmp(*args, "sendcmd")) 1259 { 1260 if (args[1]) 1261 { 1262 free(zmodem_sendcmd); 1263 zmodem_sendcmd = SaveStr(args[1]); 1264 } 1265 if (msgok) 1266 Msg(0, "zmodem sendcmd: %s", zmodem_sendcmd); 1267 break; 1268 } 1269 if (*args && !strcmp(*args, "recvcmd")) 1270 { 1271 if (args[1]) 1272 { 1273 free(zmodem_recvcmd); 1274 zmodem_recvcmd = SaveStr(args[1]); 1275 } 1276 if (msgok) 1277 Msg(0, "zmodem recvcmd: %s", zmodem_recvcmd); 1278 break; 1279 } 1280 if (*args) 1281 { 1282 for (i = 0; i < 4; i++) 1283 if (!strcmp(zmodes[i], *args)) 1284 break; 1285 if (i == 4 && !strcmp(*args, "on")) 1286 i = 1; 1287 if (i == 4) 1288 { 1289 Msg(0, "usage: zmodem off|auto|catch|pass"); 1290 break; 1291 } 1292 zmodem_mode = i; 1293 } 1294 if (msgok) 1295 Msg(0, "zmodem mode is %s", zmodes[zmodem_mode]); 1296 break; 1297#endif 1298 case RC_ZOMBIE: 1299 { 1300 if (!(s = *args)) 1301 { 1302 ZombieKey_destroy = 0; 1303 break; 1304 } 1305 if (*argl == 0 || *argl > 2) 1306 { 1307 Msg(0, "%s:zombie: one or two characters expected.", rc_name); 1308 break; 1309 } 1310 ZombieKey_destroy = args[0][0]; 1311 ZombieKey_resurrect = *argl == 2 ? args[0][1] : 0; 1312 } 1313 break; 1314 case RC_WALL: 1315#ifdef MULTIUSER 1316 s = D_user->u_name; 1317#else 1318 s = D_usertty; 1319#endif 1320 { 1321 struct display *olddisplay = display; 1322 display = 0; /* no display will cause a broadcast */ 1323 Msg(0, "%s: %s", s, *args); 1324 display = olddisplay; 1325 } 1326 break; 1327 case RC_AT: 1328 /* where this AT command comes from: */ 1329#ifdef MULTIUSER 1330 s = SaveStr(D_user->u_name); 1331 /* DO NOT RETURN FROM HERE WITHOUT RESETTING THIS: */ 1332 EffectiveAclUser = D_user; 1333#else 1334 s = SaveStr(D_usertty); 1335#endif 1336 n = strlen(args[0]); 1337 if (n) n--; 1338 /* 1339 * the windows/displays loops are quite dangerous here, take extra 1340 * care not to trigger landmines. Things may appear/disappear while 1341 * we are walking along. 1342 */ 1343 switch (args[0][n]) 1344 { 1345 case '*': /* user */ 1346 { 1347 struct display *nd; 1348 struct acluser *u; 1349 1350 if (!n) 1351 u = D_user; 1352 else 1353 for (u = users; u; u = u->u_next) 1354 { 1355 debug3("strncmp('%s', '%s', %d)\n", *args, u->u_name, n); 1356 if (!strncmp(*args, u->u_name, n)) 1357 break; 1358 } 1359 debug1("at all displays of user %s\n", u->u_name); 1360 for (display = displays; display; display = nd) 1361 { 1362 nd = display->d_next; 1363 if (D_forecv == 0) 1364 continue; 1365 flayer = D_forecv->c_layer; 1366 fore = D_fore; 1367 if (D_user != u) 1368 continue; 1369 debug1("AT display %s\n", D_usertty); 1370 DoCommand(args + 1, argl + 1); 1371 if (display) 1372 Msg(0, "command from %s: %s %s", 1373 s, args[1], args[2] ? args[2] : ""); 1374 display = NULL; 1375 flayer = 0; 1376 fore = NULL; 1377 } 1378 break; 1379 } 1380 case '%': /* display */ 1381 { 1382 struct display *nd; 1383 1384 debug1("at display matching '%s'\n", args[0]); 1385 for (display = displays; display; display = nd) 1386 { 1387 nd = display->d_next; 1388 if (D_forecv == 0) 1389 continue; 1390 fore = D_fore; 1391 flayer = D_forecv->c_layer; 1392 if (strncmp(args[0], D_usertty, n) && 1393 (strncmp("/dev/", D_usertty, 5) || 1394 strncmp(args[0], D_usertty + 5, n)) && 1395 (strncmp("/dev/tty", D_usertty, 8) || 1396 strncmp(args[0], D_usertty + 8, n))) 1397 continue; 1398 debug1("AT display %s\n", D_usertty); 1399 DoCommand(args + 1, argl + 1); 1400 if (display) 1401 Msg(0, "command from %s: %s %s", 1402 s, args[1], args[2] ? args[2] : ""); 1403 display = NULL; 1404 fore = NULL; 1405 flayer = 0; 1406 } 1407 break; 1408 } 1409 case '#': /* window */ 1410 n--; 1411 /* FALLTHROUGH */ 1412 default: 1413 { 1414 struct win *nw; 1415 int ch; 1416 1417 n++; 1418 ch = args[0][n]; 1419 args[0][n] = '\0'; 1420 if (!*args[0] || (i = WindowByNumber(args[0])) < 0) 1421 { 1422 args[0][n] = ch; /* must restore string in case of bind */ 1423 /* try looping over titles */ 1424 for (fore = windows; fore; fore = nw) 1425 { 1426 nw = fore->w_next; 1427 if (strncmp(args[0], fore->w_title, n)) 1428 continue; 1429 debug2("AT window %d(%s)\n", fore->w_number, fore->w_title); 1430 /* 1431 * consider this a bug or a feature: 1432 * while looping through windows, we have fore AND 1433 * display context. This will confuse users who try to 1434 * set up loops inside of loops, but often allows to do 1435 * what you mean, even when you adress your context wrong. 1436 */ 1437 i = 0; 1438 /* XXX: other displays? */ 1439 if (fore->w_layer.l_cvlist) 1440 display = fore->w_layer.l_cvlist->c_display; 1441 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer; 1442 DoCommand(args + 1, argl + 1); /* may destroy our display */ 1443 if (fore && fore->w_layer.l_cvlist) 1444 { 1445 display = fore->w_layer.l_cvlist->c_display; 1446 Msg(0, "command from %s: %s %s", 1447 s, args[1], args[2] ? args[2] : ""); 1448 } 1449 } 1450 display = NULL; 1451 fore = NULL; 1452 if (i < 0) 1453 Msg(0, "%s: at '%s': no such window.\n", rc_name, args[0]); 1454 break; 1455 } 1456 else if (i < MAXWIN && (fore = wtab[i])) 1457 { 1458 args[0][n] = ch; /* must restore string in case of bind */ 1459 debug2("AT window %d (%s)\n", fore->w_number, fore->w_title); 1460 if (fore->w_layer.l_cvlist) 1461 display = fore->w_layer.l_cvlist->c_display; 1462 flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer; 1463 DoCommand(args + 1, argl + 1); 1464 if (fore && fore->w_layer.l_cvlist) 1465 { 1466 display = fore->w_layer.l_cvlist->c_display; 1467 Msg(0, "command from %s: %s %s", 1468 s, args[1], args[2] ? args[2] : ""); 1469 } 1470 display = NULL; 1471 fore = NULL; 1472 } 1473 else 1474 Msg(0, "%s: at [identifier][%%|*|#] command [args]", rc_name); 1475 break; 1476 } 1477 } 1478 free(s); 1479#ifdef MULTIUSER 1480 EffectiveAclUser = NULL; 1481#endif 1482 break; 1483 1484#ifdef COPY_PASTE 1485 case RC_READREG: 1486#ifdef ENCODINGS 1487 i = fore ? fore->w_encoding : display ? display->d_encoding : 0; 1488 if (args[0] && args[1] && !strcmp(args[0], "-e")) 1489 { 1490 i = FindEncoding(args[1]); 1491 if (i == -1) 1492 { 1493 Msg(0, "%s: readreg: unknown encoding", rc_name); 1494 break; 1495 } 1496 args += 2; 1497 } 1498#endif 1499 /* 1500 * Without arguments we prompt for a destination register. 1501 * It will receive the copybuffer contents. 1502 * This is not done by RC_PASTE, as we prompt for source 1503 * (not dest) there. 1504 */ 1505 if ((s = *args) == NULL) 1506 { 1507 Input("Copy to register:", 1, INP_RAW, copy_reg_fn, NULL); 1508 break; 1509 } 1510 if (*argl != 1) 1511 { 1512 Msg(0, "%s: copyreg: character, ^x, or (octal) \\032 expected.", rc_name); 1513 break; 1514 } 1515 ch = args[0][0]; 1516 /* 1517 * With two arguments we *really* read register contents from file 1518 */ 1519 if (args[1]) 1520 { 1521 if (args[2]) 1522 { 1523 Msg(0, "%s: readreg: too many arguments", rc_name); 1524 break; 1525 } 1526 if ((s = ReadFile(args[1], &n))) 1527 { 1528 struct plop *pp = plop_tab + (int)(unsigned char)ch; 1529 1530 if (pp->buf) 1531 free(pp->buf); 1532 pp->buf = s; 1533 pp->len = n; 1534#ifdef ENCODINGS 1535 pp->enc = i; 1536#endif 1537 } 1538 } 1539 else 1540 /* 1541 * with one argument we copy the copybuffer into a specified register 1542 * This could be done with RC_PASTE too, but is here to be consistent 1543 * with the zero argument call. 1544 */ 1545 copy_reg_fn(&ch, 0, NULL); 1546 break; 1547#endif 1548 case RC_REGISTER: 1549#ifdef ENCODINGS 1550 i = fore ? fore->w_encoding : display ? display->d_encoding : 0; 1551 if (args[0] && args[1] && !strcmp(args[0], "-e")) 1552 { 1553 i = FindEncoding(args[1]); 1554 if (i == -1) 1555 { 1556 Msg(0, "%s: register: unknown encoding", rc_name); 1557 break; 1558 } 1559 args += 2; 1560 argc -= 2; 1561 } 1562#endif 1563 if (argc != 2) 1564 { 1565 Msg(0, "%s: register: illegal number of arguments.", rc_name); 1566 break; 1567 } 1568 if (*argl != 1) 1569 { 1570 Msg(0, "%s: register: character, ^x, or (octal) \\032 expected.", rc_name); 1571 break; 1572 } 1573 ch = args[0][0]; 1574#ifdef COPY_PASTE 1575 if (ch == '.') 1576 { 1577 if (user->u_plop.buf != NULL) 1578 UserFreeCopyBuffer(user); 1579 if (args[1] && args[1][0]) 1580 { 1581 user->u_plop.buf = SaveStrn(args[1], argl[1]); 1582 user->u_plop.len = argl[1]; 1583#ifdef ENCODINGS 1584 user->u_plop.enc = i; 1585#endif 1586 } 1587 } 1588#endif 1589 else 1590 { 1591 struct plop *plp = plop_tab + (int)(unsigned char)ch; 1592 1593 if (plp->buf) 1594 free(plp->buf); 1595 plp->buf = SaveStrn(args[1], argl[1]); 1596 plp->len = argl[1]; 1597#ifdef ENCODINGS 1598 plp->enc = i; 1599#endif 1600 } 1601 break; 1602 case RC_PROCESS: 1603 if ((s = *args) == NULL) 1604 { 1605 Input("Process register:", 1, INP_RAW, process_fn, NULL); 1606 break; 1607 } 1608 if (*argl != 1) 1609 { 1610 Msg(0, "%s: process: character, ^x, or (octal) \\032 expected.", rc_name); 1611 break; 1612 } 1613 ch = args[0][0]; 1614 process_fn(&ch, 0, NULL); 1615 break; 1616 case RC_STUFF: 1617 s = *args; 1618 n = *argl; 1619 if (args[1]) 1620 { 1621 if (strcmp(s, "-k")) 1622 { 1623 Msg(0, "%s: stuff: invalid option %s", rc_name, s); 1624 break; 1625 } 1626 s = args[1]; 1627 for (i = T_CAPS; i < T_OCAPS; i++) 1628 if (strcmp(term[i].tcname, s) == 0) 1629 break; 1630 if (i == T_OCAPS) 1631 { 1632 Msg(0, "%s: stuff: unknown key '%s'", rc_name, s); 1633 break; 1634 } 1635#ifdef MAPKEYS 1636 if (StuffKey(i - T_CAPS) == 0) 1637 break; 1638#endif 1639 s = display ? D_tcs[i].str : 0; 1640 if (s == 0) 1641 break; 1642 n = strlen(s); 1643 } 1644 while(n) 1645 LayProcess(&s, &n); 1646 break; 1647 case RC_REDISPLAY: 1648 Activate(-1); 1649 break; 1650 case RC_WINDOWS: 1651 ShowWindows(-1); 1652 break; 1653 case RC_VERSION: 1654 Msg(0, "screen %s", version); 1655 break; 1656 case RC_TIME: 1657 if (*args) 1658 { 1659 timestring = SaveStr(*args); 1660 break; 1661 } 1662 Msg(0, "%s", MakeWinMsg(timestring, fore, '%')); 1663 break; 1664 case RC_INFO: 1665 ShowInfo(); 1666 break; 1667 case RC_DINFO: 1668 ShowDInfo(); 1669 break; 1670 case RC_COMMAND: 1671 { 1672 struct action *ktabp = ktab; 1673 if (argc == 2 && !strcmp(*args, "-c")) 1674 { 1675 if ((ktabp = FindKtab(args[1], 0)) == 0) 1676 { 1677 Msg(0, "Unknown command class '%s'", args[1]); 1678 break; 1679 } 1680 } 1681 if (D_ESCseen != ktab || ktabp != ktab) 1682 { 1683 D_ESCseen = ktabp; 1684 break; 1685 } 1686 D_ESCseen = 0; 1687 } 1688 /* FALLTHROUGH */ 1689 case RC_OTHER: 1690 if (MoreWindows()) 1691 SwitchWindow(display && D_other ? D_other->w_number : NextWindow()); 1692 break; 1693 case RC_META: 1694 if (user->u_Esc == -1) 1695 break; 1696 ch = user->u_Esc; 1697 s = &ch; 1698 n = 1; 1699 LayProcess(&s, &n); 1700 break; 1701 case RC_XON: 1702 ch = Ctrl('q'); 1703 s = &ch; 1704 n = 1; 1705 LayProcess(&s, &n); 1706 break; 1707 case RC_XOFF: 1708 ch = Ctrl('s'); 1709 s = &ch; 1710 n = 1; 1711 LayProcess(&s, &n); 1712 break; 1713 case RC_DEFBREAKTYPE: 1714 case RC_BREAKTYPE: 1715 { 1716 static char *types[] = { "TIOCSBRK", "TCSBRK", "tcsendbreak", NULL }; 1717 extern int breaktype; 1718 1719 if (*args) 1720 { 1721 if (ParseNum(act, &n)) 1722 for (n = 0; n < (int)(sizeof(types)/sizeof(*types)); n++) 1723 { 1724 for (i = 0; i < 4; i++) 1725 { 1726 ch = args[0][i]; 1727 if (ch >= 'a' && ch <= 'z') 1728 ch -= 'a' - 'A'; 1729 if (ch != types[n][i] && (ch + ('a' - 'A')) != types[n][i]) 1730 break; 1731 } 1732 if (i == 4) 1733 break; 1734 } 1735 if (n < 0 || n >= (int)(sizeof(types)/sizeof(*types))) 1736 Msg(0, "%s invalid, chose one of %s, %s or %s", *args, types[0], types[1], types[2]); 1737 else 1738 { 1739 breaktype = n; 1740 Msg(0, "breaktype set to (%d) %s", n, types[n]); 1741 } 1742 } 1743 else 1744 Msg(0, "breaktype is (%d) %s", breaktype, types[breaktype]); 1745 } 1746 break; 1747 case RC_POW_BREAK: 1748 case RC_BREAK: 1749 n = 0; 1750 if (*args && ParseNum(act, &n)) 1751 break; 1752 SendBreak(fore, n, nr == RC_POW_BREAK); 1753 break; 1754#ifdef LOCK 1755 case RC_LOCKSCREEN: 1756 Detach(D_LOCK); 1757 break; 1758#endif 1759 case RC_WIDTH: 1760 case RC_HEIGHT: 1761 { 1762 int w, h; 1763 int what = 0; 1764 1765 i = 1; 1766 if (*args && !strcmp(*args, "-w")) 1767 what = 1; 1768 else if (*args && !strcmp(*args, "-d")) 1769 what = 2; 1770 if (what) 1771 args++; 1772 if (what == 0 && flayer && !display) 1773 what = 1; 1774 if (what == 1) 1775 { 1776 if (!flayer) 1777 { 1778 Msg(0, "%s: %s: window required", rc_name, comms[nr].name); 1779 break; 1780 } 1781 w = flayer->l_width; 1782 h = flayer->l_height; 1783 } 1784 else 1785 { 1786 if (!display) 1787 { 1788 Msg(0, "%s: %s: display required", rc_name, comms[nr].name); 1789 break; 1790 } 1791 w = D_width; 1792 h = D_height; 1793 } 1794 if (*args && args[0][0] == '-') 1795 { 1796 Msg(0, "%s: %s: unknown option %s", rc_name, comms[nr].name, *args); 1797 break; 1798 } 1799 if (nr == RC_HEIGHT) 1800 { 1801 if (!*args) 1802 { 1803#define H0height 42 1804#define H1height 24 1805 if (h == H0height) 1806 h = H1height; 1807 else if (h == H1height) 1808 h = H0height; 1809 else if (h > (H0height + H1height) / 2) 1810 h = H0height; 1811 else 1812 h = H1height; 1813 } 1814 else 1815 { 1816 h = atoi(*args); 1817 if (args[1]) 1818 w = atoi(args[1]); 1819 } 1820 } 1821 else 1822 { 1823 if (!*args) 1824 { 1825 if (w == Z0width) 1826 w = Z1width; 1827 else if (w == Z1width) 1828 w = Z0width; 1829 else if (w > (Z0width + Z1width) / 2) 1830 w = Z0width; 1831 else 1832 w = Z1width; 1833 } 1834 else 1835 { 1836 w = atoi(*args); 1837 if (args[1]) 1838 h = atoi(args[1]); 1839 } 1840 } 1841 if (*args && args[1] && args[2]) 1842 { 1843 Msg(0, "%s: %s: too many arguments", rc_name, comms[nr].name); 1844 break; 1845 } 1846 if (w <= 0) 1847 { 1848 Msg(0, "Illegal width"); 1849 break; 1850 } 1851 if (h <= 0) 1852 { 1853 Msg(0, "Illegal height"); 1854 break; 1855 } 1856 if (what == 1) 1857 { 1858 if (flayer->l_width == w && flayer->l_height == h) 1859 break; 1860 ResizeLayer(flayer, w, h, (struct display *)0); 1861 break; 1862 } 1863 if (D_width == w && D_height == h) 1864 break; 1865 if (what == 2) 1866 { 1867 ChangeScreenSize(w, h, 1); 1868 } 1869 else 1870 { 1871 if (ResizeDisplay(w, h) == 0) 1872 { 1873 Activate(D_fore ? D_fore->w_norefresh : 0); 1874 /* autofit */ 1875 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, 0); 1876 break; 1877 } 1878 if (h == D_height) 1879 Msg(0, "Your termcap does not specify how to change the terminal's width to %d.", w); 1880 else if (w == D_width) 1881 Msg(0, "Your termcap does not specify how to change the terminal's height to %d.", h); 1882 else 1883 Msg(0, "Your termcap does not specify how to change the terminal's resolution to %dx%d.", w, h); 1884 } 1885 } 1886 break; 1887 case RC_TITLE: 1888 if (*args == 0) 1889 InputAKA(); 1890 else 1891 ChangeAKA(fore, *args, strlen(*args)); 1892 break; 1893 case RC_COLON: 1894 Input(":", 100, INP_COOKED, Colonfin, NULL); 1895 if (*args && **args) 1896 { 1897 s = *args; 1898 n = strlen(s); 1899 LayProcess(&s, &n); 1900 } 1901 break; 1902 case RC_LASTMSG: 1903 if (D_status_lastmsg) 1904 Msg(0, "%s", D_status_lastmsg); 1905 break; 1906 case RC_SCREEN: 1907 DoScreen("key", args); 1908 break; 1909 case RC_WRAP: 1910 if (ParseSwitch(act, &fore->w_wrap) == 0 && msgok) 1911 Msg(0, "%cwrap", fore->w_wrap ? '+' : '-'); 1912 break; 1913 case RC_FLOW: 1914 if (*args) 1915 { 1916 if (args[0][0] == 'a') 1917 { 1918 fore->w_flow = (fore->w_flow & FLOW_AUTO) ? FLOW_AUTOFLAG |FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG; 1919 } 1920 else 1921 { 1922 if (ParseOnOff(act, &n)) 1923 break; 1924 fore->w_flow = (fore->w_flow & FLOW_AUTO) | n; 1925 } 1926 } 1927 else 1928 { 1929 if (fore->w_flow & FLOW_AUTOFLAG) 1930 fore->w_flow = (fore->w_flow & FLOW_AUTO) | FLOW_NOW; 1931 else if (fore->w_flow & FLOW_NOW) 1932 fore->w_flow &= ~FLOW_NOW; 1933 else 1934 fore->w_flow = fore->w_flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG; 1935 } 1936 SetFlow(fore->w_flow & FLOW_NOW); 1937 if (msgok) 1938 Msg(0, "%cflow%s", (fore->w_flow & FLOW_NOW) ? '+' : '-', 1939 (fore->w_flow & FLOW_AUTOFLAG) ? "(auto)" : ""); 1940 break; 1941#ifdef MULTIUSER 1942 case RC_DEFWRITELOCK: 1943 if (args[0][0] == 'a') 1944 nwin_default.wlock = WLOCK_AUTO; 1945 else 1946 { 1947 if (ParseOnOff(act, &n)) 1948 break; 1949 nwin_default.wlock = n ? WLOCK_ON : WLOCK_OFF; 1950 } 1951 break; 1952 case RC_WRITELOCK: 1953 if (*args) 1954 { 1955 if (args[0][0] == 'a') 1956 { 1957 fore->w_wlock = WLOCK_AUTO; 1958 } 1959 else 1960 { 1961 if (ParseOnOff(act, &n)) 1962 break; 1963 fore->w_wlock = n ? WLOCK_ON : WLOCK_OFF; 1964 } 1965 /* 1966 * user may have permission to change the writelock setting, 1967 * but he may never aquire the lock himself without write permission 1968 */ 1969 if (!AclCheckPermWin(D_user, ACL_WRITE, fore)) 1970 fore->w_wlockuser = D_user; 1971 } 1972 Msg(0, "writelock %s", (fore->w_wlock == WLOCK_AUTO) ? "auto" : 1973 ((fore->w_wlock == WLOCK_OFF) ? "off" : "on")); 1974 break; 1975#endif 1976 case RC_CLEAR: 1977 ResetAnsiState(fore); 1978 WriteString(fore, "\033[H\033[J", 6); 1979 break; 1980 case RC_RESET: 1981 ResetAnsiState(fore); 1982#ifdef ZMODEM 1983 if (fore->w_zdisplay) 1984 zmodem_abort(fore, fore->w_zdisplay); 1985#endif 1986 WriteString(fore, "\033c", 2); 1987 break; 1988 case RC_MONITOR: 1989 n = fore->w_monitor != MON_OFF; 1990 if (ParseSwitch(act, &n)) 1991 break; 1992 if (n) 1993 { 1994#ifdef MULTIUSER 1995 if (display) /* we tell only this user */ 1996 ACLBYTE(fore->w_mon_notify, D_user->u_id) |= ACLBIT(D_user->u_id); 1997 else 1998 for (i = 0; i < maxusercount; i++) 1999 ACLBYTE(fore->w_mon_notify, i) |= ACLBIT(i); 2000#endif 2001 if (fore->w_monitor == MON_OFF) 2002 fore->w_monitor = MON_ON; 2003 Msg(0, "Window %d (%s) is now being monitored for all activity.", fore->w_number, fore->w_title); 2004 } 2005 else 2006 { 2007#ifdef MULTIUSER 2008 if (display) /* we remove only this user */ 2009 ACLBYTE(fore->w_mon_notify, D_user->u_id) 2010 &= ~ACLBIT(D_user->u_id); 2011 else 2012 for (i = 0; i < maxusercount; i++) 2013 ACLBYTE(fore->w_mon_notify, i) &= ~ACLBIT(i); 2014 for (i = maxusercount - 1; i >= 0; i--) 2015 if (ACLBYTE(fore->w_mon_notify, i)) 2016 break; 2017 if (i < 0) 2018#endif 2019 fore->w_monitor = MON_OFF; 2020 Msg(0, "Window %d (%s) is no longer being monitored for activity.", fore->w_number, fore->w_title); 2021 } 2022 break; 2023#ifdef MULTI 2024 case RC_DISPLAYS: 2025 display_displays(); 2026 break; 2027#endif 2028 case RC_WINDOWLIST: 2029 if (!*args) 2030 display_wlist(0, WLIST_NUM); 2031 else if (!strcmp(*args, "-m") && !args[1]) 2032 display_wlist(0, WLIST_MRU); 2033 else if (!strcmp(*args, "-b") && !args[1]) 2034 display_wlist(1, WLIST_NUM); 2035 else if (!strcmp(*args, "-b") && !strcmp(args[1], "-m") && !args[2]) 2036 display_wlist(1, WLIST_MRU); 2037 else if (!strcmp(*args, "-m") && !strcmp(args[1], "-b") && !args[2]) 2038 display_wlist(1, WLIST_MRU); 2039 else if (!strcmp(*args, "string")) 2040 { 2041 if (args[1]) 2042 { 2043 if (wliststr) 2044 free(wliststr); 2045 wliststr = SaveStr(args[1]); 2046 } 2047 if (msgok) 2048 Msg(0, "windowlist string is '%s'", wliststr); 2049 } 2050 else if (!strcmp(*args, "title")) 2051 { 2052 if (args[1]) 2053 { 2054 if (wlisttit) 2055 free(wlisttit); 2056 wlisttit = SaveStr(args[1]); 2057 } 2058 if (msgok) 2059 Msg(0, "windowlist title is '%s'", wlisttit); 2060 } 2061 else 2062 Msg(0, "usage: windowlist [-b] [string [string] | title [title]]"); 2063 break; 2064 case RC_HELP: 2065 if (argc == 2 && !strcmp(*args, "-c")) 2066 { 2067 struct action *ktabp; 2068 if ((ktabp = FindKtab(args[1], 0)) == 0) 2069 { 2070 Msg(0, "Unknown command class '%s'", args[1]); 2071 break; 2072 } 2073 display_help(args[1], ktabp); 2074 } 2075 else 2076 display_help((char *)0, ktab); 2077 break; 2078 case RC_LICENSE: 2079 display_copyright(); 2080 break; 2081#ifdef COPY_PASTE 2082 case RC_COPY: 2083 if (flayer->l_layfn != &WinLf) 2084 { 2085 Msg(0, "Must be on a window layer"); 2086 break; 2087 } 2088 MarkRoutine(); 2089 break; 2090 case RC_HISTORY: 2091 { 2092 static char *pasteargs[] = {".", 0}; 2093 static int pasteargl[] = {1}; 2094 2095 if (flayer->l_layfn != &WinLf) 2096 { 2097 Msg(0, "Must be on a window layer"); 2098 break; 2099 } 2100 if (GetHistory() == 0) 2101 break; 2102 if (user->u_plop.buf == NULL) 2103 break; 2104 args = pasteargs; 2105 argl = pasteargl; 2106 } 2107 /*FALLTHROUGH*/ 2108 case RC_PASTE: 2109 { 2110 char *ss, *dbuf, dch; 2111 int l = 0; 2112# ifdef ENCODINGS 2113 int enc = -1; 2114# endif 2115 2116 /* 2117 * without args we prompt for one(!) register to be pasted in the window 2118 */ 2119 if ((s = *args) == NULL) 2120 { 2121 Input("Paste from register:", 1, INP_RAW, ins_reg_fn, NULL); 2122 break; 2123 } 2124 if (args[1] == 0 && !fore) /* no window? */ 2125 break; 2126 /* 2127 * with two arguments we paste into a destination register 2128 * (no window needed here). 2129 */ 2130 if (args[1] && argl[1] != 1) 2131 { 2132 Msg(0, "%s: paste destination: character, ^x, or (octal) \\032 expected.", 2133 rc_name); 2134 break; 2135 } 2136# ifdef ENCODINGS 2137 else if (fore) 2138 enc = fore->w_encoding; 2139# endif 2140 2141 /* 2142 * measure length of needed buffer 2143 */ 2144 for (ss = s = *args; (ch = *ss); ss++) 2145 { 2146 if (ch == '.') 2147 { 2148# ifdef ENCODINGS 2149 if (enc == -1) 2150 enc = user->u_plop.enc; 2151 if (enc != user->u_plop.enc) 2152 l += RecodeBuf((unsigned char *)user->u_plop.buf, user->u_plop.len, user->u_plop.enc, enc, (unsigned char *)0); 2153 else 2154# endif 2155 l += user->u_plop.len; 2156 } 2157 else 2158 { 2159# ifdef ENCODINGS 2160 if (enc == -1) 2161 enc = plop_tab[(int)(unsigned char)ch].enc; 2162 if (enc != plop_tab[(int)(unsigned char)ch].enc) 2163 l += RecodeBuf((unsigned char *)plop_tab[(int)(unsigned char)ch].buf, plop_tab[(int)(unsigned char)ch].len, plop_tab[(int)(unsigned char)ch].enc, enc, (unsigned char *)0); 2164 else 2165# endif 2166 l += plop_tab[(int)(unsigned char)ch].len; 2167 } 2168 } 2169 if (l == 0) 2170 { 2171 Msg(0, "empty buffer"); 2172 break; 2173 } 2174 /* 2175 * shortcut: 2176 * if there is only one source and the destination is a window, then 2177 * pass a pointer rather than duplicating the buffer. 2178 */ 2179 if (s[1] == 0 && args[1] == 0) 2180# ifdef ENCODINGS 2181 if (enc == (*s == '.' ? user->u_plop.enc : plop_tab[(int)(unsigned char)*s].enc)) 2182# endif 2183 { 2184 MakePaster(&fore->w_paster, *s == '.' ? user->u_plop.buf : plop_tab[(int)(unsigned char)*s].buf, l, 0); 2185 break; 2186 } 2187 /* 2188 * if no shortcut, we construct a buffer 2189 */ 2190 if ((dbuf = (char *)malloc(l)) == 0) 2191 { 2192 Msg(0, strnomem); 2193 break; 2194 } 2195 l = 0; 2196 /* 2197 * concatenate all sources into our own buffer, copy buffer is 2198 * special and is skipped if no display exists. 2199 */ 2200 for (ss = s; (ch = *ss); ss++) 2201 { 2202 struct plop *pp = (ch == '.' ? &user->u_plop : &plop_tab[(int)(unsigned char)ch]); 2203#ifdef ENCODINGS 2204 if (pp->enc != enc) 2205 { 2206 l += RecodeBuf((unsigned char *)pp->buf, pp->len, pp->enc, enc, (unsigned char *)dbuf + l); 2207 continue; 2208 } 2209#endif 2210 bcopy(pp->buf, dbuf + l, pp->len); 2211 l += pp->len; 2212 } 2213 /* 2214 * when called with one argument we paste our buffer into the window 2215 */ 2216 if (args[1] == 0) 2217 { 2218 MakePaster(&fore->w_paster, dbuf, l, 1); 2219 } 2220 else 2221 { 2222 /* 2223 * we have two arguments, the second is already in dch. 2224 * use this as destination rather than the window. 2225 */ 2226 dch = args[1][0]; 2227 if (dch == '.') 2228 { 2229 if (user->u_plop.buf != NULL) 2230 UserFreeCopyBuffer(user); 2231 user->u_plop.buf = dbuf; 2232 user->u_plop.len = l; 2233#ifdef ENCODINGS 2234 user->u_plop.enc = enc; 2235#endif 2236 } 2237 else 2238 { 2239 struct plop *pp = plop_tab + (int)(unsigned char)dch; 2240 if (pp->buf) 2241 free(pp->buf); 2242 pp->buf = dbuf; 2243 pp->len = l; 2244#ifdef ENCODINGS 2245 pp->enc = enc; 2246#endif 2247 } 2248 } 2249 break; 2250 } 2251 case RC_WRITEBUF: 2252 if (!user->u_plop.buf) 2253 { 2254 Msg(0, "empty buffer"); 2255 break; 2256 } 2257#ifdef ENCODINGS 2258 { 2259 struct plop oldplop; 2260 2261 oldplop = user->u_plop; 2262 if (args[0] && args[1] && !strcmp(args[0], "-e")) 2263 { 2264 int enc, l; 2265 char *newbuf; 2266 2267 enc = FindEncoding(args[1]); 2268 if (enc == -1) 2269 { 2270 Msg(0, "%s: writebuf: unknown encoding", rc_name); 2271 break; 2272 } 2273 if (enc != oldplop.enc) 2274 { 2275 l = RecodeBuf((unsigned char *)oldplop.buf, oldplop.len, oldplop.enc, enc, (unsigned char *)0); 2276 newbuf = malloc(l + 1); 2277 if (!newbuf) 2278 { 2279 Msg(0, strnomem); 2280 break; 2281 } 2282 user->u_plop.len = RecodeBuf((unsigned char *)oldplop.buf, oldplop.len, oldplop.enc, enc, (unsigned char *)newbuf); 2283 user->u_plop.buf = newbuf; 2284 user->u_plop.enc = enc; 2285 } 2286 args += 2; 2287 } 2288#endif 2289 if (args[0] && args[1]) 2290 Msg(0, "%s: writebuf: too many arguments", rc_name); 2291 else 2292 WriteFile(user, args[0], DUMP_EXCHANGE); 2293#ifdef ENCODINGS 2294 if (user->u_plop.buf != oldplop.buf) 2295 free(user->u_plop.buf); 2296 user->u_plop = oldplop; 2297 } 2298#endif 2299 break; 2300 case RC_READBUF: 2301#ifdef ENCODINGS 2302 i = fore ? fore->w_encoding : display ? display->d_encoding : 0; 2303 if (args[0] && args[1] && !strcmp(args[0], "-e")) 2304 { 2305 i = FindEncoding(args[1]); 2306 if (i == -1) 2307 { 2308 Msg(0, "%s: readbuf: unknown encoding", rc_name); 2309 break; 2310 } 2311 args += 2; 2312 } 2313#endif 2314 if (args[0] && args[1]) 2315 { 2316 Msg(0, "%s: readbuf: too many arguments", rc_name); 2317 break; 2318 } 2319 if ((s = ReadFile(args[0] ? args[0] : BufferFile, &n))) 2320 { 2321 if (user->u_plop.buf) 2322 UserFreeCopyBuffer(user); 2323 user->u_plop.len = n; 2324 user->u_plop.buf = s; 2325#ifdef ENCODINGS 2326 user->u_plop.enc = i; 2327#endif 2328 } 2329 break; 2330 case RC_REMOVEBUF: 2331 KillBuffers(); 2332 break; 2333 case RC_IGNORECASE: 2334 (void)ParseSwitch(act, &search_ic); 2335 if (msgok) 2336 Msg(0, "Will %signore case in searches", search_ic ? "" : "not "); 2337 break; 2338#endif /* COPY_PASTE */ 2339 case RC_ESCAPE: 2340 if (*argl == 0) 2341 SetEscape(user, -1, -1); 2342 else if (*argl == 2) 2343 SetEscape(user, (int)(unsigned char)args[0][0], (int)(unsigned char)args[0][1]); 2344 else 2345 { 2346 Msg(0, "%s: two characters required after escape.", rc_name); 2347 break; 2348 } 2349 /* Change defescape if master user. This is because we only 2350 * have one ktab. 2351 */ 2352 if (display && user != users) 2353 break; 2354 /* FALLTHROUGH */ 2355 case RC_DEFESCAPE: 2356 if (*argl == 0) 2357 SetEscape(NULL, -1, -1); 2358 else if (*argl == 2) 2359 SetEscape(NULL, (int)(unsigned char)args[0][0], (int)(unsigned char)args[0][1]); 2360 else 2361 { 2362 Msg(0, "%s: two characters required after defescape.", rc_name); 2363 break; 2364 } 2365#ifdef MAPKEYS 2366 CheckEscape(); 2367#endif 2368 break; 2369 case RC_CHDIR: 2370 s = *args ? *args : home; 2371 if (chdir(s) == -1) 2372 Msg(errno, "%s", s); 2373 break; 2374 case RC_SHELL: 2375 case RC_DEFSHELL: 2376 if (ParseSaveStr(act, &ShellProg) == 0) 2377 ShellArgs[0] = ShellProg; 2378 break; 2379 case RC_HARDCOPYDIR: 2380 if (*args) 2381 (void)ParseSaveStr(act, &hardcopydir); 2382 if (msgok) 2383 Msg(0, "hardcopydir is %s\n", hardcopydir && *hardcopydir ? hardcopydir : "<cwd>"); 2384 break; 2385 case RC_LOGFILE: 2386 if (*args) 2387 { 2388 if (args[1] && !(strcmp(*args, "flush"))) 2389 { 2390 log_flush = atoi(args[1]); 2391 if (msgok) 2392 Msg(0, "log flush timeout set to %ds\n", log_flush); 2393 break; 2394 } 2395 if (ParseSaveStr(act, &screenlogfile) || !msgok) 2396 break; 2397 } 2398 Msg(0, "logfile is '%s'", screenlogfile); 2399 break; 2400 case RC_LOGTSTAMP: 2401 if (!*args || !strcmp(*args, "on") || !strcmp(*args, "off")) 2402 { 2403 if (ParseSwitch(act, &logtstamp_on) == 0 && msgok) 2404 Msg(0, "timestamps turned %s", logtstamp_on ? "on" : "off"); 2405 } 2406 else if (!strcmp(*args, "string")) 2407 { 2408 if (args[1]) 2409 { 2410 if (logtstamp_string) 2411 free(logtstamp_string); 2412 logtstamp_string = SaveStr(args[1]); 2413 } 2414 if (msgok) 2415 Msg(0, "logfile timestamp is '%s'", logtstamp_string); 2416 } 2417 else if (!strcmp(*args, "after")) 2418 { 2419 if (args[1]) 2420 { 2421 logtstamp_after = atoi(args[1]); 2422 if (!msgok) 2423 break; 2424 } 2425 Msg(0, "timestamp printed after %ds\n", logtstamp_after); 2426 } 2427 else 2428 Msg(0, "usage: logtstamp [after [n]|string [str]|on|off]"); 2429 break; 2430 case RC_SHELLTITLE: 2431 (void)ParseSaveStr(act, &nwin_default.aka); 2432 break; 2433 case RC_TERMCAP: 2434 case RC_TERMCAPINFO: 2435 case RC_TERMINFO: 2436 if (!rc_name || !*rc_name) 2437 Msg(0, "Sorry, too late now. Place that in your .screenrc file."); 2438 break; 2439 case RC_SLEEP: 2440 break; /* Already handled */ 2441 case RC_TERM: 2442 s = NULL; 2443 if (ParseSaveStr(act, &s)) 2444 break; 2445 if (strlen(s) >= 20) 2446 { 2447 Msg(0, "%s: term: argument too long ( < 20)", rc_name); 2448 free(s); 2449 break; 2450 } 2451 strcpy(screenterm, s); 2452 free(s); 2453 debug1("screenterm set to %s\n", screenterm); 2454 MakeTermcap((display == 0)); 2455 debug("new termcap made\n"); 2456 break; 2457 case RC_ECHO: 2458 if (!msgok && (!rc_name || strcmp(rc_name, "-X"))) 2459 break; 2460 /* 2461 * user typed ^A:echo... well, echo isn't FinishRc's job, 2462 * but as he wanted to test us, we show good will 2463 */ 2464 if (argc > 1 && !strcmp(*args, "-n")) 2465 { 2466 args++; 2467 argc--; 2468 } 2469 s = *args; 2470 if (argc > 1 && !strcmp(*args, "-p")) 2471 { 2472 args++; 2473 argc--; 2474 s = *args; 2475 if (s) 2476 s = MakeWinMsg(s, fore, '%'); 2477 } 2478 if (s) 2479 Msg(0, "%s", s); 2480 else 2481 Msg(0, "%s: 'echo [-n] [-p] \"string\"' expected.", rc_name); 2482 break; 2483 case RC_BELL: 2484 case RC_BELL_MSG: 2485 if (*args == 0) 2486 { 2487 char buf[256]; 2488 AddXChars(buf, sizeof(buf), BellString); 2489 Msg(0, "bell_msg is '%s'", buf); 2490 break; 2491 } 2492 (void)ParseSaveStr(act, &BellString); 2493 break; 2494#ifdef COPY_PASTE 2495 case RC_BUFFERFILE: 2496 if (*args == 0) 2497 BufferFile = SaveStr(DEFAULT_BUFFERFILE); 2498 else if (ParseSaveStr(act, &BufferFile)) 2499 break; 2500 if (msgok) 2501 Msg(0, "Bufferfile is now '%s'", BufferFile); 2502 break; 2503#endif 2504 case RC_ACTIVITY: 2505 (void)ParseSaveStr(act, &ActivityString); 2506 break; 2507#if defined(DETACH) && defined(POW_DETACH) 2508 case RC_POW_DETACH_MSG: 2509 if (*args == 0) 2510 { 2511 char buf[256]; 2512 AddXChars(buf, sizeof(buf), PowDetachString); 2513 Msg(0, "pow_detach_msg is '%s'", buf); 2514 break; 2515 } 2516 (void)ParseSaveStr(act, &PowDetachString); 2517 break; 2518#endif 2519#if defined(UTMPOK) && defined(LOGOUTOK) 2520 case RC_LOGIN: 2521 n = fore->w_slot != (slot_t)-1; 2522 if (*args && !strcmp(*args, "always")) 2523 { 2524 fore->w_lflag = 3; 2525 if (!displays && n) 2526 SlotToggle(n); 2527 break; 2528 } 2529 if (*args && !strcmp(*args, "attached")) 2530 { 2531 fore->w_lflag = 1; 2532 if (!displays && n) 2533 SlotToggle(0); 2534 break; 2535 } 2536 if (ParseSwitch(act, &n) == 0) 2537 SlotToggle(n); 2538 break; 2539 case RC_DEFLOGIN: 2540 if (!strcmp(*args, "always")) 2541 nwin_default.lflag |= 2; 2542 else if (!strcmp(*args, "attached")) 2543 nwin_default.lflag &= ~2; 2544 else 2545 (void)ParseOnOff(act, &nwin_default.lflag); 2546 break; 2547#endif 2548 case RC_DEFFLOW: 2549 if (args[0] && args[1] && args[1][0] == 'i') 2550 { 2551 iflag = 1; 2552 for (display = displays; display; display = display->d_next) 2553 { 2554 if (!D_flow) 2555 continue; 2556#if defined(TERMIO) || defined(POSIX) 2557 D_NewMode.tio.c_cc[VINTR] = D_OldMode.tio.c_cc[VINTR]; 2558 D_NewMode.tio.c_lflag |= ISIG; 2559#else /* TERMIO || POSIX */ 2560 D_NewMode.m_tchars.t_intrc = D_OldMode.m_tchars.t_intrc; 2561#endif /* TERMIO || POSIX */ 2562 SetTTY(D_userfd, &D_NewMode); 2563 } 2564 } 2565 if (args[0] && args[0][0] == 'a') 2566 nwin_default.flowflag = FLOW_AUTOFLAG; 2567 else 2568 (void)ParseOnOff(act, &nwin_default.flowflag); 2569 break; 2570 case RC_DEFWRAP: 2571 (void)ParseOnOff(act, &nwin_default.wrap); 2572 break; 2573 case RC_DEFC1: 2574 (void)ParseOnOff(act, &nwin_default.c1); 2575 break; 2576#ifdef COLOR 2577 case RC_DEFBCE: 2578 (void)ParseOnOff(act, &nwin_default.bce); 2579 break; 2580#endif 2581 case RC_DEFGR: 2582 (void)ParseOnOff(act, &nwin_default.gr); 2583 break; 2584 case RC_DEFMONITOR: 2585 if (ParseOnOff(act, &n) == 0) 2586 nwin_default.monitor = (n == 0) ? MON_OFF : MON_ON; 2587 break; 2588 case RC_DEFSILENCE: 2589 if (ParseOnOff(act, &n) == 0) 2590 nwin_default.silence = (n == 0) ? SILENCE_OFF : SILENCE_ON; 2591 break; 2592 case RC_VERBOSE: 2593 if (!*args) 2594 Msg(0, "W%s echo command when creating windows.", 2595 VerboseCreate ? "ill" : "on't"); 2596 else if (ParseOnOff(act, &n) == 0) 2597 VerboseCreate = n; 2598 break; 2599 case RC_HARDSTATUS: 2600 if (display) 2601 { 2602 Msg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */ 2603 RemoveStatus(); 2604 } 2605 if (args[0] && strcmp(args[0], "on") && strcmp(args[0], "off")) 2606 { 2607 struct display *olddisplay = display; 2608 int old_use, new_use = -1; 2609 2610 s = args[0]; 2611 if (!strncmp(s, "always", 6)) 2612 s += 6; 2613 if (!strcmp(s, "lastline")) 2614 new_use = HSTATUS_LASTLINE; 2615 else if (!strcmp(s, "ignore")) 2616 new_use = HSTATUS_IGNORE; 2617 else if (!strcmp(s, "message")) 2618 new_use = HSTATUS_MESSAGE; 2619 else if (!strcmp(args[0], "string")) 2620 { 2621 if (!args[1]) 2622 { 2623 char buf[256]; 2624 AddXChars(buf, sizeof(buf), hstatusstring); 2625 Msg(0, "hardstatus string is '%s'", buf); 2626 break; 2627 } 2628 } 2629 else 2630 { 2631 Msg(0, "%s: usage: hardstatus [always]lastline|ignore|message|string [string]", rc_name); 2632 break; 2633 } 2634 if (new_use != -1) 2635 { 2636 hardstatusemu = new_use | (s == args[0] ? 0 : HSTATUS_ALWAYS); 2637 for (display = displays; display; display = display->d_next) 2638 { 2639 RemoveStatus(); 2640 new_use = hardstatusemu & ~HSTATUS_ALWAYS; 2641 if (D_HS && s == args[0]) 2642 new_use = HSTATUS_HS; 2643 ShowHStatus((char *)0); 2644 old_use = D_has_hstatus; 2645 D_has_hstatus = new_use; 2646 if ((new_use == HSTATUS_LASTLINE && old_use != HSTATUS_LASTLINE) || (new_use != HSTATUS_LASTLINE && old_use == HSTATUS_LASTLINE)) 2647 ChangeScreenSize(D_width, D_height, 1); 2648 RefreshHStatus(); 2649 } 2650 } 2651 if (args[1]) 2652 { 2653 if (hstatusstring) 2654 free(hstatusstring); 2655 hstatusstring = SaveStr(args[1]); 2656 for (display = displays; display; display = display->d_next) 2657 RefreshHStatus(); 2658 } 2659 display = olddisplay; 2660 break; 2661 } 2662 (void)ParseSwitch(act, &use_hardstatus); 2663 if (msgok) 2664 Msg(0, "messages displayed on %s", use_hardstatus ? "hardstatus line" : "window"); 2665 break; 2666 case RC_CAPTION: 2667 if (strcmp(args[0], "always") == 0 || strcmp(args[0], "splitonly") == 0) 2668 { 2669 struct display *olddisplay = display; 2670 2671 captionalways = args[0][0] == 'a'; 2672 for (display = displays; display; display = display->d_next) 2673 ChangeScreenSize(D_width, D_height, 1); 2674 display = olddisplay; 2675 } 2676 else if (strcmp(args[0], "string") == 0) 2677 { 2678 if (!args[1]) 2679 { 2680 char buf[256]; 2681 AddXChars(buf, sizeof(buf), captionstring); 2682 Msg(0, "caption string is '%s'", buf); 2683 break; 2684 } 2685 } 2686 else 2687 { 2688 Msg(0, "%s: usage: caption always|splitonly|string <string>", rc_name); 2689 break; 2690 } 2691 if (!args[1]) 2692 break; 2693 if (captionstring) 2694 free(captionstring); 2695 captionstring = SaveStr(args[1]); 2696 RedisplayDisplays(0); 2697 break; 2698 case RC_CONSOLE: 2699 n = (console_window != 0); 2700 if (ParseSwitch(act, &n)) 2701 break; 2702 if (TtyGrabConsole(fore->w_ptyfd, n, rc_name)) 2703 break; 2704 if (n == 0) 2705 Msg(0, "%s: releasing console %s", rc_name, HostName); 2706 else if (console_window) 2707 Msg(0, "%s: stealing console %s from window %d (%s)", rc_name, 2708 HostName, console_window->w_number, console_window->w_title); 2709 else 2710 Msg(0, "%s: grabbing console %s", rc_name, HostName); 2711 console_window = n ? fore : 0; 2712 break; 2713 case RC_ALLPARTIAL: 2714 if (ParseOnOff(act, &all_norefresh)) 2715 break; 2716 if (!all_norefresh && fore) 2717 Activate(-1); 2718 if (msgok) 2719 Msg(0, all_norefresh ? "No refresh on window change!\n" : 2720 "Window specific refresh\n"); 2721 break; 2722 case RC_PARTIAL: 2723 (void)ParseSwitch(act, &n); 2724 fore->w_norefresh = n; 2725 break; 2726 case RC_VBELL: 2727 if (ParseSwitch(act, &visual_bell) || !msgok) 2728 break; 2729 if (visual_bell == 0) 2730 Msg(0, "switched to audible bell."); 2731 else 2732 Msg(0, "switched to visual bell."); 2733 break; 2734 case RC_VBELLWAIT: 2735 if (ParseNum1000(act, &VBellWait) == 0 && msgok) 2736 Msg(0, "vbellwait set to %.10g seconds", VBellWait/1000.); 2737 break; 2738 case RC_MSGWAIT: 2739 if (ParseNum1000(act, &MsgWait) == 0 && msgok) 2740 Msg(0, "msgwait set to %.10g seconds", MsgWait/1000.); 2741 break; 2742 case RC_MSGMINWAIT: 2743 if (ParseNum1000(act, &MsgMinWait) == 0 && msgok) 2744 Msg(0, "msgminwait set to %.10g seconds", MsgMinWait/1000.); 2745 break; 2746 case RC_SILENCEWAIT: 2747 if (ParseNum(act, &SilenceWait)) 2748 break; 2749 if (SilenceWait < 1) 2750 SilenceWait = 1; 2751 for (p = windows; p; p = p->w_next) 2752 p->w_silencewait = SilenceWait; 2753 if (msgok) 2754 Msg(0, "silencewait set to %d seconds", SilenceWait); 2755 break; 2756 case RC_NUMBER: 2757 if (*args == 0) 2758 Msg(0, "This is window %d (%s).\n", fore->w_number, fore->w_title); 2759 else 2760 { 2761 int old = fore->w_number; 2762 2763 if (ParseNum(act, &n) || n >= maxwin) 2764 break; 2765 p = wtab[n]; 2766 wtab[n] = fore; 2767 fore->w_number = n; 2768 wtab[old] = p; 2769 if (p) 2770 p->w_number = old; 2771#ifdef MULTIUSER 2772 /* exchange the acls for these windows. */ 2773 AclWinSwap(old, n); 2774#endif 2775#ifdef UTMPOK 2776 /* exchange the utmp-slots for these windows */ 2777 if ((fore->w_slot != (slot_t) -1) && (fore->w_slot != (slot_t) 0)) 2778 { 2779 RemoveUtmp(fore); 2780 SetUtmp(fore); 2781 } 2782 if (p && (p->w_slot != (slot_t) -1) && (p->w_slot != (slot_t) 0)) 2783 { 2784 /* XXX: first display wins? */ 2785 display = fore->w_layer.l_cvlist ? fore->w_layer.l_cvlist->c_display : 0; 2786 RemoveUtmp(p); 2787 SetUtmp(p); 2788 } 2789#endif 2790 2791 WindowChanged(fore, 'n'); 2792 WindowChanged((struct win *)0, 'w'); 2793 WindowChanged((struct win *)0, 'W'); 2794 WindowChanged((struct win *)0, 0); 2795 } 2796 break; 2797 case RC_SILENCE: 2798 n = fore->w_silence != 0; 2799 i = fore->w_silencewait; 2800 if (args[0] && (args[0][0] == '-' || (args[0][0] >= '0' && args[0][0] <= '9'))) 2801 { 2802 if (ParseNum(act, &i)) 2803 break; 2804 n = i > 0; 2805 } 2806 else if (ParseSwitch(act, &n)) 2807 break; 2808 if (n) 2809 { 2810#ifdef MULTIUSER 2811 if (display) /* we tell only this user */ 2812 ACLBYTE(fore->w_lio_notify, D_user->u_id) |= ACLBIT(D_user->u_id); 2813 else 2814 for (n = 0; n < maxusercount; n++) 2815 ACLBYTE(fore->w_lio_notify, n) |= ACLBIT(n); 2816#endif 2817 fore->w_silencewait = i; 2818 fore->w_silence = SILENCE_ON; 2819 SetTimeout(&fore->w_silenceev, fore->w_silencewait * 1000); 2820 evenq(&fore->w_silenceev); 2821 2822 if (!msgok) 2823 break; 2824 Msg(0, "The window is now being monitored for %d sec. silence.", fore->w_silencewait); 2825 } 2826 else 2827 { 2828#ifdef MULTIUSER 2829 if (display) /* we remove only this user */ 2830 ACLBYTE(fore->w_lio_notify, D_user->u_id) 2831 &= ~ACLBIT(D_user->u_id); 2832 else 2833 for (n = 0; n < maxusercount; n++) 2834 ACLBYTE(fore->w_lio_notify, n) &= ~ACLBIT(n); 2835 for (i = maxusercount - 1; i >= 0; i--) 2836 if (ACLBYTE(fore->w_lio_notify, i)) 2837 break; 2838 if (i < 0) 2839#endif 2840 { 2841 fore->w_silence = SILENCE_OFF; 2842 evdeq(&fore->w_silenceev); 2843 } 2844 if (!msgok) 2845 break; 2846 Msg(0, "The window is no longer being monitored for silence."); 2847 } 2848 break; 2849#ifdef COPY_PASTE 2850 case RC_DEFSCROLLBACK: 2851 (void)ParseNum(act, &nwin_default.histheight); 2852 break; 2853 case RC_SCROLLBACK: 2854 (void)ParseNum(act, &n); 2855 ChangeWindowSize(fore, fore->w_width, fore->w_height, n); 2856 if (msgok) 2857 Msg(0, "scrollback set to %d", fore->w_histheight); 2858 break; 2859#endif 2860 case RC_SESSIONNAME: 2861 if (*args == 0) 2862 Msg(0, "This session is named '%s'\n", SockName); 2863 else 2864 { 2865 char buf[MAXPATHLEN]; 2866 2867 s = 0; 2868 if (ParseSaveStr(act, &s)) 2869 break; 2870 if (!*s || strlen(s) + (SockName - SockPath) > MAXPATHLEN - 13 || index(s, '/')) 2871 { 2872 Msg(0, "%s: bad session name '%s'\n", rc_name, s); 2873 free(s); 2874 break; 2875 } 2876 strncpy(buf, SockPath, SockName - SockPath); 2877 sprintf(buf + (SockName - SockPath), "%d.%s", (int)getpid(), s); 2878 free(s); 2879 if ((access(buf, F_OK) == 0) || (errno != ENOENT)) 2880 { 2881 Msg(0, "%s: inappropriate path: '%s'.", rc_name, buf); 2882 break; 2883 } 2884 if (rename(SockPath, buf)) 2885 { 2886 Msg(errno, "%s: failed to rename(%s, %s)", rc_name, SockPath, buf); 2887 break; 2888 } 2889 debug2("rename(%s, %s) done\n", SockPath, buf); 2890 strcpy(SockPath, buf); 2891 MakeNewEnv(); 2892 } 2893 break; 2894 case RC_SETENV: 2895 if (!args[0] || !args[1]) 2896 { 2897 debug1("RC_SETENV arguments missing: %s\n", args[0] ? args[0] : ""); 2898 InputSetenv(args[0]); 2899 } 2900 else 2901 { 2902 xsetenv(args[0], args[1]); 2903 MakeNewEnv(); 2904 } 2905 break; 2906 case RC_UNSETENV: 2907 unsetenv(*args); 2908 MakeNewEnv(); 2909 break; 2910#ifdef COPY_PASTE 2911 case RC_DEFSLOWPASTE: 2912 (void)ParseNum(act, &nwin_default.slow); 2913 break; 2914 case RC_SLOWPASTE: 2915 if (*args == 0) 2916 Msg(0, fore->w_slowpaste ? 2917 "Slowpaste in window %d is %d milliseconds." : 2918 "Slowpaste in window %d is unset.", 2919 fore->w_number, fore->w_slowpaste); 2920 else if (ParseNum(act, &fore->w_slowpaste) == 0 && msgok) 2921 Msg(0, fore->w_slowpaste ? 2922 "Slowpaste in window %d set to %d milliseconds." : 2923 "Slowpaste in window %d now unset.", 2924 fore->w_number, fore->w_slowpaste); 2925 break; 2926 case RC_MARKKEYS: 2927 if (CompileKeys(*args, *argl, mark_key_tab)) 2928 { 2929 Msg(0, "%s: markkeys: syntax error.", rc_name); 2930 break; 2931 } 2932 debug1("markkeys %s\n", *args); 2933 break; 2934# ifdef FONT 2935 case RC_PASTEFONT: 2936 if (ParseSwitch(act, &pastefont) == 0 && msgok) 2937 Msg(0, "Will %spaste font settings", pastefont ? "" : "not "); 2938 break; 2939# endif 2940 case RC_CRLF: 2941 (void)ParseSwitch(act, &join_with_cr); 2942 break; 2943 case RC_COMPACTHIST: 2944 if (ParseSwitch(act, &compacthist) == 0 && msgok) 2945 Msg(0, "%scompacting history lines", compacthist ? "" : "not "); 2946 break; 2947#endif 2948#ifdef NETHACK 2949 case RC_NETHACK: 2950 (void)ParseOnOff(act, &nethackflag); 2951 break; 2952#endif 2953 case RC_HARDCOPY_APPEND: 2954 (void)ParseOnOff(act, &hardcopy_append); 2955 break; 2956 case RC_VBELL_MSG: 2957 if (*args == 0) 2958 { 2959 char buf[256]; 2960 AddXChars(buf, sizeof(buf), VisualBellString); 2961 Msg(0, "vbell_msg is '%s'", buf); 2962 break; 2963 } 2964 (void)ParseSaveStr(act, &VisualBellString); 2965 debug1(" new vbellstr '%s'\n", VisualBellString); 2966 break; 2967 case RC_DEFMODE: 2968 if (ParseBase(act, *args, &n, 8, "octal")) 2969 break; 2970 if (n < 0 || n > 0777) 2971 { 2972 Msg(0, "%s: mode: Invalid tty mode %o", rc_name, n); 2973 break; 2974 } 2975 TtyMode = n; 2976 if (msgok) 2977 Msg(0, "Ttymode set to %03o", TtyMode); 2978 break; 2979 case RC_AUTODETACH: 2980 (void)ParseOnOff(act, &auto_detach); 2981 break; 2982 case RC_STARTUP_MESSAGE: 2983 (void)ParseOnOff(act, &default_startup); 2984 break; 2985#ifdef PASSWORD 2986 case RC_PASSWORD: 2987 if (*args) 2988 { 2989 n = (*user->u_password) ? 1 : 0; 2990 if (user->u_password != NullStr) free((char *)user->u_password); 2991 user->u_password = SaveStr(*args); 2992 if (!strcmp(user->u_password, "none")) 2993 { 2994 if (n) 2995 Msg(0, "Password checking disabled"); 2996 free(user->u_password); 2997 user->u_password = NullStr; 2998 } 2999 } 3000 else 3001 { 3002 if (!fore) 3003 { 3004 Msg(0, "%s: password: window required", rc_name); 3005 break; 3006 } 3007 Input("New screen password:", 100, INP_NOECHO, pass1, display ? (char *)D_user : (char *)users); 3008 } 3009 break; 3010#endif /* PASSWORD */ 3011 case RC_BIND: 3012 { 3013 struct action *ktabp = ktab; 3014 3015 if (argc > 2 && !strcmp(*args, "-c")) 3016 { 3017 ktabp = FindKtab(args[1], 1); 3018 if (ktabp == 0) 3019 break; 3020 args += 2; 3021 argl += 2; 3022 } 3023 if (*argl != 1) 3024 { 3025 Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.", rc_name); 3026 break; 3027 } 3028 n = (unsigned char)args[0][0]; 3029 if (args[1]) 3030 { 3031 if ((i = FindCommnr(args[1])) == RC_ILLEGAL) 3032 { 3033 Msg(0, "%s: bind: unknown command '%s'", rc_name, args[1]); 3034 break; 3035 } 3036 if (CheckArgNum(i, args + 2) < 0) 3037 break; 3038 ClearAction(&ktabp[n]); 3039 SaveAction(ktabp + n, i, args + 2, argl + 2); 3040 } 3041 else 3042 ClearAction(&ktabp[n]); 3043 } 3044 break; 3045#ifdef MAPKEYS 3046 case RC_BINDKEY: 3047 { 3048 struct action *newact; 3049 int newnr, fl = 0, kf = 0, af = 0, df = 0, mf = 0; 3050 struct display *odisp = display; 3051 int used = 0; 3052 struct kmap_ext *kme; 3053 3054 for (; *args && **args == '-'; args++, argl++) 3055 { 3056 if (strcmp(*args, "-t") == 0) 3057 fl = KMAP_NOTIMEOUT; 3058 else if (strcmp(*args, "-k") == 0) 3059 kf = 1; 3060 else if (strcmp(*args, "-a") == 0) 3061 af = 1; 3062 else if (strcmp(*args, "-d") == 0) 3063 df = 1; 3064 else if (strcmp(*args, "-m") == 0) 3065 mf = 1; 3066 else if (strcmp(*args, "--") == 0) 3067 { 3068 args++; 3069 argl++; 3070 break; 3071 } 3072 else 3073 { 3074 Msg(0, "%s: bindkey: invalid option %s", rc_name, *args); 3075 return; 3076 } 3077 } 3078 if (df && mf) 3079 { 3080 Msg(0, "%s: bindkey: -d does not work with -m", rc_name); 3081 break; 3082 } 3083 if (*args == 0) 3084 { 3085 if (mf) 3086 display_bindkey("Edit mode", mmtab); 3087 else if (df) 3088 display_bindkey("Default", dmtab); 3089 else 3090 display_bindkey("User", umtab); 3091 break; 3092 } 3093 if (kf == 0) 3094 { 3095 if (af) 3096 { 3097 Msg(0, "%s: bindkey: -a only works with -k", rc_name); 3098 break; 3099 } 3100 if (*argl == 0) 3101 { 3102 Msg(0, "%s: bindkey: empty string makes no sense", rc_name); 3103 break; 3104 } 3105 for (i = 0, kme = kmap_exts; i < kmap_extn; i++, kme++) 3106 if (kme->str == 0) 3107 { 3108 if (args[1]) 3109 break; 3110 } 3111 else 3112 if (*argl == (kme->fl & ~KMAP_NOTIMEOUT) && bcmp(kme->str, *args, *argl) == 0) 3113 break; 3114 if (i == kmap_extn) 3115 { 3116 if (!args[1]) 3117 { 3118 Msg(0, "%s: bindkey: keybinding not found", rc_name); 3119 break; 3120 } 3121 kmap_extn += 8; 3122 kmap_exts = (struct kmap_ext *)xrealloc((char *)kmap_exts, kmap_extn * sizeof(*kmap_exts)); 3123 kme = kmap_exts + i; 3124 bzero((char *)kme, 8 * sizeof(*kmap_exts)); 3125 for (; i < kmap_extn; i++, kme++) 3126 { 3127 kme->str = 0; 3128 kme->dm.nr = kme->mm.nr = kme->um.nr = RC_ILLEGAL; 3129 kme->dm.args = kme->mm.args = kme->um.args = noargs; 3130 } 3131 i -= 8; 3132 kme -= 8; 3133 } 3134 if (df == 0 && kme->dm.nr != RC_ILLEGAL) 3135 used = 1; 3136 if (mf == 0 && kme->mm.nr != RC_ILLEGAL) 3137 used = 1; 3138 if ((df || mf) && kme->um.nr != RC_ILLEGAL) 3139 used = 1; 3140 i += KMAP_KEYS + KMAP_AKEYS; 3141 newact = df ? &kme->dm : mf ? &kme->mm : &kme->um; 3142 } 3143 else 3144 { 3145 for (i = T_CAPS; i < T_OCAPS; i++) 3146 if (strcmp(term[i].tcname, *args) == 0) 3147 break; 3148 if (i == T_OCAPS) 3149 { 3150 Msg(0, "%s: bindkey: unknown key '%s'", rc_name, *args); 3151 break; 3152 } 3153 if (af && i >= T_CURSOR && i < T_OCAPS) 3154 i -= T_CURSOR - KMAP_KEYS; 3155 else 3156 i -= T_CAPS; 3157 newact = df ? &dmtab[i] : mf ? &mmtab[i] : &umtab[i]; 3158 } 3159 if (args[1]) 3160 { 3161 if ((newnr = FindCommnr(args[1])) == RC_ILLEGAL) 3162 { 3163 Msg(0, "%s: bindkey: unknown command '%s'", rc_name, args[1]); 3164 break; 3165 } 3166 if (CheckArgNum(newnr, args + 2) < 0) 3167 break; 3168 ClearAction(newact); 3169 SaveAction(newact, newnr, args + 2, argl + 2); 3170 if (kf == 0 && args[1]) 3171 { 3172 if (kme->str) 3173 free(kme->str); 3174 kme->str = SaveStrn(*args, *argl); 3175 kme->fl = fl | *argl; 3176 } 3177 } 3178 else 3179 ClearAction(newact); 3180 for (display = displays; display; display = display->d_next) 3181 remap(i, args[1] ? 1 : 0); 3182 if (kf == 0 && !args[1]) 3183 { 3184 if (!used && kme->str) 3185 { 3186 free(kme->str); 3187 kme->str = 0; 3188 kme->fl = 0; 3189 } 3190 } 3191 display = odisp; 3192 } 3193 break; 3194 case RC_MAPTIMEOUT: 3195 if (*args) 3196 { 3197 if (ParseNum(act, &n)) 3198 break; 3199 if (n < 0) 3200 { 3201 Msg(0, "%s: maptimeout: illegal time %d", rc_name, n); 3202 break; 3203 } 3204 maptimeout = n; 3205 } 3206 if (*args == 0 || msgok) 3207 Msg(0, "maptimeout is %dms", maptimeout); 3208 break; 3209 case RC_MAPNOTNEXT: 3210 D_dontmap = 1; 3211 break; 3212 case RC_MAPDEFAULT: 3213 D_mapdefault = 1; 3214 break; 3215#endif 3216#ifdef MULTIUSER 3217 case RC_ACLCHG: 3218 case RC_ACLADD: 3219 case RC_ADDACL: 3220 case RC_CHACL: 3221 UsersAcl(NULL, argc, args); 3222 break; 3223 case RC_ACLDEL: 3224 if (UserDel(args[0], NULL)) 3225 break; 3226 if (msgok) 3227 Msg(0, "%s removed from acl database", args[0]); 3228 break; 3229 case RC_ACLGRP: 3230 /* 3231 * modify a user to gain or lose rights granted to a group. 3232 * This group is actually a normal user whose rights were defined 3233 * with chacl in the usual way. 3234 */ 3235 if (args[1]) 3236 { 3237 if (strcmp(args[1], "none")) /* link a user to another user */ 3238 { 3239 if (AclLinkUser(args[0], args[1])) 3240 break; 3241 if (msgok) 3242 Msg(0, "User %s joined acl-group %s", args[0], args[1]); 3243 } 3244 else /* remove all groups from user */ 3245 { 3246 struct acluser *u; 3247 struct aclusergroup *g; 3248 3249 if (!(u = *FindUserPtr(args[0]))) 3250 break; 3251 while ((g = u->u_group)) 3252 { 3253 u->u_group = g->next; 3254 free((char *)g); 3255 } 3256 } 3257 } 3258 else /* show all groups of user */ 3259 { 3260 char buf[256], *p = buf; 3261 int ngroups = 0; 3262 struct acluser *u; 3263 struct aclusergroup *g; 3264 3265 if (!(u = *FindUserPtr(args[0]))) 3266 { 3267 if (msgok) 3268 Msg(0, "User %s does not exist.", args[0]); 3269 break; 3270 } 3271 g = u->u_group; 3272 while (g) 3273 { 3274 ngroups++; 3275 sprintf(p, "%s ", g->u->u_name); 3276 p += strlen(p); 3277 if (p > buf+200) 3278 break; 3279 g = g->next; 3280 } 3281 if (ngroups) 3282 *(--p) = '\0'; 3283 Msg(0, "%s's group%s: %s.", args[0], (ngroups == 1) ? "" : "s", 3284 (ngroups == 0) ? "none" : buf); 3285 } 3286 break; 3287 case RC_ACLUMASK: 3288 case RC_UMASK: 3289 while ((s = *args++)) 3290 { 3291 char *err = 0; 3292 3293 if (AclUmask(display ? D_user : users, s, &err)) 3294 Msg(0, "umask: %s\n", err); 3295 } 3296 break; 3297 case RC_MULTIUSER: 3298 if (ParseOnOff(act, &n)) 3299 break; 3300 multi = n ? "" : 0; 3301 chsock(); 3302 if (msgok) 3303 Msg(0, "Multiuser mode %s", multi ? "enabled" : "disabled"); 3304 break; 3305#endif /* MULTIUSER */ 3306#ifdef PSEUDOS 3307 case RC_EXEC: 3308 winexec(args); 3309 break; 3310#endif 3311#ifdef MULTI 3312 case RC_NONBLOCK: 3313 i = D_nonblock >= 0; 3314 if (*args && ((args[0][0] >= '0' && args[0][0] <= '9') || args[0][0] == '.')) 3315 { 3316 if (ParseNum1000(act, &i)) 3317 break; 3318 } 3319 else if (!ParseSwitch(act, &i)) 3320 i = i == 0 ? -1 : 1000; 3321 else 3322 break; 3323 if (msgok && i == -1) 3324 Msg(0, "display set to blocking mode"); 3325 else if (msgok && i == 0) 3326 Msg(0, "display set to nonblocking mode, no timeout"); 3327 else if (msgok) 3328 Msg(0, "display set to nonblocking mode, %.10gs timeout", i/1000.); 3329 D_nonblock = i; 3330 if (D_nonblock <= 0) 3331 evdeq(&D_blockedev); 3332 break; 3333 case RC_DEFNONBLOCK: 3334 if (*args && ((args[0][0] >= '0' && args[0][0] <= '9') || args[0][0] == '.')) 3335 { 3336 if (ParseNum1000(act, &defnonblock)) 3337 break; 3338 } 3339 else if (!ParseOnOff(act, &defnonblock)) 3340 defnonblock = defnonblock == 0 ? -1 : 1000; 3341 else 3342 break; 3343 if (display && *rc_name) 3344 { 3345 D_nonblock = defnonblock; 3346 if (D_nonblock <= 0) 3347 evdeq(&D_blockedev); 3348 } 3349 break; 3350#endif 3351 case RC_GR: 3352#ifdef ENCODINGS 3353 if (fore->w_gr == 2) 3354 fore->w_gr = 0; 3355#endif 3356 if (ParseSwitch(act, &fore->w_gr) == 0 && msgok) 3357 Msg(0, "Will %suse GR", fore->w_gr ? "" : "not "); 3358#ifdef ENCODINGS 3359 if (fore->w_gr == 0 && fore->w_FontE) 3360 fore->w_gr = 2; 3361#endif 3362 break; 3363 case RC_C1: 3364 if (ParseSwitch(act, &fore->w_c1) == 0 && msgok) 3365 Msg(0, "Will %suse C1", fore->w_c1 ? "" : "not "); 3366 break; 3367#ifdef COLOR 3368 case RC_BCE: 3369 if (ParseSwitch(act, &fore->w_bce) == 0 && msgok) 3370 Msg(0, "Will %serase with background color", fore->w_bce ? "" : "not "); 3371 break; 3372#endif 3373#ifdef ENCODINGS 3374 case RC_KANJI: 3375 case RC_ENCODING: 3376#ifdef UTF8 3377 if (*args && !strcmp(args[0], "-d")) 3378 { 3379 if (!args[1]) 3380 Msg(0, "encodings directory is %s", screenencodings ? screenencodings : "<unset>"); 3381 else 3382 { 3383 free(screenencodings); 3384 screenencodings = SaveStr(args[1]); 3385 } 3386 break; 3387 } 3388 if (*args && !strcmp(args[0], "-l")) 3389 { 3390 if (!args[1]) 3391 Msg(0, "encoding: -l: argument required"); 3392 else if (LoadFontTranslation(-1, args[1])) 3393 Msg(0, "encoding: could not load utf8 encoding file"); 3394 else if (msgok) 3395 Msg(0, "encoding: utf8 encoding file loaded"); 3396 break; 3397 } 3398#else 3399 if (*args && (!strcmp(args[0], "-l") || !strcmp(args[0], "-d"))) 3400 { 3401 if (msgok) 3402 Msg(0, "encoding: screen is not compiled for UTF-8."); 3403 break; 3404 } 3405#endif 3406 for (i = 0; i < 2; i++) 3407 { 3408 if (args[i] == 0) 3409 break; 3410 if (!strcmp(args[i], ".")) 3411 continue; 3412 n = FindEncoding(args[i]); 3413 if (n == -1) 3414 { 3415 Msg(0, "encoding: unknown encoding '%s'", args[i]); 3416 break; 3417 } 3418 if (i == 0 && fore) 3419 { 3420 WinSwitchEncoding(fore, n); 3421 ResetCharsets(fore); 3422 } 3423 else if (i && display) 3424 D_encoding = n; 3425 } 3426 break; 3427 case RC_DEFKANJI: 3428 case RC_DEFENCODING: 3429 n = FindEncoding(*args); 3430 if (n == -1) 3431 { 3432 Msg(0, "defencoding: unknown encoding '%s'", *args); 3433 break; 3434 } 3435 nwin_default.encoding = n; 3436 break; 3437#endif 3438 3439#ifdef UTF8 3440 case RC_DEFUTF8: 3441 n = nwin_default.encoding == UTF8; 3442 if (ParseSwitch(act, &n) == 0) 3443 { 3444 nwin_default.encoding = n ? UTF8 : 0; 3445 if (msgok) 3446 Msg(0, "Will %suse UTF-8 encoding for new windows", n ? "" : "not "); 3447 } 3448 break; 3449 case RC_UTF8: 3450 for (i = 0; i < 2; i++) 3451 { 3452 if (i && args[i] == 0) 3453 break; 3454 if (args[i] == 0) 3455 n = fore->w_encoding != UTF8; 3456 else if (strcmp(args[i], "off") == 0) 3457 n = 0; 3458 else if (strcmp(args[i], "on") == 0) 3459 n = 1; 3460 else 3461 { 3462 Msg(0, "utf8: illegal argument (%s)", args[i]); 3463 break; 3464 } 3465 if (i == 0) 3466 { 3467 WinSwitchEncoding(fore, n ? UTF8 : 0); 3468 if (msgok) 3469 Msg(0, "Will %suse UTF-8 encoding", n ? "" : "not "); 3470 } 3471 else if (display) 3472 D_encoding = n ? UTF8 : 0; 3473 if (args[i] == 0) 3474 break; 3475 } 3476 break; 3477#endif 3478 3479 case RC_PRINTCMD: 3480 if (*args) 3481 { 3482 if (printcmd) 3483 free(printcmd); 3484 printcmd = 0; 3485 if (**args) 3486 printcmd = SaveStr(*args); 3487 } 3488 if (*args == 0 || msgok) 3489 { 3490 if (printcmd) 3491 Msg(0, "using '%s' as print command", printcmd); 3492 else 3493 Msg(0, "using termcap entries for printing"); 3494 break; 3495 } 3496 break; 3497 3498 case RC_DIGRAPH: 3499 Input("Enter digraph: ", 10, INP_EVERY, digraph_fn, NULL); 3500 if (*args && **args) 3501 { 3502 s = *args; 3503 n = strlen(s); 3504 LayProcess(&s, &n); 3505 } 3506 break; 3507 3508 case RC_DEFHSTATUS: 3509 if (*args == 0) 3510 { 3511 char buf[256]; 3512 *buf = 0; 3513 if (nwin_default.hstatus) 3514 AddXChars(buf, sizeof(buf), nwin_default.hstatus); 3515 Msg(0, "default hstatus is '%s'", buf); 3516 break; 3517 } 3518 (void)ParseSaveStr(act, &nwin_default.hstatus); 3519 if (*nwin_default.hstatus == 0) 3520 { 3521 free(nwin_default.hstatus); 3522 nwin_default.hstatus = 0; 3523 } 3524 break; 3525 case RC_HSTATUS: 3526 (void)ParseSaveStr(act, &fore->w_hstatus); 3527 if (*fore->w_hstatus == 0) 3528 { 3529 free(fore->w_hstatus); 3530 fore->w_hstatus = 0; 3531 } 3532 WindowChanged(fore, 'h'); 3533 break; 3534 3535#ifdef FONT 3536 case RC_DEFCHARSET: 3537 case RC_CHARSET: 3538 if (*args == 0) 3539 { 3540 char buf[256]; 3541 *buf = 0; 3542 if (nwin_default.charset) 3543 AddXChars(buf, sizeof(buf), nwin_default.charset); 3544 Msg(0, "default charset is '%s'", buf); 3545 break; 3546 } 3547 n = strlen(*args); 3548 if (n == 0 || n > 6) 3549 { 3550 Msg(0, "%s: %s: string has illegal size.", rc_name, comms[nr].name); 3551 break; 3552 } 3553 if (n > 4 && ( 3554 ((args[0][4] < '0' || args[0][4] > '3') && args[0][4] != '.') || 3555 ((args[0][5] < '0' || args[0][5] > '3') && args[0][5] && args[0][5] != '.'))) 3556 { 3557 Msg(0, "%s: %s: illegal mapping number.", rc_name, comms[nr].name); 3558 break; 3559 } 3560 if (nr == RC_CHARSET) 3561 { 3562 SetCharsets(fore, *args); 3563 break; 3564 } 3565 if (nwin_default.charset) 3566 free(nwin_default.charset); 3567 nwin_default.charset = SaveStr(*args); 3568 break; 3569#endif 3570#ifdef COLOR 3571 case RC_ATTRCOLOR: 3572 s = args[0]; 3573 if (*s >= '0' && *s <= '9') 3574 i = *s - '0'; 3575 else 3576 for (i = 0; i < 8; i++) 3577 if (*s == "dubrsBiI"[i]) 3578 break; 3579 s++; 3580 nr = 0; 3581 if (*s && s[1] && !s[2]) 3582 { 3583 if (*s == 'd' && s[1] == 'd') 3584 nr = 3; 3585 else if (*s == '.' && s[1] == 'd') 3586 nr = 2; 3587 else if (*s == 'd' && s[1] == '.') 3588 nr = 1; 3589 else if (*s != '.' || s[1] != '.') 3590 s--; 3591 s += 2; 3592 } 3593 if (*s || i < 0 || i >= 8) 3594 { 3595 Msg(0, "%s: attrcolor: unknown attribute '%s'.", rc_name, args[0]); 3596 break; 3597 } 3598 n = 0; 3599 if (args[1]) 3600 n = ParseAttrColor(args[1], args[2], 1); 3601 if (n == -1) 3602 break; 3603 attr2color[i][nr] = n; 3604 n = 0; 3605 for (i = 0; i < 8; i++) 3606 if (attr2color[i][0] || attr2color[i][1] || attr2color[i][2] || attr2color[i][3]) 3607 n |= 1 << i; 3608 nattr2color = n; 3609 break; 3610#endif 3611 case RC_SORENDITION: 3612 i = 0; 3613 if (*args) 3614 { 3615 i = ParseAttrColor(*args, args[1], 1); 3616 if (i == -1) 3617 break; 3618 ApplyAttrColor(i, &mchar_so); 3619 debug2("--> %x %x\n", mchar_so.attr, mchar_so.color); 3620 } 3621 if (msgok) 3622#ifdef COLOR 3623 Msg(0, "Standout attributes 0x%02x color 0x%02x", (unsigned char)mchar_so.attr, 0x99 ^ (unsigned char)mchar_so.color); 3624#else 3625 Msg(0, "Standout attributes 0x%02x ", (unsigned char)mchar_so.attr); 3626#endif 3627 break; 3628 3629 case RC_SOURCE: 3630 do_source(*args); 3631 break; 3632 3633#ifdef MULTIUSER 3634 case RC_SU: 3635 s = NULL; 3636 if (!*args) 3637 { 3638 Msg(0, "%s:%s screen login", HostName, SockPath); 3639 InputSu(D_fore, &D_user, NULL); 3640 } 3641 else if (!args[1]) 3642 InputSu(D_fore, &D_user, args[0]); 3643 else if (!args[2]) 3644 s = DoSu(&D_user, args[0], args[1], "\377"); 3645 else 3646 s = DoSu(&D_user, args[0], args[1], args[2]); 3647 if (s) 3648 Msg(0, "%s", s); 3649 break; 3650#endif /* MULTIUSER */ 3651 case RC_SPLIT: 3652 AddCanvas(); 3653 Activate(-1); 3654 break; 3655 case RC_REMOVE: 3656 RemCanvas(); 3657 Activate(-1); 3658 break; 3659 case RC_ONLY: 3660 OneCanvas(); 3661 Activate(-1); 3662 break; 3663 case RC_FIT: 3664 D_forecv->c_xoff = D_forecv->c_xs; 3665 D_forecv->c_yoff = D_forecv->c_ys; 3666 RethinkViewportOffsets(D_forecv); 3667 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, 0); 3668 flayer = D_forecv->c_layer; 3669 LaySetCursor(); 3670 break; 3671 case RC_FOCUS: 3672 if (!*args || !strcmp(*args, "down")) 3673 D_forecv = D_forecv->c_next ? D_forecv->c_next : D_cvlist; 3674 else if (!strcmp(*args, "up")) 3675 { 3676 struct canvas *cv; 3677 for (cv = D_cvlist; cv->c_next && cv->c_next != D_forecv; cv = cv->c_next) 3678 ; 3679 D_forecv = cv; 3680 } 3681 else if (!strcmp(*args, "top")) 3682 D_forecv = D_cvlist; 3683 else if (!strcmp(*args, "bottom")) 3684 { 3685 struct canvas *cv; 3686 for (cv = D_cvlist; cv->c_next; cv = cv->c_next) 3687 ; 3688 D_forecv = cv; 3689 } 3690 else 3691 { 3692 Msg(0, "%s: usage: focus [up|down|top|bottom]", rc_name); 3693 break; 3694 } 3695 fore = D_fore = Layer2Window(D_forecv->c_layer); 3696 flayer = D_forecv->c_layer; 3697#ifdef RXVT_OSC 3698 if (D_xtermosc[2] || D_xtermosc[3]) 3699 { 3700 Activate(-1); 3701 break; 3702 } 3703#endif 3704 RefreshHStatus(); 3705#ifdef RXVT_OSC 3706 RefreshXtermOSC(); 3707#endif 3708 flayer = D_forecv->c_layer; 3709 CV_CALL(D_forecv, LayRestore();LaySetCursor()); 3710 WindowChanged(0, 'F'); 3711 break; 3712 case RC_RESIZE: 3713 if (*args) 3714 ResizeRegions(*args); 3715 else 3716 Input("resize # lines: ", 20, INP_COOKED, ResizeFin, (char*)0); 3717 break; 3718 case RC_SETSID: 3719 (void)ParseSwitch(act, &separate_sids); 3720 break; 3721 case RC_EVAL: 3722 for (; *args; args++) 3723 { 3724 char *ss = SaveStr(*args); 3725 if (*ss) 3726 Colonfin(ss, strlen(ss), (char *)0); 3727 free(ss); 3728 } 3729 break; 3730 case RC_ALTSCREEN: 3731 (void)ParseSwitch(act, &use_altscreen); 3732 if (msgok) 3733 Msg(0, "Will %sdo alternate screen switching", use_altscreen ? "" : "not "); 3734 break; 3735 case RC_MAXWIN: 3736 if (ParseNum(act, &n)) 3737 break; 3738 if (n < 1) 3739 Msg(0, "illegal maxwin number specified"); 3740 else if (n > maxwin) 3741 Msg(0, "may only decrease maxwin number"); 3742 else 3743 maxwin = n; 3744 break; 3745 case RC_BACKTICK: 3746 if (ParseBase(act, *args, &n, 10, "decimal")) 3747 break; 3748 if (!args[1]) 3749 setbacktick(n, 0, 0, (char **)0); 3750 else 3751 { 3752 int lifespan, tick; 3753 if (argc < 4) 3754 { 3755 Msg(0, "%s: usage: backtick num [lifespan tick cmd args...]", rc_name); 3756 break; 3757 } 3758 if (ParseBase(act, args[1], &lifespan, 10, "decimal")) 3759 break; 3760 if (ParseBase(act, args[2], &tick, 10, "decimal")) 3761 break; 3762 setbacktick(n, lifespan, tick, SaveArgs(args + 3)); 3763 } 3764 WindowChanged(0, '`'); 3765 break; 3766 case RC_BLANKER: 3767#ifdef BLANKER_PRG 3768 if (blankerprg) 3769 { 3770 RunBlanker(blankerprg); 3771 break; 3772 } 3773#endif 3774 ClearAll(); 3775 CursorVisibility(-1); 3776 D_blocked = 4; 3777 break; 3778#ifdef BLANKER_PRG 3779 case RC_BLANKERPRG: 3780 if (blankerprg) 3781 { 3782 char **pp; 3783 for (pp = blankerprg; *pp; pp++) 3784 free(*pp); 3785 free(blankerprg); 3786 blankerprg = 0; 3787 } 3788 if (args[0][0]) 3789 blankerprg = SaveArgs(args); 3790 break; 3791#endif 3792 case RC_IDLE: 3793 if (*args) 3794 { 3795 struct display *olddisplay = display; 3796 if (!strcmp(*args, "off")) 3797 idletimo = 0; 3798 else if (args[0][0]) 3799 idletimo = atoi(*args) * 1000; 3800 if (argc > 1) 3801 { 3802 if ((i = FindCommnr(args[1])) == RC_ILLEGAL) 3803 { 3804 Msg(0, "%s: idle: unknown command '%s'", rc_name, args[1]); 3805 break; 3806 } 3807 if (CheckArgNum(i, args + 2) < 0) 3808 break; 3809 ClearAction(&idleaction); 3810 SaveAction(&idleaction, i, args + 2, argl + 2); 3811 } 3812 for (display = displays; display; display = display->d_next) 3813 ResetIdle(); 3814 display = olddisplay; 3815 } 3816 if (msgok) 3817 { 3818 if (idletimo) 3819 Msg(0, "idle timeout %ds, %s", idletimo / 1000, comms[idleaction.nr].name); 3820 else 3821 Msg(0, "idle off"); 3822 } 3823 break; 3824 default: 3825#ifdef HAVE_BRAILLE 3826 /* key == -2: input from braille keybord, msgok always 0 */ 3827 DoBrailleAction(act, key == -2 ? 0 : msgok); 3828#endif 3829 break; 3830 } 3831 if (display != odisplay) 3832 { 3833 for (display = displays; display; display = display->d_next) 3834 if (display == odisplay) 3835 break; 3836 } 3837} 3838 3839void 3840DoCommand(argv, argl) 3841char **argv; 3842int *argl; 3843{ 3844 struct action act; 3845 3846 if ((act.nr = FindCommnr(*argv)) == RC_ILLEGAL) 3847 { 3848 Msg(0, "%s: unknown command '%s'", rc_name, *argv); 3849 return; 3850 } 3851 act.args = argv + 1; 3852 act.argl = argl + 1; 3853 DoAction(&act, -1); 3854} 3855 3856static void 3857SaveAction(act, nr, args, argl) 3858struct action *act; 3859int nr; 3860char **args; 3861int *argl; 3862{ 3863 register int argc = 0; 3864 char **pp; 3865 int *lp; 3866 3867 if (args) 3868 while (args[argc]) 3869 argc++; 3870 if (argc == 0) 3871 { 3872 act->nr = nr; 3873 act->args = noargs; 3874 act->argl = 0; 3875 return; 3876 } 3877 if ((pp = (char **)malloc((unsigned)(argc + 1) * sizeof(char **))) == 0) 3878 Panic(0, strnomem); 3879 if ((lp = (int *)malloc((unsigned)(argc) * sizeof(int *))) == 0) 3880 Panic(0, strnomem); 3881 act->nr = nr; 3882 act->args = pp; 3883 act->argl = lp; 3884 while (argc--) 3885 { 3886 *lp = argl ? *argl++ : (int)strlen(*args); 3887 *pp++ = SaveStrn(*args++, *lp++); 3888 } 3889 *pp = 0; 3890} 3891 3892static char ** 3893SaveArgs(args) 3894char **args; 3895{ 3896 register char **ap, **pp; 3897 register int argc = 0; 3898 3899 while (args[argc]) 3900 argc++; 3901 if ((pp = ap = (char **)malloc((unsigned)(argc + 1) * sizeof(char **))) == 0) 3902 Panic(0, strnomem); 3903 while (argc--) 3904 *pp++ = SaveStr(*args++); 3905 *pp = 0; 3906 return ap; 3907} 3908 3909 3910/* 3911 * buf is split into argument vector args. 3912 * leading whitespace is removed. 3913 * @!| abbreviations are expanded. 3914 * the end of buffer is recognized by '\0' or an un-escaped '#'. 3915 * " and ' are interpreted. 3916 * 3917 * argc is returned. 3918 */ 3919int 3920Parse(buf, bufl, args, argl) 3921char *buf, **args; 3922int bufl, *argl; 3923{ 3924 register char *p = buf, **ap = args, *pp; 3925 register int delim, argc; 3926 int *lp = argl; 3927 3928 debug2("Parse %d %s\n", bufl, buf); 3929 argc = 0; 3930 pp = buf; 3931 delim = 0; 3932 for (;;) 3933 { 3934 while (*p && (*p == ' ' || *p == '\t')) 3935 ++p; 3936#ifdef PSEUDOS 3937 if (argc == 0 && *p == '!') 3938 { 3939 *ap++ = "exec"; 3940 *lp++ = 4; 3941 p++; 3942 argc++; 3943 continue; 3944 } 3945#endif 3946 if (*p == '\0' || *p == '#' || *p == '\n') 3947 { 3948 *p = '\0'; 3949 for (delim = 0; delim < argc; delim++) 3950 debug1("-- %s\n", args[delim]); 3951 args[argc] = 0; 3952 return argc; 3953 } 3954 if (++argc >= MAXARGS) 3955 { 3956 Msg(0, "%s: too many tokens.", rc_name); 3957 return 0; 3958 } 3959 *ap++ = pp; 3960 3961 debug1("- new arg %s\n", p); 3962 while (*p) 3963 { 3964 if (*p == delim) 3965 delim = 0; 3966 else if (delim != '\'' && *p == '\\' && (p[1] == '\'' || p[1] == '"' || p[1] == '\\' || p[1] == '$' || p[1] == '#' || p[1] == '^' || (p[1] >= '0' && p[1] <= '7'))) 3967 { 3968 p++; 3969 if (*p >= '0' && *p <= '7') 3970 { 3971 *pp = *p - '0'; 3972 if (p[1] >= '0' && p[1] <= '7') 3973 { 3974 p++; 3975 *pp = (*pp << 3) | (*p - '0'); 3976 if (p[1] >= '0' && p[1] <= '7') 3977 { 3978 p++; 3979 *pp = (*pp << 3) | (*p - '0'); 3980 } 3981 } 3982 pp++; 3983 } 3984 else 3985 *pp++ = *p; 3986 } 3987 else if (delim != '\'' && *p == '$' && (p[1] == '{' || p[1] == ':' || (p[1] >= 'a' && p[1] <= 'z') || (p[1] >= 'A' && p[1] <= 'Z') || (p[1] >= '0' && p[1] <= '9') || p[1] == '_')) 3988 3989 { 3990 char *ps, *pe, op, *v, xbuf[11]; 3991 int vl; 3992 3993 ps = ++p; 3994 debug1("- var %s\n", ps); 3995 p++; 3996 while (*p) 3997 { 3998 if (*ps == '{' && *p == '}') 3999 break; 4000 if (*ps == ':' && *p == ':') 4001 break; 4002 if (*ps != '{' && *ps != ':' && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9') && *p != '_') 4003 break; 4004 p++; 4005 } 4006 pe = p; 4007 if (*ps == '{' || *ps == ':') 4008 { 4009 if (!*p) 4010 { 4011 Msg(0, "%s: bad variable name.", rc_name); 4012 return 0; 4013 } 4014 p++; 4015 } 4016 op = *pe; 4017 *pe = 0; 4018 debug1("- var is '%s'\n", ps); 4019 if (*ps == ':') 4020 v = gettermcapstring(ps + 1); 4021 else 4022 { 4023 if (*ps == '{') 4024 ps++; 4025 v = xbuf; 4026 if (!strcmp(ps, "TERM")) 4027 v = display ? D_termname : "unknown"; 4028 else if (!strcmp(ps, "COLUMNS")) 4029 sprintf(xbuf, "%d", display ? D_width : -1); 4030 else if (!strcmp(ps, "LINES")) 4031 sprintf(xbuf, "%d", display ? D_height : -1); 4032 else 4033 v = getenv(ps); 4034 } 4035 *pe = op; 4036 vl = v ? strlen(v) : 0; 4037 if (vl) 4038 { 4039 debug1("- sub is '%s'\n", v); 4040 if (p - pp < vl) 4041 { 4042 int right = buf + bufl - (p + strlen(p) + 1); 4043 if (right > 0) 4044 { 4045 bcopy(p, p + right, strlen(p) + 1); 4046 p += right; 4047 } 4048 } 4049 if (p - pp < vl) 4050 { 4051 Msg(0, "%s: no space left for variable expansion.", rc_name); 4052 return 0; 4053 } 4054 bcopy(v, pp, vl); 4055 pp += vl; 4056 } 4057 continue; 4058 } 4059 else if (delim != '\'' && *p == '^' && p[1]) 4060 { 4061 p++; 4062 *pp++ = *p == '?' ? '\177' : *p & 0x1f; 4063 } 4064 else if (delim == 0 && (*p == '\'' || *p == '"')) 4065 delim = *p; 4066 else if (delim == 0 && (*p == ' ' || *p == '\t' || *p == '\n')) 4067 break; 4068 else 4069 *pp++ = *p; 4070 p++; 4071 } 4072 if (delim) 4073 { 4074 Msg(0, "%s: Missing %c quote.", rc_name, delim); 4075 return 0; 4076 } 4077 if (*p) 4078 p++; 4079 *pp = 0; 4080 debug2("- arg done, '%s' rest %s\n", ap[-1], p); 4081 *lp++ = pp - ap[-1]; 4082 pp++; 4083 } 4084} 4085 4086void 4087SetEscape(u, e, me) 4088struct acluser *u; 4089int e, me; 4090{ 4091 if (u) 4092 { 4093 u->u_Esc = e; 4094 u->u_MetaEsc = me; 4095 } 4096 else 4097 { 4098 if (users) 4099 { 4100 if (DefaultEsc >= 0) 4101 ClearAction(&ktab[DefaultEsc]); 4102 if (DefaultMetaEsc >= 0) 4103 ClearAction(&ktab[DefaultMetaEsc]); 4104 } 4105 DefaultEsc = e; 4106 DefaultMetaEsc = me; 4107 if (users) 4108 { 4109 if (DefaultEsc >= 0) 4110 { 4111 ClearAction(&ktab[DefaultEsc]); 4112 ktab[DefaultEsc].nr = RC_OTHER; 4113 } 4114 if (DefaultMetaEsc >= 0) 4115 { 4116 ClearAction(&ktab[DefaultMetaEsc]); 4117 ktab[DefaultMetaEsc].nr = RC_META; 4118 } 4119 } 4120 } 4121} 4122 4123int 4124ParseSwitch(act, var) 4125struct action *act; 4126int *var; 4127{ 4128 if (*act->args == 0) 4129 { 4130 *var ^= 1; 4131 return 0; 4132 } 4133 return ParseOnOff(act, var); 4134} 4135 4136static int 4137ParseOnOff(act, var) 4138struct action *act; 4139int *var; 4140{ 4141 register int num = -1; 4142 char **args = act->args; 4143 4144 if (args[1] == 0) 4145 { 4146 if (strcmp(args[0], "on") == 0) 4147 num = 1; 4148 else if (strcmp(args[0], "off") == 0) 4149 num = 0; 4150 } 4151 if (num < 0) 4152 { 4153 Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, comms[act->nr].name); 4154 return -1; 4155 } 4156 *var = num; 4157 return 0; 4158} 4159 4160int 4161ParseSaveStr(act, var) 4162struct action *act; 4163char **var; 4164{ 4165 char **args = act->args; 4166 if (*args == 0 || args[1]) 4167 { 4168 Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name); 4169 return -1; 4170 } 4171 if (*var) 4172 free(*var); 4173 *var = SaveStr(*args); 4174 return 0; 4175} 4176 4177int 4178ParseNum(act, var) 4179struct action *act; 4180int *var; 4181{ 4182 int i; 4183 char *p, **args = act->args; 4184 4185 p = *args; 4186 if (p == 0 || *p == 0 || args[1]) 4187 { 4188 Msg(0, "%s: %s: invalid argument. Give one argument.", 4189 rc_name, comms[act->nr].name); 4190 return -1; 4191 } 4192 i = 0; 4193 while (*p) 4194 { 4195 if (*p >= '0' && *p <= '9') 4196 i = 10 * i + (*p - '0'); 4197 else 4198 { 4199 Msg(0, "%s: %s: invalid argument. Give numeric argument.", 4200 rc_name, comms[act->nr].name); 4201 return -1; 4202 } 4203 p++; 4204 } 4205 debug1("ParseNum got %d\n", i); 4206 *var = i; 4207 return 0; 4208} 4209 4210static int 4211ParseNum1000(act, var) 4212struct action *act; 4213int *var; 4214{ 4215 int i; 4216 char *p, **args = act->args; 4217 int dig = 0; 4218 4219 p = *args; 4220 if (p == 0 || *p == 0 || args[1]) 4221 { 4222 Msg(0, "%s: %s: invalid argument. Give one argument.", 4223 rc_name, comms[act->nr].name); 4224 return -1; 4225 } 4226 i = 0; 4227 while (*p) 4228 { 4229 if (*p >= '0' && *p <= '9') 4230 { 4231 if (dig < 4) 4232 i = 10 * i + (*p - '0'); 4233 else if (dig == 4 && *p >= '5') 4234 i++; 4235 if (dig) 4236 dig++; 4237 } 4238 else if (*p == '.' && !dig) 4239 dig++; 4240 else 4241 { 4242 Msg(0, "%s: %s: invalid argument. Give floating point argument.", 4243 rc_name, comms[act->nr].name); 4244 return -1; 4245 } 4246 p++; 4247 } 4248 if (dig == 0) 4249 i *= 1000; 4250 else 4251 while (dig++ < 4) 4252 i *= 10; 4253 if (i < 0) 4254 i = (int)((unsigned int)~0 >> 1); 4255 debug1("ParseNum1000 got %d\n", i); 4256 *var = i; 4257 return 0; 4258} 4259 4260static struct win * 4261WindowByName(s) 4262char *s; 4263{ 4264 struct win *p; 4265 4266 for (p = windows; p; p = p->w_next) 4267 if (!strcmp(p->w_title, s)) 4268 return p; 4269 for (p = windows; p; p = p->w_next) 4270 if (!strncmp(p->w_title, s, strlen(s))) 4271 return p; 4272 return 0; 4273} 4274 4275static int 4276WindowByNumber(str) 4277char *str; 4278{ 4279 int i; 4280 char *s; 4281 4282 for (i = 0, s = str; *s; s++) 4283 { 4284 if (*s < '0' || *s > '9') 4285 break; 4286 i = i * 10 + (*s - '0'); 4287 } 4288 return *s ? -1 : i; 4289} 4290 4291/* 4292 * Get window number from Name or Number string. 4293 * Numbers are tried first, then names, a prefix match suffices. 4294 * Be careful when assigning numeric strings as WindowTitles. 4295 */ 4296int 4297WindowByNoN(str) 4298char *str; 4299{ 4300 int i; 4301 struct win *p; 4302 4303 if ((i = WindowByNumber(str)) < 0 || i >= MAXWIN) 4304 { 4305 if ((p = WindowByName(str))) 4306 return p->w_number; 4307 return -1; 4308 } 4309 return i; 4310} 4311 4312static int 4313ParseWinNum(act, var) 4314struct action *act; 4315int *var; 4316{ 4317 char **args = act->args; 4318 int i = 0; 4319 4320 if (*args == 0 || args[1]) 4321 { 4322 Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name); 4323 return -1; 4324 } 4325 4326 i = WindowByNoN(*args); 4327 if (i < 0) 4328 { 4329 Msg(0, "%s: %s: invalid argument. Give window number or name.", 4330 rc_name, comms[act->nr].name); 4331 return -1; 4332 } 4333 debug1("ParseWinNum got %d\n", i); 4334 *var = i; 4335 return 0; 4336} 4337 4338static int 4339ParseBase(act, p, var, base, bname) 4340struct action *act; 4341char *p; 4342int *var; 4343int base; 4344char *bname; 4345{ 4346 int i = 0; 4347 int c; 4348 4349 if (*p == 0) 4350 { 4351 Msg(0, "%s: %s: empty argument.", rc_name, comms[act->nr].name); 4352 return -1; 4353 } 4354 while ((c = *p++)) 4355 { 4356 if (c >= 'a' && c <= 'z') 4357 c -= 'a' - 'A'; 4358 if (c >= 'A' && c <= 'Z') 4359 c -= 'A' - ('0' + 10); 4360 c -= '0'; 4361 if (c < 0 || c >= base) 4362 { 4363 Msg(0, "%s: %s: argument is not %s.", rc_name, comms[act->nr].name, bname); 4364 return -1; 4365 } 4366 i = base * i + c; 4367 } 4368 debug1("ParseBase got %d\n", i); 4369 *var = i; 4370 return 0; 4371} 4372 4373static int 4374IsNum(s, base) 4375register char *s; 4376register int base; 4377{ 4378 for (base += '0'; *s; ++s) 4379 if (*s < '0' || *s > base) 4380 return 0; 4381 return 1; 4382} 4383 4384int 4385IsNumColon(s, base, p, psize) 4386int base, psize; 4387char *s, *p; 4388{ 4389 char *q; 4390 if ((q = rindex(s, ':')) != 0) 4391 { 4392 strncpy(p, q + 1, psize - 1); 4393 p[psize - 1] = '\0'; 4394 *q = '\0'; 4395 } 4396 else 4397 *p = '\0'; 4398 return IsNum(s, base); 4399} 4400 4401void 4402SwitchWindow(n) 4403int n; 4404{ 4405 struct win *p; 4406 4407 debug1("SwitchWindow %d\n", n); 4408 if (n < 0 || n >= MAXWIN) 4409 { 4410 ShowWindows(-1); 4411 return; 4412 } 4413 if ((p = wtab[n]) == 0) 4414 { 4415 ShowWindows(n); 4416 return; 4417 } 4418 if (display == 0) 4419 { 4420 fore = p; 4421 return; 4422 } 4423 if (p == D_fore) 4424 { 4425 Msg(0, "This IS window %d (%s).", n, p->w_title); 4426 return; 4427 } 4428#ifdef MULTIUSER 4429 if (AclCheckPermWin(D_user, ACL_READ, p)) 4430 { 4431 Msg(0, "Access to window %d denied.", p->w_number); 4432 return; 4433 } 4434#endif 4435 SetForeWindow(p); 4436 Activate(fore->w_norefresh); 4437} 4438 4439 4440void 4441SetCanvasWindow(cv, wi) 4442struct canvas *cv; 4443struct win *wi; 4444{ 4445 struct win *p = 0, **pp; 4446 struct layer *l; 4447 struct canvas *cvp, **cvpp; 4448 4449 l = cv->c_layer; 4450 display = cv->c_display; 4451 4452 if (l) 4453 { 4454 /* remove old layer */ 4455 for (cvpp = &l->l_cvlist; (cvp = *cvpp); cvpp = &cvp->c_lnext) 4456 if (cvp == cv) 4457 break; 4458 ASSERT(cvp); 4459 *cvpp = cvp->c_lnext; 4460 4461 p = Layer2Window(l); 4462 l = cv->c_layer; 4463 cv->c_layer = 0; 4464 4465 if (p && cv == D_forecv) 4466 { 4467#ifdef MULTIUSER 4468 ReleaseAutoWritelock(display, p); 4469#endif 4470 if (p->w_silence) 4471 { 4472 SetTimeout(&p->w_silenceev, p->w_silencewait * 1000); 4473 evenq(&p->w_silenceev); 4474 } 4475 D_other = fore; 4476 D_fore = 0; 4477 } 4478 if (l->l_cvlist == 0 && (p == 0 || l != p->w_savelayer)) 4479 KillLayerChain(l); 4480 } 4481 4482 /* find right layer to display on canvas */ 4483 if (wi) 4484 { 4485 l = &wi->w_layer; 4486 if (wi->w_savelayer && (wi->w_blocked || wi->w_savelayer->l_cvlist == 0)) 4487 l = wi->w_savelayer; 4488 } 4489 else 4490 l = &cv->c_blank; 4491 4492 /* add our canvas to the layer's canvaslist */ 4493 cv->c_lnext = l->l_cvlist; 4494 l->l_cvlist = cv; 4495 cv->c_layer = l; 4496 cv->c_xoff = cv->c_xs; 4497 cv->c_yoff = cv->c_ys; 4498 RethinkViewportOffsets(cv); 4499 4500 if (flayer == 0) 4501 flayer = l; 4502 4503 if (wi && D_other == wi) 4504 D_other = wi->w_next; /* Might be 0, but that's OK. */ 4505 if (cv == D_forecv) 4506 { 4507 D_fore = wi; 4508 fore = D_fore; /* XXX ? */ 4509 if (wi) 4510 { 4511#ifdef MULTIUSER 4512 ObtainAutoWritelock(display, wi); 4513#endif 4514 /* 4515 * Place the window at the head of the most-recently-used list 4516 */ 4517 if (windows != wi) 4518 { 4519 for (pp = &windows; (p = *pp); pp = &p->w_next) 4520 if (p == wi) 4521 break; 4522 ASSERT(p); 4523 *pp = p->w_next; 4524 p->w_next = windows; 4525 windows = p; 4526 WListLinkChanged(); 4527 } 4528 } 4529 } 4530} 4531 4532 4533/* 4534 * SetForeWindow changes the window in the input focus of the display. 4535 * Puts window wi in canvas display->d_forecv. 4536 */ 4537void 4538SetForeWindow(wi) 4539struct win *wi; 4540{ 4541 struct win *p; 4542 if (display == 0) 4543 { 4544 fore = wi; 4545 return; 4546 } 4547 p = Layer2Window(D_forecv->c_layer); 4548 SetCanvasWindow(D_forecv, wi); 4549 if (p) 4550 WindowChanged(p, 'u'); 4551 if (wi) 4552 WindowChanged(wi, 'u'); 4553 flayer = D_forecv->c_layer; 4554 /* Activate called afterwards, so no RefreshHStatus needed */ 4555} 4556 4557 4558/*****************************************************************/ 4559 4560/* 4561 * Activate - make fore window active 4562 * norefresh = -1 forces a refresh, disregard all_norefresh then. 4563 */ 4564void 4565Activate(norefresh) 4566int norefresh; 4567{ 4568 debug1("Activate(%d)\n", norefresh); 4569 if (display == 0) 4570 return; 4571 if (D_status) 4572 { 4573 Msg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */ 4574 RemoveStatus(); 4575 } 4576 4577 if (MayResizeLayer(D_forecv->c_layer)) 4578 ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, display); 4579 4580 fore = D_fore; 4581 if (fore) 4582 { 4583 /* XXX ? */ 4584 if (fore->w_monitor != MON_OFF) 4585 fore->w_monitor = MON_ON; 4586 fore->w_bell = BELL_ON; 4587 WindowChanged(fore, 'f'); 4588 4589#if 0 4590 if (ResizeDisplay(fore->w_width, fore->w_height)) 4591 { 4592 debug2("Cannot resize from (%d,%d)", D_width, D_height); 4593 debug2(" to (%d,%d) -> resize window\n", fore->w_width, fore->w_height); 4594 DoResize(D_width, D_height); 4595 } 4596#endif 4597 } 4598 Redisplay(norefresh + all_norefresh); 4599} 4600 4601 4602static int 4603NextWindow() 4604{ 4605 register struct win **pp; 4606 int n = fore ? fore->w_number : -1; 4607 4608 for (pp = wtab + n + 1; pp != wtab + n; pp++) 4609 { 4610 if (pp == wtab + MAXWIN) 4611 pp = wtab; 4612 if (*pp) 4613 break; 4614 } 4615 return pp - wtab; 4616} 4617 4618static int 4619PreviousWindow() 4620{ 4621 register struct win **pp; 4622 int n = fore ? fore->w_number : MAXWIN - 1; 4623 4624 for (pp = wtab + n - 1; pp != wtab + n; pp--) 4625 { 4626 if (pp < wtab) 4627 pp = wtab + MAXWIN - 1; 4628 if (*pp) 4629 break; 4630 } 4631 return pp - wtab; 4632} 4633 4634static int 4635MoreWindows() 4636{ 4637 char *m = "No other window."; 4638 if (windows && (fore == 0 || windows->w_next)) 4639 return 1; 4640 if (fore == 0) 4641 { 4642 Msg(0, "No window available"); 4643 return 0; 4644 } 4645 Msg(0, m, fore->w_number); /* other arg for nethack */ 4646 return 0; 4647} 4648 4649void 4650KillWindow(wi) 4651struct win *wi; 4652{ 4653 struct win **pp, *p; 4654 struct canvas *cv; 4655 int gotone; 4656 4657 /* 4658 * Remove window from linked list. 4659 */ 4660 for (pp = &windows; (p = *pp); pp = &p->w_next) 4661 if (p == wi) 4662 break; 4663 ASSERT(p); 4664 *pp = p->w_next; 4665 wi->w_inlen = 0; 4666 wtab[wi->w_number] = 0; 4667 4668 if (windows == 0) 4669 { 4670 FreeWindow(wi); 4671 Finit(0); 4672 } 4673 4674 /* 4675 * switch to different window on all canvases 4676 */ 4677 for (display = displays; display; display = display->d_next) 4678 { 4679 gotone = 0; 4680 for (cv = D_cvlist; cv; cv = cv->c_next) 4681 { 4682 if (Layer2Window(cv->c_layer) != wi) 4683 continue; 4684 /* switch to other window */ 4685 SetCanvasWindow(cv, FindNiceWindow(D_other, 0)); 4686 gotone = 1; 4687 } 4688 if (gotone) 4689 { 4690#ifdef ZMODEM 4691 if (wi->w_zdisplay == display) 4692 { 4693 D_blocked = 0; 4694 D_readev.condpos = D_readev.condneg = 0; 4695 } 4696#endif 4697 Activate(-1); 4698 } 4699 } 4700 FreeWindow(wi); 4701 WindowChanged((struct win *)0, 'w'); 4702 WindowChanged((struct win *)0, 'W'); 4703 WindowChanged((struct win *)0, 0); 4704} 4705 4706static void 4707LogToggle(on) 4708int on; 4709{ 4710 char buf[1024]; 4711 4712 if ((fore->w_log != 0) == on) 4713 { 4714 if (display && !*rc_name) 4715 Msg(0, "You are %s logging.", on ? "already" : "not"); 4716 return; 4717 } 4718 if (fore->w_log != 0) 4719 { 4720 Msg(0, "Logfile \"%s\" closed.", fore->w_log->name); 4721 logfclose(fore->w_log); 4722 fore->w_log = 0; 4723 WindowChanged(fore, 'f'); 4724 return; 4725 } 4726 if (DoStartLog(fore, buf, sizeof(buf))) 4727 { 4728 Msg(errno, "Error opening logfile \"%s\"", buf); 4729 return; 4730 } 4731 if (ftell(fore->w_log->fp) == 0) 4732 Msg(0, "Creating logfile \"%s\".", fore->w_log->name); 4733 else 4734 Msg(0, "Appending to logfile \"%s\".", fore->w_log->name); 4735 WindowChanged(fore, 'f'); 4736} 4737 4738char * 4739AddWindows(buf, len, flags, where) 4740char *buf; 4741int len; 4742int flags; 4743int where; 4744{ 4745 register char *s, *ss; 4746 register struct win **pp, *p; 4747 register char *cmd; 4748 int l; 4749 4750 s = ss = buf; 4751 for (pp = ((flags & 4) && where >= 0) ? wtab + where + 1: wtab; pp < wtab + MAXWIN; pp++) 4752 { 4753 if (pp - wtab == where && ss == buf) 4754 ss = s; 4755 if ((p = *pp) == 0) 4756 continue; 4757 if ((flags & 1) && display && p == D_fore) 4758 continue; 4759 4760 cmd = p->w_title; 4761 l = strlen(cmd); 4762 if (l > 20) 4763 l = 20; 4764 if (s - buf + l > len - 24) 4765 break; 4766 if (s > buf || (flags & 4)) 4767 { 4768 *s++ = ' '; 4769 *s++ = ' '; 4770 } 4771 sprintf(s, "%d", p->w_number); 4772 if (p->w_number == where) 4773 ss = s; 4774 s += strlen(s); 4775 if (display && p == D_fore) 4776 *s++ = '*'; 4777 if (!(flags & 2)) 4778 { 4779 if (display && p == D_other) 4780 *s++ = '-'; 4781 s = AddWindowFlags(s, len, p); 4782 } 4783 *s++ = ' '; 4784 strncpy(s, cmd, l); 4785 s += l; 4786 } 4787 *s = 0; 4788 return ss; 4789} 4790 4791char * 4792AddWindowFlags(buf, len, p) 4793char *buf; 4794int len; 4795struct win *p; 4796{ 4797 char *s = buf; 4798 if (p == 0 || len < 12) 4799 { 4800 *s = 0; 4801 return s; 4802 } 4803#if 0 4804 if (display && p == D_fore) 4805 *s++ = '*'; 4806 if (display && p == D_other) 4807 *s++ = '-'; 4808#endif 4809 if (p->w_layer.l_cvlist && p->w_layer.l_cvlist->c_lnext) 4810 *s++ = '&'; 4811 if (p->w_monitor == MON_DONE) 4812 *s++ = '@'; 4813 if (p->w_bell == BELL_DONE) 4814 *s++ = '!'; 4815#ifdef UTMPOK 4816 if (p->w_slot != (slot_t) 0 && p->w_slot != (slot_t) -1) 4817 *s++ = '$'; 4818#endif 4819 if (p->w_log != 0) 4820 { 4821 strcpy(s, "(L)"); 4822 s += 3; 4823 } 4824 if (p->w_ptyfd < 0) 4825 *s++ = 'Z'; 4826 *s = 0; 4827 return s; 4828} 4829 4830char * 4831AddOtherUsers(buf, len, p) 4832char *buf; 4833int len; 4834struct win *p; 4835{ 4836 struct display *d, *olddisplay = display; 4837 struct canvas *cv; 4838 char *s; 4839 int l; 4840 4841 s = buf; 4842 for (display = displays; display; display = display->d_next) 4843 { 4844 if (D_user == olddisplay->d_user) 4845 continue; 4846 for (cv = D_cvlist; cv; cv = cv->c_next) 4847 if (Layer2Window(cv->c_layer) == p) 4848 break; 4849 if (!cv) 4850 continue; 4851 for (d = displays; d && d != display; d = d->d_next) 4852 if (D_user == d->d_user) 4853 break; 4854 if (d && d != display) 4855 continue; 4856 if (len > 1 && s != buf) 4857 { 4858 *s++ = ','; 4859 len--; 4860 } 4861 l = strlen(D_user->u_name); 4862 if (l + 1 > len) 4863 break; 4864 strcpy(s, D_user->u_name); 4865 s += l; 4866 len -= l; 4867 } 4868 *s = 0; 4869 display = olddisplay; 4870 return s; 4871} 4872 4873void 4874ShowWindows(where) 4875int where; 4876{ 4877 char buf[1024]; 4878 char *s, *ss; 4879 4880 if (!display) 4881 return; 4882 if (where == -1 && D_fore) 4883 where = D_fore->w_number; 4884 ss = AddWindows(buf, sizeof(buf), 0, where); 4885 s = buf + strlen(buf); 4886 if (ss - buf > D_width / 2) 4887 { 4888 ss -= D_width / 2; 4889 if (s - ss < D_width) 4890 { 4891 ss = s - D_width; 4892 if (ss < buf) 4893 ss = buf; 4894 } 4895 } 4896 else 4897 ss = buf; 4898 Msg(0, "%s", ss); 4899} 4900 4901static void 4902ShowInfo() 4903{ 4904 char buf[512], *p; 4905 register struct win *wp = fore; 4906 register int i; 4907 4908 if (wp == 0) 4909 { 4910 Msg(0, "(%d,%d)/(%d,%d) no window", D_x + 1, D_y + 1, D_width, D_height); 4911 return; 4912 } 4913 p = buf; 4914 if (buf < (p += GetAnsiStatus(wp, p))) 4915 *p++ = ' '; 4916 sprintf(p, "(%d,%d)/(%d,%d)", 4917 wp->w_x + 1, wp->w_y + 1, wp->w_width, wp->w_height); 4918#ifdef COPY_PASTE 4919 sprintf(p += strlen(p), "+%d", wp->w_histheight); 4920#endif 4921 sprintf(p += strlen(p), " %c%sflow", 4922 (wp->w_flow & FLOW_NOW) ? '+' : '-', 4923 (wp->w_flow & FLOW_AUTOFLAG) ? "" : 4924 ((wp->w_flow & FLOW_AUTO) ? "(+)" : "(-)")); 4925 if (!wp->w_wrap) sprintf(p += strlen(p), " -wrap"); 4926 if (wp->w_insert) sprintf(p += strlen(p), " ins"); 4927 if (wp->w_origin) sprintf(p += strlen(p), " org"); 4928 if (wp->w_keypad) sprintf(p += strlen(p), " app"); 4929 if (wp->w_log) sprintf(p += strlen(p), " log"); 4930 if (wp->w_monitor != MON_OFF) sprintf(p += strlen(p), " mon"); 4931 if (wp->w_mouse) sprintf(p += strlen(p), " mouse"); 4932#ifdef COLOR 4933 if (wp->w_bce) sprintf(p += strlen(p), " bce"); 4934#endif 4935 if (!wp->w_c1) sprintf(p += strlen(p), " -c1"); 4936 if (wp->w_norefresh) sprintf(p += strlen(p), " nored"); 4937 4938 p += strlen(p); 4939#ifdef FONT 4940# ifdef ENCODINGS 4941 if (wp->w_encoding && (display == 0 || D_encoding != wp->w_encoding || EncodingDefFont(wp->w_encoding) <= 0)) 4942 { 4943 *p++ = ' '; 4944 strcpy(p, EncodingName(wp->w_encoding)); 4945 p += strlen(p); 4946 } 4947# ifdef UTF8 4948 if (wp->w_encoding != UTF8) 4949# endif 4950# endif 4951 if (D_CC0 || (D_CS0 && *D_CS0)) 4952 { 4953 if (wp->w_gr == 2) 4954 { 4955 sprintf(p, " G%c", wp->w_Charset + '0'); 4956 if (wp->w_FontE >= ' ') 4957 p[3] = wp->w_FontE; 4958 else 4959 { 4960 p[3] = '^'; 4961 p[4] = wp->w_FontE ^ 0x40; 4962 p++; 4963 } 4964 p[4] = '['; 4965 p++; 4966 } 4967 else if (wp->w_gr) 4968 sprintf(p++, " G%c%c[", wp->w_Charset + '0', wp->w_CharsetR + '0'); 4969 else 4970 sprintf(p, " G%c[", wp->w_Charset + '0'); 4971 p += 4; 4972 for (i = 0; i < 4; i++) 4973 { 4974 if (wp->w_charsets[i] == ASCII) 4975 *p++ = 'B'; 4976 else if (wp->w_charsets[i] >= ' ') 4977 *p++ = wp->w_charsets[i]; 4978 else 4979 { 4980 *p++ = '^'; 4981 *p++ = wp->w_charsets[i] ^ 0x40; 4982 } 4983 } 4984 *p++ = ']'; 4985 *p = 0; 4986 } 4987#endif 4988 4989 if (wp->w_type == W_TYPE_PLAIN) 4990 { 4991 /* add info about modem control lines */ 4992 *p++ = ' '; 4993 TtyGetModemStatus(wp->w_ptyfd, p); 4994 } 4995#ifdef BUILTIN_TELNET 4996 else if (wp->w_type == W_TYPE_TELNET) 4997 { 4998 *p++ = ' '; 4999 TelStatus(wp, p, sizeof(buf) - 1 - (p - buf)); 5000 } 5001#endif 5002 Msg(0, "%s %d(%s)", buf, wp->w_number, wp->w_title); 5003} 5004 5005static void 5006ShowDInfo() 5007{ 5008 char buf[512], *p; 5009 if (display == 0) 5010 return; 5011 p = buf; 5012 sprintf(p, "(%d,%d)", D_width, D_height), 5013 p += strlen(p); 5014#ifdef ENCODINGS 5015 if (D_encoding) 5016 { 5017 *p++ = ' '; 5018 strcpy(p, EncodingName(D_encoding)); 5019 p += strlen(p); 5020 } 5021#endif 5022 if (D_CXT) 5023 { 5024 strcpy(p, " xterm"); 5025 p += strlen(p); 5026 } 5027#ifdef COLOR 5028 if (D_hascolor) 5029 { 5030 strcpy(p, " color"); 5031 p += strlen(p); 5032 } 5033#endif 5034#ifdef FONT 5035 if (D_CG0) 5036 { 5037 strcpy(p, " iso2022"); 5038 p += strlen(p); 5039 } 5040 else if (D_CS0 && *D_CS0) 5041 { 5042 strcpy(p, " altchar"); 5043 p += strlen(p); 5044 } 5045#endif 5046 Msg(0, "%s", buf); 5047} 5048 5049static void 5050AKAfin(buf, len, data) 5051char *buf; 5052int len; 5053char *data; /* dummy */ 5054{ 5055 ASSERT(display); 5056 if (len && fore) 5057 ChangeAKA(fore, buf, strlen(buf)); 5058} 5059 5060static void 5061InputAKA() 5062{ 5063 char *s, *ss; 5064 int n; 5065 Input("Set window's title to: ", sizeof(fore->w_akabuf) - 1, INP_COOKED, AKAfin, NULL); 5066 s = fore->w_title; 5067 if (!s) 5068 return; 5069 for (; *s; s++) 5070 { 5071 if ((*(unsigned char *)s & 0x7f) < 0x20 || *s == 0x7f) 5072 continue; 5073 ss = s; 5074 n = 1; 5075 LayProcess(&ss, &n); 5076 } 5077} 5078 5079static void 5080Colonfin(buf, len, data) 5081char *buf; 5082int len; 5083char *data; /* dummy */ 5084{ 5085 char mbuf[256]; 5086 if (len) 5087 { 5088 len = strlen(buf) + 1; 5089 if (len > (int)sizeof(mbuf)) 5090 RcLine(buf, len); 5091 else 5092 { 5093 bcopy(buf, mbuf, len); 5094 RcLine(mbuf, sizeof mbuf); 5095 } 5096 } 5097} 5098 5099static void 5100SelectFin(buf, len, data) 5101char *buf; 5102int len; 5103char *data; /* dummy */ 5104{ 5105 int n; 5106 5107 if (!len || !display) 5108 return; 5109 if (len == 1 && *buf == '-') 5110 { 5111 SetForeWindow((struct win *)0); 5112 Activate(0); 5113 return; 5114 } 5115 if ((n = WindowByNoN(buf)) < 0) 5116 return; 5117 SwitchWindow(n); 5118} 5119 5120static void 5121InputSelect() 5122{ 5123 Input("Switch to window: ", 20, INP_COOKED, SelectFin, NULL); 5124} 5125 5126static char setenv_var[31]; 5127 5128 5129static void 5130SetenvFin1(buf, len, data) 5131char *buf; 5132int len; 5133char *data; /* dummy */ 5134{ 5135 if (!len || !display) 5136 return; 5137 InputSetenv(buf); 5138} 5139 5140static void 5141SetenvFin2(buf, len, data) 5142char *buf; 5143int len; 5144char *data; /* dummy */ 5145{ 5146 if (!len || !display) 5147 return; 5148 debug2("SetenvFin2: setenv '%s' '%s'\n", setenv_var, buf); 5149 xsetenv(setenv_var, buf); 5150 MakeNewEnv(); 5151} 5152 5153static void 5154InputSetenv(arg) 5155char *arg; 5156{ 5157 static char setenv_buf[50 + sizeof(setenv_var)]; /* need to be static here, cannot be freed */ 5158 5159 if (arg) 5160 { 5161 strncpy(setenv_var, arg, sizeof(setenv_var) - 1); 5162 sprintf(setenv_buf, "Enter value for %s: ", setenv_var); 5163 Input(setenv_buf, 30, INP_COOKED, SetenvFin2, NULL); 5164 } 5165 else 5166 Input("Setenv: Enter variable name: ", 30, INP_COOKED, SetenvFin1, NULL); 5167} 5168 5169/* 5170 * the following options are understood by this parser: 5171 * -f, -f0, -f1, -fy, -fa 5172 * -t title, -T terminal-type, -h height-of-scrollback, 5173 * -ln, -l0, -ly, -l1, -l 5174 * -a, -M, -L 5175 */ 5176void 5177DoScreen(fn, av) 5178char *fn, **av; 5179{ 5180 struct NewWindow nwin; 5181 register int num; 5182 char buf[20]; 5183 5184 nwin = nwin_undef; 5185 while (av && *av && av[0][0] == '-') 5186 { 5187 if (av[0][1] == '-') 5188 { 5189 av++; 5190 break; 5191 } 5192 switch (av[0][1]) 5193 { 5194 case 'f': 5195 switch (av[0][2]) 5196 { 5197 case 'n': 5198 case '0': 5199 nwin.flowflag = FLOW_NOW * 0; 5200 break; 5201 case 'y': 5202 case '1': 5203 case '\0': 5204 nwin.flowflag = FLOW_NOW * 1; 5205 break; 5206 case 'a': 5207 nwin.flowflag = FLOW_AUTOFLAG; 5208 break; 5209 default: 5210 break; 5211 } 5212 break; 5213 case 't': /* no more -k */ 5214 if (av[0][2]) 5215 nwin.aka = &av[0][2]; 5216 else if (*++av) 5217 nwin.aka = *av; 5218 else 5219 --av; 5220 break; 5221 case 'T': 5222 if (av[0][2]) 5223 nwin.term = &av[0][2]; 5224 else if (*++av) 5225 nwin.term = *av; 5226 else 5227 --av; 5228 break; 5229 case 'h': 5230 if (av[0][2]) 5231 nwin.histheight = atoi(av[0] + 2); 5232 else if (*++av) 5233 nwin.histheight = atoi(*av); 5234 else 5235 --av; 5236 break; 5237#ifdef LOGOUTOK 5238 case 'l': 5239 switch (av[0][2]) 5240 { 5241 case 'n': 5242 case '0': 5243 nwin.lflag = 0; 5244 break; 5245 case 'y': 5246 case '1': 5247 case '\0': 5248 nwin.lflag = 1; 5249 break; 5250 case 'a': 5251 nwin.lflag = 3; 5252 break; 5253 default: 5254 break; 5255 } 5256 break; 5257#endif 5258 case 'a': 5259 nwin.aflag = 1; 5260 break; 5261 case 'M': 5262 nwin.monitor = MON_ON; 5263 break; 5264 case 'L': 5265 nwin.Lflag = 1; 5266 break; 5267 default: 5268 Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]); 5269 break; 5270 } 5271 ++av; 5272 } 5273 num = 0; 5274 if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf))) 5275 { 5276 if (*buf != '\0') 5277 nwin.aka = buf; 5278 num = atoi(*av); 5279 if (num < 0 || num > MAXWIN - 1) 5280 { 5281 Msg(0, "%s: illegal screen number %d.", fn, num); 5282 num = 0; 5283 } 5284 nwin.StartAt = num; 5285 ++av; 5286 } 5287 if (av && *av) 5288 { 5289 nwin.args = av; 5290 if (!nwin.aka) 5291 nwin.aka = Filename(*av); 5292 } 5293 MakeWindow(&nwin); 5294} 5295 5296#ifdef COPY_PASTE 5297/* 5298 * CompileKeys must be called before Markroutine is first used. 5299 * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab); 5300 * 5301 * s is an ascii string in a termcap-like syntax. It looks like 5302 * "j=u:k=d:l=r:h=l: =.:" and so on... 5303 * this example rebinds the cursormovement to the keys u (up), d (down), 5304 * l (left), r (right). placing a mark will now be done with ".". 5305 */ 5306int 5307CompileKeys(s, sl, array) 5308char *s; 5309int sl; 5310unsigned char *array; 5311{ 5312 int i; 5313 unsigned char key, value; 5314 5315 if (sl == 0) 5316 { 5317 for (i = 0; i < 256; i++) 5318 array[i] = i; 5319 return 0; 5320 } 5321 debug1("CompileKeys: '%s'\n", s); 5322 while (sl) 5323 { 5324 key = *(unsigned char *)s++; 5325 if (*s != '=' || sl < 3) 5326 return -1; 5327 sl--; 5328 do 5329 { 5330 s++; 5331 sl -= 2; 5332 value = *(unsigned char *)s++; 5333 array[value] = key; 5334 } 5335 while (*s == '=' && sl >= 2); 5336 if (sl == 0) 5337 break; 5338 if (*s++ != ':') 5339 return -1; 5340 sl--; 5341 } 5342 return 0; 5343} 5344#endif /* COPY_PASTE */ 5345 5346/* 5347 * Asynchronous input functions 5348 */ 5349 5350#if defined(DETACH) && defined(POW_DETACH) 5351static void 5352pow_detach_fn(buf, len, data) 5353char *buf; 5354int len; 5355char *data; /* dummy */ 5356{ 5357 debug("pow_detach_fn called\n"); 5358 if (len) 5359 { 5360 *buf = 0; 5361 return; 5362 } 5363 if (ktab[(int)(unsigned char)*buf].nr != RC_POW_DETACH) 5364 { 5365 if (display) 5366 write(D_userfd, "\007", 1); 5367 Msg(0, "Detach aborted."); 5368 } 5369 else 5370 Detach(D_POWER); 5371} 5372#endif /* POW_DETACH */ 5373 5374#ifdef COPY_PASTE 5375static void 5376copy_reg_fn(buf, len, data) 5377char *buf; 5378int len; 5379char *data; /* dummy */ 5380{ 5381 struct plop *pp = plop_tab + (int)(unsigned char)*buf; 5382 5383 if (len) 5384 { 5385 *buf = 0; 5386 return; 5387 } 5388 if (pp->buf) 5389 free(pp->buf); 5390 pp->buf = 0; 5391 pp->len = 0; 5392 if (D_user->u_plop.len) 5393 { 5394 if ((pp->buf = (char *)malloc(D_user->u_plop.len)) == NULL) 5395 { 5396 Msg(0, strnomem); 5397 return; 5398 } 5399 bcopy(D_user->u_plop.buf, pp->buf, D_user->u_plop.len); 5400 } 5401 pp->len = D_user->u_plop.len; 5402#ifdef ENCODINGS 5403 pp->enc = D_user->u_plop.enc; 5404#endif 5405 Msg(0, "Copied %d characters into register %c", D_user->u_plop.len, *buf); 5406} 5407 5408static void 5409ins_reg_fn(buf, len, data) 5410char *buf; 5411int len; 5412char *data; /* dummy */ 5413{ 5414 struct plop *pp = plop_tab + (int)(unsigned char)*buf; 5415 5416 5417 if (!fore) 5418 return; /* Input() should not call us w/o fore, but you never know... */ 5419 if (*buf == '.') 5420 Msg(0, "ins_reg_fn: Warning: pasting real register '.'!"); 5421 if (len) 5422 { 5423 *buf = 0; 5424 return; 5425 } 5426 if (pp->buf) 5427 { 5428 MakePaster(&fore->w_paster, pp->buf, pp->len, 0); 5429 return; 5430 } 5431 Msg(0, "Empty register."); 5432} 5433#endif /* COPY_PASTE */ 5434 5435static void 5436process_fn(buf, len, data) 5437char *buf; 5438int len; 5439char *data; /* dummy */ 5440{ 5441 struct plop *pp = plop_tab + (int)(unsigned char)*buf; 5442 5443 if (len) 5444 { 5445 *buf = 0; 5446 return; 5447 } 5448 if (pp->buf) 5449 { 5450 ProcessInput(pp->buf, pp->len); 5451 return; 5452 } 5453 Msg(0, "Empty register."); 5454} 5455 5456static void 5457confirm_fn(buf, len, data) 5458char *buf; 5459int len; 5460char *data; /* dummy */ 5461{ 5462 struct action act; 5463 5464 if (len || (*buf != 'y' && *buf != 'Y')) 5465 { 5466 *buf = 0; 5467 return; 5468 } 5469#ifdef __APPLE__ 5470 act.nr = (int)(intptr_t)data; 5471#else 5472 act.nr = (int)data; 5473#endif 5474 act.args = noargs; 5475 act.argl = 0; 5476 DoAction(&act, -1); 5477} 5478 5479#ifdef MULTIUSER 5480struct inputsu 5481{ 5482 struct acluser **up; 5483 char name[24]; 5484 char pw1[130]; /* FreeBSD crypts to 128 bytes */ 5485 char pw2[130]; 5486}; 5487 5488static void 5489su_fin(buf, len, data) 5490char *buf; 5491int len; 5492char *data; 5493{ 5494 struct inputsu *i = (struct inputsu *)data; 5495 char *p; 5496 int l; 5497 5498 if (!*i->name) 5499 { p = i->name; l = sizeof(i->name) - 1; } 5500 else if (!*i->pw1) 5501 { strcpy(p = i->pw1, "\377"); l = sizeof(i->pw1) - 1; } 5502 else 5503 { strcpy(p = i->pw2, "\377"); l = sizeof(i->pw2) - 1; } 5504 if (buf && len) 5505 strncpy(p, buf, 1 + (l < len) ? l : len); 5506 if (!*i->name) 5507 Input("Screen User: ", sizeof(i->name) - 1, INP_COOKED, su_fin, (char *)i); 5508 else if (!*i->pw1) 5509 Input("User's UNIX Password: ", sizeof(i->pw1)-1, INP_COOKED|INP_NOECHO, su_fin, (char *)i); 5510 else if (!*i->pw2) 5511 Input("User's Screen Password: ", sizeof(i->pw2)-1, INP_COOKED|INP_NOECHO, su_fin, (char *)i); 5512 else 5513 { 5514 if ((p = DoSu(i->up, i->name, i->pw2, i->pw1))) 5515 Msg(0, "%s", p); 5516 free((char *)i); 5517 } 5518} 5519 5520static int 5521InputSu(w, up, name) 5522struct win *w; 5523struct acluser **up; 5524char *name; 5525{ 5526 struct inputsu *i; 5527 5528 if (!(i = (struct inputsu *)calloc(1, sizeof(struct inputsu)))) 5529 return -1; 5530 5531 i->up = up; 5532 if (name && *name) 5533 su_fin(name, (int)strlen(name), (char *)i); /* can also initialise stuff */ 5534 else 5535 su_fin((char *)0, 0, (char *)i); 5536 return 0; 5537} 5538#endif /* MULTIUSER */ 5539 5540#ifdef PASSWORD 5541 5542static void 5543pass1(buf, len, data) 5544char *buf; 5545int len; 5546char *data; 5547{ 5548 struct acluser *u = (struct acluser *)data; 5549 5550 if (!*buf) 5551 return; 5552 ASSERT(u); 5553 if (u->u_password != NullStr) 5554 free((char *)u->u_password); 5555 u->u_password = SaveStr(buf); 5556 bzero(buf, strlen(buf)); 5557 Input("Retype new password:", 100, INP_NOECHO, pass2, data); 5558} 5559 5560static void 5561pass2(buf, len, data) 5562char *buf; 5563int len; 5564char *data; 5565{ 5566 int st; 5567 char salt[3]; 5568 struct acluser *u = (struct acluser *)data; 5569 5570 ASSERT(u); 5571 if (!buf || strcmp(u->u_password, buf)) 5572 { 5573 Msg(0, "[ Passwords don't match - checking turned off ]"); 5574 if (u->u_password != NullStr) 5575 { 5576 bzero(u->u_password, strlen(u->u_password)); 5577 free((char *)u->u_password); 5578 } 5579 u->u_password = NullStr; 5580 } 5581 else if (u->u_password[0] == '\0') 5582 { 5583 Msg(0, "[ No password - no secure ]"); 5584 if (buf) 5585 bzero(buf, strlen(buf)); 5586 } 5587 5588 if (u->u_password != NullStr) 5589 { 5590 for (st = 0; st < 2; st++) 5591 salt[st] = 'A' + (int)((time(0) >> 6 * st) % 26); 5592 salt[2] = 0; 5593 buf = crypt(u->u_password, salt); 5594 bzero(u->u_password, strlen(u->u_password)); 5595 free((char *)u->u_password); 5596 u->u_password = SaveStr(buf); 5597 bzero(buf, strlen(buf)); 5598#ifdef COPY_PASTE 5599 if (u->u_plop.buf) 5600 UserFreeCopyBuffer(u); 5601 u->u_plop.len = strlen(u->u_password); 5602# ifdef ENCODINGS 5603 u->u_plop.enc = 0; 5604#endif 5605 if (!(u->u_plop.buf = SaveStr(u->u_password))) 5606 { 5607 Msg(0, strnomem); 5608 D_user->u_plop.len = 0; 5609 } 5610 else 5611 Msg(0, "[ Password moved into copybuffer ]"); 5612#else /* COPY_PASTE */ 5613 Msg(0, "[ Crypted password is \"%s\" ]", u->u_password); 5614#endif /* COPY_PASTE */ 5615 } 5616} 5617#endif /* PASSWORD */ 5618 5619static void 5620digraph_fn(buf, len, data) 5621char *buf; 5622int len; 5623char *data; /* dummy */ 5624{ 5625 int ch, i, x; 5626 5627 ch = buf[len]; 5628 if (ch) 5629 { 5630 if (ch < ' ' || ch == '\177') 5631 return; 5632 if (len >= 1 && ((*buf == 'U' && buf[1] == '+') || (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X')))) 5633 { 5634 if (len == 1) 5635 return; 5636 if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f') && (ch < 'A' || ch > 'F')) 5637 { 5638 buf[len] = '\034'; /* ^] is ignored by Input() */ 5639 return; 5640 } 5641 if (len == (*buf == 'U' ? 5 : 3)) 5642 buf[len] = '\n'; 5643 return; 5644 } 5645 if (len && *buf == '0') 5646 { 5647 if (ch < '0' || ch > '7') 5648 { 5649 buf[len] = '\034'; /* ^] is ignored by Input() */ 5650 return; 5651 } 5652 if (len == 3) 5653 buf[len] = '\n'; 5654 return; 5655 } 5656 if (len == 1) 5657 buf[len] = '\n'; 5658 return; 5659 } 5660 buf[len] = buf[len + 1]; /* gross */ 5661 len++; 5662 if (len < 2) 5663 return; 5664 if (len >= 1 && ((*buf == 'U' && buf[1] == '+') || (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X')))) 5665 { 5666 x = 0; 5667 for (i = 2; i < len; i++) 5668 { 5669 if (buf[i] >= '0' && buf[i] <= '9') 5670 x = x * 16 | (buf[i] - '0'); 5671 else if (buf[i] >= 'a' && buf[i] <= 'f') 5672 x = x * 16 | (buf[i] - ('a' - 10)); 5673 else if (buf[i] >= 'A' && buf[i] <= 'F') 5674 x = x * 16 | (buf[i] - ('A' - 10)); 5675 else 5676 break; 5677 } 5678 } 5679 else if (buf[0] == '0') 5680 { 5681 x = 0; 5682 for (i = 1; i < len; i++) 5683 { 5684 if (buf[i] < '0' || buf[i] > '7') 5685 break; 5686 x = x * 8 | (buf[i] - '0'); 5687 } 5688 } 5689 else 5690 { 5691 for (i = 0; i < (int)(sizeof(digraphs)/sizeof(*digraphs)); i++) 5692 if ((digraphs[i][0] == (unsigned char)buf[0] && digraphs[i][1] == (unsigned char)buf[1]) || 5693 (digraphs[i][0] == (unsigned char)buf[1] && digraphs[i][1] == (unsigned char)buf[0])) 5694 break; 5695 if (i == (int)(sizeof(digraphs)/sizeof(*digraphs))) 5696 { 5697 Msg(0, "Unknown digraph"); 5698 return; 5699 } 5700 x = digraphs[i][2]; 5701 } 5702 i = 1; 5703 *buf = x; 5704#ifdef UTF8 5705 if (flayer->l_encoding == UTF8) 5706 i = ToUtf8(buf, x); /* buf is big enough for all UTF-8 codes */ 5707#endif 5708 while(i) 5709 LayProcess(&buf, &i); 5710} 5711 5712#ifdef MAPKEYS 5713int 5714StuffKey(i) 5715int i; 5716{ 5717 struct action *act; 5718 5719 debug1("StuffKey #%d", i); 5720#ifdef DEBUG 5721 if (i < KMAP_KEYS) 5722 debug1(" - %s", term[i + T_CAPS].tcname); 5723#endif 5724 if (i >= T_CURSOR - T_CAPS && i < T_KEYPAD - T_CAPS && D_cursorkeys) 5725 i += T_OCAPS - T_CURSOR; 5726 else if (i >= T_KEYPAD - T_CAPS && i < T_OCAPS - T_CAPS && D_keypad) 5727 i += T_OCAPS - T_CURSOR; 5728 debug1(" - action %d\n", i); 5729 flayer = D_forecv->c_layer; 5730 fore = D_fore; 5731 act = 0; 5732#ifdef COPY_PASTE 5733 if (InMark() || InInput() || InWList()) 5734 act = i < KMAP_KEYS+KMAP_AKEYS ? &mmtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].mm; 5735#endif 5736 if ((!act || act->nr == RC_ILLEGAL) && !D_mapdefault) 5737 act = i < KMAP_KEYS+KMAP_AKEYS ? &umtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].um; 5738 D_mapdefault = 0; 5739 if (!act || act->nr == RC_ILLEGAL) 5740 act = i < KMAP_KEYS+KMAP_AKEYS ? &dmtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].dm; 5741 if (act == 0 || act->nr == RC_ILLEGAL) 5742 return -1; 5743 DoAction(act, 0); 5744 return 0; 5745} 5746#endif 5747 5748 5749static int 5750IsOnDisplay(wi) 5751struct win *wi; 5752{ 5753 struct canvas *cv; 5754 ASSERT(display); 5755 for (cv = D_cvlist; cv; cv = cv->c_next) 5756 if (Layer2Window(cv->c_layer) == wi) 5757 return 1; 5758 return 0; 5759} 5760 5761struct win * 5762FindNiceWindow(wi, presel) 5763struct win *wi; 5764char *presel; 5765{ 5766 int i; 5767 5768 debug2("FindNiceWindow %d %s\n", wi ? wi->w_number : -1 , presel ? presel : "NULL"); 5769 if (presel) 5770 { 5771 i = WindowByNoN(presel); 5772 if (i >= 0) 5773 wi = wtab[i]; 5774 } 5775 if (!display) 5776 return wi; 5777#ifdef MULTIUSER 5778 if (wi && AclCheckPermWin(D_user, ACL_READ, wi)) 5779 wi = 0; 5780#endif 5781 if (!wi || (IsOnDisplay(wi) && !presel)) 5782 { 5783 /* try to get another window */ 5784 wi = 0; 5785#ifdef MULTIUSER 5786 for (wi = windows; wi; wi = wi->w_next) 5787 if (!wi->w_layer.l_cvlist && !AclCheckPermWin(D_user, ACL_WRITE, wi)) 5788 break; 5789 if (!wi) 5790 for (wi = windows; wi; wi = wi->w_next) 5791 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi) && !AclCheckPermWin(D_user, ACL_WRITE, wi)) 5792 break; 5793 if (!wi) 5794 for (wi = windows; wi; wi = wi->w_next) 5795 if (!wi->w_layer.l_cvlist && !AclCheckPermWin(D_user, ACL_READ, wi)) 5796 break; 5797 if (!wi) 5798 for (wi = windows; wi; wi = wi->w_next) 5799 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi) && !AclCheckPermWin(D_user, ACL_READ, wi)) 5800 break; 5801#endif 5802 if (!wi) 5803 for (wi = windows; wi; wi = wi->w_next) 5804 if (!wi->w_layer.l_cvlist) 5805 break; 5806 if (!wi) 5807 for (wi = windows; wi; wi = wi->w_next) 5808 if (wi->w_layer.l_cvlist && !IsOnDisplay(wi)) 5809 break; 5810 } 5811#ifdef MULTIUSER 5812 if (wi && AclCheckPermWin(D_user, ACL_READ, wi)) 5813 wi = 0; 5814#endif 5815 return wi; 5816} 5817 5818#if 0 5819 5820/* sorted list of all commands */ 5821static struct comm **commtab; 5822static int ncommtab; 5823 5824void 5825AddComms(cos, hand) 5826struct comm *cos; 5827void (*hand) __P((struct comm *, char **, int)); 5828{ 5829 int n, i, j, r; 5830 for (n = 0; cos[n].name; n++) 5831 ; 5832 if (n == 0) 5833 return; 5834 if (commtab) 5835 commtab = (struct commt *)realloc(commtab, sizeof(*commtab) * (ncommtab + n)); 5836 else 5837 commtab = (struct commt *)malloc(sizeof(*commtab) * (ncommtab + n)); 5838 if (!commtab) 5839 Panic(0, strnomem); 5840 for (i = 0; i < n; i++) 5841 { 5842 for (j = 0; j < ncommtab; j++) 5843 { 5844 r = strcmp(cos[i].name, commtab[j]->name); 5845 if (r == 0) 5846 Panic(0, "Duplicate command: %s\n", cos[i].name); 5847 if (r < 0) 5848 break; 5849 } 5850 for (r = ncommtab; r > j; r--) 5851 commtab[r] = commtab[r - 1]; 5852 commtab[j] = cos + i; 5853 cos[i].handler = hand; 5854 bzero(cos[i].userbits, sizeof(cos[i].userbits)); 5855 ncommtab++; 5856 } 5857} 5858 5859struct comm * 5860FindComm(str) 5861char *str; 5862{ 5863 int x, m, l = 0, r = ncommtab - 1; 5864 while (l <= r) 5865 { 5866 m = (l + r) / 2; 5867 x = strcmp(str, commtab[m]->name); 5868 if (x > 0) 5869 l = m + 1; 5870 else if (x < 0) 5871 r = m - 1; 5872 else 5873 return commtab[m]; 5874 } 5875 return 0; 5876} 5877 5878#endif 5879 5880static void 5881ResizeRegions(arg) 5882char *arg; 5883{ 5884 struct canvas *cv; 5885 int nreg, dsize, diff, siz; 5886 5887 ASSERT(display); 5888 for (nreg = 0, cv = D_cvlist; cv; cv = cv->c_next) 5889 nreg++; 5890 if (nreg < 2) 5891 { 5892 Msg(0, "resize: need more than one region"); 5893 return; 5894 } 5895 dsize = D_height - (D_has_hstatus == HSTATUS_LASTLINE); 5896 if (*arg == '=') 5897 { 5898 /* make all regions the same height */ 5899 int h = dsize; 5900 int hh, i = 0; 5901 for (cv = D_cvlist; cv; cv = cv->c_next) 5902 { 5903 hh = h / nreg-- - 1; 5904 cv->c_ys = i; 5905 cv->c_ye = i + hh - 1; 5906 cv->c_yoff = i; 5907 i += hh + 1; 5908 h -= hh + 1; 5909 } 5910 RethinkDisplayViewports(); 5911 ResizeLayersToCanvases(); 5912 return; 5913 } 5914 siz = D_forecv->c_ye - D_forecv->c_ys + 1; 5915 if (*arg == '+') 5916 diff = atoi(arg + 1); 5917 else if (*arg == '-') 5918 diff = -atoi(arg + 1); 5919 else if (!strcmp(arg, "min")) 5920 diff = 1 - siz; 5921 else if (!strcmp(arg, "max")) 5922 diff = dsize - (nreg - 1) * 2 - 1 - siz; 5923 else 5924 diff = atoi(arg) - siz; 5925 if (diff == 0) 5926 return; 5927 if (siz + diff < 1) 5928 diff = 1 - siz; 5929 if (siz + diff > dsize - (nreg - 1) * 2 - 1) 5930 diff = dsize - (nreg - 1) * 2 - 1 - siz; 5931 if (diff == 0 || siz + diff < 1) 5932 return; 5933 5934 if (diff < 0) 5935 { 5936 if (D_forecv->c_next) 5937 { 5938 D_forecv->c_ye += diff; 5939 D_forecv->c_next->c_ys += diff; 5940 D_forecv->c_next->c_yoff += diff; 5941 } 5942 else 5943 { 5944 for (cv = D_cvlist; cv; cv = cv->c_next) 5945 if (cv->c_next == D_forecv) 5946 break; 5947 ASSERT(cv); 5948 cv->c_ye -= diff; 5949 D_forecv->c_ys -= diff; 5950 D_forecv->c_yoff -= diff; 5951 } 5952 } 5953 else 5954 { 5955 int s, i = 0, found = 0, di = diff, d2; 5956 s = dsize - (nreg - 1) * 2 - 1 - siz; 5957 for (cv = D_cvlist; cv; i = cv->c_ye + 2, cv = cv->c_next) 5958 { 5959 if (cv == D_forecv) 5960 { 5961 cv->c_ye = i + (cv->c_ye - cv->c_ys) + diff; 5962 cv->c_yoff -= cv->c_ys - i; 5963 cv->c_ys = i; 5964 found = 1; 5965 continue; 5966 } 5967 s -= cv->c_ye - cv->c_ys; 5968 if (!found) 5969 { 5970 if (s >= di) 5971 continue; 5972 d2 = di - s; 5973 } 5974 else 5975 d2 = di > cv->c_ye - cv->c_ys ? cv->c_ye - cv->c_ys : di; 5976 di -= d2; 5977 cv->c_ye = i + (cv->c_ye - cv->c_ys) - d2; 5978 cv->c_yoff -= cv->c_ys - i; 5979 cv->c_ys = i; 5980 } 5981 } 5982 RethinkDisplayViewports(); 5983 ResizeLayersToCanvases(); 5984} 5985 5986static void 5987ResizeFin(buf, len, data) 5988char *buf; 5989int len; 5990char *data; 5991{ 5992 ResizeRegions(buf); 5993} 5994 5995#ifdef RXVT_OSC 5996void 5997RefreshXtermOSC() 5998{ 5999 int i; 6000 struct win *p; 6001 6002 p = Layer2Window(D_forecv->c_layer); 6003 for (i = 3; i >=0; i--) 6004 SetXtermOSC(i, p ? p->w_xtermosc[i] : 0); 6005} 6006#endif 6007 6008int 6009ParseAttrColor(s1, s2, msgok) 6010char *s1, *s2; 6011int msgok; 6012{ 6013 int i, n; 6014 char *s, *ss; 6015 int r = 0; 6016 6017 s = s1; 6018 while (*s == ' ') 6019 s++; 6020 ss = s; 6021 while (*ss && *ss != ' ') 6022 ss++; 6023 while (*ss == ' ') 6024 ss++; 6025 if (*s && (s2 || *ss || !((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || *s == '.'))) 6026 { 6027 int mode = 0, n = 0; 6028 if (*s == '+') 6029 { 6030 mode = 1; 6031 s++; 6032 } 6033 else if (*s == '-') 6034 { 6035 mode = -1; 6036 s++; 6037 } 6038 else if (*s == '!') 6039 { 6040 mode = 2; 6041 s++; 6042 } 6043 else if (*s == '=') 6044 s++; 6045 if (*s >= '0' && *s <= '9') 6046 { 6047 n = *s++ - '0'; 6048 if (*s >= '0' && *s <= '9') 6049 n = n * 16 + (*s++ - '0'); 6050 else if (*s >= 'a' && *s <= 'f') 6051 n = n * 16 + (*s++ - ('a' - 10)); 6052 else if (*s >= 'A' && *s <= 'F') 6053 n = n * 16 + (*s++ - ('A' - 10)); 6054 else if (*s && *s != ' ') 6055 { 6056 if (msgok) 6057 Msg(0, "Illegal attribute hexchar '%c'", *s); 6058 return -1; 6059 } 6060 } 6061 else 6062 { 6063 while (*s && *s != ' ') 6064 { 6065 if (*s == 'd') 6066 n |= A_DI; 6067 else if (*s == 'u') 6068 n |= A_US; 6069 else if (*s == 'b') 6070 n |= A_BD; 6071 else if (*s == 'r') 6072 n |= A_RV; 6073 else if (*s == 's') 6074 n |= A_SO; 6075 else if (*s == 'B') 6076 n |= A_BL; 6077 else 6078 { 6079 if (msgok) 6080 Msg(0, "Illegal attribute specifier '%c'", *s); 6081 return -1; 6082 } 6083 s++; 6084 } 6085 } 6086 if (*s && *s != ' ') 6087 { 6088 if (msgok) 6089 Msg(0, "junk after attribute description: '%c'", *s); 6090 return -1; 6091 } 6092 if (mode == -1) 6093 r = n << 8 | n; 6094 else if (mode == 1) 6095 r = n << 8; 6096 else if (mode == 2) 6097 r = n; 6098 else if (mode == 0) 6099 r = 0xffff ^ n; 6100 } 6101 while (*s && *s == ' ') 6102 s++; 6103 6104 if (s2) 6105 { 6106 if (*s) 6107 { 6108 if (msgok) 6109 Msg(0, "junk after description: '%c'", *s); 6110 return -1; 6111 } 6112 s = s2; 6113 while (*s && *s == ' ') 6114 s++; 6115 } 6116 6117#ifdef COLOR 6118 if (*s) 6119 { 6120 static char costr[] = "krgybmcw d i.01234567 9 f FKRGYBMCW I "; 6121 int numco = 0, j; 6122 6123 n = 0; 6124 if (*s == '.') 6125 { 6126 numco++; 6127 n = 0x0f; 6128 s++; 6129 } 6130 for (j = 0; j < 2 && *s && *s != ' '; j++) 6131 { 6132 for (i = 0; costr[i]; i++) 6133 if (*s == costr[i]) 6134 break; 6135 if (!costr[i]) 6136 { 6137 if (msgok) 6138 Msg(0, "illegal color descriptor: '%c'", *s); 6139 return -1; 6140 } 6141 numco++; 6142 n = n << 4 | (i & 15); 6143#ifdef COLORS16 6144 if (i >= 48) 6145 n = (n & 0x20ff) | 0x200; 6146#endif 6147 s++; 6148 } 6149 if ((n & 0xf00) == 0xf00) 6150 n ^= 0xf00; /* clear superflous bits */ 6151#ifdef COLORS16 6152 if (n & 0x2000) 6153 n ^= 0x2400; /* shift bit into right position */ 6154#endif 6155 if (numco == 1) 6156 n |= 0xf0; /* don't change bg color */ 6157 if (numco != 2 && n != 0xff) 6158 n |= 0x100; /* special invert mode */ 6159 if (*s && *s != ' ') 6160 { 6161 if (msgok) 6162 Msg(0, "junk after color description: '%c'", *s); 6163 return -1; 6164 } 6165 n ^= 0xff; 6166 r |= n << 16; 6167 } 6168#endif 6169 6170 while (*s && *s == ' ') 6171 s++; 6172 if (*s) 6173 { 6174 if (msgok) 6175 Msg(0, "junk after description: '%c'", *s); 6176 return -1; 6177 } 6178 debug1("ParseAttrColor %06x\n", r); 6179 return r; 6180} 6181 6182/* 6183 * Color coding: 6184 * 0-7 normal colors 6185 * 9 default color 6186 * e just set intensity 6187 * f don't change anything 6188 * Intensity is encoded into bits 17(fg) and 18(bg). 6189 */ 6190void 6191ApplyAttrColor(i, mc) 6192int i; 6193struct mchar *mc; 6194{ 6195 debug1("ApplyAttrColor %06x\n", i); 6196 mc->attr |= i >> 8 & 255; 6197 mc->attr ^= i & 255; 6198#ifdef COLOR 6199 i = (i >> 16) ^ 0xff; 6200 if ((i & 0x100) != 0) 6201 { 6202 i &= 0xeff; 6203 if (mc->attr & (A_SO|A_RV)) 6204# ifdef COLORS16 6205 i = ((i & 0x0f) << 4) | ((i & 0xf0) >> 4) | ((i & 0x200) << 1) | ((i & 0x400) >> 1); 6206# else 6207 i = ((i & 0x0f) << 4) | ((i & 0xf0) >> 4); 6208# endif 6209 } 6210# ifdef COLORS16 6211 if ((i & 0x0f) != 0x0f) 6212 mc->attr = (mc->attr & 0xbf) | ((i >> 3) & 0x40); 6213 if ((i & 0xf0) != 0xf0) 6214 mc->attr = (mc->attr & 0x7f) | ((i >> 3) & 0x80); 6215# endif 6216 mc->color = 0x99 ^ mc->color; 6217 if ((i & 0x0e) == 0x0e) 6218 i = (i & 0xf0) | (mc->color & 0x0f); 6219 if ((i & 0xe0) == 0xe0) 6220 i = (i & 0x0f) | (mc->color & 0xf0); 6221 mc->color = 0x99 ^ i; 6222 debug2("ApplyAttrColor - %02x %02x\n", mc->attr, i); 6223#endif 6224} 6225