From 5a5e2352c9a01f9076994915188c26c6b9036202 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 17:28:28 +0200 Subject: Adding upstream version 4.9.0. Signed-off-by: Daniel Baumann --- process.c | 7414 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 7414 insertions(+) create mode 100644 process.c (limited to 'process.c') diff --git a/process.c b/process.c new file mode 100644 index 0000000..004b22a --- /dev/null +++ b/process.c @@ -0,0 +1,7414 @@ +/* Copyright (c) 2010 + * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) + * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net) + * Copyright (c) 2008, 2009 + * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) + * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) + * Micah Cowan (micah@cowan.name) + * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net) + * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007 + * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) + * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) + * Copyright (c) 1987 Oliver Laumann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING); if not, see + * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + * + **************************************************************** + */ + +#include "config.h" + +#include +#include +#include +#include +#if !defined(sun) && !defined(B43) && !defined(ISC) && !defined(pyr) && !defined(_CX_UX) +# include +#endif +#include +#ifndef sun +#include +#endif + + +/* for solaris 2.1, Unixware (SVR4.2) and possibly others: */ +#ifdef HAVE_STROPTS_H +# include +#endif + +#include "screen.h" +#include "extern.h" +#include "logfile.h" +#include "layout.h" +#include "viewport.h" +#include "list_generic.h" + +extern struct comm comms[]; +extern char *rc_name; +extern char *RcFileName, *home; +extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[]; +extern char *hstatusstring, *captionstring, *timestring; +extern char *wliststr, *wlisttit; +extern int captionalways; +extern int queryflag; +extern char *hardcopydir, *screenlogfile, *logtstamp_string; +extern int log_flush, logtstamp_on, logtstamp_after; +extern char *VisualBellString; +extern int VBellWait, MsgWait, MsgMinWait, SilenceWait; +extern char SockPath[], *SockName; +extern int TtyMode, auto_detach, use_altscreen; +extern int iflag, maxwin; +extern int focusminwidth, focusminheight; +extern int use_hardstatus, visual_bell; +#ifdef COLOR +extern int attr2color[][4]; +extern int nattr2color; +#endif +extern int hardstatusemu; +extern char *printcmd; +extern int default_startup; +extern int defobuflimit; +extern int defnonblock; +extern int defmousetrack; +extern int ZombieKey_destroy; +extern int ZombieKey_resurrect; +extern int ZombieKey_onerror; +#ifdef AUTO_NUKE +extern int defautonuke; +#endif +extern int separate_sids; +extern struct NewWindow nwin_default, nwin_undef; +#ifdef COPY_PASTE +extern int join_with_cr; +extern int compacthist; +extern int search_ic; +# ifdef FONT +extern int pastefont; +# endif +extern unsigned char mark_key_tab[]; +extern char *BufferFile; +#endif +#ifdef POW_DETACH +extern char *BufferFile, *PowDetachString; +#endif +#ifdef MULTIUSER +extern struct acluser *EffectiveAclUser; /* acl.c */ +#endif +extern struct term term[]; /* terminal capabilities */ +#ifdef MAPKEYS +extern char *kmapdef[]; +extern char *kmapadef[]; +extern char *kmapmdef[]; +#endif +extern struct mchar mchar_so, mchar_null; +extern int renditions[]; +extern int VerboseCreate; +#ifdef UTF8 +extern char *screenencodings; +#endif +#ifdef DW_CHARS +extern int cjkwidth; +#endif + +static int CheckArgNum __P((int, char **)); +static void ClearAction __P((struct action *)); +static void SaveAction __P((struct action *, int, char **, int *)); +static int NextWindow __P((void)); +static int PreviousWindow __P((void)); +static int MoreWindows __P((void)); +static void CollapseWindowlist __P((void)); +static void LogToggle __P((int)); +static void ShowInfo __P((void)); +static void ShowDInfo __P((void)); +static struct win *WindowByName __P((char *)); +static int WindowByNumber __P((char *)); +static int ParseOnOff __P((struct action *, int *)); +static int ParseWinNum __P((struct action *, int *)); +static int ParseBase __P((struct action *, char *, int *, int, char *)); +static int ParseNum1000 __P((struct action *, int *)); +static char **SaveArgs __P((char **)); +static int IsNum __P((char *, int)); +static void Colonfin __P((char *, int, char *)); +static void InputSelect __P((void)); +static void InputSetenv __P((char *)); +static void InputAKA __P((void)); +#ifdef MULTIUSER +static int InputSu __P((struct win *, struct acluser **, char *)); +static void su_fin __P((char *, int, char *)); +#endif +static void AKAfin __P((char *, int, char *)); +#ifdef COPY_PASTE +static void copy_reg_fn __P((char *, int, char *)); +static void ins_reg_fn __P((char *, int, char *)); +#endif +static void process_fn __P((char *, int, char *)); +#ifdef PASSWORD +static void pass1 __P((char *, int, char *)); +static void pass2 __P((char *, int, char *)); +#endif +#ifdef POW_DETACH +static void pow_detach_fn __P((char *, int, char *)); +#endif +static void digraph_fn __P((char *, int, char *)); +static int digraph_find __P((const char *buf)); +static void confirm_fn __P((char *, int, char *)); +static int IsOnDisplay __P((struct win *)); +static void ResizeRegions __P((char *, int)); +static void ResizeFin __P((char *, int, char *)); +static struct action *FindKtab __P((char *, int)); +static void SelectFin __P((char *, int, char *)); +static void SelectLayoutFin __P((char *, int, char *)); +static void ShowWindowsX __P((char *)); + + +extern struct layer *flayer; +extern struct display *display, *displays; +extern struct win *fore, *console_window, *windows; +extern struct acluser *users; +extern struct layout *layouts, *layout_attach, layout_last_marker; +extern struct layout *laytab[]; + +extern char screenterm[], HostName[], version[]; +extern struct NewWindow nwin_undef, nwin_default; +extern struct LayFuncs WinLf, MarkLf; + +extern const int Z0width, Z1width; +extern int real_uid, real_gid; + +#ifdef NETHACK +extern int nethackflag; +#endif + + +extern struct win **wtab; + +#ifdef MULTIUSER +extern char *multi; +extern int maxusercount; +#endif +char NullStr[] = ""; + +struct plop plop_tab[MAX_PLOP_DEFS]; + +#ifndef PTYMODE +# define PTYMODE 0622 +#endif + +int TtyMode = PTYMODE; +int hardcopy_append = 0; +int all_norefresh = 0; +#ifdef ZMODEM +int zmodem_mode = 0; +char *zmodem_sendcmd; +char *zmodem_recvcmd; +static char *zmodes[4] = {"off", "auto", "catch", "pass"}; +#endif + +int idletimo; +struct action idleaction; +#ifdef BLANKER_PRG +char **blankerprg; +#endif + +struct action ktab[256 + KMAP_KEYS]; /* command key translation table */ +struct kclass { + struct kclass *next; + char *name; + struct action ktab[256 + KMAP_KEYS]; +}; +struct kclass *kclasses; + +#ifdef MAPKEYS +struct action umtab[KMAP_KEYS+KMAP_AKEYS]; +struct action dmtab[KMAP_KEYS+KMAP_AKEYS]; +struct action mmtab[KMAP_KEYS+KMAP_AKEYS]; +struct kmap_ext *kmap_exts; +int kmap_extn; +static int maptimeout = 300; +#endif + +#ifndef MAX_DIGRAPH +#define MAX_DIGRAPH 512 +#endif + +struct digraph +{ + unsigned char d[2]; + int value; +}; + +/* digraph table taken from old vim and rfc1345 */ +static struct digraph digraphs[MAX_DIGRAPH + 1] = { + {{' ', ' '}, 160}, /*   */ + {{'N', 'S'}, 160}, /*   */ + {{'~', '!'}, 161}, /* ¡ */ + {{'!', '!'}, 161}, /* ¡ */ + {{'!', 'I'}, 161}, /* ¡ */ + {{'c', '|'}, 162}, /* ¢ */ + {{'c', 't'}, 162}, /* ¢ */ + {{'$', '$'}, 163}, /* £ */ + {{'P', 'd'}, 163}, /* £ */ + {{'o', 'x'}, 164}, /* ¤ */ + {{'C', 'u'}, 164}, /* ¤ */ + {{'C', 'u'}, 164}, /* ¤ */ + {{'E', 'u'}, 164}, /* ¤ */ + {{'Y', '-'}, 165}, /* ¥ */ + {{'Y', 'e'}, 165}, /* ¥ */ + {{'|', '|'}, 166}, /* ¦ */ + {{'B', 'B'}, 166}, /* ¦ */ + {{'p', 'a'}, 167}, /* § */ + {{'S', 'E'}, 167}, /* § */ + {{'"', '"'}, 168}, /* ¨ */ + {{'\'', ':'}, 168}, /* ¨ */ + {{'c', 'O'}, 169}, /* © */ + {{'C', 'o'}, 169}, /* © */ + {{'a', '-'}, 170}, /* ª */ + {{'<', '<'}, 171}, /* « */ + {{'-', ','}, 172}, /* ¬ */ + {{'N', 'O'}, 172}, /* ¬ */ + {{'-', '-'}, 173}, /* ­ */ + {{'r', 'O'}, 174}, /* ® */ + {{'R', 'g'}, 174}, /* ® */ + {{'-', '='}, 175}, /* ¯ */ + {{'\'', 'm'}, 175}, /* ¯ */ + {{'~', 'o'}, 176}, /* ° */ + {{'D', 'G'}, 176}, /* ° */ + {{'+', '-'}, 177}, /* ± */ + {{'2', '2'}, 178}, /* ² */ + {{'2', 'S'}, 178}, /* ² */ + {{'3', '3'}, 179}, /* ³ */ + {{'3', 'S'}, 179}, /* ³ */ + {{'\'', '\''}, 180}, /* ´ */ + {{'j', 'u'}, 181}, /* µ */ + {{'M', 'y'}, 181}, /* µ */ + {{'p', 'p'}, 182}, /* ¶ */ + {{'P', 'I'}, 182}, /* ¶ */ + {{'~', '.'}, 183}, /* · */ + {{'.', 'M'}, 183}, /* · */ + {{',', ','}, 184}, /* ¸ */ + {{'\'', ','}, 184}, /* ¸ */ + {{'1', '1'}, 185}, /* ¹ */ + {{'1', 'S'}, 185}, /* ¹ */ + {{'o', '-'}, 186}, /* º */ + {{'>', '>'}, 187}, /* » */ + {{'1', '4'}, 188}, /* ¼ */ + {{'1', '2'}, 189}, /* ½ */ + {{'3', '4'}, 190}, /* ¾ */ + {{'~', '?'}, 191}, /* ¿ */ + {{'?', '?'}, 191}, /* ¿ */ + {{'?', 'I'}, 191}, /* ¿ */ + {{'A', '`'}, 192}, /* À */ + {{'A', '!'}, 192}, /* À */ + {{'A', '\''}, 193}, /* Á */ + {{'A', '^'}, 194}, /* Â */ + {{'A', '>'}, 194}, /* Â */ + {{'A', '~'}, 195}, /* Ã */ + {{'A', '?'}, 195}, /* Ã */ + {{'A', '"'}, 196}, /* Ä */ + {{'A', ':'}, 196}, /* Ä */ + {{'A', '@'}, 197}, /* Å */ + {{'A', 'A'}, 197}, /* Å */ + {{'A', 'E'}, 198}, /* Æ */ + {{'C', ','}, 199}, /* Ç */ + {{'E', '`'}, 200}, /* È */ + {{'E', '!'}, 200}, /* È */ + {{'E', '\''}, 201}, /* É */ + {{'E', '^'}, 202}, /* Ê */ + {{'E', '>'}, 202}, /* Ê */ + {{'E', '"'}, 203}, /* Ë */ + {{'E', ':'}, 203}, /* Ë */ + {{'I', '`'}, 204}, /* Ì */ + {{'I', '!'}, 204}, /* Ì */ + {{'I', '\''}, 205}, /* Í */ + {{'I', '^'}, 206}, /* Î */ + {{'I', '>'}, 206}, /* Î */ + {{'I', '"'}, 207}, /* Ï */ + {{'I', ':'}, 207}, /* Ï */ + {{'D', '-'}, 208}, /* Ð */ + {{'N', '~'}, 209}, /* Ñ */ + {{'N', '?'}, 209}, /* Ñ */ + {{'O', '`'}, 210}, /* Ò */ + {{'O', '!'}, 210}, /* Ò */ + {{'O', '\''}, 211}, /* Ó */ + {{'O', '^'}, 212}, /* Ô */ + {{'O', '>'}, 212}, /* Ô */ + {{'O', '~'}, 213}, /* Õ */ + {{'O', '?'}, 213}, /* Õ */ + {{'O', '"'}, 214}, /* Ö */ + {{'O', ':'}, 214}, /* Ö */ + {{'/', '\\'}, 215}, /* × */ + {{'*', 'x'}, 215}, /* × */ + {{'O', '/'}, 216}, /* Ø */ + {{'U', '`'}, 217}, /* Ù */ + {{'U', '!'}, 217}, /* Ù */ + {{'U', '\''}, 218}, /* Ú */ + {{'U', '^'}, 219}, /* Û */ + {{'U', '>'}, 219}, /* Û */ + {{'U', '"'}, 220}, /* Ü */ + {{'U', ':'}, 220}, /* Ü */ + {{'Y', '\''}, 221}, /* Ý */ + {{'I', 'p'}, 222}, /* Þ */ + {{'T', 'H'}, 222}, /* Þ */ + {{'s', 's'}, 223}, /* ß */ + {{'s', '"'}, 223}, /* ß */ + {{'a', '`'}, 224}, /* à */ + {{'a', '!'}, 224}, /* à */ + {{'a', '\''}, 225}, /* á */ + {{'a', '^'}, 226}, /* â */ + {{'a', '>'}, 226}, /* â */ + {{'a', '~'}, 227}, /* ã */ + {{'a', '?'}, 227}, /* ã */ + {{'a', '"'}, 228}, /* ä */ + {{'a', ':'}, 228}, /* ä */ + {{'a', 'a'}, 229}, /* å */ + {{'a', 'e'}, 230}, /* æ */ + {{'c', ','}, 231}, /* ç */ + {{'e', '`'}, 232}, /* è */ + {{'e', '!'}, 232}, /* è */ + {{'e', '\''}, 233}, /* é */ + {{'e', '^'}, 234}, /* ê */ + {{'e', '>'}, 234}, /* ê */ + {{'e', '"'}, 235}, /* ë */ + {{'e', ':'}, 235}, /* ë */ + {{'i', '`'}, 236}, /* ì */ + {{'i', '!'}, 236}, /* ì */ + {{'i', '\''}, 237}, /* í */ + {{'i', '^'}, 238}, /* î */ + {{'i', '>'}, 238}, /* î */ + {{'i', '"'}, 239}, /* ï */ + {{'i', ':'}, 239}, /* ï */ + {{'d', '-'}, 240}, /* ð */ + {{'n', '~'}, 241}, /* ñ */ + {{'n', '?'}, 241}, /* ñ */ + {{'o', '`'}, 242}, /* ò */ + {{'o', '!'}, 242}, /* ò */ + {{'o', '\''}, 243}, /* ó */ + {{'o', '^'}, 244}, /* ô */ + {{'o', '>'}, 244}, /* ô */ + {{'o', '~'}, 245}, /* õ */ + {{'o', '?'}, 245}, /* õ */ + {{'o', '"'}, 246}, /* ö */ + {{'o', ':'}, 246}, /* ö */ + {{':', '-'}, 247}, /* ÷ */ + {{'o', '/'}, 248}, /* ø */ + {{'u', '`'}, 249}, /* ù */ + {{'u', '!'}, 249}, /* ù */ + {{'u', '\''}, 250}, /* ú */ + {{'u', '^'}, 251}, /* û */ + {{'u', '>'}, 251}, /* û */ + {{'u', '"'}, 252}, /* ü */ + {{'u', ':'}, 252}, /* ü */ + {{'y', '\''}, 253}, /* ý */ + {{'i', 'p'}, 254}, /* þ */ + {{'t', 'h'}, 254}, /* þ */ + {{'y', '"'}, 255}, /* ÿ */ + {{'y', ':'}, 255}, /* ÿ */ + {{'"', '['}, 196}, /* Ä */ + {{'"', '\\'}, 214}, /* Ö */ + {{'"', ']'}, 220}, /* Ü */ + {{'"', '{'}, 228}, /* ä */ + {{'"', '|'}, 246}, /* ö */ + {{'"', '}'}, 252}, /* ü */ + {{'"', '~'}, 223} /* ß */ +}; + +#define RESIZE_FLAG_H 1 +#define RESIZE_FLAG_V 2 +#define RESIZE_FLAG_L 4 + +static char *resizeprompts[] = { + "resize # lines: ", + "resize -h # lines: ", + "resize -v # lines: ", + "resize -b # lines: ", + "resize -l # lines: ", + "resize -l -h # lines: ", + "resize -l -v # lines: ", + "resize -l -b # lines: ", +}; + + +static int +parse_input_int(buf, len, val) +const char *buf; +int len; +int *val; +{ + int x = 0, i; + if (len >= 1 && ((*buf == 'U' && buf[1] == '+') || (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X')))) + { + x = 0; + for (i = 2; i < len; i++) + { + if (buf[i] >= '0' && buf[i] <= '9') + x = x * 16 | (buf[i] - '0'); + else if (buf[i] >= 'a' && buf[i] <= 'f') + x = x * 16 | (buf[i] - ('a' - 10)); + else if (buf[i] >= 'A' && buf[i] <= 'F') + x = x * 16 | (buf[i] - ('A' - 10)); + else + return 0; + } + } + else if (buf[0] == '0') + { + x = 0; + for (i = 1; i < len; i++) + { + if (buf[i] < '0' || buf[i] > '7') + return 0; + x = x * 8 | (buf[i] - '0'); + } + } + else + return 0; + *val = x; + return 1; +} + +char *noargs[1]; + +int enter_window_name_mode = 0; + +void +InitKeytab() +{ + register unsigned int i; +#ifdef MAPKEYS + char *argarr[2]; +#endif + + for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++) + { + ktab[i].nr = RC_ILLEGAL; + ktab[i].args = noargs; + ktab[i].argl = 0; + } +#ifdef MAPKEYS + for (i = 0; i < KMAP_KEYS+KMAP_AKEYS; i++) + { + umtab[i].nr = RC_ILLEGAL; + umtab[i].args = noargs; + umtab[i].argl = 0; + dmtab[i].nr = RC_ILLEGAL; + dmtab[i].args = noargs; + dmtab[i].argl = 0; + mmtab[i].nr = RC_ILLEGAL; + mmtab[i].args = noargs; + mmtab[i].argl = 0; + } + argarr[1] = 0; + for (i = 0; i < NKMAPDEF; i++) + { + if (i + KMAPDEFSTART < T_CAPS) + continue; + if (i + KMAPDEFSTART >= T_CAPS + KMAP_KEYS) + continue; + if (kmapdef[i] == 0) + continue; + argarr[0] = kmapdef[i]; + SaveAction(dmtab + i + (KMAPDEFSTART - T_CAPS), RC_STUFF, argarr, 0); + } + for (i = 0; i < NKMAPADEF; i++) + { + if (i + KMAPADEFSTART < T_CURSOR) + continue; + if (i + KMAPADEFSTART >= T_CURSOR + KMAP_AKEYS) + continue; + if (kmapadef[i] == 0) + continue; + argarr[0] = kmapadef[i]; + SaveAction(dmtab + i + (KMAPADEFSTART - T_CURSOR + KMAP_KEYS), RC_STUFF, argarr, 0); + } + for (i = 0; i < NKMAPMDEF; i++) + { + if (i + KMAPMDEFSTART < T_CAPS) + continue; + if (i + KMAPMDEFSTART >= T_CAPS + KMAP_KEYS) + continue; + if (kmapmdef[i] == 0) + continue; + argarr[0] = kmapmdef[i]; + argarr[1] = 0; + SaveAction(mmtab + i + (KMAPMDEFSTART - T_CAPS), RC_STUFF, argarr, 0); + } +#endif + + ktab['h'].nr = RC_HARDCOPY; +#ifdef BSDJOBS + ktab['z'].nr = ktab[Ctrl('z')].nr = RC_SUSPEND; +#endif + ktab['c'].nr = ktab[Ctrl('c')].nr = RC_SCREEN; + ktab[' '].nr = ktab[Ctrl(' ')].nr = + ktab['n'].nr = ktab[Ctrl('n')].nr = RC_NEXT; + ktab['N'].nr = RC_NUMBER; + ktab[Ctrl('h')].nr = ktab[0177].nr = ktab['p'].nr = ktab[Ctrl('p')].nr = RC_PREV; + ktab['k'].nr = ktab[Ctrl('k')].nr = RC_KILL; + ktab['l'].nr = ktab[Ctrl('l')].nr = RC_REDISPLAY; + ktab['w'].nr = ktab[Ctrl('w')].nr = RC_WINDOWS; + ktab['v'].nr = RC_VERSION; + ktab[Ctrl('v')].nr = RC_DIGRAPH; + ktab['q'].nr = ktab[Ctrl('q')].nr = RC_XON; + ktab['s'].nr = ktab[Ctrl('s')].nr = RC_XOFF; + ktab['t'].nr = ktab[Ctrl('t')].nr = RC_TIME; + ktab['i'].nr = ktab[Ctrl('i')].nr = RC_INFO; + ktab['m'].nr = ktab[Ctrl('m')].nr = RC_LASTMSG; + ktab['A'].nr = RC_TITLE; +#if defined(UTMPOK) && defined(LOGOUTOK) + ktab['L'].nr = RC_LOGIN; +#endif + ktab[','].nr = RC_LICENSE; + ktab['W'].nr = RC_WIDTH; + ktab['.'].nr = RC_DUMPTERMCAP; + ktab[Ctrl('\\')].nr = RC_QUIT; +#ifdef DETACH + ktab['d'].nr = ktab[Ctrl('d')].nr = RC_DETACH; +# ifdef POW_DETACH + ktab['D'].nr = RC_POW_DETACH; +# endif +#endif + ktab['r'].nr = ktab[Ctrl('r')].nr = RC_WRAP; + ktab['f'].nr = ktab[Ctrl('f')].nr = RC_FLOW; + ktab['C'].nr = RC_CLEAR; + ktab['Z'].nr = RC_RESET; + ktab['H'].nr = RC_LOG; + ktab['M'].nr = RC_MONITOR; + ktab['?'].nr = RC_HELP; +#ifdef MULTI + ktab['*'].nr = RC_DISPLAYS; +#endif + { + char *args[2]; + args[0] = "-"; + args[1] = NULL; + SaveAction(ktab + '-', RC_SELECT, args, 0); + } + for (i = 0; i < ((maxwin && maxwin < 10) ? maxwin : 10); i++) + { + char *args[2], arg1[10]; + args[0] = arg1; + args[1] = 0; + sprintf(arg1, "%d", i); + SaveAction(ktab + '0' + i, RC_SELECT, args, 0); + } + ktab['\''].nr = RC_SELECT; /* calling a window by name */ + { + char *args[2]; + args[0] = "-b"; + args[1] = 0; + SaveAction(ktab + '"', RC_WINDOWLIST, args, 0); + } + ktab[Ctrl('G')].nr = RC_VBELL; + ktab[':'].nr = RC_COLON; +#ifdef COPY_PASTE + ktab['['].nr = ktab[Ctrl('[')].nr = RC_COPY; + { + char *args[2]; + args[0] = "."; + args[1] = 0; + SaveAction(ktab + ']', RC_PASTE, args, 0); + SaveAction(ktab + Ctrl(']'), RC_PASTE, args, 0); + } + ktab['{'].nr = RC_HISTORY; + ktab['}'].nr = RC_HISTORY; + ktab['>'].nr = RC_WRITEBUF; + ktab['<'].nr = RC_READBUF; + ktab['='].nr = RC_REMOVEBUF; +#endif +#ifdef POW_DETACH + ktab['D'].nr = RC_POW_DETACH; +#endif +#ifdef LOCK + ktab['x'].nr = ktab[Ctrl('x')].nr = RC_LOCKSCREEN; +#endif + ktab['b'].nr = ktab[Ctrl('b')].nr = RC_BREAK; + ktab['B'].nr = RC_POW_BREAK; + ktab['_'].nr = RC_SILENCE; + ktab['S'].nr = RC_SPLIT; + ktab['Q'].nr = RC_ONLY; + ktab['X'].nr = RC_REMOVE; + ktab['F'].nr = RC_FIT; + ktab['\t'].nr = RC_FOCUS; + { + char *args[2]; + args[0] = "prev"; + args[1] = 0; + SaveAction(ktab + T_BACKTAB - T_CAPS + 256, RC_FOCUS, args, 0); + } + { + char *args[2]; + args[0] = "-v"; + args[1] = 0; + SaveAction(ktab + '|', RC_SPLIT, args, 0); + } + /* These come last; they may want overwrite others: */ + if (DefaultEsc >= 0) + { + ClearAction(&ktab[DefaultEsc]); + ktab[DefaultEsc].nr = RC_OTHER; + } + if (DefaultMetaEsc >= 0) + { + ClearAction(&ktab[DefaultMetaEsc]); + ktab[DefaultMetaEsc].nr = RC_META; + } + + idleaction.nr = RC_BLANKER; + idleaction.args = noargs; + idleaction.argl = 0; +} + +static struct action * +FindKtab(class, create) +char *class; +int create; +{ + struct kclass *kp, **kpp; + int i; + + if (class == 0) + return ktab; + for (kpp = &kclasses; (kp = *kpp) != 0; kpp = &kp->next) + if (!strcmp(kp->name, class)) + break; + if (kp == 0) + { + if (!create) + return 0; + if (strlen(class) > 80) + { + Msg(0, "Command class name too long."); + return 0; + } + kp = malloc(sizeof(*kp)); + if (kp == 0) + { + Msg(0, "%s", strnomem); + return 0; + } + kp->name = SaveStr(class); + for (i = 0; i < (int)(sizeof(kp->ktab)/sizeof(*kp->ktab)); i++) + { + kp->ktab[i].nr = RC_ILLEGAL; + kp->ktab[i].args = noargs; + kp->ktab[i].argl = 0; + kp->ktab[i].quiet = 0; + } + kp->next = 0; + *kpp = kp; + } + return kp->ktab; +} + +static void +ClearAction(act) +struct action *act; +{ + char **p; + + if (act->nr == RC_ILLEGAL) + return; + act->nr = RC_ILLEGAL; + if (act->args == noargs) + return; + for (p = act->args; *p; p++) + free(*p); + free((char *)act->args); + act->args = noargs; + act->argl = 0; +} + +/* + * ProcessInput: process input from display and feed it into + * the layer on canvas D_forecv. + */ + +#ifdef MAPKEYS + +/* + * This ProcessInput just does the keybindings and passes + * everything else on to ProcessInput2. + */ + +void +ProcessInput(ibuf, ilen) +char *ibuf; +int ilen; +{ + int ch, slen; + unsigned char *s, *q; + int i, l; + char *p; + + debug1("ProcessInput: %d bytes\n", ilen); + if (display == 0 || ilen == 0) + return; + if (D_seql) + evdeq(&D_mapev); + slen = ilen; + s = (unsigned char *)ibuf; + while (ilen-- > 0) + { + ch = *s++; + if (D_dontmap || !D_nseqs) + { + D_dontmap = 0; + continue; + } + for (;;) + { + debug3("cmp %c %c[%d]\n", ch, *D_seqp, D_seqp - D_kmaps); + if (*D_seqp != ch) + { + l = D_seqp[D_seqp[-D_seql-1] + 1]; + if (l) + { + D_seqp += l * 2 + 4; + debug1("miss %d\n", D_seqp - D_kmaps); + continue; + } + debug("complete miss\n"); + D_mapdefault = 0; + l = D_seql; + p = (char *)D_seqp - l; + D_seql = 0; + D_seqp = D_kmaps + 3; + if (l == 0) + break; + if ((q = D_seqh) != 0) + { + D_seqh = 0; + i = q[0] << 8 | q[1]; + i &= ~KMAP_NOTIMEOUT; + debug1("Mapping former hit #%d - ", i); + debug2("%d(%s) - ", q[2], q + 3); + if (StuffKey(i)) + ProcessInput2((char *)q + 3, q[2]); + if (display == 0) + return; + l -= q[2]; + p += q[2]; + } + else + D_dontmap = 1; + debug1("flush old %d\n", l); + ProcessInput(p, l); + if (display == 0) + return; + evdeq(&D_mapev); + continue; + } + if (D_seql++ == 0) + { + /* Finish old stuff */ + slen -= ilen + 1; + debug1("finish old %d\n", slen); + if (slen) + ProcessInput2(ibuf, slen); + if (display == 0) + return; + D_seqh = 0; + } + ibuf = (char *)s; + slen = ilen; + D_seqp++; + l = D_seql; + debug2("length am %d, want %d\n", l, D_seqp[-l - 1]); + if (l == D_seqp[-l - 1]) + { + if (D_seqp[l] != l) + { + q = D_seqp + 1 + l; + if (D_kmaps + D_nseqs > q && q[2] > l && !bcmp(D_seqp - l, q + 3, l)) + { + debug1("have another mapping (%s), delay execution\n", q + 3); + D_seqh = D_seqp - 3 - l; + D_seqp = q + 3 + l; + break; + } + } + i = D_seqp[-l - 3] << 8 | D_seqp[-l - 2]; + i &= ~KMAP_NOTIMEOUT; + debug1("Mapping #%d - ", i); + p = (char *)D_seqp - l; + debug2("%d(%s) - ", l, p); + D_seql = 0; + D_seqp = D_kmaps + 3; + D_seqh = 0; + if (StuffKey(i)) + ProcessInput2(p, l); + if (display == 0) + return; + } + break; + } + } + if (D_seql) + { + debug("am in sequence -> check for timeout\n"); + l = D_seql; + for (s = D_seqp; ; s += i * 2 + 4) + { + if (s[-l-3] & KMAP_NOTIMEOUT >> 8) + break; + if ((i = s[s[-l-1] + 1]) == 0) + { + SetTimeout(&D_mapev, maptimeout); + evenq(&D_mapev); + break; + } + } + } + ProcessInput2(ibuf, slen); +} + +#else +# define ProcessInput2 ProcessInput +#endif + + +/* + * Here only the screen escape commands are handled. + */ + +void +ProcessInput2(ibuf, ilen) +char *ibuf; +int ilen; +{ + char *s; + int ch, slen; + struct action *ktabp; + + debug1("ProcessInput2: %d bytes\n", ilen); + while (ilen && display) + { + debug1(" - ilen now %d bytes\n", ilen); + flayer = D_forecv->c_layer; + fore = D_fore; + slen = ilen; + s = ibuf; + if (!D_ESCseen) + { + while (ilen > 0) + { + if ((unsigned char)*s++ == D_user->u_Esc) + break; + ilen--; + } + slen -= ilen; + if (slen) + DoProcess(fore, &ibuf, &slen, 0); + if (--ilen == 0) + { + D_ESCseen = ktab; + WindowChanged(fore, 'E'); + } + } + if (ilen <= 0) + return; + ktabp = D_ESCseen ? D_ESCseen : ktab; + if (D_ESCseen) + { + D_ESCseen = 0; + WindowChanged(fore, 'E'); + } + ch = (unsigned char)*s; + + /* + * As users have different esc characters, but a common ktab[], + * we fold back the users esc and meta-esc key to the Default keys + * that can be looked up in the ktab[]. grmbl. jw. + * XXX: make ktab[] a per user thing. + */ + if (ch == D_user->u_Esc) + ch = DefaultEsc; + else if (ch == D_user->u_MetaEsc) + ch = DefaultMetaEsc; + + if (ch >= 0) + DoAction(&ktabp[ch], ch); + ibuf = (char *)(s + 1); + ilen--; + } +} + +void +DoProcess(p, bufp, lenp, pa) +struct win *p; +char **bufp; +int *lenp; +struct paster *pa; +{ + int oldlen; + struct display *d = display; + +#ifdef COPY_PASTE + /* XXX -> PasteStart */ + if (pa && *lenp > 1 && p && p->w_slowpaste) + { + /* schedule slowpaste event */ + SetTimeout(&p->w_paster.pa_slowev, p->w_slowpaste); + evenq(&p->w_paster.pa_slowev); + return; + } +#endif + while (flayer && *lenp) + { +#ifdef COPY_PASTE + if (!pa && p && p->w_paster.pa_pastelen && flayer == p->w_paster.pa_pastelayer) + { + debug("layer is busy - beep!\n"); + WBell(p, visual_bell); + *bufp += *lenp; + *lenp = 0; + display = d; + return; + } +#endif + oldlen = *lenp; + LayProcess(bufp, lenp); +#ifdef COPY_PASTE + if (pa && !pa->pa_pastelayer) + break; /* flush rest of paste */ +#endif + if (*lenp == oldlen) + { + if (pa) + { + display = d; + return; + } + /* We're full, let's beep */ + debug("layer is full - beep!\n"); + WBell(p, visual_bell); + break; + } + } + *bufp += *lenp; + *lenp = 0; + display = d; +#ifdef COPY_PASTE + if (pa && pa->pa_pastelen == 0) + FreePaster(pa); +#endif +} + +int +FindCommnr(str) +const char *str; +{ + int x, m, l = 0, r = RC_LAST; + while (l <= r) + { + m = (l + r) / 2; + x = strcmp(str, comms[m].name); + if (x > 0) + l = m + 1; + else if (x < 0) + r = m - 1; + else + return m; + } + return RC_ILLEGAL; +} + +static int +CheckArgNum(nr, args) +int nr; +char **args; +{ + int i, n; + static char *argss[] = {"no", "one", "two", "three", "four", "OOPS"}; + static char *orformat[] = + { + "%s: %s: %s argument%s required", + "%s: %s: %s or %s argument%s required", + "%s: %s: %s, %s or %s argument%s required", + "%s: %s: %s, %s, %s or %s argument%s required" + }; + + n = comms[nr].flags & ARGS_MASK; + for (i = 0; args[i]; i++) + ; + if (comms[nr].flags & ARGS_ORMORE) + { + if (i < n) + { + Msg(0, "%s: %s: at least %s argument%s required", + rc_name, comms[nr].name, argss[n], n != 1 ? "s" : ""); + return -1; + } + } + else if ((comms[nr].flags & ARGS_PLUS1) && + (comms[nr].flags & ARGS_PLUS2) && + (comms[nr].flags & ARGS_PLUS3)) + { + if (i != n && i != n + 1 && i != n + 2 && i != n + 3) + { + Msg(0, orformat[3], rc_name, comms[nr].name, argss[n], + argss[n + 1], argss[n + 2], argss[n + 3], ""); + return -1; + } + } + else if ((comms[nr].flags & ARGS_PLUS1) && + (comms[nr].flags & ARGS_PLUS2)) + { + if (i != n && i != n + 1 && i != n + 2) + { + Msg(0, orformat[2], rc_name, comms[nr].name, argss[n], + argss[n + 1], argss[n + 2], ""); + return -1; + } + } + else if ((comms[nr].flags & ARGS_PLUS1) && + (comms[nr].flags & ARGS_PLUS3)) + { + if (i != n && i != n + 1 && i != n + 3) + { + Msg(0, orformat[2], rc_name, comms[nr].name, argss[n], + argss[n + 1], argss[n + 3], ""); + return -1; + } + } + else if ((comms[nr].flags & ARGS_PLUS2) && + (comms[nr].flags & ARGS_PLUS3)) + { + if (i != n && i != n + 2 && i != n + 3) + { + Msg(0, orformat[2], rc_name, comms[nr].name, argss[n], + argss[n + 2], argss[n + 3], ""); + return -1; + } + } + else if (comms[nr].flags & ARGS_PLUS1) + { + if (i != n && i != n + 1) + { + Msg(0, orformat[1], rc_name, comms[nr].name, argss[n], + argss[n + 1], n != 0 ? "s" : ""); + return -1; + } + } + else if (comms[nr].flags & ARGS_PLUS2) + { + if (i != n && i != n + 2) + { + Msg(0, orformat[1], rc_name, comms[nr].name, argss[n], + argss[n + 2], "s"); + return -1; + } + } + else if (comms[nr].flags & ARGS_PLUS3) + { + if (i != n && i != n + 3) + { + Msg(0, orformat[1], rc_name, comms[nr].name, argss[n], + argss[n + 3], ""); + return -1; + } + } + else if (i != n) + { + Msg(0, orformat[0], rc_name, comms[nr].name, argss[n], n != 1 ? "s" : ""); + return -1; + } + return i; +} + +static void +StuffFin(buf, len, data) +char *buf; +int len; +char *data; +{ + if (!flayer) + return; + while(len) + LayProcess(&buf, &len); +} + +/* If the command is not 'quieted', then use Msg to output the message. If it's a remote + * query, then Msg takes care of also outputting the message to the querying client. + * + * If we want the command to be quiet, and it's a remote query, then use QueryMsg so that + * the response does go back to the querying client. + * + * If the command is quieted, and it's not a remote query, then just don't print the message. + */ +#define OutputMsg (!act->quiet ? Msg : queryflag >= 0 ? QueryMsg : Dummy) + +/*ARGSUSED*/ +void +DoAction(act, key) +struct action *act; +int key; +{ + int nr = act->nr; + char **args = act->args; + int *argl = act->argl; + struct win *p; + int argc, i, n, msgok; + char *s; + char ch; + struct display *odisplay = display; + struct acluser *user; + + user = display ? D_user : users; + if (nr == RC_ILLEGAL) + { + debug1("key '%c': No action\n", key); + return; + } + n = comms[nr].flags; + /* Commands will have a CAN_QUERY flag, depending on whether they have + * something to return on a query. For example, 'windows' can return a result, + * but 'other' cannot. + * If some command causes an error, then it should reset queryflag to -1, so that + * the process requesting the query can be notified that an error happened. + */ + if (!(n & CAN_QUERY) && queryflag >= 0) + { + /* Query flag is set, but this command cannot be queried. */ + OutputMsg(0, "%s command cannot be queried.", comms[nr].name); + queryflag = -1; + return; + } + if ((n & NEED_DISPLAY) && display == 0) + { + OutputMsg(0, "%s: %s: display required", rc_name, comms[nr].name); + queryflag = -1; + return; + } + if ((n & NEED_FORE) && fore == 0) + { + OutputMsg(0, "%s: %s: window required", rc_name, comms[nr].name); + queryflag = -1; + return; + } + if ((n & NEED_LAYER) && flayer == 0) + { + OutputMsg(0, "%s: %s: display or window required", rc_name, comms[nr].name); + queryflag = -1; + return; + } + if ((argc = CheckArgNum(nr, args)) < 0) + return; +#ifdef MULTIUSER + if (display) + { + if (AclCheckPermCmd(D_user, ACL_EXEC, &comms[nr])) + { + OutputMsg(0, "%s: %s: permission denied (user %s)", + rc_name, comms[nr].name, (EffectiveAclUser ? EffectiveAclUser : D_user)->u_name); + queryflag = -1; + return; + } + } +#endif /* MULTIUSER */ + + msgok = display && !*rc_name; + switch(nr) + { + case RC_SELECT: + if (!*args) + InputSelect(); + else if (args[0][0] == '-' && !args[0][1]) + { + SetForeWindow((struct win *)0); + Activate(0); + } + else if (args[0][0] == '.' && !args[0][1]) + { + if (!fore) + { + OutputMsg(0, "select . needs a window"); + queryflag = -1; + } + else + { + SetForeWindow(fore); + Activate(0); + } + } + else if (ParseWinNum(act, &n) == 0) + SwitchWindow(n); + else if (queryflag >= 0) + queryflag = -1; /* ParseWinNum already prints out an appropriate error message. */ + break; +#ifdef AUTO_NUKE + case RC_DEFAUTONUKE: + if (ParseOnOff(act, &defautonuke) == 0 && msgok) + OutputMsg(0, "Default autonuke turned %s", defautonuke ? "on" : "off"); + if (display && *rc_name) + D_auto_nuke = defautonuke; + break; + case RC_AUTONUKE: + if (ParseOnOff(act, &D_auto_nuke) == 0 && msgok) + OutputMsg(0, "Autonuke turned %s", D_auto_nuke ? "on" : "off"); + break; +#endif + case RC_DEFOBUFLIMIT: + if (ParseNum(act, &defobuflimit) == 0 && msgok) + OutputMsg(0, "Default limit set to %d", defobuflimit); + if (display && *rc_name) + { + D_obufmax = defobuflimit; + D_obuflenmax = D_obuflen - D_obufmax; + } + break; + case RC_OBUFLIMIT: + if (*args == 0) + OutputMsg(0, "Limit is %d, current buffer size is %d", D_obufmax, D_obuflen); + else if (ParseNum(act, &D_obufmax) == 0 && msgok) + OutputMsg(0, "Limit set to %d", D_obufmax); + D_obuflenmax = D_obuflen - D_obufmax; + break; + case RC_DUMPTERMCAP: + WriteFile(user, (char *)0, DUMP_TERMCAP); + break; + case RC_HARDCOPY: + { + int mode = DUMP_HARDCOPY; + char *file = NULL; + + if (args[0]) + { + if (!strcmp(*args, "-h")) + { + mode = DUMP_SCROLLBACK; + file = args[1]; + } + else if (!strcmp(*args, "--") && args[1]) + file = args[1]; + else + file = args[0]; + } + + if (args[0] && file == args[0] && args[1]) + { + OutputMsg(0, "%s: hardcopy: too many arguments", rc_name); + break; + } + WriteFile(user, file, mode); + } + break; + case RC_DEFLOG: + (void)ParseOnOff(act, &nwin_default.Lflag); + break; + case RC_LOG: + n = fore->w_log ? 1 : 0; + ParseSwitch(act, &n); + LogToggle(n); + break; +#ifdef BSDJOBS + case RC_SUSPEND: + Detach(D_STOP); + break; +#endif + case RC_NEXT: + if (MoreWindows()) + SwitchWindow(NextWindow()); + break; + case RC_PREV: + if (MoreWindows()) + SwitchWindow(PreviousWindow()); + break; + case RC_KILL: + { + char *name; + + if (key >= 0) + { +#ifdef PSEUDOS + Input(fore->w_pwin ? "Really kill this filter [y/n]" : "Really kill this window [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_KILL); +#else + Input("Really kill this window [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_KILL); +#endif + break; + } + n = fore->w_number; +#ifdef PSEUDOS + if (fore->w_pwin) + { + FreePseudowin(fore); + OutputMsg(0, "Filter removed."); + break; + } +#endif + name = SaveStr(fore->w_title); + KillWindow(fore); + OutputMsg(0, "Window %d (%s) killed.", n, name); + if (name) + free(name); + break; + } + case RC_QUIT: + if (key >= 0) + { + Input("Really quit and kill all your windows [y/n]", 1, INP_RAW, confirm_fn, NULL, RC_QUIT); + break; + } + Finit(0); + /* NOTREACHED */ +#ifdef DETACH + case RC_DETACH: + if (*args && !strcmp(*args, "-h")) + Hangup(); + else + Detach(D_DETACH); + break; +# ifdef POW_DETACH + case RC_POW_DETACH: + if (key >= 0) + { + static char buf[2]; + + buf[0] = key; + Input(buf, 1, INP_RAW, pow_detach_fn, NULL, 0); + } + else + Detach(D_POWER); /* detach and kill Attacher's parent */ + break; +# endif +#endif + case RC_DEBUG: +#ifdef DEBUG + if (!*args) + { + if (dfp) + OutputMsg(0, "debugging info is written to %s/", DEBUGDIR); + else + OutputMsg(0, "debugging is currently off. Use 'debug on' to enable."); + break; + } + if (dfp) + { + debug("debug: closing debug file.\n"); + fflush(dfp); + fclose(dfp); + dfp = NULL; + } + if (strcmp("off", *args)) + opendebug(0, 1); +# ifdef SIG_NODEBUG + else if (display) + kill(D_userpid, SIG_NODEBUG); /* a one shot item, but hey... */ +# endif /* SIG_NODEBUG */ +#else + if (*args == 0 || strcmp("off", *args)) + OutputMsg(0, "Sorry, screen was compiled without -DDEBUG option."); +#endif + break; +#ifdef ZMODEM + case RC_ZMODEM: + if (*args && !strcmp(*args, "sendcmd")) + { + if (args[1]) + { + free(zmodem_sendcmd); + zmodem_sendcmd = SaveStr(args[1]); + } + if (msgok) + OutputMsg(0, "zmodem sendcmd: %s", zmodem_sendcmd); + break; + } + if (*args && !strcmp(*args, "recvcmd")) + { + if (args[1]) + { + free(zmodem_recvcmd); + zmodem_recvcmd = SaveStr(args[1]); + } + if (msgok) + OutputMsg(0, "zmodem recvcmd: %s", zmodem_recvcmd); + break; + } + if (*args) + { + for (i = 0; i < 4; i++) + if (!strcmp(zmodes[i], *args)) + break; + if (i == 4 && !strcmp(*args, "on")) + i = 1; + if (i == 4) + { + OutputMsg(0, "usage: zmodem off|auto|catch|pass"); + break; + } + zmodem_mode = i; + } + if (msgok) + OutputMsg(0, "zmodem mode is %s", zmodes[zmodem_mode]); + break; +#endif + case RC_UNBINDALL: + { + register unsigned int i; + + for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++) + ClearAction(&ktab[i]); + OutputMsg(0, "Unbound all keys." ); + break; + } + case RC_ZOMBIE: + { + if (!(s = *args)) + { + ZombieKey_destroy = 0; + break; + } + if (*argl == 0 || *argl > 2) + { + OutputMsg(0, "%s:zombie: one or two characters expected.", rc_name); + break; + } + if (args[1]) + { + if (!strcmp(args[1], "onerror")) + { + ZombieKey_onerror = 1; + } else { + OutputMsg(0, "usage: zombie [keys [onerror]]"); + break; + } + } else + ZombieKey_onerror = 0; + ZombieKey_destroy = args[0][0]; + ZombieKey_resurrect = *argl == 2 ? args[0][1] : 0; + } + break; + case RC_WALL: +#ifdef MULTIUSER + s = D_user->u_name; +#else + s = D_usertty; +#endif + { + struct display *olddisplay = display; + display = 0; /* no display will cause a broadcast */ + OutputMsg(0, "%s: %s", s, *args); + display = olddisplay; + } + break; + case RC_AT: + /* where this AT command comes from: */ + if (!user) + break; +#ifdef MULTIUSER + s = SaveStr(user->u_name); + /* DO NOT RETURN FROM HERE WITHOUT RESETTING THIS: */ + EffectiveAclUser = user; +#else + s = SaveStr(display ? D_usertty : user->u_name); +#endif + n = strlen(args[0]); + if (n) n--; + /* + * the windows/displays loops are quite dangerous here, take extra + * care not to trigger landmines. Things may appear/disappear while + * we are walking along. + */ + switch (args[0][n]) + { + case '*': /* user */ + { + struct display *nd; + struct acluser *u; + + if (!n) + u = user; + else + { + for (u = users; u; u = u->u_next) + { + debug3("strncmp('%s', '%s', %d)\n", *args, u->u_name, n); + if (!strncmp(*args, u->u_name, n)) + break; + } + if (!u) + { + args[0][n] = '\0'; + OutputMsg(0, "Did not find any user matching '%s'", args[0]); + break; + } + } + debug1("at all displays of user %s\n", u->u_name); + for (display = displays; display; display = nd) + { + nd = display->d_next; + if (D_forecv == 0) + continue; + flayer = D_forecv->c_layer; + fore = D_fore; + if (D_user != u) + continue; + debug1("AT display %s\n", D_usertty); + DoCommand(args + 1, argl + 1); + if (display) + OutputMsg(0, "command from %s: %s %s", + s, args[1], args[2] ? args[2] : ""); + display = NULL; + flayer = 0; + fore = NULL; + } + break; + } + case '%': /* display */ + { + struct display *nd; + + debug1("at display matching '%s'\n", args[0]); + for (display = displays; display; display = nd) + { + nd = display->d_next; + if (D_forecv == 0) + continue; + fore = D_fore; + flayer = D_forecv->c_layer; + if (strncmp(args[0], D_usertty, n) && + (strncmp("/dev/", D_usertty, 5) || + strncmp(args[0], D_usertty + 5, n)) && + (strncmp("/dev/tty", D_usertty, 8) || + strncmp(args[0], D_usertty + 8, n))) + continue; + debug1("AT display %s\n", D_usertty); + DoCommand(args + 1, argl + 1); + if (display) + OutputMsg(0, "command from %s: %s %s", + s, args[1], args[2] ? args[2] : ""); + display = NULL; + fore = NULL; + flayer = 0; + } + break; + } + case '#': /* window */ + n--; + /* FALLTHROUGH */ + default: + { + struct win *nw; + int ch; + + n++; + ch = args[0][n]; + args[0][n] = '\0'; + if (!*args[0] || (i = WindowByNumber(args[0])) < 0) + { + args[0][n] = ch; /* must restore string in case of bind */ + /* try looping over titles */ + for (fore = windows; fore; fore = nw) + { + nw = fore->w_next; + if (strncmp(args[0], fore->w_title, n)) + continue; + debug2("AT window %d(%s)\n", fore->w_number, fore->w_title); + /* + * consider this a bug or a feature: + * while looping through windows, we have fore AND + * display context. This will confuse users who try to + * set up loops inside of loops, but often allows to do + * what you mean, even when you adress your context wrong. + */ + i = 0; + /* XXX: other displays? */ + if (fore->w_layer.l_cvlist) + display = fore->w_layer.l_cvlist->c_display; + flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer; + DoCommand(args + 1, argl + 1); /* may destroy our display */ + if (fore && fore->w_layer.l_cvlist) + { + display = fore->w_layer.l_cvlist->c_display; + OutputMsg(0, "command from %s: %s %s", + s, args[1], args[2] ? args[2] : ""); + } + } + display = NULL; + fore = NULL; + if (i < 0) + OutputMsg(0, "%s: at '%s': no such window.\n", rc_name, args[0]); + break; + } + else if (i < maxwin && (fore = wtab[i])) + { + args[0][n] = ch; /* must restore string in case of bind */ + debug2("AT window %d (%s)\n", fore->w_number, fore->w_title); + if (fore->w_layer.l_cvlist) + display = fore->w_layer.l_cvlist->c_display; + flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer; + DoCommand(args + 1, argl + 1); + if (fore && fore->w_layer.l_cvlist) + { + display = fore->w_layer.l_cvlist->c_display; + OutputMsg(0, "command from %s: %s %s", + s, args[1], args[2] ? args[2] : ""); + } + display = NULL; + fore = NULL; + } + else + OutputMsg(0, "%s: at [identifier][%%|*|#] command [args]", rc_name); + break; + } + } + free(s); +#ifdef MULTIUSER + EffectiveAclUser = NULL; +#endif + break; + +#ifdef COPY_PASTE + case RC_READREG: +#ifdef ENCODINGS + i = fore ? fore->w_encoding : display ? display->d_encoding : 0; + if (args[0] && args[1] && !strcmp(args[0], "-e")) + { + i = FindEncoding(args[1]); + if (i == -1) + { + OutputMsg(0, "%s: readreg: unknown encoding", rc_name); + break; + } + args += 2; + } +#endif + /* + * Without arguments we prompt for a destination register. + * It will receive the copybuffer contents. + * This is not done by RC_PASTE, as we prompt for source + * (not dest) there. + */ + if ((s = *args) == NULL) + { + Input("Copy to register:", 1, INP_RAW, copy_reg_fn, NULL, 0); + break; + } + if (*argl != 1) + { + OutputMsg(0, "%s: copyreg: character, ^x, or (octal) \\032 expected.", rc_name); + break; + } + ch = args[0][0]; + /* + * With two arguments we *really* read register contents from file + */ + if (args[1]) + { + if (args[2]) + { + OutputMsg(0, "%s: readreg: too many arguments", rc_name); + break; + } + if ((s = ReadFile(args[1], &n))) + { + struct plop *pp = plop_tab + (int)(unsigned char)ch; + + if (pp->buf) + free(pp->buf); + pp->buf = s; + pp->len = n; +#ifdef ENCODINGS + pp->enc = i; +#endif + } + } + else + /* + * with one argument we copy the copybuffer into a specified register + * This could be done with RC_PASTE too, but is here to be consistent + * with the zero argument call. + */ + copy_reg_fn(&ch, 0, NULL); + break; +#endif + case RC_REGISTER: +#ifdef ENCODINGS + i = fore ? fore->w_encoding : display ? display->d_encoding : 0; + if (args[0] && args[1] && !strcmp(args[0], "-e")) + { + i = FindEncoding(args[1]); + if (i == -1) + { + OutputMsg(0, "%s: register: unknown encoding", rc_name); + break; + } + args += 2; + argc -= 2; + } +#endif + if (argc != 2) + { + OutputMsg(0, "%s: register: illegal number of arguments.", rc_name); + break; + } + if (*argl != 1) + { + OutputMsg(0, "%s: register: character, ^x, or (octal) \\032 expected.", rc_name); + break; + } + ch = args[0][0]; +#ifdef COPY_PASTE + if (ch == '.') + { + if (user->u_plop.buf != NULL) + UserFreeCopyBuffer(user); + if (args[1] && args[1][0]) + { + user->u_plop.buf = SaveStrn(args[1], argl[1]); + user->u_plop.len = argl[1]; +#ifdef ENCODINGS + user->u_plop.enc = i; +#endif + } + } + else +#endif + { + struct plop *plp = plop_tab + (int)(unsigned char)ch; + + if (plp->buf) + free(plp->buf); + plp->buf = SaveStrn(args[1], argl[1]); + plp->len = argl[1]; +#ifdef ENCODINGS + plp->enc = i; +#endif + } + break; + case RC_PROCESS: + if ((s = *args) == NULL) + { + Input("Process register:", 1, INP_RAW, process_fn, NULL, 0); + break; + } + if (*argl != 1) + { + OutputMsg(0, "%s: process: character, ^x, or (octal) \\032 expected.", rc_name); + break; + } + ch = args[0][0]; + process_fn(&ch, 0, NULL); + break; + case RC_STUFF: + s = *args; + if (!args[0]) + { + Input("Stuff:", 100, INP_COOKED, StuffFin, NULL, 0); + break; + } + n = *argl; + if (args[1]) + { + if (strcmp(s, "-k")) + { + OutputMsg(0, "%s: stuff: invalid option %s", rc_name, s); + break; + } + s = args[1]; + for (i = T_CAPS; i < T_OCAPS; i++) + if (strcmp(term[i].tcname, s) == 0) + break; + if (i == T_OCAPS) + { + OutputMsg(0, "%s: stuff: unknown key '%s'", rc_name, s); + break; + } +#ifdef MAPKEYS + if (StuffKey(i - T_CAPS) == 0) + break; +#endif + s = display ? D_tcs[i].str : 0; + if (s == 0) + break; + n = strlen(s); + } + while(n) + LayProcess(&s, &n); + break; + case RC_REDISPLAY: + Activate(-1); + break; + case RC_WINDOWS: + if (args[0]) { + ShowWindowsX(args[0]); + break; + } + ShowWindows(-1); + break; + case RC_VERSION: + OutputMsg(0, "screen %s", version); + break; + case RC_TIME: + if (*args) + { + timestring = SaveStr(*args); + break; + } + OutputMsg(0, "%s", MakeWinMsg(timestring, fore, '%')); + break; + case RC_INFO: + ShowInfo(); + break; + case RC_DINFO: + ShowDInfo(); + break; + case RC_COMMAND: + { + struct action *ktabp = ktab; + if (argc == 2 && !strcmp(*args, "-c")) + { + if ((ktabp = FindKtab(args[1], 0)) == 0) + { + OutputMsg(0, "Unknown command class '%s'", args[1]); + break; + } + } + if (D_ESCseen != ktab || ktabp != ktab) + { + if (D_ESCseen != ktabp) + { + D_ESCseen = ktabp; + WindowChanged(fore, 'E'); + } + break; + } + if (D_ESCseen) + { + D_ESCseen = 0; + WindowChanged(fore, 'E'); + } + } + /* FALLTHROUGH */ + case RC_OTHER: + if (MoreWindows()) + SwitchWindow(display && D_other ? D_other->w_number : NextWindow()); + break; + case RC_META: + if (user->u_Esc == -1) + break; + ch = user->u_Esc; + s = &ch; + n = 1; + LayProcess(&s, &n); + break; + case RC_XON: + ch = Ctrl('q'); + s = &ch; + n = 1; + LayProcess(&s, &n); + break; + case RC_XOFF: + ch = Ctrl('s'); + s = &ch; + n = 1; + LayProcess(&s, &n); + break; + case RC_DEFBREAKTYPE: + case RC_BREAKTYPE: + { + static char *types[] = { "TIOCSBRK", "TCSBRK", "tcsendbreak", NULL }; + extern int breaktype; + + if (*args) + { + if (ParseNum(act, &n)) + for (n = 0; n < (int)(sizeof(types)/sizeof(*types)); n++) + { + for (i = 0; i < 4; i++) + { + ch = args[0][i]; + if (ch >= 'a' && ch <= 'z') + ch -= 'a' - 'A'; + if (ch != types[n][i] && (ch + ('a' - 'A')) != types[n][i]) + break; + } + if (i == 4) + break; + } + if (n < 0 || n >= (int)(sizeof(types)/sizeof(*types))) + OutputMsg(0, "%s invalid, chose one of %s, %s or %s", *args, types[0], types[1], types[2]); + else + { + breaktype = n; + OutputMsg(0, "breaktype set to (%d) %s", n, types[n]); + } + } + else + OutputMsg(0, "breaktype is (%d) %s", breaktype, types[breaktype]); + } + break; + case RC_POW_BREAK: + case RC_BREAK: + n = 0; + if (*args && ParseNum(act, &n)) + break; + SendBreak(fore, n, nr == RC_POW_BREAK); + break; +#ifdef LOCK + case RC_LOCKSCREEN: + Detach(D_LOCK); + break; +#endif + case RC_WIDTH: + case RC_HEIGHT: + { + int w, h; + int what = 0; + + i = 1; + if (*args && !strcmp(*args, "-w")) + what = 1; + else if (*args && !strcmp(*args, "-d")) + what = 2; + if (what) + args++; + if (what == 0 && flayer && !display) + what = 1; + if (what == 1) + { + if (!flayer) + { + OutputMsg(0, "%s: %s: window required", rc_name, comms[nr].name); + break; + } + w = flayer->l_width; + h = flayer->l_height; + } + else + { + if (!display) + { + OutputMsg(0, "%s: %s: display required", rc_name, comms[nr].name); + break; + } + w = D_width; + h = D_height; + } + if (*args && args[0][0] == '-') + { + OutputMsg(0, "%s: %s: unknown option %s", rc_name, comms[nr].name, *args); + break; + } + if (nr == RC_HEIGHT) + { + if (!*args) + { +#define H0height 42 +#define H1height 24 + if (h == H0height) + h = H1height; + else if (h == H1height) + h = H0height; + else if (h > (H0height + H1height) / 2) + h = H0height; + else + h = H1height; + } + else + { + h = atoi(*args); + if (args[1]) + w = atoi(args[1]); + } + } + else + { + if (!*args) + { + if (w == Z0width) + w = Z1width; + else if (w == Z1width) + w = Z0width; + else if (w > (Z0width + Z1width) / 2) + w = Z0width; + else + w = Z1width; + } + else + { + w = atoi(*args); + if (args[1]) + h = atoi(args[1]); + } + } + if (*args && args[1] && args[2]) + { + OutputMsg(0, "%s: %s: too many arguments", rc_name, comms[nr].name); + break; + } + if (w <= 0) + { + OutputMsg(0, "Illegal width"); + break; + } + if (h <= 0) + { + OutputMsg(0, "Illegal height"); + break; + } + if (what == 1) + { + if (flayer->l_width == w && flayer->l_height == h) + break; + ResizeLayer(flayer, w, h, (struct display *)0); + break; + } + if (D_width == w && D_height == h) + break; + if (what == 2) + { + ChangeScreenSize(w, h, 1); + } + else + { + if (ResizeDisplay(w, h) == 0) + { + Activate(D_fore ? D_fore->w_norefresh : 0); + /* autofit */ + ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, 0); + break; + } + if (h == D_height) + OutputMsg(0, "Your termcap does not specify how to change the terminal's width to %d.", w); + else if (w == D_width) + OutputMsg(0, "Your termcap does not specify how to change the terminal's height to %d.", h); + else + OutputMsg(0, "Your termcap does not specify how to change the terminal's resolution to %dx%d.", w, h); + } + } + break; + case RC_DEFDYNAMICTITLE: + (void)ParseOnOff(act, &nwin_default.dynamicaka); + break; + case RC_DYNAMICTITLE: + (void)ParseOnOff(act, &fore->w_dynamicaka); + break; + case RC_TITLE: + if (queryflag >= 0) + { + if (fore) + OutputMsg(0, "%s", fore->w_title); + else + queryflag = -1; + break; + } + if (*args == 0) + InputAKA(); + else + ChangeAKA(fore, *args, strlen(*args)); + break; + case RC_COLON: + Input(":", MAXSTR, INP_EVERY, Colonfin, NULL, 0); + if (*args && **args) + { + s = *args; + n = strlen(s); + LayProcess(&s, &n); + } + break; + case RC_LASTMSG: + if (D_status_lastmsg) + OutputMsg(0, "%s", D_status_lastmsg); + break; + case RC_SCREEN: + DoScreen("key", args); + break; + case RC_WRAP: + if (ParseSwitch(act, &fore->w_wrap) == 0 && msgok) + OutputMsg(0, "%cwrap", fore->w_wrap ? '+' : '-'); + break; + case RC_FLOW: + if (*args) + { + if (args[0][0] == 'a') + { + fore->w_flow = (fore->w_flow & FLOW_AUTO) ? FLOW_AUTOFLAG |FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG; + } + else + { + if (ParseOnOff(act, &n)) + break; + fore->w_flow = (fore->w_flow & FLOW_AUTO) | n; + } + } + else + { + if (fore->w_flow & FLOW_AUTOFLAG) + fore->w_flow = (fore->w_flow & FLOW_AUTO) | FLOW_NOW; + else if (fore->w_flow & FLOW_NOW) + fore->w_flow &= ~FLOW_NOW; + else + fore->w_flow = fore->w_flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG; + } + SetFlow(fore->w_flow & FLOW_NOW); + if (msgok) + OutputMsg(0, "%cflow%s", (fore->w_flow & FLOW_NOW) ? '+' : '-', + (fore->w_flow & FLOW_AUTOFLAG) ? "(auto)" : ""); + break; +#ifdef MULTIUSER + case RC_DEFWRITELOCK: + if (args[0][0] == 'a') + nwin_default.wlock = WLOCK_AUTO; + else + { + if (ParseOnOff(act, &n)) + break; + nwin_default.wlock = n ? WLOCK_ON : WLOCK_OFF; + } + break; + case RC_WRITELOCK: + if (*args) + { + if (args[0][0] == 'a') + { + fore->w_wlock = WLOCK_AUTO; + } + else + { + if (ParseOnOff(act, &n)) + break; + fore->w_wlock = n ? WLOCK_ON : WLOCK_OFF; + } + /* + * user may have permission to change the writelock setting, + * but he may never aquire the lock himself without write permission + */ + if (!AclCheckPermWin(D_user, ACL_WRITE, fore)) + fore->w_wlockuser = D_user; + } + OutputMsg(0, "writelock %s", (fore->w_wlock == WLOCK_AUTO) ? "auto" : + ((fore->w_wlock == WLOCK_OFF) ? "off" : "on")); + break; +#endif + case RC_CLEAR: + ResetAnsiState(fore); + WriteString(fore, "\033[H\033[J", 6); + break; + case RC_RESET: + ResetAnsiState(fore); +#ifdef ZMODEM + if (fore->w_zdisplay) + zmodem_abort(fore, fore->w_zdisplay); +#endif + WriteString(fore, "\033c", 2); + break; + case RC_MONITOR: + n = fore->w_monitor != MON_OFF; +#ifdef MULTIUSER + if (display) + n = n && (ACLBYTE(fore->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id)); +#endif + if (ParseSwitch(act, &n)) + break; + if (n) + { +#ifdef MULTIUSER + if (display) /* we tell only this user */ + ACLBYTE(fore->w_mon_notify, D_user->u_id) |= ACLBIT(D_user->u_id); + else + for (i = 0; i < maxusercount; i++) + ACLBYTE(fore->w_mon_notify, i) |= ACLBIT(i); +#endif + if (fore->w_monitor == MON_OFF) + fore->w_monitor = MON_ON; + OutputMsg(0, "Window %d (%s) is now being monitored for all activity.", fore->w_number, fore->w_title); + } + else + { +#ifdef MULTIUSER + if (display) /* we remove only this user */ + ACLBYTE(fore->w_mon_notify, D_user->u_id) + &= ~ACLBIT(D_user->u_id); + else + for (i = 0; i < maxusercount; i++) + ACLBYTE(fore->w_mon_notify, i) &= ~ACLBIT(i); + for (i = maxusercount - 1; i >= 0; i--) + if (ACLBYTE(fore->w_mon_notify, i)) + break; + if (i < 0) +#endif + fore->w_monitor = MON_OFF; + OutputMsg(0, "Window %d (%s) is no longer being monitored for activity.", fore->w_number, fore->w_title); + } + break; +#ifdef MULTI + case RC_DISPLAYS: + display_displays(); + break; +#endif + case RC_WINDOWLIST: + if (!*args) + display_windows(0, WLIST_NUM, (struct win *)0); + else if (!strcmp(*args, "string")) + { + if (args[1]) + { + if (wliststr) + free(wliststr); + wliststr = SaveStr(args[1]); + } + if (msgok) + OutputMsg(0, "windowlist string is '%s'", wliststr); + } + else if (!strcmp(*args, "title")) + { + if (args[1]) + { + if (wlisttit) + free(wlisttit); + wlisttit = SaveStr(args[1]); + } + if (msgok) + OutputMsg(0, "windowlist title is '%s'", wlisttit); + } + else + { + int flag = 0; + int blank = 0; + for (i = 0; i < argc; i++) + if (!args[i]) + continue; + else if (!strcmp(args[i], "-m")) + flag |= WLIST_MRU; + else if (!strcmp(args[i], "-b")) + blank = 1; + else if (!strcmp(args[i], "-g")) + flag |= WLIST_NESTED; + else + { + OutputMsg(0, "usage: windowlist [-b] [-g] [-m] [string [string] | title [title]]"); + break; + } + if (i == argc) + display_windows(blank, flag, (struct win *)0); + } + break; + case RC_HELP: + if (argc == 2 && !strcmp(*args, "-c")) + { + struct action *ktabp; + if ((ktabp = FindKtab(args[1], 0)) == 0) + { + OutputMsg(0, "Unknown command class '%s'", args[1]); + break; + } + display_help(args[1], ktabp); + } + else + display_help((char *)0, ktab); + break; + case RC_LICENSE: + display_copyright(); + break; +#ifdef COPY_PASTE + case RC_COPY: + if (flayer->l_layfn != &WinLf) + { + OutputMsg(0, "Must be on a window layer"); + break; + } + MarkRoutine(); + WindowChanged(fore, 'P'); + break; + case RC_HISTORY: + { + static char *pasteargs[] = {".", 0}; + static int pasteargl[] = {1}; + + if (flayer->l_layfn != &WinLf) + { + OutputMsg(0, "Must be on a window layer"); + break; + } + if (GetHistory() == 0) + break; + if (user->u_plop.buf == NULL) + break; + args = pasteargs; + argl = pasteargl; + } + /*FALLTHROUGH*/ + case RC_PASTE: + { + char *ss, *dbuf, dch; + int l = 0; +# ifdef ENCODINGS + int enc = -1; +# endif + + /* + * without args we prompt for one(!) register to be pasted in the window + */ + if ((s = *args) == NULL) + { + Input("Paste from register:", 1, INP_RAW, ins_reg_fn, NULL, 0); + break; + } + if (args[1] == 0 && !fore) /* no window? */ + break; + /* + * with two arguments we paste into a destination register + * (no window needed here). + */ + if (args[1] && argl[1] != 1) + { + OutputMsg(0, "%s: paste destination: character, ^x, or (octal) \\032 expected.", + rc_name); + break; + } +# ifdef ENCODINGS + else if (fore) + enc = fore->w_encoding; +# endif + + /* + * measure length of needed buffer + */ + for (ss = s = *args; (ch = *ss); ss++) + { + if (ch == '.') + { +# ifdef ENCODINGS + if (enc == -1) + enc = user->u_plop.enc; + if (enc != user->u_plop.enc) + l += RecodeBuf((unsigned char *)user->u_plop.buf, user->u_plop.len, user->u_plop.enc, enc, (unsigned char *)0); + else +# endif + l += user->u_plop.len; + } + else + { +# ifdef ENCODINGS + if (enc == -1) + enc = plop_tab[(int)(unsigned char)ch].enc; + if (enc != plop_tab[(int)(unsigned char)ch].enc) + 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); + else +# endif + l += plop_tab[(int)(unsigned char)ch].len; + } + } + if (l == 0) + { + OutputMsg(0, "empty buffer"); + break; + } + /* + * shortcut: + * if there is only one source and the destination is a window, then + * pass a pointer rather than duplicating the buffer. + */ + if (s[1] == 0 && args[1] == 0) +# ifdef ENCODINGS + if (enc == (*s == '.' ? user->u_plop.enc : plop_tab[(int)(unsigned char)*s].enc)) +# endif + { + MakePaster(&fore->w_paster, *s == '.' ? user->u_plop.buf : plop_tab[(int)(unsigned char)*s].buf, l, 0); + break; + } + /* + * if no shortcut, we construct a buffer + */ + if ((dbuf = (char *)malloc(l)) == 0) + { + OutputMsg(0, "%s", strnomem); + break; + } + l = 0; + /* + * concatenate all sources into our own buffer, copy buffer is + * special and is skipped if no display exists. + */ + for (ss = s; (ch = *ss); ss++) + { + struct plop *pp = (ch == '.' ? &user->u_plop : &plop_tab[(int)(unsigned char)ch]); +#ifdef ENCODINGS + if (pp->enc != enc) + { + l += RecodeBuf((unsigned char *)pp->buf, pp->len, pp->enc, enc, (unsigned char *)dbuf + l); + continue; + } +#endif + bcopy(pp->buf, dbuf + l, pp->len); + l += pp->len; + } + /* + * when called with one argument we paste our buffer into the window + */ + if (args[1] == 0) + { + MakePaster(&fore->w_paster, dbuf, l, 1); + } + else + { + /* + * we have two arguments, the second is already in dch. + * use this as destination rather than the window. + */ + dch = args[1][0]; + if (dch == '.') + { + if (user->u_plop.buf != NULL) + UserFreeCopyBuffer(user); + user->u_plop.buf = dbuf; + user->u_plop.len = l; +#ifdef ENCODINGS + user->u_plop.enc = enc; +#endif + } + else + { + struct plop *pp = plop_tab + (int)(unsigned char)dch; + if (pp->buf) + free(pp->buf); + pp->buf = dbuf; + pp->len = l; +#ifdef ENCODINGS + pp->enc = enc; +#endif + } + } + break; + } + case RC_WRITEBUF: + if (!user->u_plop.buf) + { + OutputMsg(0, "empty buffer"); + break; + } +#ifdef ENCODINGS + { + struct plop oldplop; + + oldplop = user->u_plop; + if (args[0] && args[1] && !strcmp(args[0], "-e")) + { + int enc, l; + char *newbuf; + + enc = FindEncoding(args[1]); + if (enc == -1) + { + OutputMsg(0, "%s: writebuf: unknown encoding", rc_name); + break; + } + if (enc != oldplop.enc) + { + l = RecodeBuf((unsigned char *)oldplop.buf, oldplop.len, oldplop.enc, enc, (unsigned char *)0); + newbuf = malloc(l + 1); + if (!newbuf) + { + OutputMsg(0, "%s", strnomem); + break; + } + user->u_plop.len = RecodeBuf((unsigned char *)oldplop.buf, oldplop.len, oldplop.enc, enc, (unsigned char *)newbuf); + user->u_plop.buf = newbuf; + user->u_plop.enc = enc; + } + args += 2; + } +#endif + if (args[0] && args[1]) + OutputMsg(0, "%s: writebuf: too many arguments", rc_name); + else + WriteFile(user, args[0], DUMP_EXCHANGE); +#ifdef ENCODINGS + if (user->u_plop.buf != oldplop.buf) + free(user->u_plop.buf); + user->u_plop = oldplop; + } +#endif + break; + case RC_READBUF: +#ifdef ENCODINGS + i = fore ? fore->w_encoding : display ? display->d_encoding : 0; + if (args[0] && args[1] && !strcmp(args[0], "-e")) + { + i = FindEncoding(args[1]); + if (i == -1) + { + OutputMsg(0, "%s: readbuf: unknown encoding", rc_name); + break; + } + args += 2; + } +#endif + if (args[0] && args[1]) + { + OutputMsg(0, "%s: readbuf: too many arguments", rc_name); + break; + } + if ((s = ReadFile(args[0] ? args[0] : BufferFile, &n))) + { + if (user->u_plop.buf) + UserFreeCopyBuffer(user); + user->u_plop.len = n; + user->u_plop.buf = s; +#ifdef ENCODINGS + user->u_plop.enc = i; +#endif + } + break; + case RC_REMOVEBUF: + KillBuffers(); + break; + case RC_IGNORECASE: + (void)ParseSwitch(act, &search_ic); + if (msgok) + OutputMsg(0, "Will %signore case in searches", search_ic ? "" : "not "); + break; +#endif /* COPY_PASTE */ + case RC_ESCAPE: + if (*argl == 0) + SetEscape(user, -1, -1); + else if (*argl == 2) + SetEscape(user, (int)(unsigned char)args[0][0], (int)(unsigned char)args[0][1]); + else + { + OutputMsg(0, "%s: two characters required after escape.", rc_name); + break; + } + /* Change defescape if master user. This is because we only + * have one ktab. + */ + if (display && user != users) + break; + /* FALLTHROUGH */ + case RC_DEFESCAPE: + if (*argl == 0) + SetEscape(NULL, -1, -1); + else if (*argl == 2) + SetEscape(NULL, (int)(unsigned char)args[0][0], (int)(unsigned char)args[0][1]); + else + { + OutputMsg(0, "%s: two characters required after defescape.", rc_name); + break; + } +#ifdef MAPKEYS + CheckEscape(); +#endif + break; + case RC_CHDIR: + s = *args ? *args : home; + if (chdir(s) == -1) + OutputMsg(errno, "%s", s); + break; + case RC_SHELL: + case RC_DEFSHELL: + if (ParseSaveStr(act, &ShellProg) == 0) + ShellArgs[0] = ShellProg; + break; + case RC_HARDCOPYDIR: + if (*args) + (void)ParseSaveStr(act, &hardcopydir); + if (msgok) + OutputMsg(0, "hardcopydir is %s\n", hardcopydir && *hardcopydir ? hardcopydir : ""); + break; + case RC_LOGFILE: + if (*args) + { + char buf[1024]; + if (args[1] && !(strcmp(*args, "flush"))) + { + log_flush = atoi(args[1]); + if (msgok) + OutputMsg(0, "log flush timeout set to %ds\n", log_flush); + break; + } + if (ParseSaveStr(act, &screenlogfile)) + break; + if (fore && fore->w_log) + if (DoStartLog(fore, buf, sizeof(buf))) + OutputMsg(0, "Error opening logfile \"%s\"", buf); + if (!msgok) + break; + } + OutputMsg(0, "logfile is '%s'", screenlogfile); + break; + case RC_LOGTSTAMP: + if (!*args || !strcmp(*args, "on") || !strcmp(*args, "off")) + { + if (ParseSwitch(act, &logtstamp_on) == 0 && msgok) + OutputMsg(0, "timestamps turned %s", logtstamp_on ? "on" : "off"); + } + else if (!strcmp(*args, "string")) + { + if (args[1]) + { + if (logtstamp_string) + free(logtstamp_string); + logtstamp_string = SaveStr(args[1]); + } + if (msgok) + OutputMsg(0, "logfile timestamp is '%s'", logtstamp_string); + } + else if (!strcmp(*args, "after")) + { + if (args[1]) + { + logtstamp_after = atoi(args[1]); + if (!msgok) + break; + } + OutputMsg(0, "timestamp printed after %ds\n", logtstamp_after); + } + else + OutputMsg(0, "usage: logtstamp [after [n]|string [str]|on|off]"); + break; + case RC_SHELLTITLE: + (void)ParseSaveStr(act, &nwin_default.aka); + break; + case RC_TERMCAP: + case RC_TERMCAPINFO: + case RC_TERMINFO: + if (!rc_name || !*rc_name) + OutputMsg(0, "Sorry, too late now. Place that in your .screenrc file."); + break; + case RC_SLEEP: + break; /* Already handled */ + case RC_TERM: + s = NULL; + if (ParseSaveStr(act, &s)) + break; + if (strlen(s) > MAXTERMLEN) + { + OutputMsg(0, "%s: term: argument too long ( < %d)", rc_name, MAXTERMLEN); + free(s); + break; + } + strncpy(screenterm, s, MAXTERMLEN); + screenterm[MAXTERMLEN] = '\0'; + free(s); + debug1("screenterm set to %s\n", screenterm); + MakeTermcap((display == 0)); + debug("new termcap made\n"); + break; + case RC_ECHO: + if (!msgok && (!rc_name || strcmp(rc_name, "-X"))) + break; + /* + * user typed ^A:echo... well, echo isn't FinishRc's job, + * but as he wanted to test us, we show good will + */ + if (argc > 1 && !strcmp(*args, "-n")) + { + args++; + argc--; + } + s = *args; + if (argc > 1 && !strcmp(*args, "-p")) + { + args++; + argc--; + s = *args; + if (s) + s = MakeWinMsg(s, fore, '%'); + } + if (s) + OutputMsg(0, "%s", s); + else + { + OutputMsg(0, "%s: 'echo [-n] [-p] \"string\"' expected.", rc_name); + queryflag = -1; + } + break; + case RC_BELL: + case RC_BELL_MSG: + if (*args == 0) + { + char buf[256]; + AddXChars(buf, sizeof(buf), BellString); + OutputMsg(0, "bell_msg is '%s'", buf); + break; + } + (void)ParseSaveStr(act, &BellString); + break; +#ifdef COPY_PASTE + case RC_BUFFERFILE: + if (*args == 0) + BufferFile = SaveStr(DEFAULT_BUFFERFILE); + else if (ParseSaveStr(act, &BufferFile)) + break; + if (msgok) + OutputMsg(0, "Bufferfile is now '%s'", BufferFile); + break; +#endif + case RC_ACTIVITY: + (void)ParseSaveStr(act, &ActivityString); + break; +#if defined(DETACH) && defined(POW_DETACH) + case RC_POW_DETACH_MSG: + if (*args == 0) + { + char buf[256]; + AddXChars(buf, sizeof(buf), PowDetachString); + OutputMsg(0, "pow_detach_msg is '%s'", buf); + break; + } + (void)ParseSaveStr(act, &PowDetachString); + break; +#endif +#if defined(UTMPOK) && defined(LOGOUTOK) + case RC_LOGIN: + n = fore->w_slot != (slot_t)-1; + if (*args && !strcmp(*args, "always")) + { + fore->w_lflag = 3; + if (!displays && n) + SlotToggle(n); + break; + } + if (*args && !strcmp(*args, "attached")) + { + fore->w_lflag = 1; + if (!displays && n) + SlotToggle(0); + break; + } + if (ParseSwitch(act, &n) == 0) + SlotToggle(n); + break; + case RC_DEFLOGIN: + if (!strcmp(*args, "always")) + nwin_default.lflag |= 2; + else if (!strcmp(*args, "attached")) + nwin_default.lflag &= ~2; + else + (void)ParseOnOff(act, &nwin_default.lflag); + break; +#endif + case RC_DEFFLOW: + if (args[0] && args[1] && args[1][0] == 'i') + { + iflag = 1; + for (display = displays; display; display = display->d_next) + { + if (!D_flow) + continue; +#if defined(TERMIO) || defined(POSIX) + D_NewMode.tio.c_cc[VINTR] = D_OldMode.tio.c_cc[VINTR]; + D_NewMode.tio.c_lflag |= ISIG; +#else /* TERMIO || POSIX */ + D_NewMode.m_tchars.t_intrc = D_OldMode.m_tchars.t_intrc; +#endif /* TERMIO || POSIX */ + SetTTY(D_userfd, &D_NewMode); + } + } + if (args[0] && args[0][0] == 'a') + nwin_default.flowflag = FLOW_AUTOFLAG; + else + (void)ParseOnOff(act, &nwin_default.flowflag); + break; + case RC_DEFWRAP: + (void)ParseOnOff(act, &nwin_default.wrap); + break; + case RC_DEFC1: + (void)ParseOnOff(act, &nwin_default.c1); + break; +#ifdef COLOR + case RC_DEFBCE: + (void)ParseOnOff(act, &nwin_default.bce); + break; +#endif + case RC_DEFGR: + (void)ParseOnOff(act, &nwin_default.gr); + break; + case RC_DEFMONITOR: + if (ParseOnOff(act, &n) == 0) + nwin_default.monitor = (n == 0) ? MON_OFF : MON_ON; + break; + case RC_DEFMOUSETRACK: + if (ParseOnOff(act, &n) == 0) + defmousetrack = (n == 0) ? 0 : 1000; + break; + case RC_MOUSETRACK: + if (!args[0]) + { + OutputMsg(0, "Mouse tracking for this display is turned %s", D_mousetrack ? "on" : "off"); + } + else if (ParseOnOff(act, &n) == 0) + { + D_mousetrack = n == 0 ? 0 : 1000; + if (D_fore) + MouseMode(D_fore->w_mouse); + } + break; + case RC_DEFSILENCE: + if (ParseOnOff(act, &n) == 0) + nwin_default.silence = (n == 0) ? SILENCE_OFF : SILENCE_ON; + break; + case RC_VERBOSE: + if (!*args) + OutputMsg(0, "W%s echo command when creating windows.", + VerboseCreate ? "ill" : "on't"); + else if (ParseOnOff(act, &n) == 0) + VerboseCreate = n; + break; + case RC_HARDSTATUS: + if (display) + { + OutputMsg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */ + RemoveStatus(); + } + if (args[0] && strcmp(args[0], "on") && strcmp(args[0], "off")) + { + struct display *olddisplay = display; + int old_use, new_use = -1; + + s = args[0]; + if (!strncmp(s, "always", 6)) + s += 6; + if (!strcmp(s, "firstline")) + new_use = HSTATUS_FIRSTLINE; + else if (!strcmp(s, "lastline")) + new_use = HSTATUS_LASTLINE; + else if (!strcmp(s, "ignore")) + new_use = HSTATUS_IGNORE; + else if (!strcmp(s, "message")) + new_use = HSTATUS_MESSAGE; + else if (!strcmp(args[0], "string")) + { + if (!args[1]) + { + char buf[256]; + AddXChars(buf, sizeof(buf), hstatusstring); + OutputMsg(0, "hardstatus string is '%s'", buf); + break; + } + } + else + { + OutputMsg(0, "%s: usage: hardstatus [always]lastline|ignore|message|string [string]", rc_name); + break; + } + if (new_use != -1) + { + hardstatusemu = new_use | (s == args[0] ? 0 : HSTATUS_ALWAYS); + for (display = displays; display; display = display->d_next) + { + RemoveStatus(); + new_use = hardstatusemu & ~HSTATUS_ALWAYS; + if (D_HS && s == args[0]) + new_use = HSTATUS_HS; + ShowHStatus((char *)0); + old_use = D_has_hstatus; + D_has_hstatus = new_use; + if ((new_use == HSTATUS_LASTLINE && old_use != HSTATUS_LASTLINE) || (new_use != HSTATUS_LASTLINE && old_use == HSTATUS_LASTLINE)) + ChangeScreenSize(D_width, D_height, 1); + if ((new_use == HSTATUS_FIRSTLINE && old_use != HSTATUS_FIRSTLINE) || (new_use != HSTATUS_FIRSTLINE && old_use == HSTATUS_FIRSTLINE)) + ChangeScreenSize(D_width, D_height, 1); + RefreshHStatus(); + } + } + if (args[1]) + { + if (hstatusstring) + free(hstatusstring); + hstatusstring = SaveStr(args[1]); + for (display = displays; display; display = display->d_next) + RefreshHStatus(); + } + display = olddisplay; + break; + } + (void)ParseSwitch(act, &use_hardstatus); + if (msgok) + OutputMsg(0, "messages displayed on %s", use_hardstatus ? "hardstatus line" : "window"); + break; + case RC_CAPTION: + if (strcmp(args[0], "always") == 0 || strcmp(args[0], "splitonly") == 0) + { + struct display *olddisplay = display; + + captionalways = args[0][0] == 'a'; + for (display = displays; display; display = display->d_next) + ChangeScreenSize(D_width, D_height, 1); + display = olddisplay; + } + else if (strcmp(args[0], "string") == 0) + { + if (!args[1]) + { + char buf[256]; + AddXChars(buf, sizeof(buf), captionstring); + OutputMsg(0, "caption string is '%s'", buf); + break; + } + } + else + { + OutputMsg(0, "%s: usage: caption always|splitonly|string ", rc_name); + break; + } + if (!args[1]) + break; + if (captionstring) + free(captionstring); + captionstring = SaveStr(args[1]); + RedisplayDisplays(0); + break; + case RC_CONSOLE: + n = (console_window != 0); + if (ParseSwitch(act, &n)) + break; + if (TtyGrabConsole(fore->w_ptyfd, n, rc_name)) + break; + if (n == 0) + OutputMsg(0, "%s: releasing console %s", rc_name, HostName); + else if (console_window) + OutputMsg(0, "%s: stealing console %s from window %d (%s)", rc_name, + HostName, console_window->w_number, console_window->w_title); + else + OutputMsg(0, "%s: grabbing console %s", rc_name, HostName); + console_window = n ? fore : 0; + break; + case RC_ALLPARTIAL: + if (ParseOnOff(act, &all_norefresh)) + break; + if (!all_norefresh && fore) + Activate(-1); + if (msgok) + OutputMsg(0, all_norefresh ? "No refresh on window change!\n" : + "Window specific refresh\n"); + break; + case RC_PARTIAL: + (void)ParseSwitch(act, &n); + fore->w_norefresh = n; + break; + case RC_VBELL: + if (ParseSwitch(act, &visual_bell) || !msgok) + break; + if (visual_bell == 0) + OutputMsg(0, "switched to audible bell."); + else + OutputMsg(0, "switched to visual bell."); + break; + case RC_VBELLWAIT: + if (ParseNum1000(act, &VBellWait) == 0 && msgok) + OutputMsg(0, "vbellwait set to %.10g seconds", VBellWait/1000.); + break; + case RC_MSGWAIT: + if (ParseNum1000(act, &MsgWait) == 0 && msgok) + OutputMsg(0, "msgwait set to %.10g seconds", MsgWait/1000.); + break; + case RC_MSGMINWAIT: + if (ParseNum1000(act, &MsgMinWait) == 0 && msgok) + OutputMsg(0, "msgminwait set to %.10g seconds", MsgMinWait/1000.); + break; + case RC_SILENCEWAIT: + if (ParseNum(act, &SilenceWait)) + break; + if (SilenceWait < 1) + SilenceWait = 1; + for (p = windows; p; p = p->w_next) + p->w_silencewait = SilenceWait; + if (msgok) + OutputMsg(0, "silencewait set to %d seconds", SilenceWait); + break; + case RC_BUMPRIGHT: + if (fore->w_number < NextWindow()) + WindowChangeNumber(fore->w_number, NextWindow()); + break; + case RC_BUMPLEFT: + if (fore->w_number > PreviousWindow()) + WindowChangeNumber(fore->w_number, PreviousWindow()); + break; + case RC_COLLAPSE: + CollapseWindowlist(); + break; + case RC_NUMBER: + if (*args == 0) + OutputMsg(0, queryflag >= 0 ? "%d (%s)" : "This is window %d (%s).", fore->w_number, fore->w_title); + else + { + int old = fore->w_number; + int rel = 0, parse; + if (args[0][0] == '+') + rel = 1; + else if (args[0][0] == '-') + rel = -1; + if (rel) + ++act->args[0]; + parse = ParseNum(act, &n); + if (rel) + --act->args[0]; + if (parse) + break; + if (rel > 0) + n += old; + else if (rel < 0) + n = old - n; + if (!WindowChangeNumber(old, n)) + { + /* Window number could not be changed. */ + queryflag = -1; + return; + } + } + break; + + case RC_ZOMBIE_TIMEOUT: + if (argc != 1) { + Msg(0, "Setting zombie polling needs a timeout arg\n"); + break; + } + + nwin_default.poll_zombie_timeout = atoi(args[0]); + if (fore) + fore->w_poll_zombie_timeout = nwin_default.poll_zombie_timeout; + debug1("Setting zombie polling to %d\n", nwin_default.poll_zombie_timeout); + break; + + case RC_SORT: + if (fore) { + /* Better do not allow this. Not sure what the utmp stuff in number + * command above is for (you get four entries in e.g. /var/log/wtmp + * per number switch). But I don't know enough about this. + */ + Msg(0, "Sorting inside a window is not allowed. Push CTRL-a \" " + "and try again\n"); + break; + } + /* + * Simple sort algorithm: Look out for the smallest, put it + * to the first place, look out for the 2nd smallest, ... + */ + for (i = 0; i < maxwin ; i++) { + if (wtab[i] == NULL) + continue; + n = i; + + for (nr = i + 1; nr < maxwin; nr++) { + if (wtab[nr] == NULL) + continue; + debug2("Testing window %d and %d.\n", nr, n); + if (strcmp(wtab[nr]->w_title,wtab[n]->w_title) < 0) + n = nr; + } + + if (n != i) { + debug2("Exchange window %d and %d.\n", i, n); + p = wtab[n]; + wtab[n] = wtab[i]; + wtab[i] = p; + wtab[n]->w_number = n; + wtab[i]->w_number = i; +#ifdef MULTIUSER + /* exchange the acls for these windows. */ + AclWinSwap(i, n); +#endif + } + } + WindowChanged((struct win *)0, 0); + break; + + case RC_SILENCE: + n = fore->w_silence != 0; + i = fore->w_silencewait; + if (args[0] && (args[0][0] == '-' || (args[0][0] >= '0' && args[0][0] <= '9'))) + { + if (ParseNum(act, &i)) + break; + n = i > 0; + } + else if (ParseSwitch(act, &n)) + break; + if (n) + { +#ifdef MULTIUSER + if (display) /* we tell only this user */ + ACLBYTE(fore->w_lio_notify, D_user->u_id) |= ACLBIT(D_user->u_id); + else + for (n = 0; n < maxusercount; n++) + ACLBYTE(fore->w_lio_notify, n) |= ACLBIT(n); +#endif + fore->w_silencewait = i; + fore->w_silence = SILENCE_ON; + SetTimeout(&fore->w_silenceev, fore->w_silencewait * 1000); + evenq(&fore->w_silenceev); + + if (!msgok) + break; + OutputMsg(0, "The window is now being monitored for %d sec. silence.", fore->w_silencewait); + } + else + { +#ifdef MULTIUSER + if (display) /* we remove only this user */ + ACLBYTE(fore->w_lio_notify, D_user->u_id) + &= ~ACLBIT(D_user->u_id); + else + for (n = 0; n < maxusercount; n++) + ACLBYTE(fore->w_lio_notify, n) &= ~ACLBIT(n); + for (i = maxusercount - 1; i >= 0; i--) + if (ACLBYTE(fore->w_lio_notify, i)) + break; + if (i < 0) +#endif + { + fore->w_silence = SILENCE_OFF; + evdeq(&fore->w_silenceev); + } + if (!msgok) + break; + OutputMsg(0, "The window is no longer being monitored for silence."); + } + break; +#ifdef COPY_PASTE + case RC_DEFSCROLLBACK: + (void)ParseNum(act, &nwin_default.histheight); + break; + case RC_SCROLLBACK: + if (flayer->l_layfn == &MarkLf) + { + OutputMsg(0, "Cannot resize scrollback buffer in copy/scrollback mode."); + break; + } + (void)ParseNum(act, &n); + ChangeWindowSize(fore, fore->w_width, fore->w_height, n); + if (msgok) + OutputMsg(0, "scrollback set to %d", fore->w_histheight); + break; +#endif + case RC_SESSIONNAME: + if (*args == 0) + OutputMsg(0, "This session is named '%s'\n", SockName); + else + { + char buf[MAXPATHLEN]; + + s = 0; + if (ParseSaveStr(act, &s)) + break; + if (!*s || strlen(s) + (SockName - SockPath) > MAXPATHLEN - 13 || index(s, '/')) + { + OutputMsg(0, "%s: bad session name '%s'\n", rc_name, s); + free(s); + break; + } + strncpy(buf, SockPath, SockName - SockPath); + sprintf(buf + (SockName - SockPath), "%d.%s", (int)getpid(), s); + free(s); + if ((access(buf, F_OK) == 0) || (errno != ENOENT)) + { + OutputMsg(0, "%s: inappropriate path: '%s'.", rc_name, buf); + break; + } + if (rename(SockPath, buf)) + { + OutputMsg(errno, "%s: failed to rename(%s, %s)", rc_name, SockPath, buf); + break; + } + debug2("rename(%s, %s) done\n", SockPath, buf); + strcpy(SockPath, buf); + MakeNewEnv(); + WindowChanged((struct win *)0, 'S'); + } + break; + case RC_SETENV: + if (!args[0] || !args[1]) + { + debug1("RC_SETENV arguments missing: %s\n", args[0] ? args[0] : ""); + InputSetenv(args[0]); + } + else + { + xsetenv(args[0], args[1]); + MakeNewEnv(); + } + break; + case RC_UNSETENV: + unsetenv(*args); + MakeNewEnv(); + break; +#ifdef COPY_PASTE + case RC_DEFSLOWPASTE: + (void)ParseNum(act, &nwin_default.slow); + break; + case RC_SLOWPASTE: + if (*args == 0) + OutputMsg(0, fore->w_slowpaste ? + "Slowpaste in window %d is %d milliseconds." : + "Slowpaste in window %d is unset.", + fore->w_number, fore->w_slowpaste); + else if (ParseNum(act, &fore->w_slowpaste) == 0 && msgok) + OutputMsg(0, fore->w_slowpaste ? + "Slowpaste in window %d set to %d milliseconds." : + "Slowpaste in window %d now unset.", + fore->w_number, fore->w_slowpaste); + break; + case RC_MARKKEYS: + if (CompileKeys(*args, *argl, mark_key_tab)) + { + OutputMsg(0, "%s: markkeys: syntax error.", rc_name); + break; + } + debug1("markkeys %s\n", *args); + break; +# ifdef FONT + case RC_PASTEFONT: + if (ParseSwitch(act, &pastefont) == 0 && msgok) + OutputMsg(0, "Will %spaste font settings", pastefont ? "" : "not "); + break; +# endif + case RC_CRLF: + (void)ParseSwitch(act, &join_with_cr); + break; + case RC_COMPACTHIST: + if (ParseSwitch(act, &compacthist) == 0 && msgok) + OutputMsg(0, "%scompacting history lines", compacthist ? "" : "not "); + break; +#endif +#ifdef NETHACK + case RC_NETHACK: + (void)ParseOnOff(act, &nethackflag); + break; +#else + case RC_NETHACK: + Msg(0, "nethack disabled at build time"); + break; +#endif + case RC_HARDCOPY_APPEND: + (void)ParseOnOff(act, &hardcopy_append); + break; + case RC_VBELL_MSG: + if (*args == 0) + { + char buf[256]; + AddXChars(buf, sizeof(buf), VisualBellString); + OutputMsg(0, "vbell_msg is '%s'", buf); + break; + } + (void)ParseSaveStr(act, &VisualBellString); + debug1(" new vbellstr '%s'\n", VisualBellString); + break; + case RC_DEFMODE: + if (ParseBase(act, *args, &n, 8, "octal")) + break; + if (n < 0 || n > 0777) + { + OutputMsg(0, "%s: mode: Invalid tty mode %o", rc_name, n); + break; + } + TtyMode = n; + if (msgok) + OutputMsg(0, "Ttymode set to %03o", TtyMode); + break; + case RC_AUTODETACH: + (void)ParseOnOff(act, &auto_detach); + break; + case RC_STARTUP_MESSAGE: + (void)ParseOnOff(act, &default_startup); + break; +#ifdef PASSWORD + case RC_PASSWORD: + if (*args) + { + n = (*user->u_password) ? 1 : 0; + if (user->u_password != NullStr) free((char *)user->u_password); + user->u_password = SaveStr(*args); + if (!strcmp(user->u_password, "none")) + { + if (n) + OutputMsg(0, "Password checking disabled"); + free(user->u_password); + user->u_password = NullStr; + } + } + else + { + if (!fore) + { + OutputMsg(0, "%s: password: window required", rc_name); + break; + } + Input("New screen password:", 100, INP_NOECHO, pass1, display ? (char *)D_user : (char *)users, 0); + } + break; +#endif /* PASSWORD */ + case RC_BIND: + { + struct action *ktabp = ktab; + int kflag = 0; + + for (;;) + { + if (argc > 2 && !strcmp(*args, "-c")) + { + ktabp = FindKtab(args[1], 1); + if (ktabp == 0) + break; + args += 2; + argl += 2; + argc -= 2; + } + else if (argc > 1 && !strcmp(*args, "-k")) + { + kflag = 1; + args++; + argl++; + argc--; + } + else + break; + } +#ifdef MAPKEYS + if (kflag) + { + for (n = 0; n < KMAP_KEYS; n++) + if (strcmp(term[n + T_CAPS].tcname, *args) == 0) + break; + if (n == KMAP_KEYS) + { + OutputMsg(0, "%s: bind: unknown key '%s'", rc_name, *args); + break; + } + n += 256; + } + else +#endif + if (*argl != 1) + { + OutputMsg(0, "%s: bind: character, ^x, or (octal) \\032 expected.", rc_name); + break; + } + else + n = (unsigned char)args[0][0]; + + if (args[1]) + { + if ((i = FindCommnr(args[1])) == RC_ILLEGAL) + { + OutputMsg(0, "%s: bind: unknown command '%s'", rc_name, args[1]); + break; + } + if (CheckArgNum(i, args + 2) < 0) + break; + ClearAction(&ktabp[n]); + SaveAction(ktabp + n, i, args + 2, argl + 2); + } + else + ClearAction(&ktabp[n]); + } + break; +#ifdef MAPKEYS + case RC_BINDKEY: + { + struct action *newact; + int newnr, fl = 0, kf = 0, af = 0, df = 0, mf = 0; + struct display *odisp = display; + int used = 0; + struct kmap_ext *kme = NULL; + + for (; *args && **args == '-'; args++, argl++) + { + if (strcmp(*args, "-t") == 0) + fl = KMAP_NOTIMEOUT; + else if (strcmp(*args, "-k") == 0) + kf = 1; + else if (strcmp(*args, "-a") == 0) + af = 1; + else if (strcmp(*args, "-d") == 0) + df = 1; + else if (strcmp(*args, "-m") == 0) + mf = 1; + else if (strcmp(*args, "--") == 0) + { + args++; + argl++; + break; + } + else + { + OutputMsg(0, "%s: bindkey: invalid option %s", rc_name, *args); + return; + } + } + if (df && mf) + { + OutputMsg(0, "%s: bindkey: -d does not work with -m", rc_name); + break; + } + if (*args == 0) + { + if (mf) + display_bindkey("Edit mode", mmtab); + else if (df) + display_bindkey("Default", dmtab); + else + display_bindkey("User", umtab); + break; + } + if (kf == 0) + { + if (af) + { + OutputMsg(0, "%s: bindkey: -a only works with -k", rc_name); + break; + } + if (*argl == 0) + { + OutputMsg(0, "%s: bindkey: empty string makes no sense", rc_name); + break; + } + for (i = 0, kme = kmap_exts; i < kmap_extn; i++, kme++) + if (kme->str == 0) + { + if (args[1]) + break; + } + else + if (*argl == (kme->fl & ~KMAP_NOTIMEOUT) && bcmp(kme->str, *args, *argl) == 0) + break; + if (i == kmap_extn) + { + if (!args[1]) + { + OutputMsg(0, "%s: bindkey: keybinding not found", rc_name); + break; + } + kmap_extn += 8; + kmap_exts = (struct kmap_ext *)xrealloc((char *)kmap_exts, kmap_extn * sizeof(*kmap_exts)); + kme = kmap_exts + i; + bzero((char *)kme, 8 * sizeof(*kmap_exts)); + for (; i < kmap_extn; i++, kme++) + { + kme->str = 0; + kme->dm.nr = kme->mm.nr = kme->um.nr = RC_ILLEGAL; + kme->dm.args = kme->mm.args = kme->um.args = noargs; + kme->dm.argl = kme->mm.argl = kme->um.argl = 0; + } + i -= 8; + kme -= 8; + } + if (df == 0 && kme->dm.nr != RC_ILLEGAL) + used = 1; + if (mf == 0 && kme->mm.nr != RC_ILLEGAL) + used = 1; + if ((df || mf) && kme->um.nr != RC_ILLEGAL) + used = 1; + i += KMAP_KEYS + KMAP_AKEYS; + newact = df ? &kme->dm : mf ? &kme->mm : &kme->um; + } + else + { + for (i = T_CAPS; i < T_OCAPS; i++) + if (strcmp(term[i].tcname, *args) == 0) + break; + if (i == T_OCAPS) + { + OutputMsg(0, "%s: bindkey: unknown key '%s'", rc_name, *args); + break; + } + if (af && i >= T_CURSOR && i < T_OCAPS) + i -= T_CURSOR - KMAP_KEYS; + else + i -= T_CAPS; + newact = df ? &dmtab[i] : mf ? &mmtab[i] : &umtab[i]; + } + if (args[1]) + { + if ((newnr = FindCommnr(args[1])) == RC_ILLEGAL) + { + OutputMsg(0, "%s: bindkey: unknown command '%s'", rc_name, args[1]); + break; + } + if (CheckArgNum(newnr, args + 2) < 0) + break; + ClearAction(newact); + SaveAction(newact, newnr, args + 2, argl + 2); + if (kf == 0 && args[1]) + { + if (kme->str) + free(kme->str); + kme->str = SaveStrn(*args, *argl); + kme->fl = fl | *argl; + } + } + else + ClearAction(newact); + for (display = displays; display; display = display->d_next) + remap(i, args[1] ? 1 : 0); + if (kf == 0 && !args[1]) + { + if (!used && kme->str) + { + free(kme->str); + kme->str = 0; + kme->fl = 0; + } + } + display = odisp; + } + break; + case RC_MAPTIMEOUT: + if (*args) + { + if (ParseNum(act, &n)) + break; + if (n < 0) + { + OutputMsg(0, "%s: maptimeout: illegal time %d", rc_name, n); + break; + } + maptimeout = n; + } + if (*args == 0 || msgok) + OutputMsg(0, "maptimeout is %dms", maptimeout); + break; + case RC_MAPNOTNEXT: + D_dontmap = 1; + break; + case RC_MAPDEFAULT: + D_mapdefault = 1; + break; +#endif +#ifdef MULTIUSER + case RC_ACLCHG: + case RC_ACLADD: + case RC_ADDACL: + case RC_CHACL: + UsersAcl(NULL, argc, args); + break; + case RC_ACLDEL: + if (UserDel(args[0], NULL)) + break; + if (msgok) + OutputMsg(0, "%s removed from acl database", args[0]); + break; + case RC_ACLGRP: + /* + * modify a user to gain or lose rights granted to a group. + * This group is actually a normal user whose rights were defined + * with chacl in the usual way. + */ + if (args[1]) + { + if (strcmp(args[1], "none")) /* link a user to another user */ + { + if (AclLinkUser(args[0], args[1])) + break; + if (msgok) + OutputMsg(0, "User %s joined acl-group %s", args[0], args[1]); + } + else /* remove all groups from user */ + { + struct acluser *u; + struct aclusergroup *g; + + if (!(u = *FindUserPtr(args[0]))) + break; + while ((g = u->u_group)) + { + u->u_group = g->next; + free((char *)g); + } + } + } + else /* show all groups of user */ + { + char buf[256], *p = buf; + int ngroups = 0; + struct acluser *u; + struct aclusergroup *g; + + if (!(u = *FindUserPtr(args[0]))) + { + if (msgok) + OutputMsg(0, "User %s does not exist.", args[0]); + break; + } + g = u->u_group; + while (g) + { + ngroups++; + sprintf(p, "%s ", g->u->u_name); + p += strlen(p); + if (p > buf+200) + break; + g = g->next; + } + if (ngroups) + *(--p) = '\0'; + OutputMsg(0, "%s's group%s: %s.", args[0], (ngroups == 1) ? "" : "s", + (ngroups == 0) ? "none" : buf); + } + break; + case RC_ACLUMASK: + case RC_UMASK: + while ((s = *args++)) + { + char *err = 0; + + if (AclUmask(display ? D_user : users, s, &err)) + OutputMsg(0, "umask: %s\n", err); + } + break; + case RC_MULTIUSER: + if (ParseOnOff(act, &n)) + break; + multi = n ? "" : 0; + chsock(); + if (msgok) + OutputMsg(0, "Multiuser mode %s", multi ? "enabled" : "disabled"); + break; +#endif /* MULTIUSER */ +#ifdef PSEUDOS + case RC_EXEC: + winexec(args); + break; +#endif +#ifdef MULTI + case RC_NONBLOCK: + i = D_nonblock >= 0; + if (*args && ((args[0][0] >= '0' && args[0][0] <= '9') || args[0][0] == '.')) + { + if (ParseNum1000(act, &i)) + break; + } + else if (!ParseSwitch(act, &i)) + i = i == 0 ? -1 : 1000; + else + break; + if (msgok && i == -1) + OutputMsg(0, "display set to blocking mode"); + else if (msgok && i == 0) + OutputMsg(0, "display set to nonblocking mode, no timeout"); + else if (msgok) + OutputMsg(0, "display set to nonblocking mode, %.10gs timeout", i/1000.); + D_nonblock = i; + if (D_nonblock <= 0) + evdeq(&D_blockedev); + break; + case RC_DEFNONBLOCK: + if (*args && ((args[0][0] >= '0' && args[0][0] <= '9') || args[0][0] == '.')) + { + if (ParseNum1000(act, &defnonblock)) + break; + } + else if (!ParseOnOff(act, &defnonblock)) + defnonblock = defnonblock == 0 ? -1 : 1000; + else + break; + if (display && *rc_name) + { + D_nonblock = defnonblock; + if (D_nonblock <= 0) + evdeq(&D_blockedev); + } + break; +#endif + case RC_GR: +#ifdef ENCODINGS + if (fore->w_gr == 2) + fore->w_gr = 0; +#endif + if (ParseSwitch(act, &fore->w_gr) == 0 && msgok) + OutputMsg(0, "Will %suse GR", fore->w_gr ? "" : "not "); +#ifdef ENCODINGS + if (fore->w_gr == 0 && fore->w_FontE) + fore->w_gr = 2; +#endif + break; + case RC_C1: + if (ParseSwitch(act, &fore->w_c1) == 0 && msgok) + OutputMsg(0, "Will %suse C1", fore->w_c1 ? "" : "not "); + break; +#ifdef COLOR + case RC_BCE: + if (ParseSwitch(act, &fore->w_bce) == 0 && msgok) + OutputMsg(0, "Will %serase with background color", fore->w_bce ? "" : "not "); + break; +#endif +#ifdef ENCODINGS + case RC_KANJI: + case RC_ENCODING: +#ifdef UTF8 + if (*args && !strcmp(args[0], "-d")) + { + if (!args[1]) + OutputMsg(0, "encodings directory is %s", screenencodings ? screenencodings : ""); + else + { + free(screenencodings); + screenencodings = SaveStr(args[1]); + } + break; + } + if (*args && !strcmp(args[0], "-l")) + { + if (!args[1]) + OutputMsg(0, "encoding: -l: argument required"); + else if (LoadFontTranslation(-1, args[1])) + OutputMsg(0, "encoding: could not load utf8 encoding file"); + else if (msgok) + OutputMsg(0, "encoding: utf8 encoding file loaded"); + break; + } +#else + if (*args && (!strcmp(args[0], "-l") || !strcmp(args[0], "-d"))) + { + if (msgok) + OutputMsg(0, "encoding: screen is not compiled for UTF-8."); + break; + } +#endif + for (i = 0; i < 2; i++) + { + if (args[i] == 0) + break; + if (!strcmp(args[i], ".")) + continue; + n = FindEncoding(args[i]); + if (n == -1) + { + OutputMsg(0, "encoding: unknown encoding '%s'", args[i]); + break; + } + if (i == 0 && fore) + { + WinSwitchEncoding(fore, n); + ResetCharsets(fore); + } + else if (i && display) + D_encoding = n; + } + break; + case RC_DEFKANJI: + case RC_DEFENCODING: + n = FindEncoding(*args); + if (n == -1) + { + OutputMsg(0, "defencoding: unknown encoding '%s'", *args); + break; + } + nwin_default.encoding = n; + break; +#endif + +#ifdef UTF8 + case RC_DEFUTF8: + n = nwin_default.encoding == UTF8; + if (ParseSwitch(act, &n) == 0) + { + nwin_default.encoding = n ? UTF8 : 0; + if (msgok) + OutputMsg(0, "Will %suse UTF-8 encoding for new windows", n ? "" : "not "); + } + break; + case RC_UTF8: + for (i = 0; i < 2; i++) + { + if (i && args[i] == 0) + break; + if (args[i] == 0) + n = fore->w_encoding != UTF8; + else if (strcmp(args[i], "off") == 0) + n = 0; + else if (strcmp(args[i], "on") == 0) + n = 1; + else + { + OutputMsg(0, "utf8: illegal argument (%s)", args[i]); + break; + } + if (i == 0) + { + WinSwitchEncoding(fore, n ? UTF8 : 0); + if (msgok) + OutputMsg(0, "Will %suse UTF-8 encoding", n ? "" : "not "); + } + else if (display) + D_encoding = n ? UTF8 : 0; + if (args[i] == 0) + break; + } + break; +#endif + + case RC_PRINTCMD: + if (*args) + { + if (printcmd) + free(printcmd); + printcmd = 0; + if (**args) + printcmd = SaveStr(*args); + } + if (*args == 0 || msgok) + { + if (printcmd) + OutputMsg(0, "using '%s' as print command", printcmd); + else + OutputMsg(0, "using termcap entries for printing"); + break; + } + break; + + case RC_DIGRAPH: + if (argl && argl[0] > 0 && args[1] && argl[1] > 0) + { + if (argl[0] != 2) + { + OutputMsg(0, "Two characters expected to define a digraph"); + break; + } + i = digraph_find(args[0]); + digraphs[i].d[0] = args[0][0]; + digraphs[i].d[1] = args[0][1]; + if (!parse_input_int(args[1], argl[1], &digraphs[i].value)) + { + if (!(digraphs[i].value = atoi(args[1]))) + { + if (!args[1][1]) + digraphs[i].value = (int)args[1][0]; +#ifdef UTF8 + else + { + int t; + unsigned char *s = (unsigned char *)args[1]; + digraphs[i].value = 0; + while (*s) + { + t = FromUtf8(*s++, &digraphs[i].value); + if (t == -1) + continue; + if (t == -2) + digraphs[i].value = 0; + else + digraphs[i].value = t; + break; + } + } +#endif + } + } + break; + } + Input("Enter digraph: ", 10, INP_EVERY, digraph_fn, NULL, 0); + if (*args && **args) + { + s = *args; + n = strlen(s); + LayProcess(&s, &n); + } + break; + + case RC_DEFHSTATUS: + if (*args == 0) + { + char buf[256]; + *buf = 0; + if (nwin_default.hstatus) + AddXChars(buf, sizeof(buf), nwin_default.hstatus); + OutputMsg(0, "default hstatus is '%s'", buf); + break; + } + (void)ParseSaveStr(act, &nwin_default.hstatus); + if (*nwin_default.hstatus == 0) + { + free(nwin_default.hstatus); + nwin_default.hstatus = 0; + } + break; + case RC_HSTATUS: + (void)ParseSaveStr(act, &fore->w_hstatus); + if (*fore->w_hstatus == 0) + { + free(fore->w_hstatus); + fore->w_hstatus = 0; + } + WindowChanged(fore, 'h'); + break; + +#ifdef FONT + case RC_DEFCHARSET: + case RC_CHARSET: + if (*args == 0) + { + char buf[256]; + *buf = 0; + if (nwin_default.charset) + AddXChars(buf, sizeof(buf), nwin_default.charset); + OutputMsg(0, "default charset is '%s'", buf); + break; + } + n = strlen(*args); + if (n == 0 || n > 6) + { + OutputMsg(0, "%s: %s: string has illegal size.", rc_name, comms[nr].name); + break; + } + if (n > 4 && ( + ((args[0][4] < '0' || args[0][4] > '3') && args[0][4] != '.') || + ((args[0][5] < '0' || args[0][5] > '3') && args[0][5] && args[0][5] != '.'))) + { + OutputMsg(0, "%s: %s: illegal mapping number.", rc_name, comms[nr].name); + break; + } + if (nr == RC_CHARSET) + { + SetCharsets(fore, *args); + break; + } + if (nwin_default.charset) + free(nwin_default.charset); + nwin_default.charset = SaveStr(*args); + break; +#endif +#ifdef COLOR + case RC_ATTRCOLOR: + s = args[0]; + if (*s >= '0' && *s <= '9') + i = *s - '0'; + else + for (i = 0; i < 8; i++) + if (*s == "dubrsBiI"[i]) + break; + s++; + nr = 0; + if (*s && s[1] && !s[2]) + { + if (*s == 'd' && s[1] == 'd') + nr = 3; + else if (*s == '.' && s[1] == 'd') + nr = 2; + else if (*s == 'd' && s[1] == '.') + nr = 1; + else if (*s != '.' || s[1] != '.') + s--; + s += 2; + } + if (*s || i < 0 || i >= 8) + { + OutputMsg(0, "%s: attrcolor: unknown attribute '%s'.", rc_name, args[0]); + break; + } + n = 0; + if (args[1]) + n = ParseAttrColor(args[1], args[2], 1); + if (n == -1) + break; + attr2color[i][nr] = n; + n = 0; + for (i = 0; i < 8; i++) + if (attr2color[i][0] || attr2color[i][1] || attr2color[i][2] || attr2color[i][3]) + n |= 1 << i; + nattr2color = n; + break; +#endif + case RC_RENDITION: + i = -1; + if (strcmp(args[0], "bell") == 0) + { + i = REND_BELL; + } + else if (strcmp(args[0], "monitor") == 0) + { + i = REND_MONITOR; + } + else if (strcmp(args[0], "silence") == 0) + { + i = REND_SILENCE; + } + else if (strcmp(args[0], "so") != 0) + { + OutputMsg(0, "Invalid option '%s' for rendition", args[0]); + break; + } + + ++args; + ++argl; + + if (i != -1) + { + renditions[i] = ParseAttrColor(args[0], args[1], 1); + WindowChanged((struct win *)0, 'w'); + WindowChanged((struct win *)0, 'W'); + WindowChanged((struct win *)0, 0); + break; + } + + /* We are here, means we want to set the sorendition. */ + /* FALLTHROUGH*/ + case RC_SORENDITION: + i = 0; + if (*args) + { + i = ParseAttrColor(*args, args[1], 1); + if (i == -1) + break; + ApplyAttrColor(i, &mchar_so); + WindowChanged((struct win *)0, 0); + debug2("--> %x %x\n", mchar_so.attr, mchar_so.color); + } + if (msgok) +#ifdef COLOR + OutputMsg(0, "Standout attributes 0x%02x color 0x%02x", (unsigned char)mchar_so.attr, 0x99 ^ (unsigned char)mchar_so.color); +#else + OutputMsg(0, "Standout attributes 0x%02x ", (unsigned char)mchar_so.attr); +#endif + break; + + case RC_SOURCE: + do_source(*args); + break; + +#ifdef MULTIUSER + case RC_SU: + s = NULL; + if (!*args) + { + OutputMsg(0, "%s:%s screen login", HostName, SockPath); + InputSu(D_fore, &D_user, NULL); + } + else if (!args[1]) + InputSu(D_fore, &D_user, args[0]); + else if (!args[2]) + s = DoSu(&D_user, args[0], args[1], "\377"); + else + s = DoSu(&D_user, args[0], args[1], args[2]); + if (s) + OutputMsg(0, "%s", s); + break; +#endif /* MULTIUSER */ + case RC_SPLIT: + s = args[0]; + if (s && !strcmp(s, "-v")) + AddCanvas(SLICE_HORI); + else + AddCanvas(SLICE_VERT); + Activate(-1); + break; + case RC_REMOVE: + RemCanvas(); + Activate(-1); + break; + case RC_ONLY: + OneCanvas(); + Activate(-1); + break; + case RC_FIT: + D_forecv->c_xoff = D_forecv->c_xs; + D_forecv->c_yoff = D_forecv->c_ys; + RethinkViewportOffsets(D_forecv); + ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, 0); + flayer = D_forecv->c_layer; + LaySetCursor(); + break; + case RC_FOCUS: + { + struct canvas *cv = 0; + if (!*args || !strcmp(*args, "next")) + cv = D_forecv->c_next ? D_forecv->c_next : D_cvlist; + else if (!strcmp(*args, "prev")) + { + for (cv = D_cvlist; cv->c_next && cv->c_next != D_forecv; cv = cv->c_next) + ; + } + else if (!strcmp(*args, "top")) + cv = D_cvlist; + else if (!strcmp(*args, "bottom")) + { + for (cv = D_cvlist; cv->c_next; cv = cv->c_next) + ; + } + else if (!strcmp(*args, "up")) + cv = FindCanvas(D_forecv->c_xs, D_forecv->c_ys - 1); + else if (!strcmp(*args, "down")) + cv = FindCanvas(D_forecv->c_xs, D_forecv->c_ye + 2); + else if (!strcmp(*args, "left")) + cv = FindCanvas(D_forecv->c_xs - 1, D_forecv->c_ys); + else if (!strcmp(*args, "right")) + cv = FindCanvas(D_forecv->c_xe + 1, D_forecv->c_ys); + else + { + OutputMsg(0, "%s: usage: focus [next|prev|up|down|left|right|top|bottom]", rc_name); + break; + } + SetForeCanvas(display, cv); + } + break; + case RC_RESIZE: + i = 0; + if (D_forecv->c_slorient == SLICE_UNKN) + { + OutputMsg(0, "resize: need more than one region"); + break; + } + for (; *args; args++) + { + if (!strcmp(*args, "-h")) + i |= RESIZE_FLAG_H; + else if (!strcmp(*args, "-v")) + i |= RESIZE_FLAG_V; + else if (!strcmp(*args, "-b")) + i |= RESIZE_FLAG_H | RESIZE_FLAG_V; + else if (!strcmp(*args, "-p")) + i |= D_forecv->c_slorient == SLICE_VERT ? RESIZE_FLAG_H : RESIZE_FLAG_V; + else if (!strcmp(*args, "-l")) + i |= RESIZE_FLAG_L; + else + break; + } + if (*args && args[1]) + { + OutputMsg(0, "%s: usage: resize [-h] [-v] [-l] [num]\n", rc_name); + break; + } + if (*args) + ResizeRegions(*args, i); + else + Input(resizeprompts[i], 20, INP_EVERY, ResizeFin, (char*)0, i); + break; + case RC_SETSID: + (void)ParseSwitch(act, &separate_sids); + break; + case RC_EVAL: + args = SaveArgs(args); + for (i = 0; args[i]; i++) + { + if (args[i][0]) + Colonfin(args[i], strlen(args[i]), (char *)0); + free(args[i]); + } + free(args); + break; + case RC_ALTSCREEN: + (void)ParseSwitch(act, &use_altscreen); + if (msgok) + OutputMsg(0, "Will %sdo alternate screen switching", use_altscreen ? "" : "not "); + break; + case RC_MAXWIN: + if (!args[0]) + { + OutputMsg(0, "maximum windows allowed: %d", maxwin); + break; + } + if (ParseNum(act, &n)) + break; + if (n < 1) + OutputMsg(0, "illegal maxwin number specified"); + else if (n > 2048) + OutputMsg(0, "maximum 2048 windows allowed"); + else if (n > maxwin && windows) + OutputMsg(0, "may increase maxwin only when there's no window"); + else + { + if (!windows) + { + wtab = realloc(wtab, n * sizeof(struct win *)); + bzero(wtab, n * sizeof(struct win *)); + } + maxwin = n; + } + break; + case RC_BACKTICK: + if (ParseBase(act, *args, &n, 10, "decimal")) + break; + if (!args[1]) + setbacktick(n, 0, 0, (char **)0); + else + { + int lifespan, tick; + if (argc < 4) + { + OutputMsg(0, "%s: usage: backtick num [lifespan tick cmd args...]", rc_name); + break; + } + if (ParseBase(act, args[1], &lifespan, 10, "decimal")) + break; + if (ParseBase(act, args[2], &tick, 10, "decimal")) + break; + setbacktick(n, lifespan, tick, SaveArgs(args + 3)); + } + WindowChanged(0, '`'); + break; + case RC_BLANKER: +#ifdef BLANKER_PRG + if (blankerprg) + { + RunBlanker(blankerprg); + break; + } +#endif + ClearAll(); + CursorVisibility(-1); + D_blocked = 4; + break; +#ifdef BLANKER_PRG + case RC_BLANKERPRG: + if (!args[0]) + { + if (blankerprg) + { + char path[MAXPATHLEN]; + char *p = path, **pp; + for (pp = blankerprg; *pp; pp++) + p += snprintf(p, sizeof(path) - (p - path) - 1, "%s ", *pp); + *(p - 1) = '\0'; + OutputMsg(0, "blankerprg: %s", path); + } + else + OutputMsg(0, "No blankerprg set."); + break; + } + if (blankerprg) + { + char **pp; + for (pp = blankerprg; *pp; pp++) + free(*pp); + free(blankerprg); + blankerprg = 0; + } + if (args[0][0]) + blankerprg = SaveArgs(args); + break; +#endif + case RC_IDLE: + if (*args) + { + struct display *olddisplay = display; + if (!strcmp(*args, "off")) + idletimo = 0; + else if (args[0][0]) + idletimo = atoi(*args) * 1000; + if (argc > 1) + { + if ((i = FindCommnr(args[1])) == RC_ILLEGAL) + { + OutputMsg(0, "%s: idle: unknown command '%s'", rc_name, args[1]); + break; + } + if (CheckArgNum(i, args + 2) < 0) + break; + ClearAction(&idleaction); + SaveAction(&idleaction, i, args + 2, argl + 2); + } + for (display = displays; display; display = display->d_next) + ResetIdle(); + display = olddisplay; + } + if (msgok) + { + if (idletimo) + OutputMsg(0, "idle timeout %ds, %s", idletimo / 1000, comms[idleaction.nr].name); + else + OutputMsg(0, "idle off"); + } + break; + case RC_FOCUSMINSIZE: + for (i = 0; i < 2 && args[i]; i++) + { + if (!strcmp(args[i], "max") || !strcmp(args[i], "_")) + n = -1; + else + n = atoi(args[i]); + if (i == 0) + focusminwidth = n; + else + focusminheight = n; + } + if (msgok) + { + char b[2][20]; + for (i = 0; i < 2; i++) + { + n = i == 0 ? focusminwidth : focusminheight; + if (n == -1) + strcpy(b[i], "max"); + else + sprintf(b[i], "%d", n); + } + OutputMsg(0, "focus min size is %s %s\n", b[0], b[1]); + } + break; + case RC_GROUP: + if (*args) + { + fore->w_group = 0; + if (args[0][0]) + { + fore->w_group = WindowByName(*args); + if (fore->w_group == fore || (fore->w_group && fore->w_group->w_type != W_TYPE_GROUP)) + fore->w_group = 0; + } + WindowChanged((struct win *)0, 'w'); + WindowChanged((struct win *)0, 'W'); + WindowChanged((struct win *)0, 0); + } + if (msgok) + { + if (fore->w_group) + OutputMsg(0, "window group is %d (%s)\n", fore->w_group->w_number, fore->w_group->w_title); + else + OutputMsg(0, "window belongs to no group"); + } + break; + case RC_LAYOUT: + // A number of the subcommands for "layout" are ignored, or not processed correctly when there + // is no attached display. + + if (!strcmp(args[0], "title")) + { + if (!display) + { + if (!args[1]) // There is no display, and there is no new title. Ignore. + break; + if (!layout_attach || layout_attach == &layout_last_marker) + layout_attach = CreateLayout(args[1], 0); + else + RenameLayout(layout_attach, args[1]); + break; + } + + if (!D_layout) + { + OutputMsg(0, "not on a layout"); + break; + } + if (!args[1]) + { + OutputMsg(0, "current layout is %d (%s)", D_layout->lay_number, D_layout->lay_title); + break; + } + RenameLayout(D_layout, args[1]); + } + else if (!strcmp(args[0], "number")) + { + if (!display) + { + if (args[1] && layout_attach && layout_attach != &layout_last_marker) + RenumberLayout(layout_attach, atoi(args[1])); + break; + } + + if (!D_layout) + { + OutputMsg(0, "not on a layout"); + break; + } + if (!args[1]) + { + OutputMsg(0, "This is layout %d (%s).\n", D_layout->lay_number, D_layout->lay_title); + break; + } + RenumberLayout(D_layout, atoi(args[1])); + break; + } + else if (!strcmp(args[0], "autosave")) + { + if (!display) + { + if (args[1] && layout_attach && layout_attach != &layout_last_marker) + { + if (!strcmp(args[1], "on")) + layout_attach->lay_autosave = 1; + else if (!strcmp(args[1], "off")) + layout_attach->lay_autosave = 0; + } + break; + } + + if (!D_layout) + { + OutputMsg(0, "not on a layout"); + break; + } + if (args[1]) + { + if (!strcmp(args[1], "on")) + D_layout->lay_autosave = 1; + else if (!strcmp(args[1], "off")) + D_layout->lay_autosave = 0; + else + { + OutputMsg(0, "invalid argument. Give 'on' or 'off"); + break; + } + } + if (msgok) + OutputMsg(0, "autosave is %s", D_layout->lay_autosave ? "on" : "off"); + } + else if (!strcmp(args[0], "new")) + { + char *t = args[1]; + n = 0; + if (t) + { + while (*t >= '0' && *t <= '9') + t++; + if (t != args[1] && (!*t || *t == ':')) + { + n = atoi(args[1]); + if (*t) + t++; + } + else + t = args[1]; + } + if (!t || !*t) + t = "layout"; + NewLayout(t, n); + Activate(-1); + } + else if (!strcmp(args[0], "save")) + { + if (!args[1]) + { + OutputMsg(0, "usage: layout save "); + break; + } + if (display) + SaveLayout(args[1], &D_canvas); + } + else if (!strcmp(args[0], "select")) + { + if (!display) + { + if (args[1]) + layout_attach = FindLayout(args[1]); + break; + } + if (!args[1]) + { + Input("Switch to layout: ", 20, INP_COOKED, SelectLayoutFin, NULL, 0); + break; + } + SelectLayoutFin(args[1], strlen(args[1]), (char *)0); + } + else if (!strcmp(args[0], "next")) + { + if (!display) + { + if (layout_attach && layout_attach != &layout_last_marker) + layout_attach = layout_attach->lay_next ? layout_attach->lay_next : layouts;; + break; + } + struct layout *lay = D_layout; + if (lay) + lay = lay->lay_next ? lay->lay_next : layouts; + else + lay = layouts; + if (!lay) + { + OutputMsg(0, "no layout defined"); + break; + } + if (lay == D_layout) + break; + LoadLayout(lay, &D_canvas); + Activate(-1); + } + else if (!strcmp(args[0], "prev")) + { + struct layout *lay = display ? D_layout : layout_attach; + struct layout *target = lay; + if (lay) + { + for (lay = layouts; lay->lay_next && lay->lay_next != target; lay = lay->lay_next) + ; + } + else + lay = layouts; + + if (!display) + { + layout_attach = lay; + break; + } + + if (!lay) + { + OutputMsg(0, "no layout defined"); + break; + } + if (lay == D_layout) + break; + LoadLayout(lay, &D_canvas); + Activate(-1); + } + else if (!strcmp(args[0], "attach")) + { + if (!args[1]) + { + if (!layout_attach) + OutputMsg(0, "no attach layout set"); + else if (layout_attach == &layout_last_marker) + OutputMsg(0, "will attach to last layout"); + else + OutputMsg(0, "will attach to layout %d (%s)", layout_attach->lay_number, layout_attach->lay_title); + break; + } + if (!strcmp(args[1], ":last")) + layout_attach = &layout_last_marker; + else if (!args[1][0]) + layout_attach = 0; + else + { + struct layout *lay; + lay = FindLayout(args[1]); + if (!lay) + { + OutputMsg(0, "unknown layout '%s'", args[1]); + break; + } + layout_attach = lay; + } + } + else if (!strcmp(args[0], "show")) + { + ShowLayouts(-1); + } + else if (!strcmp(args[0], "remove")) + { + struct layout *lay = display ? D_layout : layouts; + if (args[1]) + { + lay = layouts ? FindLayout(args[1]) : (struct layout *)0; + if (!lay) + { + OutputMsg(0, "unknown layout '%s'", args[1]); + break; + } + } + if (lay) + RemoveLayout(lay); + } + else if (!strcmp(args[0], "dump")) + { + if (!display) + OutputMsg(0, "Must have a display for 'layout dump'."); + else if (!LayoutDumpCanvas(&D_canvas, args[1] ? args[1] : "layout-dump")) + OutputMsg(errno, "Error dumping layout."); + else + OutputMsg(0, "Layout dumped to \"%s\"", args[1] ? args[1] : "layout-dump"); + } + else + OutputMsg(0, "unknown layout subcommand"); + break; +#ifdef DW_CHARS + case RC_CJKWIDTH: + if(ParseSwitch(act, &cjkwidth) == 0) + { + if(msgok) + OutputMsg(0, "Treat ambiguous width characters as %s width", cjkwidth ? "full" : "half"); + } + break; +#endif + default: +#ifdef HAVE_BRAILLE + /* key == -2: input from braille keybord, msgok always 0 */ + DoBrailleAction(act, key == -2 ? 0 : msgok); +#endif + break; + } + if (display != odisplay) + { + for (display = displays; display; display = display->d_next) + if (display == odisplay) + break; + } +} +#undef OutputMsg + +void +CollapseWindowlist() +/* renumber windows from 0, leaving no gaps */ +{ + int pos, moveto=0; + + for (pos = 1; pos < MAXWIN; pos++) + if (wtab[pos]) + for (; moveto < pos; moveto++) + if (!wtab[moveto]) + { + WindowChangeNumber(pos, moveto); + break; + } +} + +void +DoCommand(argv, argl) +char **argv; +int *argl; +{ + struct action act; + const char *cmd = *argv; + + act.quiet = 0; + /* For now, we actually treat both 'supress error' and 'suppress normal message' as the + * same, and ignore all messages on either flag. If we wanted to do otherwise, we would + * need to change the definition of 'OutputMsg' slightly. */ + if (*cmd == '@') /* Suppress error */ + { + act.quiet |= 0x01; + cmd++; + } + if (*cmd == '-') /* Suppress normal message */ + { + act.quiet |= 0x02; + cmd++; + } + + if ((act.nr = FindCommnr(cmd)) == RC_ILLEGAL) + { + Msg(0, "%s: unknown command '%s'", rc_name, cmd); + return; + } + act.args = argv + 1; + act.argl = argl + 1; + DoAction(&act, -1); +} + +static void +SaveAction(act, nr, args, argl) +struct action *act; +int nr; +char **args; +int *argl; +{ + register int argc = 0; + char **pp; + int *lp; + + if (args) + while (args[argc]) + argc++; + if (argc == 0) + { + act->nr = nr; + act->args = noargs; + act->argl = 0; + return; + } + if ((pp = (char **)malloc((unsigned)(argc + 1) * sizeof(char *))) == 0) + Panic(0, "%s", strnomem); + if ((lp = (int *)malloc((unsigned)(argc) * sizeof(int))) == 0) + Panic(0, "%s", strnomem); + act->nr = nr; + act->args = pp; + act->argl = lp; + while (argc--) + { + *lp = argl ? *argl++ : (int)strlen(*args); + *pp++ = SaveStrn(*args++, *lp++); + } + *pp = 0; +} + +static char ** +SaveArgs(args) +char **args; +{ + register char **ap, **pp; + register int argc = 0; + + while (args[argc]) + argc++; + if ((pp = ap = (char **)malloc((unsigned)(argc + 1) * sizeof(char **))) == 0) + Panic(0, "%s", strnomem); + while (argc--) + *pp++ = SaveStr(*args++); + *pp = 0; + return ap; +} + + +/* + * buf is split into argument vector args. + * leading whitespace is removed. + * @!| abbreviations are expanded. + * the end of buffer is recognized by '\0' or an un-escaped '#'. + * " and ' are interpreted. + * + * argc is returned. + */ +int +Parse(buf, bufl, args, argl) +char *buf, **args; +int bufl, *argl; +{ + register char *p = buf, **ap = args, *pp; + register int delim, argc; + int *lp = argl; + + debug2("Parse %d %s\n", bufl, buf); + argc = 0; + pp = buf; + delim = 0; + for (;;) + { + *lp = 0; + while (*p && (*p == ' ' || *p == '\t')) + ++p; +#ifdef PSEUDOS + if (argc == 0 && *p == '!') + { + *ap++ = "exec"; + *lp++ = 4; + p++; + argc++; + continue; + } +#endif + if (*p == '\0' || *p == '#' || *p == '\n') + { + *p = '\0'; + for (delim = 0; delim < argc; delim++) + debug1("-- %s\n", args[delim]); + args[argc] = 0; + return argc; + } + if (++argc >= MAXARGS) + { + Msg(0, "%s: too many tokens.", rc_name); + return 0; + } + *ap++ = pp; + + debug1("- new arg %s\n", p); + while (*p) + { + if (*p == delim) + delim = 0; + else if (delim != '\'' && *p == '\\' && (p[1] == 'n' || p[1] == 'r' || p[1] == 't' || p[1] == '\'' || p[1] == '"' || p[1] == '\\' || p[1] == '$' || p[1] == '#' || p[1] == '^' || (p[1] >= '0' && p[1] <= '7'))) + { + p++; + if (*p >= '0' && *p <= '7') + { + *pp = *p - '0'; + if (p[1] >= '0' && p[1] <= '7') + { + p++; + *pp = (*pp << 3) | (*p - '0'); + if (p[1] >= '0' && p[1] <= '7') + { + p++; + *pp = (*pp << 3) | (*p - '0'); + } + } + pp++; + } + else + { + switch (*p) + { + case 'n': *pp = '\n'; break; + case 'r': *pp = '\r'; break; + case 't': *pp = '\t'; break; + default: *pp = *p; break; + } + pp++; + } + } + 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] == '_')) + + { + char *ps, *pe, op, *v, xbuf[11], path[MAXPATHLEN]; + int vl; + + ps = ++p; + debug1("- var %s\n", ps); + p++; + while (*p) + { + if (*ps == '{' && *p == '}') + break; + if (*ps == ':' && *p == ':') + break; + if (*ps != '{' && *ps != ':' && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9') && *p != '_') + break; + p++; + } + pe = p; + if (*ps == '{' || *ps == ':') + { + if (!*p) + { + Msg(0, "%s: bad variable name.", rc_name); + return 0; + } + p++; + } + op = *pe; + *pe = 0; + debug1("- var is '%s'\n", ps); + if (*ps == ':') + v = gettermcapstring(ps + 1); + else + { + if (*ps == '{') + ps++; + v = xbuf; + if (!strcmp(ps, "TERM")) + v = display ? D_termname : "unknown"; + else if (!strcmp(ps, "COLUMNS")) + sprintf(xbuf, "%d", display ? D_width : -1); + else if (!strcmp(ps, "LINES")) + sprintf(xbuf, "%d", display ? D_height : -1); + else if (!strcmp(ps, "PID")) + sprintf(xbuf, "%d", getpid()); + else if (!strcmp(ps, "PWD")) + { + if (getcwd(path, sizeof(path) - 1) == 0) + v = "?"; + else + v = path; + } + else if (!strcmp(ps, "STY")) + { + if ((v = strchr(SockName, '.'))) /* Skip the PID */ + v++; + else + v = SockName; + } + else + v = getenv(ps); + } + *pe = op; + vl = v ? strlen(v) : 0; + if (vl) + { + debug1("- sub is '%s'\n", v); + if (p - pp < vl) + { + int right = buf + bufl - (p + strlen(p) + 1); + if (right > 0) + { + bcopy(p, p + right, strlen(p) + 1); + p += right; + } + } + if (p - pp < vl) + { + Msg(0, "%s: no space left for variable expansion.", rc_name); + return 0; + } + bcopy(v, pp, vl); + pp += vl; + } + continue; + } + else if (delim != '\'' && *p == '^' && p[1]) + { + p++; + *pp++ = *p == '?' ? '\177' : *p & 0x1f; + } + else if (delim == 0 && (*p == '\'' || *p == '"')) + delim = *p; + else if (delim == 0 && (*p == ' ' || *p == '\t' || *p == '\n')) + break; + else + *pp++ = *p; + p++; + } + if (delim) + { + Msg(0, "%s: Missing %c quote.", rc_name, delim); + return 0; + } + if (*p) + p++; + *pp = 0; + debug2("- arg done, '%s' rest %s\n", ap[-1], p); + *lp++ = pp - ap[-1]; + pp++; + } +} + +void +SetEscape(u, e, me) +struct acluser *u; +int e, me; +{ + if (u) + { + u->u_Esc = e; + u->u_MetaEsc = me; + } + else + { + if (users) + { + if (DefaultEsc >= 0) + ClearAction(&ktab[DefaultEsc]); + if (DefaultMetaEsc >= 0) + ClearAction(&ktab[DefaultMetaEsc]); + } + DefaultEsc = e; + DefaultMetaEsc = me; + if (users) + { + if (DefaultEsc >= 0) + { + ClearAction(&ktab[DefaultEsc]); + ktab[DefaultEsc].nr = RC_OTHER; + } + if (DefaultMetaEsc >= 0) + { + ClearAction(&ktab[DefaultMetaEsc]); + ktab[DefaultMetaEsc].nr = RC_META; + } + } + } +} + +int +ParseSwitch(act, var) +struct action *act; +int *var; +{ + if (*act->args == 0) + { + *var ^= 1; + return 0; + } + return ParseOnOff(act, var); +} + +static int +ParseOnOff(act, var) +struct action *act; +int *var; +{ + register int num = -1; + char **args = act->args; + + if (args[1] == 0) + { + if (strcmp(args[0], "on") == 0) + num = 1; + else if (strcmp(args[0], "off") == 0) + num = 0; + } + if (num < 0) + { + Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, comms[act->nr].name); + return -1; + } + *var = num; + return 0; +} + +int +ParseSaveStr(act, var) +struct action *act; +char **var; +{ + char **args = act->args; + if (*args == 0 || args[1]) + { + Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name); + return -1; + } + if (*var) + free(*var); + *var = SaveStr(*args); + return 0; +} + +int +ParseNum(act, var) +struct action *act; +int *var; +{ + int i; + char *p, **args = act->args; + + p = *args; + if (p == 0 || *p == 0 || args[1]) + { + Msg(0, "%s: %s: invalid argument. Give one argument.", + rc_name, comms[act->nr].name); + return -1; + } + i = 0; + while (*p) + { + if (*p >= '0' && *p <= '9') + i = 10 * i + (*p - '0'); + else + { + Msg(0, "%s: %s: invalid argument. Give numeric argument.", + rc_name, comms[act->nr].name); + return -1; + } + p++; + } + debug1("ParseNum got %d\n", i); + *var = i; + return 0; +} + +static int +ParseNum1000(act, var) +struct action *act; +int *var; +{ + int i; + char *p, **args = act->args; + int dig = 0; + + p = *args; + if (p == 0 || *p == 0 || args[1]) + { + Msg(0, "%s: %s: invalid argument. Give one argument.", + rc_name, comms[act->nr].name); + return -1; + } + i = 0; + while (*p) + { + if (*p >= '0' && *p <= '9') + { + if (dig < 4) + i = 10 * i + (*p - '0'); + else if (dig == 4 && *p >= '5') + i++; + if (dig) + dig++; + } + else if (*p == '.' && !dig) + dig++; + else + { + Msg(0, "%s: %s: invalid argument. Give floating point argument.", + rc_name, comms[act->nr].name); + return -1; + } + p++; + } + if (dig == 0) + i *= 1000; + else + while (dig++ < 4) + i *= 10; + if (i < 0) + i = (int)((unsigned int)~0 >> 1); + debug1("ParseNum1000 got %d\n", i); + *var = i; + return 0; +} + +static struct win * +WindowByName(s) +char *s; +{ + struct win *p; + + for (p = windows; p; p = p->w_next) + if (!strcmp(p->w_title, s)) + return p; + for (p = windows; p; p = p->w_next) + if (!strncmp(p->w_title, s, strlen(s))) + return p; + return 0; +} + +static int +WindowByNumber(str) +char *str; +{ + int i; + char *s; + + for (i = 0, s = str; *s; s++) + { + if (*s < '0' || *s > '9') + break; + i = i * 10 + (*s - '0'); + } + return *s ? -1 : i; +} + +/* + * Get window number from Name or Number string. + * Numbers are tried first, then names, a prefix match suffices. + * Be careful when assigning numeric strings as WindowTitles. + */ +int +WindowByNoN(str) +char *str; +{ + int i; + struct win *p; + + if ((i = WindowByNumber(str)) < 0 || i >= maxwin) + { + if ((p = WindowByName(str))) + return p->w_number; + return -1; + } + return i; +} + +static int +ParseWinNum(act, var) +struct action *act; +int *var; +{ + char **args = act->args; + int i = 0; + + if (*args == 0 || args[1]) + { + Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name); + return -1; + } + + i = WindowByNoN(*args); + if (i < 0) + { + Msg(0, "%s: %s: invalid argument. Give window number or name.", + rc_name, comms[act->nr].name); + return -1; + } + debug1("ParseWinNum got %d\n", i); + *var = i; + return 0; +} + +static int +ParseBase(act, p, var, base, bname) +struct action *act; +char *p; +int *var; +int base; +char *bname; +{ + int i = 0; + int c; + + if (*p == 0) + { + Msg(0, "%s: %s: empty argument.", rc_name, comms[act->nr].name); + return -1; + } + while ((c = *p++)) + { + if (c >= 'a' && c <= 'z') + c -= 'a' - 'A'; + if (c >= 'A' && c <= 'Z') + c -= 'A' - ('0' + 10); + c -= '0'; + if (c < 0 || c >= base) + { + Msg(0, "%s: %s: argument is not %s.", rc_name, comms[act->nr].name, bname); + return -1; + } + i = base * i + c; + } + debug1("ParseBase got %d\n", i); + *var = i; + return 0; +} + +static int +IsNum(s, base) +register char *s; +register int base; +{ + for (base += '0'; *s; ++s) + if (*s < '0' || *s > base) + return 0; + return 1; +} + +int +IsNumColon(s, base, p, psize) +int base, psize; +char *s, *p; +{ + char *q; + if ((q = rindex(s, ':')) != 0) + { + strncpy(p, q + 1, psize - 1); + p[psize - 1] = '\0'; + *q = '\0'; + } + else + *p = '\0'; + return IsNum(s, base); +} + +void +SwitchWindow(n) +int n; +{ + struct win *p; + + debug1("SwitchWindow %d\n", n); + if (n < 0 || n >= maxwin) + { + ShowWindows(-1); + return; + } + if ((p = wtab[n]) == 0) + { + ShowWindows(n); + return; + } + if (display == 0) + { + fore = p; + return; + } + if (p == D_fore) + { + Msg(0, "This IS window %d (%s).", n, p->w_title); + return; + } +#ifdef MULTIUSER + if (AclCheckPermWin(D_user, ACL_READ, p)) + { + Msg(0, "Access to window %d denied.", p->w_number); + return; + } +#endif + SetForeWindow(p); + Activate(fore->w_norefresh); +} + +/* + * SetForeWindow changes the window in the input focus of the display. + * Puts window wi in canvas display->d_forecv. + */ +void +SetForeWindow(wi) +struct win *wi; +{ + struct win *p; + if (display == 0) + { + fore = wi; + return; + } + p = Layer2Window(D_forecv->c_layer); + SetCanvasWindow(D_forecv, wi); + if (p) + WindowChanged(p, 'u'); + if (wi) + WindowChanged(wi, 'u'); + flayer = D_forecv->c_layer; + /* Activate called afterwards, so no RefreshHStatus needed */ +} + + +/*****************************************************************/ + +/* + * Activate - make fore window active + * norefresh = -1 forces a refresh, disregard all_norefresh then. + */ +void +Activate(norefresh) +int norefresh; +{ + debug1("Activate(%d)\n", norefresh); + if (display == 0) + return; + if (D_status) + { + Msg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */ + RemoveStatus(); + } + + if (MayResizeLayer(D_forecv->c_layer)) + ResizeLayer(D_forecv->c_layer, D_forecv->c_xe - D_forecv->c_xs + 1, D_forecv->c_ye - D_forecv->c_ys + 1, display); + + fore = D_fore; + if (fore) + { + /* XXX ? */ + if (fore->w_monitor != MON_OFF) + fore->w_monitor = MON_ON; + fore->w_bell = BELL_ON; + WindowChanged(fore, 'f'); + +#if 0 + if (ResizeDisplay(fore->w_width, fore->w_height)) + { + debug2("Cannot resize from (%d,%d)", D_width, D_height); + debug2(" to (%d,%d) -> resize window\n", fore->w_width, fore->w_height); + DoResize(D_width, D_height); + } +#endif + } + Redisplay(norefresh + all_norefresh); +} + + +static int +NextWindow() +{ + register struct win **pp; + int n = fore ? fore->w_number : maxwin; + struct win *group = fore ? fore->w_group : 0; + + for (pp = fore ? wtab + n + 1 : wtab; pp != wtab + n; pp++) + { + if (pp == wtab + maxwin) + pp = wtab; + if (*pp) + { + if (!fore || group == (*pp)->w_group) + break; + } + } + if (pp == wtab + n) + return -1; + return pp - wtab; +} + +static int +PreviousWindow() +{ + register struct win **pp; + int n = fore ? fore->w_number : -1; + struct win *group = fore ? fore->w_group : 0; + + for (pp = wtab + n - 1; pp != wtab + n; pp--) + { + if (pp == wtab - 1) + pp = wtab + maxwin - 1; + if (*pp) + { + if (!fore || group == (*pp)->w_group) + break; + } + } + if (pp == wtab + n) + return -1; + return pp - wtab; +} + +static int +MoreWindows() +{ + char *m = "No other window."; + if (windows && (fore == 0 || windows->w_next)) + return 1; + if (fore == 0) + { + Msg(0, "No window available"); + return 0; + } + Msg(0, m, fore->w_number); /* other arg for nethack */ + return 0; +} + +void +KillWindow(wi) +struct win *wi; +{ + struct win **pp, *p; + struct canvas *cv; + int gotone; + struct layout *lay; + + /* + * Remove window from linked list. + */ + for (pp = &windows; (p = *pp); pp = &p->w_next) + if (p == wi) + break; + ASSERT(p); + *pp = p->w_next; + wi->w_inlen = 0; + wtab[wi->w_number] = 0; + + if (windows == 0) + { + FreeWindow(wi); + Finit(0); + } + + /* + * switch to different window on all canvases + */ + for (display = displays; display; display = display->d_next) + { + gotone = 0; + for (cv = D_cvlist; cv; cv = cv->c_next) + { + if (Layer2Window(cv->c_layer) != wi) + continue; + /* switch to other window */ + SetCanvasWindow(cv, FindNiceWindow(D_other, 0)); + gotone = 1; + } + if (gotone) + { +#ifdef ZMODEM + if (wi->w_zdisplay == display) + { + D_blocked = 0; + D_readev.condpos = D_readev.condneg = 0; + } +#endif + Activate(-1); + } + } + + /* do the same for the layouts */ + for (lay = layouts; lay; lay = lay->lay_next) + UpdateLayoutCanvas(&lay->lay_canvas, wi); + + FreeWindow(wi); + WindowChanged((struct win *)0, 'w'); + WindowChanged((struct win *)0, 'W'); + WindowChanged((struct win *)0, 0); +} + +static void +LogToggle(on) +int on; +{ + char buf[1024]; + + if ((fore->w_log != 0) == on) + { + if (display && !*rc_name) + Msg(0, "You are %s logging.", on ? "already" : "not"); + return; + } + if (fore->w_log != 0) + { + Msg(0, "Logfile \"%s\" closed.", fore->w_log->name); + logfclose(fore->w_log); + fore->w_log = 0; + WindowChanged(fore, 'f'); + return; + } + if (DoStartLog(fore, buf, sizeof(buf))) + { + Msg(errno, "Error opening logfile \"%s\"", buf); + return; + } + if (ftell(fore->w_log->fp) == 0) + Msg(0, "Creating logfile \"%s\".", fore->w_log->name); + else + Msg(0, "Appending to logfile \"%s\".", fore->w_log->name); + WindowChanged(fore, 'f'); +} + +char * +AddWindows(buf, len, flags, where) +char *buf; +int len; +int flags; +int where; +{ + register char *s, *ss; + register struct win **pp, *p; + register char *cmd; + int l; + + s = ss = buf; + if ((flags & 8) && where < 0) + { + *s = 0; + return ss; + } + for (pp = ((flags & 4) && where >= 0) ? wtab + where + 1: wtab; pp < wtab + maxwin; pp++) + { + int rend = -1; + if (pp - wtab == where && ss == buf) + ss = s; + if ((p = *pp) == 0) + continue; + if ((flags & 1) && display && p == D_fore) + continue; + if (display && D_fore && D_fore->w_group != p->w_group) + continue; + + cmd = p->w_title; + l = strlen(cmd); + if (l > 20) + l = 20; + if (s - buf + l > len - 24) + break; + if (s > buf || (flags & 4)) + { + *s++ = ' '; + *s++ = ' '; + } + if (p->w_number == where) + { + ss = s; + if (flags & 8) + break; + } + if (!(flags & 4) || where < 0 || ((flags & 4) && where < p->w_number)) + { + if (p->w_monitor == MON_DONE && renditions[REND_MONITOR] != -1) + rend = renditions[REND_MONITOR]; + else if ((p->w_bell == BELL_DONE || p->w_bell == BELL_FOUND) && renditions[REND_BELL] != -1) + rend = renditions[REND_BELL]; + else if ((p->w_silence == SILENCE_FOUND || p->w_silence == SILENCE_DONE) && renditions[REND_SILENCE] != -1) + rend = renditions[REND_SILENCE]; + } + if (rend != -1) + AddWinMsgRend(s, rend); + sprintf(s, "%d", p->w_number); + s += strlen(s); + if (display && p == D_fore) + *s++ = '*'; + if (!(flags & 2)) + { + if (display && p == D_other) + *s++ = '-'; + s = AddWindowFlags(s, len, p); + } + *s++ = ' '; + strncpy(s, cmd, l); + s += l; + if (rend != -1) + AddWinMsgRend(s, -1); + } + *s = 0; + return ss; +} + +char * +AddWindowFlags(buf, len, p) +char *buf; +int len; +struct win *p; +{ + char *s = buf; + if (p == 0 || len < 12) + { + *s = 0; + return s; + } +#if 0 + if (display && p == D_fore) + *s++ = '*'; + if (display && p == D_other) + *s++ = '-'; +#endif + if (p->w_layer.l_cvlist && p->w_layer.l_cvlist->c_lnext) + *s++ = '&'; + if (p->w_monitor == MON_DONE +#ifdef MULTIUSER + && display && (ACLBYTE(p->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id)) +#endif + ) + *s++ = '@'; + if (p->w_bell == BELL_DONE) + *s++ = '!'; +#ifdef UTMPOK + if (p->w_slot != (slot_t) 0 && p->w_slot != (slot_t) -1) + *s++ = '$'; +#endif + if (p->w_log != 0) + { + strcpy(s, "(L)"); + s += 3; + } + if (p->w_ptyfd < 0 && p->w_type != W_TYPE_GROUP) + *s++ = 'Z'; + *s = 0; + return s; +} + +char * +AddOtherUsers(buf, len, p) +char *buf; +int len; +struct win *p; +{ + struct display *d, *olddisplay = display; + struct canvas *cv; + char *s; + int l; + + s = buf; + for (display = displays; display; display = display->d_next) + { + if (olddisplay && D_user == olddisplay->d_user) + continue; + for (cv = D_cvlist; cv; cv = cv->c_next) + if (Layer2Window(cv->c_layer) == p) + break; + if (!cv) + continue; + for (d = displays; d && d != display; d = d->d_next) + if (D_user == d->d_user) + break; + if (d && d != display) + continue; + if (len > 1 && s != buf) + { + *s++ = ','; + len--; + } + l = strlen(D_user->u_name); + if (l + 1 > len) + break; + strcpy(s, D_user->u_name); + s += l; + len -= l; + } + *s = 0; + display = olddisplay; + return s; +} + +void +ShowWindows(where) +int where; +{ + char buf[1024]; + char *s, *ss; + + if (display && where == -1 && D_fore) + where = D_fore->w_number; + ss = AddWindows(buf, sizeof(buf), 0, where); + s = buf + strlen(buf); + if (display && ss - buf > D_width / 2) + { + ss -= D_width / 2; + if (s - ss < D_width) + { + ss = s - D_width; + if (ss < buf) + ss = buf; + } + } + else + ss = buf; + Msg(0, "%s", ss); +} + +/* +* String Escape based windows listing +* mls: currently does a Msg() call for each(!) window, dunno why +*/ +static void +ShowWindowsX(str) +char *str; +{ + int i; + debug1("ShowWindowsX: string [%s]", str); + for (i = 0; i < maxwin ; i++) { + if (!wtab[i]) + continue; + Msg(0, "%s", MakeWinMsg(str, wtab[i], '%')); + } +} + + +static void +ShowInfo() +{ + char buf[512], *p; + register struct win *wp = fore; + register int i; + + if (wp == 0) + { + Msg(0, "(%d,%d)/(%d,%d) no window", D_x + 1, D_y + 1, D_width, D_height); + return; + } + p = buf; + if (buf < (p += GetAnsiStatus(wp, p))) + *p++ = ' '; + sprintf(p, "(%d,%d)/(%d,%d)", + wp->w_x + 1, wp->w_y + 1, wp->w_width, wp->w_height); +#ifdef COPY_PASTE + sprintf(p += strlen(p), "+%d", wp->w_histheight); +#endif + sprintf(p += strlen(p), " %c%sflow", + (wp->w_flow & FLOW_NOW) ? '+' : '-', + (wp->w_flow & FLOW_AUTOFLAG) ? "" : + ((wp->w_flow & FLOW_AUTO) ? "(+)" : "(-)")); + if (!wp->w_wrap) sprintf(p += strlen(p), " -wrap"); + if (wp->w_insert) sprintf(p += strlen(p), " ins"); + if (wp->w_origin) sprintf(p += strlen(p), " org"); + if (wp->w_keypad) sprintf(p += strlen(p), " app"); + if (wp->w_log) sprintf(p += strlen(p), " log"); + if (wp->w_monitor != MON_OFF +#ifdef MULTIUSER + && (ACLBYTE(wp->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id)) +#endif + ) + sprintf(p += strlen(p), " mon"); + if (wp->w_mouse) sprintf(p += strlen(p), " mouse"); +#ifdef COLOR + if (wp->w_bce) sprintf(p += strlen(p), " bce"); +#endif + if (!wp->w_c1) sprintf(p += strlen(p), " -c1"); + if (wp->w_norefresh) sprintf(p += strlen(p), " nored"); + + p += strlen(p); +#ifdef FONT +# ifdef ENCODINGS + if (wp->w_encoding && (display == 0 || D_encoding != wp->w_encoding || EncodingDefFont(wp->w_encoding) <= 0)) + { + *p++ = ' '; + strcpy(p, EncodingName(wp->w_encoding)); + p += strlen(p); + } +# ifdef UTF8 + if (wp->w_encoding != UTF8) +# endif +# endif + if (display && (D_CC0 || (D_CS0 && *D_CS0))) + { + if (wp->w_gr == 2) + { + sprintf(p, " G%c", wp->w_Charset + '0'); + if (wp->w_FontE >= ' ') + p[3] = wp->w_FontE; + else + { + p[3] = '^'; + p[4] = wp->w_FontE ^ 0x40; + p++; + } + p[4] = '['; + p++; + } + else if (wp->w_gr) + sprintf(p++, " G%c%c[", wp->w_Charset + '0', wp->w_CharsetR + '0'); + else + sprintf(p, " G%c[", wp->w_Charset + '0'); + p += 4; + for (i = 0; i < 4; i++) + { + if (wp->w_charsets[i] == ASCII) + *p++ = 'B'; + else if (wp->w_charsets[i] >= ' ') + *p++ = wp->w_charsets[i]; + else + { + *p++ = '^'; + *p++ = wp->w_charsets[i] ^ 0x40; + } + } + *p++ = ']'; + *p = 0; + } +#endif + + if (wp->w_type == W_TYPE_PLAIN) + { + /* add info about modem control lines */ + *p++ = ' '; + TtyGetModemStatus(wp->w_ptyfd, p); + } +#ifdef BUILTIN_TELNET + else if (wp->w_type == W_TYPE_TELNET) + { + *p++ = ' '; + TelStatus(wp, p, sizeof(buf) - 1 - (p - buf)); + } +#endif + Msg(0, "%s %d(%s)", buf, wp->w_number, wp->w_title); +} + +static void +ShowDInfo() +{ + char buf[512], *p; + if (display == 0) + return; + p = buf; + sprintf(p, "(%d,%d)", D_width, D_height), + p += strlen(p); +#ifdef ENCODINGS + if (D_encoding) + { + *p++ = ' '; + strcpy(p, EncodingName(D_encoding)); + p += strlen(p); + } +#endif + if (D_CXT) + { + strcpy(p, " xterm"); + p += strlen(p); + } +#ifdef COLOR + if (D_hascolor) + { + strcpy(p, " color"); + p += strlen(p); + } +#endif +#ifdef FONT + if (D_CG0) + { + strcpy(p, " iso2022"); + p += strlen(p); + } + else if (D_CS0 && *D_CS0) + { + strcpy(p, " altchar"); + p += strlen(p); + } +#endif + Msg(0, "%s", buf); +} + +static void +AKAfin(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + ASSERT(display); + if (len && fore) + ChangeAKA(fore, buf, strlen(buf)); + + enter_window_name_mode = 0; +} + +static void +InputAKA() +{ + char *s, *ss; + int n; + + if (enter_window_name_mode == 1) return; + + enter_window_name_mode = 1; + + Input("Set window's title to: ", sizeof(fore->w_akabuf) - 1, INP_COOKED, AKAfin, NULL, 0); + s = fore->w_title; + if (!s) + return; + for (; *s; s++) + { + if ((*(unsigned char *)s & 0x7f) < 0x20 || *s == 0x7f) + continue; + ss = s; + n = 1; + LayProcess(&ss, &n); + } +} + +static void +Colonfin(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + char mbuf[256]; + + RemoveStatus(); + if (buf[len] == '\t') + { + int m, x; + int l = 0, r = RC_LAST; + int showmessage = 0; + char *s = buf; + + while (*s && s - buf < len) + if (*s++ == ' ') + return; + + /* Showing a message when there's no hardstatus or caption cancels the input */ + if (display && + (captionalways || D_has_hstatus == HSTATUS_LASTLINE || (D_canvas.c_slperp && D_canvas.c_slperp->c_slnext))) + showmessage = 1; + + while (l <= r) + { + m = (l + r) / 2; + x = strncmp(buf, comms[m].name, len); + if (x > 0) + l = m + 1; + else if (x < 0) + r = m - 1; + else + { + s = mbuf; + for (l = m - 1; l >= 0 && strncmp(buf, comms[l].name, len) == 0; l--) + ; + for (m = ++l; m <= r && strncmp(buf, comms[m].name, len) == 0 && s - mbuf < sizeof(mbuf); m++) + s += snprintf(s, sizeof(mbuf) - (s - mbuf), " %s", comms[m].name); + if (l < m - 1) + { + if (showmessage) + Msg(0, "Possible commands:%s", mbuf); + } + else + { + s = mbuf; + len = snprintf(mbuf, sizeof(mbuf), "%s \t", comms[l].name + len); + if (len > 0 && len < sizeof(mbuf)) + LayProcess(&s, &len); + } + break; + } + } + if (l > r && showmessage) + Msg(0, "No commands matching '%*s'", len, buf); + return; + } + + if (!len || buf[len]) + return; + + len = strlen(buf) + 1; + if (len > (int)sizeof(mbuf)) + RcLine(buf, len); + else + { + bcopy(buf, mbuf, len); + RcLine(mbuf, sizeof mbuf); + } +} + +static void +SelectFin(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + int n; + + if (!len || !display) + return; + if (len == 1 && *buf == '-') + { + SetForeWindow((struct win *)0); + Activate(0); + return; + } + if ((n = WindowByNoN(buf)) < 0) + return; + SwitchWindow(n); +} + +static void +SelectLayoutFin(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + struct layout *lay; + + if (!len || !display) + return; + if (len == 1 && *buf == '-') + { + LoadLayout((struct layout *)0, (struct canvas *)0); + Activate(0); + return; + } + lay = FindLayout(buf); + if (!lay) + Msg(0, "No such layout\n"); + else if (lay == D_layout) + Msg(0, "This IS layout %d (%s).\n", lay->lay_number, lay->lay_title); + else + { + LoadLayout(lay, &D_canvas); + Activate(0); + } +} + + +static void +InputSelect() +{ + Input("Switch to window: ", 20, INP_COOKED, SelectFin, NULL, 0); +} + +static char setenv_var[31]; + + +static void +SetenvFin1(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + if (!len || !display) + return; + InputSetenv(buf); +} + +static void +SetenvFin2(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + if (!len || !display) + return; + debug2("SetenvFin2: setenv '%s' '%s'\n", setenv_var, buf); + xsetenv(setenv_var, buf); + MakeNewEnv(); +} + +static void +InputSetenv(arg) +char *arg; +{ + static char setenv_buf[50 + sizeof(setenv_var)]; /* need to be static here, cannot be freed */ + + if (arg) + { + strncpy(setenv_var, arg, sizeof(setenv_var) - 1); + sprintf(setenv_buf, "Enter value for %s: ", setenv_var); + Input(setenv_buf, 30, INP_COOKED, SetenvFin2, NULL, 0); + } + else + Input("Setenv: Enter variable name: ", 30, INP_COOKED, SetenvFin1, NULL, 0); +} + +/* + * the following options are understood by this parser: + * -f, -f0, -f1, -fy, -fa + * -t title, -T terminal-type, -h height-of-scrollback, + * -ln, -l0, -ly, -l1, -l + * -a, -M, -L + */ +void +DoScreen(fn, av) +char *fn, **av; +{ + struct NewWindow nwin; + register int num; + char buf[20]; + + nwin = nwin_undef; + while (av && *av && av[0][0] == '-') + { + if (av[0][1] == '-') + { + av++; + break; + } + switch (av[0][1]) + { + case 'f': + switch (av[0][2]) + { + case 'n': + case '0': + nwin.flowflag = FLOW_NOW * 0; + break; + case 'y': + case '1': + case '\0': + nwin.flowflag = FLOW_NOW * 1; + break; + case 'a': + nwin.flowflag = FLOW_AUTOFLAG; + break; + default: + break; + } + break; + case 't': /* no more -k */ + if (av[0][2]) + nwin.aka = &av[0][2]; + else if (*++av) + nwin.aka = *av; + else + --av; + break; + case 'T': + if (av[0][2]) + nwin.term = &av[0][2]; + else if (*++av) + nwin.term = *av; + else + --av; + break; + case 'h': + if (av[0][2]) + nwin.histheight = atoi(av[0] + 2); + else if (*++av) + nwin.histheight = atoi(*av); + else + --av; + break; +#ifdef LOGOUTOK + case 'l': + switch (av[0][2]) + { + case 'n': + case '0': + nwin.lflag = 0; + break; + case 'y': + case '1': + case '\0': + nwin.lflag = 1; + break; + case 'a': + nwin.lflag = 3; + break; + default: + break; + } + break; +#endif + case 'a': + nwin.aflag = 1; + break; + case 'M': + nwin.monitor = MON_ON; + break; + case 'L': + nwin.Lflag = 1; + break; + default: + Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]); + break; + } + ++av; + } + if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf))) + { + if (*buf != '\0') + nwin.aka = buf; + num = atoi(*av); + if (num < 0 || (maxwin && num > maxwin - 1) || (!maxwin && num > MAXWIN - 1)) + { + Msg(0, "%s: illegal screen number %d.", fn, num); + num = 0; + } + nwin.StartAt = num; + ++av; + } + if (av && *av) + { + nwin.args = av; + if (!nwin.aka) + nwin.aka = Filename(*av); + } + MakeWindow(&nwin); +} + +#ifdef COPY_PASTE +/* + * CompileKeys must be called before Markroutine is first used. + * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab); + * + * s is an ascii string in a termcap-like syntax. It looks like + * "j=u:k=d:l=r:h=l: =.:" and so on... + * this example rebinds the cursormovement to the keys u (up), d (down), + * l (left), r (right). placing a mark will now be done with ".". + */ +int +CompileKeys(s, sl, array) +char *s; +int sl; +unsigned char *array; +{ + int i; + unsigned char key, value; + + if (sl == 0) + { + for (i = 0; i < 256; i++) + array[i] = i; + return 0; + } + debug1("CompileKeys: '%s'\n", s); + while (sl) + { + key = *(unsigned char *)s++; + if (*s != '=' || sl < 3) + return -1; + sl--; + do + { + s++; + sl -= 2; + value = *(unsigned char *)s++; + array[value] = key; + } + while (*s == '=' && sl >= 2); + if (sl == 0) + break; + if (*s++ != ':') + return -1; + sl--; + } + return 0; +} +#endif /* COPY_PASTE */ + +/* + * Asynchronous input functions + */ + +#if defined(DETACH) && defined(POW_DETACH) +static void +pow_detach_fn(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + debug("pow_detach_fn called\n"); + if (len) + { + memset(buf, 0, len); + return; + } + if (ktab[(int)(unsigned char)*buf].nr != RC_POW_DETACH) + { + if (display) + write(D_userfd, "\007", 1); + Msg(0, "Detach aborted."); + } + else + Detach(D_POWER); +} +#endif /* POW_DETACH */ + +#ifdef COPY_PASTE +static void +copy_reg_fn(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + struct plop *pp = plop_tab + (int)(unsigned char)*buf; + + if (len) + { + memset(buf, 0, len); + return; + } + if (pp->buf) + free(pp->buf); + pp->buf = 0; + pp->len = 0; + if (D_user->u_plop.len) + { + if ((pp->buf = (char *)malloc(D_user->u_plop.len)) == NULL) + { + Msg(0, "%s", strnomem); + return; + } + bcopy(D_user->u_plop.buf, pp->buf, D_user->u_plop.len); + } + pp->len = D_user->u_plop.len; +#ifdef ENCODINGS + pp->enc = D_user->u_plop.enc; +#endif + Msg(0, "Copied %d characters into register %c", D_user->u_plop.len, *buf); +} + +static void +ins_reg_fn(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + struct plop *pp = plop_tab + (int)(unsigned char)*buf; + + if (len) + { + memset(buf, 0, len); + return; + } + if (!fore) + return; /* Input() should not call us w/o fore, but you never know... */ + if (*buf == '.') + Msg(0, "ins_reg_fn: Warning: pasting real register '.'!"); + if (pp->buf) + { + MakePaster(&fore->w_paster, pp->buf, pp->len, 0); + return; + } + Msg(0, "Empty register."); +} +#endif /* COPY_PASTE */ + +static void +process_fn(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + struct plop *pp = plop_tab + (int)(unsigned char)*buf; + + if (len) + { + memset(buf, 0, len); + return; + } + if (pp->buf) + { + ProcessInput(pp->buf, pp->len); + return; + } + Msg(0, "Empty register."); +} + +static void +confirm_fn(buf, len, data) +char *buf; +int len; +char *data; +{ + struct action act; + + if (len || (*buf != 'y' && *buf != 'Y')) + { + memset(buf, 0, len); + return; + } + act.nr = *(int *)data; + act.args = noargs; + act.argl = 0; + act.quiet = 0; + DoAction(&act, -1); +} + +#ifdef MULTIUSER +struct inputsu +{ + struct acluser **up; + char name[24]; + char pw1[130]; /* FreeBSD crypts to 128 bytes */ + char pw2[130]; +}; + +static void +su_fin(buf, len, data) +char *buf; +int len; +char *data; +{ + struct inputsu *i = (struct inputsu *)data; + char *p; + int l; + + if (!*i->name) + { p = i->name; l = sizeof(i->name) - 1; } + else if (!*i->pw1) + { strcpy(p = i->pw1, "\377"); l = sizeof(i->pw1) - 1; } + else + { strcpy(p = i->pw2, "\377"); l = sizeof(i->pw2) - 1; } + if (buf && len) + strncpy(p, buf, 1 + ((l < len) ? l : len)); + if (!*i->name) + Input("Screen User: ", sizeof(i->name) - 1, INP_COOKED, su_fin, (char *)i, 0); + else if (!*i->pw1) + Input("User's UNIX Password: ", sizeof(i->pw1)-1, INP_COOKED|INP_NOECHO, su_fin, (char *)i, 0); + else if (!*i->pw2) + Input("User's Screen Password: ", sizeof(i->pw2)-1, INP_COOKED|INP_NOECHO, su_fin, (char *)i, 0); + else + { + if ((p = DoSu(i->up, i->name, i->pw2, i->pw1))) + Msg(0, "%s", p); + free((char *)i); + } +} + +static int +InputSu(w, up, name) +struct win *w; +struct acluser **up; +char *name; +{ + struct inputsu *i; + + if (!(i = (struct inputsu *)calloc(1, sizeof(struct inputsu)))) + return -1; + + i->up = up; + if (name && *name) + su_fin(name, (int)strlen(name), (char *)i); /* can also initialise stuff */ + else + su_fin((char *)0, 0, (char *)i); + return 0; +} +#endif /* MULTIUSER */ + +#ifdef PASSWORD + +static void +pass1(buf, len, data) +char *buf; +int len; +char *data; +{ + struct acluser *u = (struct acluser *)data; + + if (!*buf) + return; + ASSERT(u); + if (u->u_password != NullStr) + free((char *)u->u_password); + u->u_password = SaveStr(buf); + bzero(buf, strlen(buf)); + Input("Retype new password:", 100, INP_NOECHO, pass2, data, 0); +} + +static void +pass2(buf, len, data) +char *buf; +int len; +char *data; +{ + int st; + char salt[3]; + struct acluser *u = (struct acluser *)data; + + ASSERT(u); + if (!buf || strcmp(u->u_password, buf)) + { + Msg(0, "[ Passwords don't match - checking turned off ]"); + if (u->u_password != NullStr) + { + bzero(u->u_password, strlen(u->u_password)); + free((char *)u->u_password); + } + u->u_password = NullStr; + } + else if (u->u_password[0] == '\0') + { + Msg(0, "[ No password - no secure ]"); + if (buf) + bzero(buf, strlen(buf)); + } + + if (u->u_password != NullStr) + { + for (st = 0; st < 2; st++) + salt[st] = 'A' + (int)((time(0) >> 6 * st) % 26); + salt[2] = 0; + buf = crypt(u->u_password, salt); + bzero(u->u_password, strlen(u->u_password)); + free((char *)u->u_password); + if (!buf) + { + Msg(0, "[ crypt() error - no secure ]"); + u->u_password = NullStr; + return; + } + u->u_password = SaveStr(buf); + bzero(buf, strlen(buf)); +#ifdef COPY_PASTE + if (u->u_plop.buf) + UserFreeCopyBuffer(u); + u->u_plop.len = strlen(u->u_password); +# ifdef ENCODINGS + u->u_plop.enc = 0; +#endif + if (!(u->u_plop.buf = SaveStr(u->u_password))) + { + Msg(0, "%s", strnomem); + D_user->u_plop.len = 0; + } + else + Msg(0, "[ Password moved into copybuffer ]"); +#else /* COPY_PASTE */ + Msg(0, "[ Crypted password is \"%s\" ]", u->u_password); +#endif /* COPY_PASTE */ + } +} +#endif /* PASSWORD */ + +static int +digraph_find(buf) +const char *buf; +{ + int i; + for (i = 0; i < MAX_DIGRAPH && digraphs[i].d[0]; i++) + if ((digraphs[i].d[0] == (unsigned char)buf[0] && digraphs[i].d[1] == (unsigned char)buf[1]) || + (digraphs[i].d[0] == (unsigned char)buf[1] && digraphs[i].d[1] == (unsigned char)buf[0])) + break; + return i; +} + +static void +digraph_fn(buf, len, data) +char *buf; +int len; +char *data; /* dummy */ +{ + int ch, i, x; + + ch = buf[len]; + if (ch) + { + buf[len + 1] = ch; /* so we can restore it later */ + if (ch < ' ' || ch == '\177') + return; + if (len >= 1 && ((*buf == 'U' && buf[1] == '+') || (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X')))) + { + if (len == 1) + return; + if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f') && (ch < 'A' || ch > 'F')) + { + buf[len] = '\034'; /* ^] is ignored by Input() */ + return; + } + if (len == (*buf == 'U' ? 5 : 3)) + buf[len] = '\n'; + return; + } + if (len && *buf == '0') + { + if (ch < '0' || ch > '7') + { + buf[len] = '\034'; /* ^] is ignored by Input() */ + return; + } + if (len == 3) + buf[len] = '\n'; + return; + } + if (len == 1) + buf[len] = '\n'; + return; + } + if (len < 1) + return; + if (buf[len + 1]) + { + buf[len] = buf[len + 1]; /* stored above */ + len++; + } + if (len < 2) + return; + if (!parse_input_int(buf, len, &x)) + { + i = digraph_find(buf); + if ((x = digraphs[i].value) <= 0) + { + Msg(0, "Unknown digraph"); + return; + } + } + i = 1; + *buf = x; +#ifdef UTF8 + if (flayer->l_encoding == UTF8) + i = ToUtf8(buf, x); /* buf is big enough for all UTF-8 codes */ +#endif + while(i) + LayProcess(&buf, &i); +} + +#ifdef MAPKEYS +int +StuffKey(i) +int i; +{ + struct action *act; + int discard = 0; + int keyno = i; + + debug1("StuffKey #%d", i); +#ifdef DEBUG + if (i < KMAP_KEYS) + debug1(" - %s", term[i + T_CAPS].tcname); +#endif + + if (i < KMAP_KEYS && D_ESCseen) + { + struct action *act = &D_ESCseen[i + 256]; + if (act->nr != RC_ILLEGAL) + { + D_ESCseen = 0; + WindowChanged(fore, 'E'); + DoAction(act, i + 256); + return 0; + } + discard = 1; + } + + if (i >= T_CURSOR - T_CAPS && i < T_KEYPAD - T_CAPS && D_cursorkeys) + i += T_OCAPS - T_CURSOR; + else if (i >= T_KEYPAD - T_CAPS && i < T_OCAPS - T_CAPS && D_keypad) + i += T_OCAPS - T_CURSOR; + debug1(" - action %d\n", i); + flayer = D_forecv->c_layer; + fore = D_fore; + act = 0; +#ifdef COPY_PASTE + if (flayer && flayer->l_mode == 1) + act = i < KMAP_KEYS+KMAP_AKEYS ? &mmtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].mm; +#endif + if ((!act || act->nr == RC_ILLEGAL) && !D_mapdefault) + act = i < KMAP_KEYS+KMAP_AKEYS ? &umtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].um; + if (!act || act->nr == RC_ILLEGAL) + act = i < KMAP_KEYS+KMAP_AKEYS ? &dmtab[i] : &kmap_exts[i - (KMAP_KEYS+KMAP_AKEYS)].dm; + + if (discard && (!act || act->nr != RC_COMMAND)) + { + /* if the input was just a single byte we let it through */ + if (D_tcs[keyno + T_CAPS].str && strlen(D_tcs[keyno + T_CAPS].str) == 1) + return -1; + if (D_ESCseen) + { + D_ESCseen = 0; + WindowChanged(fore, 'E'); + } + return 0; + } + D_mapdefault = 0; + + if (act == 0 || act->nr == RC_ILLEGAL) + return -1; + DoAction(act, 0); + return 0; +} +#endif + + +static int +IsOnDisplay(wi) +struct win *wi; +{ + struct canvas *cv; + ASSERT(display); + for (cv = D_cvlist; cv; cv = cv->c_next) + if (Layer2Window(cv->c_layer) == wi) + return 1; + return 0; +} + +struct win * +FindNiceWindow(wi, presel) +struct win *wi; +char *presel; +{ + int i; + + debug2("FindNiceWindow %d %s\n", wi ? wi->w_number : -1 , presel ? presel : "NULL"); + if (presel) + { + i = WindowByNoN(presel); + if (i >= 0) + wi = wtab[i]; + } + if (!display) + return wi; +#ifdef MULTIUSER + if (wi && AclCheckPermWin(D_user, ACL_READ, wi)) + wi = 0; +#endif + if (!wi || (IsOnDisplay(wi) && !presel)) + { + /* try to get another window */ + wi = 0; +#ifdef MULTIUSER + for (wi = windows; wi; wi = wi->w_next) + if (!wi->w_layer.l_cvlist && !AclCheckPermWin(D_user, ACL_WRITE, wi)) + break; + if (!wi) + for (wi = windows; wi; wi = wi->w_next) + if (wi->w_layer.l_cvlist && !IsOnDisplay(wi) && !AclCheckPermWin(D_user, ACL_WRITE, wi)) + break; + if (!wi) + for (wi = windows; wi; wi = wi->w_next) + if (!wi->w_layer.l_cvlist && !AclCheckPermWin(D_user, ACL_READ, wi)) + break; + if (!wi) + for (wi = windows; wi; wi = wi->w_next) + if (wi->w_layer.l_cvlist && !IsOnDisplay(wi) && !AclCheckPermWin(D_user, ACL_READ, wi)) + break; +#endif + if (!wi) + for (wi = windows; wi; wi = wi->w_next) + if (!wi->w_layer.l_cvlist) + break; + if (!wi) + for (wi = windows; wi; wi = wi->w_next) + if (wi->w_layer.l_cvlist && !IsOnDisplay(wi)) + break; + } +#ifdef MULTIUSER + if (wi && AclCheckPermWin(D_user, ACL_READ, wi)) + wi = 0; +#endif + return wi; +} + +#if 0 + +/* sorted list of all commands */ +static struct comm **commtab; +static int ncommtab; + +void +AddComms(cos, hand) +struct comm *cos; +void (*hand) __P((struct comm *, char **, int)); +{ + int n, i, j, r; + for (n = 0; cos[n].name; n++) + ; + if (n == 0) + return; + if (commtab) + commtab = (struct commt *)realloc(commtab, sizeof(*commtab) * (ncommtab + n)); + else + commtab = (struct commt *)malloc(sizeof(*commtab) * (ncommtab + n)); + if (!commtab) + Panic(0, strnomem); + for (i = 0; i < n; i++) + { + for (j = 0; j < ncommtab; j++) + { + r = strcmp(cos[i].name, commtab[j]->name); + if (r == 0) + Panic(0, "Duplicate command: %s\n", cos[i].name); + if (r < 0) + break; + } + for (r = ncommtab; r > j; r--) + commtab[r] = commtab[r - 1]; + commtab[j] = cos + i; + cos[i].handler = hand; + bzero(cos[i].userbits, sizeof(cos[i].userbits)); + ncommtab++; + } +} + +struct comm * +FindComm(str) +char *str; +{ + int x, m, l = 0, r = ncommtab - 1; + while (l <= r) + { + m = (l + r) / 2; + x = strcmp(str, commtab[m]->name); + if (x > 0) + l = m + 1; + else if (x < 0) + r = m - 1; + else + return commtab[m]; + } + return 0; +} + +#endif + +static int +CalcSlicePercent(cv, percent) +struct canvas *cv; +int percent; +{ + int w, wsum, up; + if (!cv || !cv->c_slback) + return percent; + up = CalcSlicePercent(cv->c_slback->c_slback, percent); + w = cv->c_slweight; + for (cv = cv->c_slback->c_slperp, wsum = 0; cv; cv = cv->c_slnext) + wsum += cv->c_slweight; + if (wsum == 0) + return 0; + return (up * w) / wsum; +} + +static int +ChangeCanvasSize(fcv, abs, diff, gflag, percent) +struct canvas *fcv; /* make this canvas bigger */ +int abs; /* mode: 0:rel 1:abs 2:max */ +int diff; /* change this much */ +int gflag; /* go up if neccessary */ +int percent; +{ + struct canvas *cv; + int done, have, m, dir; + + debug3("ChangeCanvasSize abs %d diff %d percent=%d\n", abs, diff, percent); + if (abs == 0 && diff == 0) + return 0; + if (abs == 2) + { + if (diff == 0) + fcv->c_slweight = 0; + else + { + for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext) + cv->c_slweight = 0; + fcv->c_slweight = 1; + cv = fcv->c_slback->c_slback; + if (gflag && cv && cv->c_slback) + ChangeCanvasSize(cv, abs, diff, gflag, percent); + } + return diff; + } + if (abs) + { + if (diff < 0) + diff = 0; + if (percent && diff > percent) + diff = percent; + } + if (percent) + { + int wsum, up; + for (cv = fcv->c_slback->c_slperp, wsum = 0; cv; cv = cv->c_slnext) + wsum += cv->c_slweight; + if (wsum) + { + up = gflag ? CalcSlicePercent(fcv->c_slback->c_slback, percent) : percent; + debug3("up=%d, wsum=%d percent=%d\n", up, wsum, percent); + if (wsum < 1000) + { + int scale = wsum < 10 ? 1000 : 100; + for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext) + cv->c_slweight *= scale; + wsum *= scale; + debug1("scaled wsum to %d\n", wsum); + } + for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext) + { + if (cv->c_slweight) + { + cv->c_slweight = (cv->c_slweight * up) / percent; + if (cv->c_slweight == 0) + cv->c_slweight = 1; + } + debug1(" - weight %d\n", cv->c_slweight); + } + diff = (diff * wsum) / percent; + percent = wsum; + } + } + else + { + if (abs && diff == (fcv->c_slorient == SLICE_VERT ? fcv->c_ye - fcv->c_ys + 2 : fcv->c_xe - fcv->c_xs + 2)) + return 0; + /* fix weights to real size (can't be helped, sorry) */ + for (cv = fcv->c_slback->c_slperp; cv; cv = cv->c_slnext) + { + cv->c_slweight = cv->c_slorient == SLICE_VERT ? cv->c_ye - cv->c_ys + 2 : cv->c_xe - cv->c_xs + 2; + debug1(" - weight %d\n", cv->c_slweight); + } + } + if (abs) + diff = diff - fcv->c_slweight; + debug1("diff = %d\n", diff); + if (diff == 0) + return 0; + if (diff < 0) + { + cv = fcv->c_slnext ? fcv->c_slnext : fcv->c_slprev; + fcv->c_slweight += diff; + cv->c_slweight -= diff; + return diff; + } + done = 0; + dir = 1; + for (cv = fcv->c_slnext; diff > 0; cv = dir > 0 ? cv->c_slnext : cv->c_slprev) + { + if (!cv) + { + debug1("reached end, dir is %d\n", dir); + if (dir == -1) + break; + dir = -1; + cv = fcv; + continue; + } + if (percent) + m = 1; + else + m = cv->c_slperp ? CountCanvasPerp(cv) * 2 : 2; + debug2("min is %d, have %d\n", m, cv->c_slweight); + if (cv->c_slweight > m) + { + have = cv->c_slweight - m; + if (have > diff) + have = diff; + debug1("subtract %d\n", have); + cv->c_slweight -= have; + done += have; + diff -= have; + } + } + if (diff && gflag) + { + /* need more room! */ + cv = fcv->c_slback->c_slback; + if (cv && cv->c_slback) + done += ChangeCanvasSize(fcv->c_slback->c_slback, 0, diff, gflag, percent); + } + fcv->c_slweight += done; + debug1("ChangeCanvasSize returns %d\n", done); + return done; +} + +static void +ResizeRegions(arg, flags) +char *arg; +int flags; +{ + struct canvas *cv; + int diff, l; + int gflag = 0, abs = 0, percent = 0; + int orient = 0; + + ASSERT(display); + if (!*arg) + return; + if (D_forecv->c_slorient == SLICE_UNKN) + { + Msg(0, "resize: need more than one region"); + return; + } + gflag = flags & RESIZE_FLAG_L ? 0 : 1; + orient |= flags & RESIZE_FLAG_H ? SLICE_HORI : 0; + orient |= flags & RESIZE_FLAG_V ? SLICE_VERT : 0; + if (orient == 0) + orient = D_forecv->c_slorient; + l = strlen(arg); + if (*arg == '=') + { + /* make all regions the same height */ + struct canvas *cv = gflag ? &D_canvas : D_forecv->c_slback; + if (cv->c_slperp->c_slorient & orient) + EqualizeCanvas(cv->c_slperp, gflag); + /* can't use cv->c_slorient directly as it can be D_canvas */ + if ((cv->c_slperp->c_slorient ^ (SLICE_HORI ^ SLICE_VERT)) & orient) + { + if (cv->c_slback) + { + cv = cv->c_slback; + EqualizeCanvas(cv->c_slperp, gflag); + } + else + EqualizeCanvas(cv, gflag); + } + ResizeCanvas(cv); + RecreateCanvasChain(); + RethinkDisplayViewports(); + ResizeLayersToCanvases(); + return; + } + if (!strcmp(arg, "min") || !strcmp(arg, "0")) + { + abs = 2; + diff = 0; + } + else if (!strcmp(arg, "max") || !strcmp(arg, "_")) + { + abs = 2; + diff = 1; + } + else + { + if (l > 0 && arg[l - 1] == '%') + percent = 1000; + if (*arg == '+') + diff = atoi(arg + 1); + else if (*arg == '-') + diff = -atoi(arg + 1); + else + { + diff = atoi(arg); /* +1 because of caption line */ + if (diff < 0) + diff = 0; + abs = diff == 0 ? 2 : 1; + } + } + if (!abs && !diff) + return; + if (percent) + diff = diff * percent / 100; + cv = D_forecv; + if (cv->c_slorient & orient) + ChangeCanvasSize(cv, abs, diff, gflag, percent); + if (cv->c_slback->c_slorient & orient) + ChangeCanvasSize(cv->c_slback, abs, diff, gflag, percent); + + ResizeCanvas(&D_canvas); + RecreateCanvasChain(); + RethinkDisplayViewports(); + ResizeLayersToCanvases(); + return; + +#if 0 + + if (siz + diff < 1) + diff = 1 - siz; + if (siz + diff > dsize - (nreg - 1) * 2 - 1) + diff = dsize - (nreg - 1) * 2 - 1 - siz; + if (diff == 0 || siz + diff < 1) + return; + + if (diff < 0) + { + if (D_forecv->c_next) + { + D_forecv->c_ye += diff; + D_forecv->c_next->c_ys += diff; + D_forecv->c_next->c_yoff += diff; + } + else + { + for (cv = D_cvlist; cv; cv = cv->c_next) + if (cv->c_next == D_forecv) + break; + ASSERT(cv); + cv->c_ye -= diff; + D_forecv->c_ys -= diff; + D_forecv->c_yoff -= diff; + } + } + else + { + int s, i = 0, found = 0, di = diff, d2; + s = dsize - (nreg - 1) * 2 - 1 - siz; + for (cv = D_cvlist; cv; i = cv->c_ye + 2, cv = cv->c_next) + { + if (cv == D_forecv) + { + cv->c_ye = i + (cv->c_ye - cv->c_ys) + diff; + cv->c_yoff -= cv->c_ys - i; + cv->c_ys = i; + found = 1; + continue; + } + s -= cv->c_ye - cv->c_ys; + if (!found) + { + if (s >= di) + continue; + d2 = di - s; + } + else + d2 = di > cv->c_ye - cv->c_ys ? cv->c_ye - cv->c_ys : di; + di -= d2; + cv->c_ye = i + (cv->c_ye - cv->c_ys) - d2; + cv->c_yoff -= cv->c_ys - i; + cv->c_ys = i; + } + } + RethinkDisplayViewports(); + ResizeLayersToCanvases(); +#endif +} + +static void +ResizeFin(buf, len, data) +char *buf; +int len; +char *data; +{ + int ch; + int flags = *(int *)data; + ch = ((unsigned char *)buf)[len]; + if (ch == 0) + { + ResizeRegions(buf, flags); + return; + } + if (ch == 'h') + flags ^= RESIZE_FLAG_H; + else if (ch == 'v') + flags ^= RESIZE_FLAG_V; + else if (ch == 'b') + flags |= RESIZE_FLAG_H|RESIZE_FLAG_V; + else if (ch == 'p') + flags ^= D_forecv->c_slorient == SLICE_VERT ? RESIZE_FLAG_H : RESIZE_FLAG_V; + else if (ch == 'l') + flags ^= RESIZE_FLAG_L; + else + return; + inp_setprompt(resizeprompts[flags], NULL); + *(int *)data = flags; + buf[len] = '\034'; +} + +void +SetForeCanvas(d, cv) +struct display *d; +struct canvas *cv; +{ + struct display *odisplay = display; + if (d->d_forecv == cv) + return; + + display = d; + D_forecv = cv; + if ((focusminwidth && (focusminwidth < 0 || D_forecv->c_xe - D_forecv->c_xs + 1 < focusminwidth)) || + (focusminheight && (focusminheight < 0 || D_forecv->c_ye - D_forecv->c_ys + 1 < focusminheight))) + { + ResizeCanvas(&D_canvas); + RecreateCanvasChain(); + RethinkDisplayViewports(); + ResizeLayersToCanvases(); /* redisplays */ + } + fore = D_fore = Layer2Window(D_forecv->c_layer); + if (D_other == fore) + D_other = 0; + flayer = D_forecv->c_layer; +#ifdef RXVT_OSC + if (D_xtermosc[2] || D_xtermosc[3]) + { + Activate(-1); + } + else +#endif + { + RefreshHStatus(); +#ifdef RXVT_OSC + RefreshXtermOSC(); +#endif + flayer = D_forecv->c_layer; + CV_CALL(D_forecv, LayRestore();LaySetCursor()); + WindowChanged(0, 'F'); + } + + display = odisplay; +} + +#ifdef RXVT_OSC +void +RefreshXtermOSC() +{ + int i; + struct win *p; + + p = Layer2Window(D_forecv->c_layer); + for (i = 4; i >=0; i--) + SetXtermOSC(i, p ? p->w_xtermosc[i] : 0, "\a"); +} +#endif + +int +ParseAttrColor(s1, s2, msgok) +char *s1, *s2; +int msgok; +{ + int i, n; + char *s, *ss; + int r = 0; + + s = s1; + while (*s == ' ') + s++; + ss = s; + while (*ss && *ss != ' ') + ss++; + while (*ss == ' ') + ss++; + if (*s && (s2 || *ss || !((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || *s == '.'))) + { + int mode = 0, n = 0; + if (*s == '+') + { + mode = 1; + s++; + } + else if (*s == '-') + { + mode = -1; + s++; + } + else if (*s == '!') + { + mode = 2; + s++; + } + else if (*s == '=') + s++; + if (*s >= '0' && *s <= '9') + { + n = *s++ - '0'; + if (*s >= '0' && *s <= '9') + n = n * 16 + (*s++ - '0'); + else if (*s >= 'a' && *s <= 'f') + n = n * 16 + (*s++ - ('a' - 10)); + else if (*s >= 'A' && *s <= 'F') + n = n * 16 + (*s++ - ('A' - 10)); + else if (*s && *s != ' ') + { + if (msgok) + Msg(0, "Illegal attribute hexchar '%c'", *s); + return -1; + } + } + else + { + while (*s && *s != ' ') + { + if (*s == 'd') + n |= A_DI; + else if (*s == 'u') + n |= A_US; + else if (*s == 'b') + n |= A_BD; + else if (*s == 'r') + n |= A_RV; + else if (*s == 's') + n |= A_SO; + else if (*s == 'B') + n |= A_BL; + else + { + if (msgok) + Msg(0, "Illegal attribute specifier '%c'", *s); + return -1; + } + s++; + } + } + if (*s && *s != ' ') + { + if (msgok) + Msg(0, "junk after attribute description: '%c'", *s); + return -1; + } + if (mode == -1) + r = n << 8 | n; + else if (mode == 1) + r = n << 8; + else if (mode == 2) + r = n; + else if (mode == 0) + r = 0xffff ^ n; + } + while (*s && *s == ' ') + s++; + + if (s2) + { + if (*s) + { + if (msgok) + Msg(0, "junk after description: '%c'", *s); + return -1; + } + s = s2; + while (*s && *s == ' ') + s++; + } + +#ifdef COLOR + if (*s) + { + static char costr[] = "krgybmcw d i.01234567 9 f FKRGYBMCW I "; + int numco = 0, j; + + n = 0; + if (*s == '.') + { + numco++; + n = 0x0f; + s++; + } + for (j = 0; j < 2 && *s && *s != ' '; j++) + { + for (i = 0; costr[i]; i++) + if (*s == costr[i]) + break; + if (!costr[i]) + { + if (msgok) + Msg(0, "illegal color descriptor: '%c'", *s); + return -1; + } + numco++; + n = n << 4 | (i & 15); +#ifdef COLORS16 + if (i >= 48) + n = (n & 0x20ff) | 0x200; +#endif + s++; + } + if ((n & 0xf00) == 0xf00) + n ^= 0xf00; /* clear superflous bits */ +#ifdef COLORS16 + if (n & 0x2000) + n ^= 0x2400; /* shift bit into right position */ +#endif + if (numco == 1) + n |= 0xf0; /* don't change bg color */ + if (numco != 2 && n != 0xff) + n |= 0x100; /* special invert mode */ + if (*s && *s != ' ') + { + if (msgok) + Msg(0, "junk after color description: '%c'", *s); + return -1; + } + n ^= 0xff; + r |= n << 16; + } +#endif + + while (*s && *s == ' ') + s++; + if (*s) + { + if (msgok) + Msg(0, "junk after description: '%c'", *s); + return -1; + } + debug1("ParseAttrColor %06x\n", r); + return r; +} + +/* + * Color coding: + * 0-7 normal colors + * 9 default color + * e just set intensity + * f don't change anything + * Intensity is encoded into bits 17(fg) and 18(bg). + */ +void +ApplyAttrColor(i, mc) +int i; +struct mchar *mc; +{ + debug1("ApplyAttrColor %06x\n", i); + mc->attr |= i >> 8 & 255; + mc->attr ^= i & 255; +#ifdef COLOR + i = (i >> 16) ^ 0xff; + if ((i & 0x100) != 0) + { + i &= 0xeff; + if (mc->attr & (A_SO|A_RV)) +# ifdef COLORS16 + i = ((i & 0x0f) << 4) | ((i & 0xf0) >> 4) | ((i & 0x200) << 1) | ((i & 0x400) >> 1); +# else + i = ((i & 0x0f) << 4) | ((i & 0xf0) >> 4); +# endif + } +# ifdef COLORS16 + if ((i & 0x0f) != 0x0f) + mc->attr = (mc->attr & 0xbf) | ((i >> 3) & 0x40); + if ((i & 0xf0) != 0xf0) + mc->attr = (mc->attr & 0x7f) | ((i >> 3) & 0x80); +# endif + mc->color = 0x99 ^ mc->color; + if ((i & 0x0e) == 0x0e) + i = (i & 0xf0) | (mc->color & 0x0f); + if ((i & 0xe0) == 0xe0) + i = (i & 0x0f) | (mc->color & 0xf0); + mc->color = 0x99 ^ i; + debug2("ApplyAttrColor - %02x %02x\n", mc->attr, i); +#endif +} -- cgit v1.2.3