home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / screen-3.5 / part07 / process.c < prev   
Encoding:
C/C++ Source or Header  |  1993-07-25  |  51.0 KB  |  2,459 lines

  1. /* Copyright (c) 1993
  2.  *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  3.  *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  4.  * Copyright (c) 1987 Oliver Laumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program (see the file COPYING); if not, write to the
  18.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  ****************************************************************
  21.  */
  22.  
  23. #include "rcs.h"
  24. RCS_ID("$Id: process.c,v 1.12 1993/07/21 15:43:19 mlschroe Exp $ FAU")
  25.  
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <signal.h>
  29. #include <fcntl.h>
  30. #if !defined(sun) && !defined(B43) && !defined(ISC) && !defined(pyr) && !defined(_CX_UX)
  31. # include <time.h>
  32. #endif
  33. #include <sys/time.h>
  34. #ifndef sun
  35. #include <sys/ioctl.h>
  36. #endif
  37.  
  38.  
  39. #include "config.h"
  40. #include "screen.h"
  41. #include "extern.h"
  42.  
  43. #if defined(sun) && defined(SVR4)
  44. # include <sys/stropts.h>
  45. #endif
  46.  
  47. extern struct comm comms[];
  48. extern char *rc_name;
  49. extern char *RcFileName, *home, *extra_incap, *extra_outcap;
  50. extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[];
  51. extern char *hardcopydir, *screenlogdir;
  52. extern char *VisualBellString;
  53. extern int VBellWait, MsgWait, MsgMinWait, SilenceWait;
  54. extern char Esc, MetaEsc;
  55. extern char SockPath[], *SockNamePtr;
  56. extern int TtyMode, auto_detach;
  57. extern int iflag;
  58. extern int default_wrap;
  59. extern int use_hardstatus, visual_bell, default_monitor;
  60. extern int default_startup;
  61. extern int slowpaste, defobuflimit;
  62. #ifdef AUTO_NUKE
  63. extern int defautonuke;
  64. #endif
  65. extern char screenterm[];
  66. extern int intrc, origintrc; /* display? */
  67. extern struct NewWindow nwin_default, nwin_undef;
  68. #ifdef COPY_PASTE
  69. extern int join_with_cr;
  70. extern char mark_key_tab[];
  71. extern char *BufferFile;
  72. #endif
  73. #ifdef POW_DETACH
  74. extern char *BufferFile, *PowDetachString;
  75. #endif
  76. extern time_t Now;
  77.  
  78.  
  79. static int  CheckArgNum __P((int, char **));
  80. static void FreeKey __P((int));
  81. static int  NextWindow __P((void));
  82. static int  PreviousWindow __P((void));
  83. static int  MoreWindows __P((void));
  84. static void LogToggle __P((int));
  85. static void ShowTime __P((void));
  86. static void ShowInfo __P((void));
  87. static void SwitchWindow __P((int));
  88. static char **SaveArgs __P((char **));
  89. static struct win *WindowByName __P((char *));
  90. static int  ParseSwitch __P((struct action *, int *));
  91. static int  ParseOnOff __P((struct action *, int *));
  92. static int  ParseSaveStr __P((struct action *act, char **));
  93. static int  ParseNum __P((struct action *act, int *));
  94. static int  ParseWinNum __P((struct action *act, int *));
  95. static int  ParseOct __P((struct action *act, int *));
  96. static char *ParseChar __P((char *, char *));
  97. static int  IsNum __P((char *, int));
  98. static int  IsNumColon __P((char *, int, char *, int));
  99. static void InputColon __P((void));
  100. static void Colonfin __P((char *, int));
  101. static void InputSelect __P((void));
  102. static void InputAKA __P((void));
  103. static void AKAfin __P((char *, int));
  104. #ifdef COPY_PASTE
  105. static void copy_reg_fn __P((char *, int));
  106. static void ins_reg_fn __P((char *, int));
  107. #endif
  108. static void process_fn __P((char *, int));
  109. #ifdef PASSWORD
  110. static void pass1 __P((char *, int));
  111. static void pass2 __P((char *, int));
  112. #endif
  113. #ifdef POW_DETACH
  114. static void pow_detach_fn __P((char *, int));
  115. #endif
  116.  
  117.  
  118.  
  119. extern struct display *display, *displays;
  120. extern struct win *fore, *console_window, *windows;
  121.  
  122. extern char screenterm[], HostName[], version[];
  123. extern struct NewWindow nwin_undef, nwin_default;
  124. extern struct LayFuncs WinLf;
  125. extern struct layer BlankLayer;
  126.  
  127. extern int Z0width, Z1width;
  128. extern int real_uid, real_gid;
  129. extern int visual_bell, default_monitor;
  130.  
  131. #ifdef NETHACK
  132. extern int nethackflag;
  133. #endif
  134.  
  135.  
  136. struct win *wtab[MAXWIN];    /* window table */
  137. struct action ktab[256];    /* command key translation table */
  138.  
  139.  
  140. #ifdef MULTIUSER
  141. extern char *multi;
  142. #endif
  143. #ifdef PASSWORD
  144. int CheckPassword;
  145. char Password[20];
  146. #endif
  147.  
  148. #define MAX_PLOP_DEFS 256
  149.  
  150. static struct plop
  151. {
  152.   char *buf;
  153.   int len;
  154. } plop_tab[MAX_PLOP_DEFS];
  155.  
  156.  
  157. char Esc = Ctrl('a');
  158. char MetaEsc = 'a';
  159. #ifdef PTYMODE
  160. int TtyMode = PTYMODE;
  161. #else
  162. int TtyMode = 0622;
  163. #endif
  164. int hardcopy_append = 0;
  165. int all_norefresh = 0;
  166.  
  167.  
  168. char *noargs[1];
  169.  
  170. void
  171. InitKeytab()
  172. {
  173.   register unsigned int i;
  174.  
  175.   for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
  176.     {
  177.       ktab[i].nr = RC_ILLEGAL;
  178.       ktab[i].args = noargs;
  179.     }
  180.  
  181.   ktab['h'].nr = ktab[Ctrl('h')].nr = RC_HARDCOPY;
  182. #ifdef BSDJOBS
  183.   ktab['z'].nr = ktab[Ctrl('z')].nr = RC_SUSPEND;
  184. #endif
  185.   ktab['c'].nr = ktab[Ctrl('c')].nr = RC_SCREEN;
  186.   ktab[' '].nr = ktab[Ctrl(' ')].nr =
  187.     ktab['n'].nr = ktab[Ctrl('n')].nr = RC_NEXT;
  188.   ktab['N'].nr = RC_NUMBER;
  189.   ktab[Ctrl('h')].nr = ktab[0177].nr = ktab['p'].nr = ktab[Ctrl('p')].nr = RC_PREV;
  190.   ktab['k'].nr = ktab[Ctrl('k')].nr = RC_KILL;
  191.   ktab['l'].nr = ktab[Ctrl('l')].nr = RC_REDISPLAY;
  192.   ktab['w'].nr = ktab[Ctrl('w')].nr = RC_WINDOWS;
  193.   ktab['v'].nr = ktab[Ctrl('v')].nr = RC_VERSION;
  194.   ktab['q'].nr = ktab[Ctrl('q')].nr = RC_XON;
  195.   ktab['s'].nr = ktab[Ctrl('s')].nr = RC_XOFF;
  196.   ktab['t'].nr = ktab[Ctrl('t')].nr = RC_TIME;
  197.   ktab['i'].nr = ktab[Ctrl('i')].nr = RC_INFO;
  198.   ktab['m'].nr = ktab[Ctrl('m')].nr = RC_LASTMSG;
  199.   ktab['A'].nr = RC_AKA;
  200. #ifdef UTMPOK
  201.   ktab['L'].nr = RC_LOGIN;
  202. #endif
  203.   ktab[','].nr = RC_LICENSE;
  204.   ktab['W'].nr = RC_WIDTH;
  205.   ktab['.'].nr = RC_DUMPTERMCAP;
  206.   ktab[Ctrl('\\')].nr = RC_QUIT;
  207.   ktab['d'].nr = ktab[Ctrl('d')].nr = RC_DETACH;
  208.   ktab['r'].nr = ktab[Ctrl('r')].nr = RC_WRAP;
  209.   ktab['f'].nr = ktab[Ctrl('f')].nr = RC_FLOW;
  210.   ktab['C'].nr = RC_CLEAR;
  211.   ktab['Z'].nr = RC_RESET;
  212.   ktab['H'].nr = RC_LOG;
  213.   ktab[(unsigned int)Esc].nr = RC_OTHER;
  214.   ktab[(unsigned int)MetaEsc].nr = RC_META;
  215.   ktab['M'].nr = RC_MONITOR;
  216.   ktab['?'].nr = RC_HELP;
  217.   for (i = 0; i < ((MAXWIN < 10) ? MAXWIN : 10); i++)
  218.     {
  219.       char *args[2], arg1[10];
  220.       args[0] = arg1;
  221.       args[1] = 0;
  222.       sprintf(arg1, "%d", i);
  223.       ktab['0' + i].nr = RC_SELECT;
  224.       ktab['0' + i].args = SaveArgs(args);
  225.     }
  226.   ktab[Ctrl('G')].nr = RC_VBELL;
  227.   ktab[':'].nr = RC_COLON;
  228. #ifdef COPY_PASTE
  229.   ktab['['].nr = ktab[Ctrl('[')].nr = RC_COPY;
  230.   ktab[']'].nr = ktab[Ctrl(']')].nr = RC_PASTE;
  231.   ktab['{'].nr = RC_HISTORY;
  232.   ktab['}'].nr = RC_HISTORY;
  233.   ktab['>'].nr = RC_WRITEBUF;
  234.   ktab['<'].nr = RC_READBUF;
  235.   ktab['='].nr = RC_REMOVEBUF;
  236.   ktab['\''].nr = ktab['"'].nr = RC_SELECT; /* calling a window by name */
  237. #endif
  238. #ifdef POW_DETACH
  239.   ktab['D'].nr = RC_POW_DETACH;
  240. #endif
  241. #ifdef LOCK
  242.   ktab['x'].nr = ktab[Ctrl('x')].nr = RC_LOCKSCREEN;
  243. #endif
  244.   ktab['b'].nr = ktab[Ctrl('b')].nr = RC_BREAK;
  245.   ktab['B'].nr = RC_POW_BREAK;
  246.   ktab['_'].nr = RC_SILENCE;
  247. }
  248.  
  249. static void
  250. FreeKey(key)
  251. int key;
  252. {
  253.   char **p;
  254.  
  255.   struct action *act = &ktab[key];
  256.   if (act->nr == RC_ILLEGAL)
  257.     return;
  258.   act->nr = RC_ILLEGAL;
  259.   if (act->args == noargs)
  260.     return;
  261.   for (p = act->args; *p; p++)
  262.     free(*p);
  263.   free(act->args);
  264.   act->args = noargs;
  265. }
  266.  
  267. void
  268. ProcessInput(ibuf, ilen)
  269. char *ibuf;
  270. int ilen;
  271. {
  272.   char *s;
  273.   int slen;
  274.  
  275.   while (display)
  276.     {
  277.       fore = d_fore;
  278.       slen = ilen;
  279.       s = ibuf;
  280.       while (ilen > 0)
  281.     {
  282.       if (*s++ == Esc)
  283.         break;
  284.       ilen--;
  285.     }
  286.       slen -= ilen;
  287.       while (slen)
  288.     Process(&ibuf, &slen);
  289.       if (--ilen == 0)
  290.     d_ESCseen = 1;
  291.       if (ilen <= 0)
  292.     return;
  293.       DoAction(&ktab[(int)(unsigned char)*s], (int)(unsigned char)*s);
  294.       ibuf = s + 1;
  295.       ilen--;
  296.     }
  297. }
  298.  
  299. int
  300. FindCommnr(str)
  301. char *str;
  302. {
  303.   int x, m, l = 0, r = RC_LAST;
  304.   while (l <= r)
  305.     {
  306.       m = (l + r) / 2;
  307.       x = strcmp(str, comms[m].name);
  308.       if (x > 0)
  309.     l = m + 1;
  310.       else if (x < 0)
  311.     r = m - 1;
  312.       else
  313.     return m;
  314.     }
  315.   return RC_ILLEGAL;
  316. }
  317.  
  318. static int
  319. CheckArgNum(nr, args)
  320. int nr;
  321. char **args;
  322. {
  323.   int i, n;
  324.   static char *argss[] = {"no", "one", "two", "three"};
  325.  
  326.   n = comms[nr].flags & ARGS_MASK;
  327.   for (i = 0; args[i]; i++)
  328.     ;
  329.   if (comms[nr].flags & ARGS_ORMORE)
  330.     {
  331.       if (i < n)
  332.     {
  333.       Msg(0, "%s: %s: at least %s argument%s required", rc_name, comms[nr].name, argss[n], n != 1 ? "s" : "");
  334.       return -1;
  335.     }
  336.     }
  337.   else if (comms[nr].flags & ARGS_PLUSONE)
  338.     {
  339.       if (i != n && i != n + 1)
  340.     {
  341.       Msg(0, "%s: %s: %s or %s argument%s required", rc_name, comms[nr].name, argss[n], argss[n + 1], n != 0 ? "s" : "");
  342.           return -1;
  343.     }
  344.     }
  345.   else if (i != n)
  346.     {
  347.       Msg(0, "%s: %s: %s argument%s required", rc_name, comms[nr].name, argss[n], n != 1 ? "s" : "");
  348.       return -1;
  349.     }
  350.   return 0;
  351. }
  352.  
  353. /*ARGSUSED*/
  354. void
  355. DoAction(act, key)
  356. struct action *act;
  357. int key;
  358. {
  359.   int nr = act->nr;
  360.   char **args = act->args;
  361.   struct win *p;
  362.   int i, n, msgok;
  363.   char *s;
  364.   char ch;
  365.  
  366.   if (nr == RC_ILLEGAL)
  367.     {
  368.       debug1("key '%c': No action\n", key);
  369.       return;
  370.     }
  371.   n = comms[nr].flags;
  372.   if ((n & NEED_DISPLAY) && display == 0)
  373.     {
  374.       Msg(0, "%s: %s: display required", rc_name, comms[nr].name);
  375.       return;
  376.     }
  377.   if ((n & NEED_FORE) && fore == 0)
  378.     {
  379.       Msg(0, "%s: %s: window required", rc_name, comms[nr].name);
  380.       return;
  381.     }
  382.   if (CheckArgNum(nr, args))
  383.     return;
  384. #ifdef MULTIUSER
  385.   if (multi && display)
  386.     {
  387.       if (AclCheckPermCmd(d_user, ACL_EXEC, &comms[nr]))
  388.     return;
  389.     }
  390. #endif /* MULTIUSER */
  391.   msgok = display && !*rc_name;
  392.   switch(nr)
  393.     {
  394.     case RC_SELECT:
  395.       if (!*args)
  396.         InputSelect();
  397.       else if (ParseWinNum(act, &n) == 0)
  398.         SwitchWindow(n);
  399.       break;
  400. #ifdef AUTO_NUKE
  401.     case RC_DEFAUTONUKE:
  402.       if (ParseOnOff(act, &defautonuke) == 0 && msgok)
  403.     Msg(0, "Default autonuke turned %s", defautonuke ? "on" : "off");
  404.       if (display && *rc_name)
  405.     d_auto_nuke = defautonuke;
  406.       break;
  407.     case RC_AUTONUKE:
  408.       if (ParseOnOff(act, &d_auto_nuke) == 0 && msgok)
  409.     Msg(0, "Autonuke turned %s", d_auto_nuke ? "on" : "off");
  410.       break;
  411. #endif
  412.     case RC_DUPLICATE:
  413.       if (!*args)
  414.     {
  415.       if (fore->w_dupto >= 0)
  416.         Msg(0, "Duplicating output to window %d", fore->w_dupto);
  417.       else
  418.         Msg(0, "No duplicate from here\n");
  419.       break;
  420.     }
  421.       if (!strcmp(*args, "off"))
  422.         {
  423.       fore->w_dupto = -1;
  424.       break;
  425.     }
  426.       while (*args)
  427.         {
  428.       n = WindowByNoN(*args++);
  429.           if (n < 0)
  430.         {
  431.           Msg(0, "Invalid window description");
  432.           continue;
  433.         }
  434.       if ((p = wtab[n]) == 0)
  435.         {
  436.           Msg(0, "Window %d does not exist", n);
  437.           continue;
  438.         }
  439.       for (nr = fore->w_number; wtab[nr] && wtab[nr]->w_dupto >= 0;nr = wtab[nr]->w_dupto)
  440.         {
  441.           if (wtab[nr]->w_dupto == n)
  442.         {
  443.           Msg(0, "Cyclic dup detected\n");
  444.           return;
  445.         }
  446.         }
  447.       wtab[n]->w_dupto = fore->w_number;
  448.     }
  449.       break;
  450.     case RC_DEFOBUFLIMIT:
  451.       if (ParseNum(act, &defobuflimit) == 0 && msgok)
  452.     Msg(0, "Default limit set to %d", defobuflimit);
  453.       if (display && *rc_name)
  454.     d_obufmax = defobuflimit;
  455.       break;
  456.     case RC_OBUFLIMIT:
  457.       if (*args == 0)
  458.     Msg(0, "Limit is %d, current buffer size is %d", d_obufmax, d_obuflen);
  459.       else if (ParseNum(act, &d_obufmax) == 0 && msgok)
  460.     Msg(0, "Limit set to %d", d_obufmax);
  461.       break;
  462.     case RC_DUMPTERMCAP:
  463.       WriteFile(DUMP_TERMCAP);
  464.       break;
  465.     case RC_HARDCOPY:
  466.       WriteFile(DUMP_HARDCOPY);
  467.       break;
  468.     case RC_LOG:
  469.       n = fore->w_logfp ? 1 : 0;
  470.       ParseSwitch(act, &n);
  471.       LogToggle(n);
  472.       break;
  473. #ifdef BSDJOBS
  474.     case RC_SUSPEND:
  475.       Detach(D_STOP);
  476.       break;
  477. #endif
  478.     case RC_NEXT:
  479.       if (MoreWindows())
  480.     SwitchWindow(NextWindow());
  481.       break;
  482.     case RC_PREV:
  483.       if (MoreWindows())
  484.     SwitchWindow(PreviousWindow());
  485.       break;
  486.     case RC_KILL:
  487.       {
  488.     char *name;
  489.  
  490.     n = fore->w_number;
  491. #ifdef PSEUDOS
  492.     if (fore->w_pwin)
  493.       {
  494.         FreePseudowin(fore);
  495. #ifdef NETHACK
  496.         if (nethackflag)
  497.           Msg(0, "You have a sad feeling for a moment...");
  498.         else
  499. #endif
  500.         Msg(0, "Filter removed.");
  501.         break;
  502.       }
  503. #endif
  504.     name = SaveStr(fore->w_aka);
  505.     KillWindow(fore);
  506. #ifdef NETHACK
  507.     if (nethackflag)
  508.       Msg(0, "You destroy poor window %d (%s).", n, name);
  509.     else
  510. #endif
  511.     Msg(0, "Window %d (%s) killed.", n, name);
  512.     if (name)
  513.       free(name);
  514.     break;
  515.       }
  516.     case RC_QUIT:
  517.       Finit(0);
  518.       /* NOTREACHED */
  519.     case RC_DETACH:
  520.       Detach(D_DETACH);
  521.       break;
  522. #ifdef POW_DETACH
  523.     case RC_POW_DETACH:
  524.       if (key >= 0)
  525.     {
  526.       static char buf[2];
  527.  
  528.       buf[0] = key;
  529.       Input(buf, 1, pow_detach_fn, INP_RAW);
  530.     }
  531.       else
  532.         Detach(D_POWER); /* detach and kill Attacher's parent */
  533.       break;
  534. #endif
  535. #ifdef COPY_PASTE
  536.     case RC_COPY_REG:
  537.       if ((s = *args) == NULL)
  538.     {
  539.       Input("Copy to register:", 1, copy_reg_fn, INP_RAW);
  540.       break;
  541.     }
  542.       if ((s = ParseChar(s, &ch)) == NULL || *s)
  543.     {
  544.       Msg(0, "%s: copy_reg: character, ^x, or (octal) \\032 expected.",
  545.           rc_name);
  546.       break;
  547.     }
  548.       copy_reg_fn(&ch, 0);
  549.       break;
  550.     case RC_INS_REG:
  551.       if ((s = *args) == NULL)
  552.     {
  553.       Input("Insert from register:", 1, ins_reg_fn, INP_RAW);
  554.       break;
  555.     }
  556.       if ((s = ParseChar(s, &ch)) == NULL || *s)
  557.     {
  558.       Msg(0, "%s: ins_reg: character, ^x, or (octal) \\032 expected.",
  559.           rc_name);
  560.       break;
  561.     }
  562.       ins_reg_fn(&ch, 0);
  563.       break;
  564. #endif
  565.     case RC_REGISTER:
  566.       if ((s = ParseChar(*args, &ch)) == NULL || *s)
  567.     Msg(0, "%s: register: character, ^x, or (octal) \\032 expected.",
  568.         rc_name);
  569.       else
  570.     {
  571.       struct plop *plp = plop_tab + (int)(unsigned char)ch;
  572.  
  573.       if (plp->buf)
  574.         free(plp->buf);
  575.       plp->buf = SaveStr(args[1]);
  576.       plp->len = strlen(args[1]);
  577.     }
  578.       break;
  579.     case RC_PROCESS:
  580.       if ((s = *args) == NULL)
  581.     {
  582.       Input("Process register:", 1, process_fn, INP_RAW);
  583.       break;
  584.     }
  585.       if ((s = ParseChar(s, &ch)) == NULL || *s)
  586.     {
  587.       Msg(0, "%s: process: character, ^x, or (octal) \\032 expected.",
  588.           rc_name);
  589.       break;
  590.     }
  591.       process_fn(&ch, 0);
  592.       break;
  593.     case RC_REDISPLAY:
  594.       Activate(-1);
  595.       break;
  596.     case RC_WINDOWS:
  597.       ShowWindows();
  598.       break;
  599.     case RC_VERSION:
  600.       Msg(0, "screen %s", version);
  601.       break;
  602.     case RC_TIME:
  603.       ShowTime();
  604.       break;
  605.     case RC_INFO:
  606.       ShowInfo();
  607.       break;
  608.     case RC_OTHER:
  609.       if (MoreWindows())
  610.     SwitchWindow(d_other ? d_other->w_number : NextWindow());
  611.       break;
  612.     case RC_META:
  613.       ch = Esc;
  614.       s = &ch;
  615.       n = 1;
  616.       Process(&s, &n);
  617.       break;
  618.     case RC_XON:
  619.       ch = Ctrl('q');
  620.       s = &ch;
  621.       n = 1;
  622.       Process(&s, &n);
  623.       break;
  624.     case RC_XOFF:
  625.       ch = Ctrl('s');
  626.       s = &ch;
  627.       n = 1;
  628.       Process(&s, &n);
  629.       break;
  630.     case RC_POW_BREAK:
  631.     case RC_BREAK:
  632.       n = 0;
  633.       if (*args && ParseNum(act, &n))
  634.     break;
  635.       SendBreak(fore, n, nr == RC_POW_BREAK);
  636.       break;
  637. #ifdef LOCK
  638.     case RC_LOCKSCREEN:
  639.       Detach(D_LOCK);
  640.       break;
  641. #endif
  642.     case RC_WIDTH:
  643.       if (*args)
  644.     {
  645.       if (ParseNum(act, &n))
  646.         break;
  647.     }
  648.       else
  649.     {
  650.       if (d_width == Z0width)
  651.         n = Z1width;
  652.       else if (d_width == Z1width)
  653.         n = Z0width;
  654.       else if (d_width > (Z0width + Z1width) / 2)
  655.         n = Z0width;
  656.       else
  657.         n = Z1width;
  658.     }
  659.       if (n <= 0)
  660.         {
  661.       Msg(0, "Illegal width");
  662.       break;
  663.     }
  664.       if (n == d_width)
  665.     break;
  666.       if (ResizeDisplay(n, d_height) == 0)
  667.     {
  668.       DoResize(d_width, d_height);
  669.       Activate(d_fore ? d_fore->w_norefresh : 0);
  670.     }
  671.       else
  672.     Msg(0, "Your termcap does not specify how to change the terminal's width to %d.", n);
  673.       break;
  674.     case RC_HEIGHT:
  675.       if (*args)
  676.     {
  677.       if (ParseNum(act, &n))
  678.         break;
  679.     }
  680.       else
  681.     {
  682. #define H0height 42
  683. #define H1height 24
  684.       if (d_height == H0height)
  685.         n = H1height;
  686.       else if (d_height == H1height)
  687.         n = H0height;
  688.       else if (d_height > (H0height + H1height) / 2)
  689.         n = H0height;
  690.       else
  691.         n = H1height;
  692.     }
  693.       if (n <= 0)
  694.         {
  695.       Msg(0, "Illegal height");
  696.       break;
  697.     }
  698.       if (n == d_height)
  699.     break;
  700.       if (ResizeDisplay(d_width, n) == 0)
  701.     {
  702.       DoResize(d_width, d_height);
  703.       Activate(d_fore ? d_fore->w_norefresh : 0);
  704.     }
  705.       else
  706.     Msg(0, "Your termcap does not specify how to change the terminal's height to %d.", n);
  707.       break;
  708.     case RC_AKA:
  709.       if (*args == 0)
  710.     InputAKA();
  711.       else
  712.     ChangeAKA(fore, *args, 20);
  713.       break;
  714.     case RC_COLON:
  715.       InputColon();
  716.       break;
  717.     case RC_LASTMSG:
  718.       if (d_status_lastmsg)
  719.     Msg(0, "%s", d_status_lastmsg);
  720.       break;
  721.     case RC_SCREEN:
  722.       DoScreen("key", args);
  723.       break;
  724.     case RC_WRAP:
  725.       if (ParseSwitch(act, &fore->w_wrap) == 0 && msgok)
  726.         Msg(0, "%cwrap", fore->w_wrap ? '+' : '-');
  727.       break;
  728.     case RC_FLOW:
  729.       if (*args)
  730.     {
  731.       if (args[0][0] == 'a')
  732.         {
  733.           fore->w_flow = (fore->w_flow & FLOW_AUTO) ? FLOW_AUTOFLAG |FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
  734.         }
  735.       else
  736.         {
  737.           if (ParseOnOff(act, &n))
  738.         break;
  739.           fore->w_flow = (fore->w_flow & FLOW_AUTO) | n;
  740.         }
  741.     }
  742.       else
  743.     {
  744.       if (fore->w_flow & FLOW_AUTOFLAG)
  745.         fore->w_flow = (fore->w_flow & FLOW_AUTO) | FLOW_NOW;
  746.       else if (fore->w_flow & FLOW_NOW)
  747.         fore->w_flow &= ~FLOW_NOW;
  748.       else
  749.         fore->w_flow = fore->w_flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
  750.     }
  751.       SetFlow(fore->w_flow & FLOW_NOW);
  752.       if (msgok)
  753.     Msg(0, "%cflow%s", (fore->w_flow & FLOW_NOW) ? '+' : '-',
  754.         (fore->w_flow & FLOW_AUTOFLAG) ? "(auto)" : "");
  755.       break;
  756.     case RC_WRITELOCK:
  757.       if (*args)
  758.     {
  759.       if (args[0][0] == 'a')
  760.         {
  761.           fore->w_wlock = WLOCK_AUTO;
  762.         }
  763.       else
  764.         {
  765.           if (ParseOnOff(act, &n))
  766.         break;
  767.           fore->w_wlock = n ? WLOCK_ON : WLOCK_OFF;
  768.         }
  769.     }
  770.       fore->w_wlockuser = d_user;
  771.       Msg(0, "writelock %s", (fore->w_wlock == WLOCK_AUTO) ? "auto" :
  772.       ((fore->w_wlock == WLOCK_OFF) ? "off" : "on"));
  773.       break;
  774.     case RC_CLEAR:
  775.       if (fore->w_state == LIT)
  776.     WriteString(fore, "\033[H\033[J", 6);
  777.       break;
  778.     case RC_RESET:
  779.       if (fore->w_state == LIT)
  780.     WriteString(fore, "\033c", 2);
  781.       break;
  782.     case RC_MONITOR:
  783.       n = fore->w_monitor == MON_ON;
  784.       if (ParseSwitch(act, &n))
  785.     break;
  786.       if (n)
  787.     {
  788.       fore->w_monitor = MON_ON;
  789. #ifdef NETHACK
  790.       if (nethackflag)
  791.         Msg(0, "You feel like someone is watching you...");
  792.       else
  793. #endif
  794.         Msg(0, "Window %d (%s) is now being monitored for all activity.", 
  795.         fore->w_number, fore->w_aka);
  796.     }
  797.       else
  798.     {
  799.       fore->w_monitor = MON_OFF;
  800. #ifdef NETHACK
  801.       if (nethackflag)
  802.         Msg(0, "You no longer sense the watcher's presence.");
  803.       else
  804. #endif
  805.         Msg(0, "Window %d (%s) is no longer being monitored for activity.", 
  806.         fore->w_number, fore->w_aka);
  807.     }
  808.       break;
  809.     case RC_HELP:
  810.       display_help();
  811.       break;
  812.     case RC_LICENSE:
  813.       display_copyright();
  814.       break;
  815. #ifdef COPY_PASTE
  816.     case RC_COPY:
  817.       if (d_layfn != &WinLf)
  818.     {
  819.       Msg(0, "Must be on a window layer");
  820.       break;
  821.     }
  822.       MarkRoutine();
  823.       break;
  824.     case RC_HISTORY:
  825.       if (d_layfn != &WinLf)
  826.     {
  827.       Msg(0, "Must be on a window layer");
  828.       break;
  829.     }
  830.       if (GetHistory())
  831.     if (d_copybuffer != NULL)
  832.       {
  833.         fore->w_pastebuffer = d_copybuffer;
  834.         fore->w_pastelen = d_copylen;
  835.       }
  836.       break;
  837.     case RC_PASTE:
  838.       if (d_copybuffer == NULL)
  839.     {
  840. #ifdef NETHACK
  841.       if (nethackflag)
  842.         Msg(0, "Nothing happens.");
  843.       else
  844. #endif
  845.       Msg(0, "empty buffer");
  846.       break;
  847.     }
  848.       fore->w_pastebuffer = d_copybuffer;
  849.       fore->w_pastelen = d_copylen;
  850.       break;
  851.     case RC_WRITEBUF:
  852.       if (d_copybuffer == NULL)
  853.     {
  854. #ifdef NETHACK
  855.       if (nethackflag)
  856.         Msg(0, "Nothing happens.");
  857.       else
  858. #endif
  859.       Msg(0, "empty buffer");
  860.       break;
  861.     }
  862.       WriteFile(DUMP_EXCHANGE);
  863.       break;
  864.     case RC_READBUF:
  865.       ReadFile();
  866.       break;
  867.     case RC_REMOVEBUF:
  868.       KillBuffers();
  869.       break;
  870. #endif                /* COPY_PASTE */
  871.     case RC_ESCAPE:
  872.       FreeKey((int)(unsigned char)Esc);
  873.       FreeKey((int)(unsigned char)MetaEsc);
  874.       if (ParseEscape(*args))
  875.     {
  876.       Msg(0, "%s: two characters required after escape.", rc_name);
  877.       break;
  878.     }
  879.       FreeKey((int)(unsigned char)Esc);
  880.       FreeKey((int)(unsigned char)MetaEsc);
  881.       ktab[(int)(unsigned char)Esc].nr = RC_OTHER;
  882.       ktab[(int)(unsigned char)MetaEsc].nr = RC_META;
  883.       break;
  884.     case RC_CHDIR:
  885.       s = *args ? *args : home;
  886.       if (chdir(s) == -1)
  887.     Msg(errno, "%s", s);
  888.       break;
  889.     case RC_SHELL:
  890.       if (ParseSaveStr(act, &ShellProg) == 0)
  891.         ShellArgs[0] = ShellProg;
  892.       break;
  893.     case RC_HARDCOPYDIR:
  894.       (void)ParseSaveStr(act, &hardcopydir);
  895.       break;
  896.     case RC_LOGDIR:
  897.       (void)ParseSaveStr(act, &screenlogdir);
  898.       break;
  899.     case RC_SHELLAKA:
  900.       (void)ParseSaveStr(act, &nwin_default.aka);
  901.       break;
  902.     case RC_SLEEP:
  903.     case RC_TERMCAP:
  904.     case RC_TERMINFO:
  905.       break;            /* Already handled */
  906.     case RC_TERM:
  907.       s = NULL;
  908.       if (ParseSaveStr(act, &s))
  909.     break;
  910.       if (strlen(s) >= 20)
  911.     {
  912.       Msg(0,"%s: term: argument too long ( < 20)", rc_name);
  913.       free(s);
  914.       break;
  915.     }
  916.       strcpy(screenterm, s);
  917.       free(s);
  918.       debug1("screenterm set to %s\n", screenterm);
  919.       MakeTermcap(display == 0);
  920.       debug("new termcap made\n");
  921.       break;
  922.     case RC_ECHO:
  923.       if (msgok)
  924.     {
  925.       /*
  926.        * d_user typed ^A:echo... well, echo isn't FinishRc's job,
  927.        * but as he wanted to test us, we show good will
  928.        */
  929.       if (*args && (args[1] == 0 || (strcmp(args[1], "-n") == 0 && args[2] == 0)))
  930.         Msg(0, "%s", args[1] ? args[1] : *args);
  931.       else
  932.          Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
  933.     }
  934.       break;
  935.     case RC_BELL:
  936.       (void)ParseSaveStr(act, &BellString);
  937.       break;
  938. #ifdef COPY_PASTE
  939.     case RC_BUFFERFILE:
  940.       if (*args == 0)
  941.     BufferFile = SaveStr(DEFAULT_BUFFERFILE);
  942.       else if (ParseSaveStr(act, &BufferFile))
  943.         break;
  944.       if (msgok)
  945.         Msg(0, "Bufferfile is now '%s'\n", BufferFile);
  946.       break;
  947. #endif
  948.     case RC_ACTIVITY:
  949.       (void)ParseSaveStr(act, &ActivityString);
  950.       break;
  951. #ifdef POW_DETACH
  952.     case RC_POW_DETACH_MSG:
  953.       (void)ParseSaveStr(act, &PowDetachString);
  954.       break;
  955. #endif
  956. #ifdef UTMPOK
  957.     case RC_DEFLOGIN:
  958.       (void)ParseOnOff(act, &nwin_default.lflag);
  959.       break;
  960.     case RC_LOGIN:
  961.       n = fore->w_slot != (slot_t)-1;
  962.       if (ParseSwitch(act, &n) == 0)
  963.         SlotToggle(n);
  964.       break;
  965. #endif
  966.     case RC_DEFFLOW:
  967.       if (args[0] && args[1] && args[1][0] == 'i')
  968.     {
  969.       iflag = 1;
  970.       if ((intrc == VDISABLE) && (origintrc != VDISABLE))
  971.         {
  972. #if defined(TERMIO) || defined(POSIX)
  973.           intrc = d_NewMode.tio.c_cc[VINTR] = origintrc;
  974.           d_NewMode.tio.c_lflag |= ISIG;
  975. #else /* TERMIO || POSIX */
  976.           intrc = d_NewMode.m_tchars.t_intrc = origintrc;
  977. #endif /* TERMIO || POSIX */
  978.  
  979.           if (display)
  980.         SetTTY(d_userfd, &d_NewMode);
  981.         }
  982.     }
  983.       if (args[0] && args[0][0] == 'a')
  984.     nwin_default.flowflag = FLOW_AUTOFLAG;
  985.       else
  986.     (void)ParseOnOff(act, &nwin_default.flowflag);
  987.       break;
  988.     case RC_DEFWRAP:
  989.       (void)ParseOnOff(act, &default_wrap);
  990.       break;
  991.     case RC_HARDSTATUS:
  992.       RemoveStatus();
  993.       (void)ParseSwitch(act, &use_hardstatus);
  994.       break;
  995.     case RC_DEFMONITOR:
  996.       if (ParseOnOff(act, &n) == 0)
  997.         default_monitor = (n == 0) ? MON_OFF : MON_ON;
  998.       break;
  999.     case RC_CONSOLE:
  1000.       n = (console_window != 0);
  1001.       if (ParseSwitch(act, &n))
  1002.         break;
  1003.       if (TtyGrabConsole(fore->w_ptyfd, n, rc_name))
  1004.     break;
  1005.       if (n == 0)
  1006.       Msg(0, "%s: releasing console %s", rc_name, HostName);
  1007.       else if (console_window)
  1008.       Msg(0, "%s: stealing console %s from window %d (%s)", rc_name, 
  1009.           HostName, console_window->w_number, console_window->w_aka);
  1010.       else
  1011.       Msg(0, "%s: grabbing console %s", rc_name, HostName);
  1012.       console_window = n ? fore : 0;
  1013.       break;
  1014.     case RC_ALLPARTIAL:
  1015.       if (ParseOnOff(act, &all_norefresh))
  1016.     break;
  1017.       if (all_norefresh)
  1018.     Msg(0, "No refresh on window change!\n");
  1019.       else
  1020.     {
  1021.       if (fore)
  1022.         Activate(-1);
  1023.       Msg(0, "Window specific refresh\n");
  1024.     }
  1025.       break;
  1026.     case RC_PARTIAL:
  1027.       (void)ParseSwitch(act, &n);
  1028.       fore->w_norefresh = n;
  1029.       break;
  1030.     case RC_VBELL:
  1031.       if (ParseSwitch(act, &visual_bell) || !msgok)
  1032.         break;
  1033.       if (visual_bell == 0)
  1034.     {
  1035. #ifdef NETHACK
  1036.       if (nethackflag)
  1037.         Msg(0, "Suddenly you can't see your bell!");
  1038.       else
  1039. #endif
  1040.       Msg(0, "switched to audible bell.");
  1041.     }
  1042.       else
  1043.     {
  1044. #ifdef NETHACK
  1045.       if (nethackflag)
  1046.         Msg(0, "Your bell is no longer invisible.");
  1047.       else
  1048. #endif
  1049.       Msg(0, "switched to visual bell.");
  1050.     }
  1051.       break;
  1052.     case RC_VBELLWAIT:
  1053.       if (ParseNum(act, &VBellWait) == 0 && msgok)
  1054.         Msg(0, "vbellwait set to %d seconds", VBellWait);
  1055.       break;
  1056.     case RC_MSGWAIT:
  1057.       if (ParseNum(act, &MsgWait) == 0 && msgok)
  1058.         Msg(0, "msgwait set to %d seconds", MsgWait);
  1059.       break;
  1060.     case RC_MSGMINWAIT:
  1061.       if (ParseNum(act, &MsgMinWait) == 0 && msgok)
  1062.         Msg(0, "msgminwait set to %d seconds", MsgMinWait);
  1063.       break;
  1064.     case RC_SILENCEWAIT:
  1065.       if ((ParseNum(act, &SilenceWait) == 0) && msgok)
  1066.         {
  1067.       if (SilenceWait < 1)
  1068.         SilenceWait = 1;
  1069.       for (p = windows; p; p = p->w_next)
  1070.         if (p->w_tstamp.seconds)
  1071.           p->w_tstamp.seconds = SilenceWait;
  1072.       Msg(0, "silencewait set to %d seconds", SilenceWait);
  1073.     }
  1074.       break;
  1075.     case RC_NUMBER:
  1076.       if (*args == 0)
  1077.         Msg(0, "This is window %d (%s).\n", fore->w_number, fore->w_aka);
  1078.       else
  1079.         {
  1080.       int old = fore->w_number;
  1081.  
  1082.       if (ParseNum(act, &n) || n >= MAXWIN)
  1083.         break;
  1084.       p = wtab[n];
  1085.       wtab[n] = fore;
  1086.       fore->w_number = n;
  1087.       wtab[old] = p;
  1088.       if (p)
  1089.         p->w_number = old;
  1090. #ifdef MULTIUSER
  1091.       AclWinSwap(old, n);
  1092. #endif
  1093.     }
  1094.       break;
  1095.     case RC_SILENCE:
  1096.       n = fore->w_tstamp.seconds != 0;
  1097.       i = SilenceWait;
  1098.       if (args[0] && 
  1099.           (args[0][0] == '-' || (args[0][0] >= '0' && args[0][0] <= '9')))
  1100.         {
  1101.       if (ParseNum(act, &i))
  1102.         break;
  1103.       n = i;
  1104.     }
  1105.       else if (ParseSwitch(act, &n))
  1106.         break;
  1107.       if (n)
  1108.         {
  1109.       fore->w_tstamp.lastio = time(0);
  1110.       fore->w_tstamp.seconds = i;
  1111.       if (!msgok)
  1112.         break;
  1113. #ifdef NETHACK
  1114.       if (nethackflag)
  1115.         Msg(0, "You feel like someone is waiting for %d sec. silence...",
  1116.             fore->w_tstamp.seconds);
  1117.       else
  1118. #endif
  1119.         Msg(0, "Window %d (%s) is now being monitored for %d sec. silence.",
  1120.             fore->w_number, fore->w_aka, fore->w_tstamp.seconds);
  1121.     }
  1122.       else
  1123.         {
  1124.       fore->w_tstamp.lastio = (time_t)0;
  1125.       fore->w_tstamp.seconds = 0;
  1126.       if (!msgok)
  1127.         break;
  1128. #ifdef NETHACK
  1129.       if (nethackflag)
  1130.         Msg(0, "You no longer sense the watcher's silence.");
  1131.       else
  1132. #endif
  1133.         Msg(0, "Window %d (%s) is no longer being monitored for silence.", 
  1134.         fore->w_number, fore->w_aka);
  1135.     }
  1136.       break;
  1137. #ifdef COPY_PASTE
  1138.     case RC_DEFSCROLLBACK:
  1139.       (void)ParseNum(act, &nwin_default.histheight);
  1140.       break;
  1141.     case RC_SCROLLBACK:
  1142.       (void)ParseNum(act, &n);
  1143.       ChangeScrollback(fore, n, d_width);
  1144.       if (msgok)
  1145.     Msg(0, "scrollback set to %d", fore->w_histheight);
  1146.       break;
  1147. #endif
  1148.     case RC_SESSIONNAME:
  1149.       if (*args == 0)
  1150.     Msg(0, "This session is named '%s'\n", SockNamePtr);
  1151.       else
  1152.     {
  1153.       char buf[MAXPATHLEN];
  1154.  
  1155.       s = NULL;
  1156.       if (ParseSaveStr(act, &s))
  1157.         break;
  1158.       if (!*s || strlen(s) > MAXPATHLEN - 13)
  1159.         {
  1160.           Msg(0, "%s: bad session name '%s'\n", rc_name, s);
  1161.           free(s);
  1162.           break;
  1163.         }
  1164.       sprintf(buf, "%s", SockPath);
  1165.       sprintf(buf + (SockNamePtr - SockPath), "%d.%s", getpid(), s); 
  1166.       free(s);
  1167.       if ((access(buf, F_OK) == 0) || (errno != ENOENT))
  1168.         {
  1169.           Msg(0, "%s: inappropriate path: '%s'.", rc_name, buf);
  1170.           break;
  1171.         }
  1172.       if (rename(SockPath, buf))
  1173.         {
  1174.           Msg(errno, "%s: failed to rename(%s, %s)", rc_name, SockPath, buf);
  1175.           break;
  1176.         }
  1177.       debug2("rename(%s, %s) done\n", SockPath, buf);
  1178.       sprintf(SockPath, "%s", buf);
  1179.       MakeNewEnv();
  1180.     }
  1181.       break;
  1182.     case RC_SETENV:
  1183. #ifndef USESETENV
  1184.     {
  1185.       char *buf;
  1186.       int l;
  1187.  
  1188.       if ((buf = (char *)malloc((l = strlen(args[0])) + 
  1189.                      strlen(args[1]) + 2)) == NULL)
  1190.         {
  1191.           Msg(0, strnomem);
  1192.           break;
  1193.         }
  1194.       strcpy(buf, args[0]);
  1195.       buf[l] = '=';
  1196.       strcpy(buf + l + 1, args[1]);
  1197.       putenv(buf);
  1198. # ifdef NEEDPUTENV
  1199.       /*
  1200.        * we use our own putenv(), knowing that it does a malloc()
  1201.        * the string space, we can free our buf now. 
  1202.        */
  1203.       free(buf);
  1204. # else /* NEEDSETENV */
  1205.       /*
  1206.        * For all sysv-ish systems that link a standard putenv() 
  1207.        * the string-space buf is added to the environment and must not
  1208.        * be freed, or modified.
  1209.        * We are sorry to say that memory is lost here, when setting 
  1210.        * the same variable again and again.
  1211.        */
  1212. # endif /* NEEDSETENV */
  1213.     }
  1214. #else /* USESETENV */
  1215. # if defined(linux) || defined(__386BSD__) || defined(BSDI)
  1216.       setenv(args[0], args[1], 0);
  1217. # else
  1218.       setenv(args[0], args[1]);
  1219. # endif /* linux || __386BSD__ || BSDI */
  1220. #endif /* USESETENV */
  1221.       MakeNewEnv();
  1222.       break;
  1223.     case RC_UNSETENV:
  1224.       unsetenv(*args);
  1225.       MakeNewEnv();
  1226.       break;
  1227.     case RC_SLOWPASTE:
  1228.       if (ParseNum(act, &slowpaste) == 0 && msgok)
  1229.     Msg(0, "slowpaste set to %d milliseconds", slowpaste);
  1230.       break;
  1231. #ifdef COPY_PASTE
  1232.     case RC_MARKKEYS:
  1233.       s = NULL;
  1234.       if (ParseSaveStr(act, &s))
  1235.         break;
  1236.       if (CompileKeys(s, mark_key_tab))
  1237.     {
  1238.       Msg(0, "%s: markkeys: syntax error.", rc_name);
  1239.       free(s);
  1240.       break;
  1241.     }
  1242.       debug1("markkeys %s\n", *args);
  1243.       free(s);
  1244.       break;
  1245. #endif
  1246. #ifdef NETHACK
  1247.     case RC_NETHACK:
  1248.       (void)ParseOnOff(act, &nethackflag);
  1249.       break;
  1250. #endif
  1251.     case RC_HARDCOPY_APPEND:
  1252.       (void)ParseOnOff(act, &hardcopy_append);
  1253.       break;
  1254.     case RC_VBELL_MSG:
  1255.       (void)ParseSaveStr(act, &VisualBellString);
  1256.       debug1(" new vbellstr '%s'\n", VisualBellString);
  1257.       break;
  1258.     case RC_DEFMODE:
  1259.       if (ParseOct(act, &n))
  1260.         break;
  1261.       if (n < 0 || n > 0777)
  1262.     {
  1263.       Msg(0, "%s: mode: Invalid tty mode %o", rc_name, n);
  1264.           break;
  1265.     }
  1266.       TtyMode = n;
  1267.       if (msgok)
  1268.     Msg(0, "Ttymode set to %03o", TtyMode);
  1269.       break;
  1270. #ifdef COPY_PASTE
  1271.     case RC_CRLF:
  1272.       (void)ParseOnOff(act, &join_with_cr);
  1273.       break;
  1274. #endif
  1275.     case RC_AUTODETACH:
  1276.       (void)ParseOnOff(act, &auto_detach);
  1277.       break;
  1278.     case RC_STARTUP_MESSAGE:
  1279.       (void)ParseOnOff(act, &default_startup);
  1280.       break;
  1281. #ifdef PASSWORD
  1282.     case RC_PASSWORD:
  1283.       CheckPassword = 1;
  1284.       if (*args)
  1285.     {
  1286.       strncpy(Password, *args, sizeof(Password) - 1);
  1287.       if (!strcmp(Password, "none"))
  1288.         CheckPassword = 0;
  1289.     }
  1290.       else
  1291.     {
  1292.       if (display == 0)
  1293.         {
  1294.           debug("prompting for password on no display???\n");
  1295.           break;
  1296.         }
  1297.       Input("New screen password:", sizeof(Password) - 1, pass1, 
  1298.         INP_NOECHO);
  1299.     }
  1300.       break;
  1301. #endif                /* PASSWORD */
  1302.     case RC_BIND:
  1303.       if ((s = ParseChar(*args, &ch)) == NULL || *s)
  1304.     {
  1305.       Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.",
  1306.           rc_name);
  1307.       break;
  1308.     }
  1309.       n = (unsigned char)ch;
  1310.       FreeKey(n);
  1311.       if (args[1])
  1312.     {
  1313.       if ((i = FindCommnr(args[1])) == RC_ILLEGAL)
  1314.         {
  1315.           Msg(0, "%s: bind: unknown command '%s'", rc_name, args[1]);
  1316.           break;
  1317.         }
  1318.       if (CheckArgNum(i, args + 2))
  1319.         break;
  1320.       ktab[n].nr = i;
  1321.       if (args[2])
  1322.         ktab[n].args = SaveArgs(args + 2);
  1323.     }
  1324.       break;
  1325. #ifdef MULTIUSER
  1326.     case RC_ACLCHG:
  1327.     case RC_ACLADD:
  1328.     {
  1329.       struct user **u;
  1330.       
  1331.       u = FindUserPtr(args[0]);
  1332.       UserAdd(args[0], NULL, u);
  1333.       if (args[1] && args[2])
  1334.         AclSetPerm(*u, args[1], args[2]);
  1335.       else
  1336.         AclSetPerm(*u, "+rwx", "#?"); 
  1337.       break;
  1338.     }
  1339.     case RC_ACLDEL:
  1340.         {
  1341.       if (UserDel(args[0], NULL))
  1342.         break;
  1343.       if (msgok)
  1344.         Msg(0, "%s removed from acl database", args[0]);
  1345.       break;
  1346.         }
  1347.     case RC_ACLGRP:
  1348.         {
  1349.       break;
  1350.     }
  1351.     case RC_MULTIUSER:
  1352.       if (ParseOnOff(act, &n))
  1353.     break;
  1354.       multi = n ? "" : 0;
  1355.       chsock();
  1356.       if (msgok)
  1357.     Msg(0, "Multiuser mode %s", multi ? "enabled" : "disabled");
  1358.       break;
  1359. #endif /* MULTIUSER */
  1360. #ifdef PSEUDOS
  1361.     case RC_EXEC:
  1362.       winexec(args);
  1363.       break;
  1364. #endif
  1365. #ifdef MULTI
  1366.     case RC_CLONE:
  1367.       execclone(args);
  1368.       break;
  1369. #endif
  1370.     default:
  1371.       break;
  1372.     }
  1373. }
  1374.  
  1375. static char **
  1376. SaveArgs(args)
  1377. char **args;
  1378. {
  1379.   register char **ap, **pp;
  1380.   register int argc = 0;
  1381.  
  1382.   while (args[argc])
  1383.     argc++;
  1384.   if ((pp = ap = (char **) malloc((unsigned) (argc + 1) * sizeof(char **))) == 0)
  1385.     Panic(0, strnomem);
  1386.   while (argc--)
  1387.     {
  1388.       *pp++ = SaveStr(*args++);
  1389.     }
  1390.   *pp = 0;
  1391.   return ap;
  1392. }
  1393.  
  1394. int 
  1395. Parse(buf, args)
  1396. char *buf, **args;
  1397. {
  1398.   register char *p = buf, **ap = args;
  1399.   register int delim, argc;
  1400.  
  1401.   argc = 0;
  1402.   for (;;)
  1403.     {
  1404.       while (*p && (*p == ' ' || *p == '\t'))
  1405.     ++p;
  1406. #ifdef PSEUDOS
  1407.       if (argc == 0 && (*p == '!' || *p == '|'))
  1408.     {
  1409.       *ap++ = "exec";
  1410.       if (*p == '!')
  1411.         p++;
  1412.       while (*p == ' ')
  1413.         p++;
  1414.       argc++;
  1415.     }
  1416. #endif
  1417.       if (*p == '\0' || *p == '#')
  1418.     {
  1419.       *p = '\0';
  1420.       args[argc] = 0;
  1421.       return argc;
  1422.     }
  1423.       if (++argc >= MAXARGS)
  1424.     {
  1425.       Msg(0, "%s: too many tokens.", rc_name);
  1426.       return 0;
  1427.     }
  1428.       delim = 0;
  1429.       if (*p == '"' || *p == '\'')
  1430.     delim = *p++;
  1431.       *ap++ = p;
  1432.       while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  1433.     ++p;
  1434.       if (*p == '\0')
  1435.     {
  1436.       if (delim)
  1437.         {
  1438.           Msg(0, "%s: Missing quote.", rc_name);
  1439.           return 0;
  1440.         }
  1441.     }
  1442.       else
  1443.         *p++ = '\0';
  1444.     }
  1445. }
  1446.  
  1447. int 
  1448. ParseEscape(p)
  1449. char *p;
  1450. {
  1451.   if ((p = ParseChar(p, &Esc)) == NULL ||
  1452.       (p = ParseChar(p, &MetaEsc)) == NULL || *p)
  1453.     return -1;
  1454.   return 0;
  1455. }
  1456.  
  1457. static int
  1458. ParseSwitch(act, var)
  1459. struct action *act;
  1460. int *var;
  1461. {
  1462.   if (*act->args == 0)
  1463.     {
  1464.       *var ^= 1;
  1465.       return 0;
  1466.     }
  1467.   return ParseOnOff(act, var);
  1468. }
  1469.  
  1470. static int
  1471. ParseOnOff(act, var)
  1472. struct action *act;
  1473. int *var;
  1474. {
  1475.   register int num = -1;
  1476.   char **args = act->args;
  1477.  
  1478.   if (args[1] == 0)
  1479.     {
  1480.       if (strcmp(args[0], "on") == 0)
  1481.     num = 1;
  1482.       else if (strcmp(args[0], "off") == 0)
  1483.     num = 0;
  1484.     }
  1485.   if (num < 0)
  1486.     {
  1487.       Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, comms[act->nr].name);
  1488.       return -1;
  1489.     }
  1490.   *var = num;
  1491.   return 0;
  1492. }
  1493.  
  1494. static int
  1495. ParseSaveStr(act, var)
  1496. struct action *act;
  1497. char **var;
  1498. {
  1499.   char **args = act->args;
  1500.   if (*args == 0 || args[1])
  1501.     {
  1502.       Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name);
  1503.       return -1;
  1504.     }
  1505.   if (*var)
  1506.     free(*var);
  1507.   *var = SaveStr(*args);
  1508.   return 0;
  1509. }
  1510.  
  1511. static int
  1512. ParseNum(act, var)
  1513. struct action *act;
  1514. int *var;
  1515. {
  1516.   int i;
  1517.   char *p, **args = act->args;
  1518.  
  1519.   p = *args;
  1520.   if (p == 0 || *p == 0 || args[1])
  1521.     {
  1522.       Msg(0, "%s: %s: invalid argument. Give one argument.",
  1523.           rc_name, comms[act->nr].name);
  1524.       return -1;
  1525.     }
  1526.   i = 0; 
  1527.   while (*p)
  1528.     {
  1529.       if (*p >= '0' && *p <= '9')
  1530.     i = 10 * i + (*p - '0');
  1531.       else
  1532.     {
  1533.       Msg(0, "%s: %s: invalid argument. Give numeric argument.",
  1534.           rc_name, comms[act->nr].name);
  1535.       return -1;
  1536.     }    
  1537.       p++;
  1538.     }
  1539.   debug1("ParseNum got %d\n", i);
  1540.   *var = i;
  1541.   return 0;
  1542. }
  1543.  
  1544. static struct win *
  1545. WindowByName(s)
  1546. char *s;
  1547. {
  1548.   struct win *p;
  1549.  
  1550.   for (p = windows; p; p = p->w_next)
  1551.     if (!strncmp(p->w_aka, s, strlen(s)))
  1552.       return p;
  1553.   return NULL;
  1554. }
  1555.  
  1556. /* 
  1557.  * Get window number from Name or Number string.
  1558.  * Numbers are tried first, then names, a prefix match suffices.
  1559.  * Be careful when assigning numeric strings as WindowTitles.
  1560.  */
  1561. int
  1562. WindowByNoN(str)
  1563. char *str;
  1564. {
  1565.   int i;
  1566.   char *s;
  1567.   struct win *p;
  1568.   
  1569.   for (i = 0, s = str; *s; s++)
  1570.     {
  1571.       if (*s < '0' || *s > '9')
  1572.     break;
  1573.       i = i * 10 + (*s - '0');
  1574.     }
  1575.   if (*s || i < 0 || i >= MAXWIN)
  1576.     {
  1577.       if ((p = WindowByName(str)))
  1578.     return p->w_number;
  1579.       return -1;
  1580.     }
  1581.   return i;
  1582. }
  1583.  
  1584. static int
  1585. ParseWinNum(act, var)
  1586. struct action *act;
  1587. int *var;
  1588. {
  1589.   char **args = act->args;
  1590.   int i = 0;
  1591.  
  1592.   if (*args == 0 || args[1])
  1593.     {
  1594.       Msg(0, "%s: %s: one argument required.", rc_name, comms[act->nr].name);
  1595.       return -1;
  1596.     }
  1597.   
  1598.   i = WindowByNoN(*args);
  1599.   if (i < 0)
  1600.     {
  1601.       Msg(0, "%s: %s: invalid argument. Give window number or name.",
  1602.           rc_name, comms[act->nr].name);
  1603.       return -1;
  1604.     }
  1605.   debug1("ParseWinNum got %d\n", i);
  1606.   *var = i;
  1607.   return 0;
  1608. }
  1609.  
  1610. static int
  1611. ParseOct(act, var)
  1612. struct action *act;
  1613. int *var;
  1614. {
  1615.   char *p, **args = act->args;
  1616.   int i = 0; 
  1617.  
  1618.   p = *args;
  1619.   if (p == 0 || *p == 0 || args[1])
  1620.     {
  1621.       Msg(0, "%s: %s: invalid argument. Give one octal argument.",
  1622.           rc_name, comms[act->nr].name);
  1623.       return -1;
  1624.     }
  1625.   while (*p)
  1626.     {
  1627.       if (*p >= '0' && *p <= '7')
  1628.     i = 8 * i + (*p - '0');
  1629.       else
  1630.     {
  1631.       Msg(0, "%s: %s: invalid argument. Give octal argument.",
  1632.           rc_name, comms[act->nr].name);
  1633.       return -1;
  1634.     }    
  1635.       p++;
  1636.     }
  1637.   debug1("ParseOct got %d\n", i);
  1638.   *var = i;
  1639.   return 0;
  1640. }
  1641.  
  1642. static char *
  1643. ParseChar(p, cp)
  1644. char *p, *cp;
  1645. {
  1646.   if (*p == 0)
  1647.     return 0;
  1648.   if (*p == '^')
  1649.     {
  1650.       if (*++p == '?')
  1651.         *cp = '\177';
  1652.       else if (*p >= '@')
  1653.         *cp = Ctrl(*p);
  1654.       else
  1655.         return 0;
  1656.       ++p;
  1657.     }
  1658.   else if (*p == '\\' && *++p <= '7' && *p >= '0')
  1659.     {
  1660.       *cp = 0;
  1661.       do
  1662.         *cp = *cp * 8 + *p - '0';
  1663.       while (*++p <= '7' && *p >= '0');
  1664.     }
  1665.   else
  1666.     *cp = *p++;
  1667.   return p;
  1668. }
  1669.  
  1670.  
  1671. static
  1672. int IsNum(s, base)
  1673. register char *s;
  1674. register int base;
  1675. {
  1676.   for (base += '0'; *s; ++s)
  1677.     if (*s < '0' || *s > base)
  1678.       return 0;
  1679.   return 1;
  1680. }
  1681.  
  1682. static int
  1683. IsNumColon(s, base, p, psize)
  1684. int base, psize;
  1685. char *s, *p;
  1686. {
  1687.   char *q;
  1688.   if ((q = rindex(s, ':')) != NULL)
  1689.     {
  1690.       strncpy(p, q + 1, psize - 1);
  1691.       p[psize - 1] = '\0';
  1692.       *q = '\0';
  1693.     }
  1694.   else
  1695.     *p = '\0';
  1696.   return IsNum(s, base);
  1697. }
  1698.  
  1699. static void
  1700. SwitchWindow(n)
  1701. int n;
  1702. {
  1703.   struct win *p;
  1704.  
  1705.   debug1("SwitchWindow %d\n", n);
  1706.   if (display == 0)
  1707.     return;
  1708.   if (n < 0 || n >= MAXWIN || (p = wtab[n]) == 0)
  1709.     {
  1710.       ShowWindows();
  1711.       return;
  1712.     }
  1713.   if (p == d_fore)
  1714.     {
  1715.       Msg(0, "This IS window %d (%s).", n, p->w_aka);
  1716.       return;
  1717.     }
  1718.   if (p->w_display)
  1719.     {
  1720.       Msg(0, "Window %d (%s) is on another display.", n, p->w_aka);
  1721.       return;
  1722.     }
  1723.   SetForeWindow(p);
  1724.   Activate(fore->w_norefresh);  
  1725. }  
  1726.  
  1727. void
  1728. SetForeWindow(wi)
  1729. struct win *wi;
  1730. {
  1731.   struct win *p, **pp;
  1732.   struct layer *l;
  1733.   /*
  1734.    * If we come from another window, make it inactive.
  1735.    */
  1736.   if (display)
  1737.     {
  1738.       fore = d_fore;
  1739.       if (fore)
  1740.     {
  1741.       /* release auto writelock when user has no other display here */
  1742.       if (fore->w_wlock == WLOCK_AUTO && fore->w_wlockuser == d_user)
  1743.         {
  1744.           struct display *d;
  1745.  
  1746.           for (d = displays; d; d = d->_d_next)
  1747.             if (( d != display) && (d->_d_fore == fore))
  1748.           break;
  1749.           debug3("%s %s autolock on win %d\n", 
  1750.                  d_user->u_name, d?"keeps":"releases", fore->w_number);
  1751.           if (!d)
  1752.             fore->w_wlockuser = NULL;
  1753.         }
  1754.       /* deactivate old window. */
  1755.       if (fore->w_tstamp.seconds)
  1756.         fore->w_tstamp.lastio = Now;
  1757.       d_other = fore;
  1758.       fore->w_active = 0;
  1759.       fore->w_display = 0;
  1760.     }
  1761.       else
  1762.     {
  1763.       /* put all the display layers on the window. */
  1764.       for (l = d_lay; l; l = l->l_next)
  1765.         if (l->l_next == &BlankLayer)
  1766.           {
  1767.         l->l_next = wi->w_lay;
  1768.         wi->w_lay = d_lay;
  1769.         for (l = d_lay; l != wi->w_lay; l = l->l_next)
  1770.           l->l_block |= wi->w_lay->l_block;
  1771.         break;
  1772.           }
  1773.     }
  1774.       d_fore = wi;
  1775.       if (d_other == wi)
  1776.     d_other = 0;
  1777.       d_lay = wi->w_lay;
  1778.       d_layfn = d_lay->l_layfn;
  1779.       if ((wi->w_wlock == WLOCK_AUTO) && !wi->w_wlockuser)
  1780.         {
  1781.       debug2("%s obtained auto writelock for window %d\n",
  1782.            d_user->u_name, wi->w_number);
  1783.           wi->w_wlockuser = d_user;
  1784.         }
  1785.     }
  1786.   fore = wi;
  1787.   fore->w_display = display;
  1788.   if (!fore->w_lay)
  1789.     fore->w_active = 1;
  1790.   /*
  1791.    * Place the window at the head of the most-recently-used list.
  1792.    */
  1793.   for (pp = &windows; (p = *pp); pp = &p->w_next)
  1794.     if (p == wi)
  1795.       break;
  1796.   ASSERT(p);
  1797.   *pp = p->w_next;
  1798.   p->w_next = windows;
  1799.   windows = p;
  1800. }
  1801.  
  1802. static int
  1803. NextWindow()
  1804. {
  1805.   register struct win **pp;
  1806.   int n = fore ? fore->w_number : 0;
  1807.  
  1808.   for (pp = wtab + n + 1; pp != wtab + n; pp++)
  1809.     {
  1810.       if (pp == wtab + MAXWIN)
  1811.     pp = wtab;
  1812.       if (*pp)
  1813.     break;
  1814.     }
  1815.   return pp - wtab;
  1816. }
  1817.  
  1818. static int
  1819. PreviousWindow()
  1820. {
  1821.   register struct win **pp;
  1822.   int n = fore ? fore->w_number : MAXWIN - 1;
  1823.  
  1824.   for (pp = wtab + n - 1; pp != wtab + n; pp--)
  1825.     {
  1826.       if (pp < wtab)
  1827.     pp = wtab + MAXWIN - 1;
  1828.       if (*pp)
  1829.     break;
  1830.     }
  1831.   return pp - wtab;
  1832. }
  1833.  
  1834. static int
  1835. MoreWindows()
  1836. {
  1837.   if (windows && windows->w_next)
  1838.     return 1;
  1839.   if (fore == 0)
  1840.     {
  1841.       Msg(0, "No window available");
  1842.       return 0;
  1843.     }
  1844. #ifdef NETHACK
  1845.   if (nethackflag)
  1846.     Msg(0, "You cannot escape from window %d!", fore->w_number);
  1847.   else
  1848. #endif
  1849.   Msg(0, "No other window.");
  1850.   return 0;
  1851. }
  1852.  
  1853. void
  1854. KillWindow(wi)
  1855. struct win *wi;
  1856. {
  1857.   struct win **pp, *p;
  1858.  
  1859.   display = wi->w_display;
  1860.   if (display)
  1861.     {
  1862.       if (wi == d_fore)
  1863.     {
  1864.       RemoveStatus();
  1865.       if (d_lay != &wi->w_winlay)
  1866.         ExitOverlayPage();
  1867.       d_fore = 0;
  1868.       d_lay = &BlankLayer;
  1869.       d_layfn = BlankLayer.l_layfn;
  1870.     }
  1871.     }
  1872.  
  1873.   for (pp = &windows; (p = *pp); pp = &p->w_next)
  1874.     if (p == wi)
  1875.       break;
  1876.   ASSERT(p);
  1877.   *pp = p->w_next;
  1878.   /*
  1879.    * Remove window from linked list.
  1880.    */
  1881.   wi->w_inlen = 0;
  1882.   wtab[wi->w_number] = 0;
  1883.   FreeWindow(wi);
  1884.   /*
  1885.    * If the foreground window disappeared check the head of the linked list
  1886.    * of windows for the most recently used window. If no window is alive at
  1887.    * all, exit.
  1888.    */
  1889.   if (display && d_fore)
  1890.     return;
  1891.   if (windows == 0)
  1892.     Finit(0);
  1893.   SwitchWindow(windows->w_number);
  1894. }
  1895.  
  1896. static void
  1897. LogToggle(on)
  1898. int on;
  1899. {
  1900.   char buf[1024];
  1901.  
  1902.   if ((fore->w_logfp != 0) == on)
  1903.     {
  1904.       if (display && !*rc_name)
  1905.     Msg(0, "You are %s logging.", on ? "already" : "not");
  1906.       return;
  1907.     }
  1908.   if (screenlogdir)
  1909.     sprintf(buf, "%s/screenlog.%d", screenlogdir, fore->w_number);
  1910.   else
  1911.     sprintf(buf, "screenlog.%d", fore->w_number);
  1912.   if (fore->w_logfp != NULL)
  1913.     {
  1914. #ifdef NETHACK
  1915.       if (nethackflag)
  1916.     Msg(0, "You put away your scroll of logging named \"%s\".", buf);
  1917.       else
  1918. #endif
  1919.       Msg(0, "Logfile \"%s\" closed.", buf);
  1920.       fclose(fore->w_logfp);
  1921.       fore->w_logfp = NULL;
  1922.       return;
  1923.     }
  1924.   if ((fore->w_logfp = secfopen(buf, "a")) == NULL)
  1925.     {
  1926. #ifdef NETHACK
  1927.       if (nethackflag)
  1928.     Msg(0, "You don't seem to have a scroll of logging named \"%s\".", buf);
  1929.       else
  1930. #endif
  1931.       Msg(errno, "Error opening logfile \"%s\"", buf);
  1932.       return;
  1933.     }
  1934. #ifdef NETHACK
  1935.   if (nethackflag)
  1936.     Msg(0, "You %s your scroll of logging named \"%s\".",
  1937.     ftell(fore->w_logfp) ? "add to" : "start writing on", buf);
  1938.   else
  1939. #endif
  1940.   Msg(0, "%s logfile \"%s\"", ftell(fore->w_logfp) ? "Appending to" : "Creating", buf);
  1941. }
  1942.  
  1943. void
  1944. ShowWindows()
  1945. {
  1946.   char buf[1024];
  1947.   register char *s, *ss;
  1948.   register struct win **pp, *p;
  1949.   register char *cmd;
  1950.  
  1951.   ASSERT(display);
  1952.   s = ss = buf;
  1953.   for (pp = wtab; pp < wtab + MAXWIN; pp++)
  1954.     {
  1955.       if ((p = *pp) == 0)
  1956.     continue;
  1957.  
  1958.       cmd = p->w_aka;
  1959.       if (s - buf + strlen(cmd) > sizeof(buf) - 6)
  1960.     break;
  1961.       if (s > buf)
  1962.     {
  1963.       *s++ = ' ';
  1964.       *s++ = ' ';
  1965.     }
  1966.       sprintf(s, "%d", p->w_number);
  1967.       s += strlen(s);
  1968.       if (p == fore)
  1969.     {
  1970.       ss = s;
  1971.       *s++ = '*';
  1972.     }
  1973.       else if (p == d_other)
  1974.     *s++ = '-';
  1975.       if (p->w_display && p->w_display != display)
  1976.     *s++ = '&';
  1977.       if (p->w_monitor == MON_DONE || p->w_monitor == MON_MSG)
  1978.     *s++ = '@';
  1979.       if (p->w_bell == BELL_DONE || p->w_bell == BELL_MSG)
  1980.     *s++ = '!';
  1981. #ifdef UTMPOK
  1982.       if (p->w_slot != (slot_t) 0 && p->w_slot != (slot_t) -1)
  1983.     *s++ = '$';
  1984. #endif
  1985.       if (p->w_logfp != NULL)
  1986.     {
  1987.       strcpy(s, "(L)");
  1988.       s += 3;
  1989.     }
  1990.       *s++ = ' ';
  1991.       strcpy(s, cmd);
  1992.       s += strlen(s);
  1993.       if (p == fore)
  1994.     {
  1995.       /* 
  1996.        * this is usually done by Activate(), but when looking
  1997.        * on your current window, you may get annoyed, as there is still
  1998.        * that temporal '!' and '@' displayed.
  1999.        * So we remove that after displaying it once.
  2000.        */
  2001.       p->w_bell = BELL_OFF;
  2002.       if (p->w_monitor != MON_OFF)
  2003.         p->w_monitor = MON_ON;
  2004.     }
  2005.     }
  2006.   *s++ = ' ';
  2007.   *s = '\0';
  2008.   if (ss - buf > d_width / 2)
  2009.     {
  2010.       ss -= d_width / 2;
  2011.       if (s - ss < d_width)
  2012.     {
  2013.       ss = s - d_width;
  2014.       if (ss < buf)
  2015.         ss = buf;
  2016.     }
  2017.     }
  2018.   else
  2019.     ss = buf;
  2020.   Msg(0, "%s", ss);
  2021. }
  2022.  
  2023.  
  2024. static void
  2025. ShowTime()
  2026. {
  2027.   char buf[512];
  2028.   struct tm *tp;
  2029.   time_t now;
  2030.  
  2031.   (void) time(&now);
  2032.   tp = localtime(&now);
  2033.   sprintf(buf, "%2d:%02d:%02d %s", tp->tm_hour, tp->tm_min, tp->tm_sec,
  2034.       HostName);
  2035. #ifdef LOADAV
  2036.   AddLoadav(buf + strlen(buf));
  2037. #endif /* LOADAV */
  2038.   Msg(0, "%s", buf);
  2039. }
  2040.  
  2041. static void
  2042. ShowInfo()
  2043. {
  2044.   char buf[512], *p;
  2045.   register struct win *wp = fore;
  2046.   register int i;
  2047.  
  2048.   if (wp == 0)
  2049.     {
  2050.       Msg(0, "(%d,%d)/(%d,%d) no window", d_x + 1, d_y + 1, d_width, d_height);
  2051.       return;
  2052.     }
  2053. #ifdef COPY_PASTE
  2054.   sprintf(buf, "(%d,%d)/(%d,%d)+%d %c%sflow %cins %corg %cwrap %capp %clog %cmon %cr",
  2055. #else
  2056.   sprintf(buf, "(%d,%d)/(%d,%d) %c%sflow %cins %corg %cwrap %capp %clog %cmon %cr",
  2057. #endif
  2058.       wp->w_x + 1, wp->w_y + 1, wp->w_width, wp->w_height,
  2059. #ifdef COPY_PASTE
  2060.       wp->w_histheight,
  2061. #endif
  2062.       (wp->w_flow & FLOW_NOW) ? '+' : '-',
  2063.       (wp->w_flow & FLOW_AUTOFLAG) ? "" : ((wp->w_flow & FLOW_AUTO) ? "(+)" : "(-)"),
  2064.       wp->w_insert ? '+' : '-', wp->w_origin ? '+' : '-',
  2065.       wp->w_wrap ? '+' : '-', wp->w_keypad ? '+' : '-',
  2066.       (wp->w_logfp != NULL) ? '+' : '-',
  2067.       (wp->w_monitor != MON_OFF) ? '+' : '-',
  2068.       wp->w_norefresh ? '-' : '+');
  2069.   if (CG0)
  2070.     {
  2071.       p = buf + strlen(buf);
  2072.       sprintf(p, " G%1d [", wp->w_Charset);
  2073.       for (i = 0; i < 4; i++)
  2074.     p[i + 5] = wp->w_charsets[i] ? wp->w_charsets[i] : 'B';
  2075.       p[9] = ']';
  2076.       p[10] = '\0';
  2077.     }
  2078.   Msg(0, "%s", buf);
  2079. }
  2080.  
  2081.  
  2082. static void
  2083. AKAfin(buf, len)
  2084. char *buf;
  2085. int len;
  2086. {
  2087.   ASSERT(display);
  2088.   if (len && fore)
  2089.     ChangeAKA(fore, buf, 20);
  2090. }
  2091.  
  2092. static void
  2093. InputAKA()
  2094. {
  2095.   Input("Set window's a.k.a. to: ", 20, AKAfin, INP_COOKED);
  2096. }
  2097.  
  2098. static void
  2099. Colonfin(buf, len)
  2100. char *buf;
  2101. int len;
  2102. {
  2103.   if (len)
  2104.     RcLine(buf);
  2105. }
  2106.  
  2107. static void
  2108. InputColon()
  2109. {
  2110.   Input(":", 100, Colonfin, INP_COOKED);
  2111. }
  2112.  
  2113. static void
  2114. SelectFin(buf, len)
  2115. char *buf;
  2116. int len;
  2117. {
  2118.   int n;
  2119.  
  2120.   if (!len || !display)
  2121.     return;
  2122.   if ((n = WindowByNoN(buf)) < 0)
  2123.     return;
  2124.   SwitchWindow(n);
  2125. }
  2126.     
  2127. static void
  2128. InputSelect()
  2129. {
  2130.   Input("Switch to window: ", 20, SelectFin, INP_COOKED);
  2131. }
  2132.  
  2133. void
  2134. DoScreen(fn, av)
  2135. char *fn, **av;
  2136. {
  2137.   struct NewWindow nwin;
  2138.   register int num;
  2139.   char buf[20];
  2140.   char termbuf[25];
  2141.  
  2142.   nwin = nwin_undef;
  2143.   termbuf[0] = '\0';
  2144.   while (av && *av && av[0][0] == '-')
  2145.     {
  2146.       switch (av[0][1])
  2147.     {
  2148.     case 'f':
  2149.       switch (av[0][2])
  2150.         {
  2151.         case 'n':
  2152.         case '0':
  2153.           nwin.flowflag = FLOW_NOW * 0;
  2154.           break;
  2155.         case 'y':
  2156.         case '1':
  2157.         case '\0':
  2158.           nwin.flowflag = FLOW_NOW * 1;
  2159.           break;
  2160.         case 'a':
  2161.           nwin.flowflag = FLOW_AUTOFLAG;
  2162.           break;
  2163.         default:
  2164.           break;
  2165.         }
  2166.       break;
  2167.     case 'k':
  2168.     case 't':
  2169.       if (av[0][2])
  2170.         nwin.aka = &av[0][2];
  2171.       else if (*++av)
  2172.         nwin.aka = *av;
  2173.       else
  2174.         --av;
  2175.       break;
  2176.     case 'T':
  2177.       if (av[0][2])
  2178.         nwin.term = &av[0][2];
  2179.       else if (*++av)
  2180.         nwin.term = *av;
  2181.       else
  2182.         --av;
  2183.       break;
  2184.     case 'h':
  2185.       if (av[0][2])
  2186.         nwin.histheight = atoi(av[0] + 2);
  2187.       else if (*++av)
  2188.         nwin.histheight = atoi(*av);
  2189.       else 
  2190.         --av;
  2191.       break;
  2192.     case 'l':
  2193.       switch (av[0][2])
  2194.         {
  2195.         case 'n':
  2196.         case '0':
  2197.           nwin.lflag = 0;
  2198.           break;
  2199.         case 'y':
  2200.         case '1':
  2201.         case '\0':
  2202.           nwin.lflag = 1;
  2203.           break;
  2204.         default:
  2205.           break;
  2206.         }
  2207.       break;
  2208.     case 'a':
  2209.       nwin.aflag = 1;
  2210.       break;
  2211.     case 'M':
  2212.       nwin.monitor = MON_ON;
  2213. debug("nwin.monitor = MON_ON;\n");
  2214.       break;
  2215.     default:
  2216.       Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]);
  2217.       break;
  2218.     }
  2219.       ++av;
  2220.     }
  2221.   num = 0;
  2222.   if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf)))
  2223.     {
  2224.       if (*buf != '\0')
  2225.     nwin.aka = buf;
  2226.       num = atoi(*av);
  2227.       if (num < 0 || num > MAXWIN - 1)
  2228.     {
  2229.       Msg(0, "%s: illegal screen number %d.", fn, num);
  2230.       num = 0;
  2231.     }
  2232.       nwin.StartAt = num;
  2233.       ++av;
  2234.     }
  2235.   if (av && *av)
  2236.     {
  2237.       nwin.args = av;
  2238.       if (!nwin.aka)
  2239.         nwin.aka = Filename(*av);
  2240.     }
  2241.   MakeWindow(&nwin);
  2242. }
  2243.  
  2244. #ifdef COPY_PASTE
  2245. /*
  2246.  * CompileKeys must be called before Markroutine is first used.
  2247.  * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab);
  2248.  *
  2249.  * s is an ascii string in a termcap-like syntax. It looks like
  2250.  *   "j=u:k=d:l=r:h=l: =.:" and so on...
  2251.  * this example rebinds the cursormovement to the keys u (up), d (down),
  2252.  * l (left), r (right). placing a mark will now be done with ".".
  2253.  */
  2254. int
  2255. CompileKeys(s, array)
  2256. char *s, *array;
  2257. {
  2258.   int i;
  2259.   unsigned char key, value;
  2260.  
  2261.   if (!s || !*s)
  2262.     {
  2263.       for (i = 0; i < 256; i++)
  2264.         array[i] = i;
  2265.       return 0;
  2266.     }
  2267.   debug1("CompileKeys: '%s'\n", s);
  2268.   while (*s)
  2269.     {
  2270.       s = ParseChar(s, (char *) &key);
  2271.       if (*s != '=')
  2272.     return -1;
  2273.       do 
  2274.     {
  2275.           s = ParseChar(++s, (char *) &value);
  2276.       array[value] = key;
  2277.     }
  2278.       while (*s == '=');
  2279.       if (!*s) 
  2280.     break;
  2281.       if (*s++ != ':')
  2282.     return -1;
  2283.     }
  2284.   return 0;
  2285. }
  2286. #endif /* COPY_PASTE */
  2287.  
  2288. /*
  2289.  *  Asynchronous input functions
  2290.  */
  2291.  
  2292. #ifdef POW_DETACH
  2293. static void
  2294. pow_detach_fn(buf, len)
  2295. char *buf;
  2296. int len;
  2297. {
  2298.   if (len)
  2299.     {
  2300.       *buf = 0;
  2301.       return;
  2302.     }
  2303.   if (ktab[(int)(unsigned char)*buf].nr != RC_POW_DETACH)
  2304.     {
  2305.       if (display)
  2306.         write(d_userfd, "\007", 1);
  2307. #ifdef NETHACK
  2308.       if (nethackflag)
  2309.      Msg(0, "The blast of disintegration whizzes by you!");
  2310. #endif
  2311.     }
  2312.   else
  2313.     Detach(D_POWER);
  2314. }
  2315. #endif /* POW_DETACH */
  2316.  
  2317. #ifdef COPY_PASTE
  2318. static void
  2319. copy_reg_fn(buf, len)
  2320. char *buf;
  2321. int len;
  2322. {
  2323.   struct plop *pp = plop_tab + (int)(unsigned char)*buf;
  2324.  
  2325.   if (len)
  2326.     {
  2327.       *buf = 0;
  2328.       return;
  2329.     }
  2330.   if (pp->buf)
  2331.     free(pp->buf);
  2332.   if ((pp->buf = (char *)malloc(d_copylen)) == NULL)
  2333.     {
  2334.       Msg(0, strnomem);
  2335.       return;
  2336.     }
  2337.   bcopy(d_copybuffer, pp->buf, d_copylen);
  2338.   pp->len = d_copylen;
  2339.   Msg(0, "Copied %d characters into register %c", d_copylen, *buf);
  2340. }
  2341.  
  2342. static void
  2343. ins_reg_fn(buf, len)
  2344. char *buf;
  2345. int len;
  2346. {
  2347.   struct plop *pp = plop_tab + (int)(unsigned char)*buf;
  2348.  
  2349.   if (len)
  2350.     {
  2351.       *buf = 0;
  2352.       return;
  2353.     }
  2354.   if (pp->buf)
  2355.     {
  2356.       fore->w_pastebuffer  = pp->buf;
  2357.       fore->w_pastelen = pp->len;
  2358.       return;
  2359.     }
  2360. #ifdef NETHACK
  2361.   if (nethackflag)
  2362.     Msg(0, "Nothing happens.");
  2363.   else
  2364. #endif
  2365.   Msg(0, "Empty register.");
  2366. }
  2367. #endif /* COPY_PASTE */
  2368.  
  2369. static void
  2370. process_fn(buf, len)
  2371. char *buf;
  2372. int len;
  2373. {
  2374.   struct plop *pp = plop_tab + (int)(unsigned char)*buf;
  2375.  
  2376.   if (len)
  2377.     {
  2378.       *buf = 0;
  2379.       return;
  2380.     }
  2381.   if (pp->buf)
  2382.     {
  2383.       ProcessInput(pp->buf, pp->len);
  2384.       return;
  2385.     }
  2386. #ifdef NETHACK
  2387.   if (nethackflag)
  2388.     Msg(0, "Nothing happens.");
  2389.   else
  2390. #endif
  2391.   Msg(0, "Empty register.");
  2392. }
  2393.  
  2394.  
  2395. #ifdef PASSWORD
  2396.  
  2397. /* ARGSUSED */
  2398. static void
  2399. pass1(buf, len)
  2400. char *buf;
  2401. int len;
  2402. {
  2403.   strncpy(Password, buf, sizeof(Password) - 1);
  2404.   Input("Retype new password:", sizeof(Password) - 1, pass2, 1);
  2405. }
  2406.  
  2407. /* ARGSUSED */
  2408. static void
  2409. pass2(buf, len)
  2410. char *buf;
  2411. int len;
  2412. {
  2413.   int st;
  2414.   char salt[2];
  2415.  
  2416.   if (buf == 0 || strcmp(Password, buf))
  2417.     {
  2418. #ifdef NETHACK
  2419.       if (nethackflag)
  2420.     Msg(0, "[ Passwords don't match - your armor crumbles away ]");
  2421.       else
  2422. #endif /* NETHACK */
  2423.         Msg(0, "[ Passwords don't match - checking turned off ]");
  2424.       CheckPassword = 0;
  2425.     }
  2426.   if (Password[0] == '\0')
  2427.     {
  2428.       Msg(0, "[ No password - no secure ]");
  2429.       CheckPassword = 0;
  2430.     }
  2431.   for (st = 0; st < 2; st++)
  2432.     salt[st] = 'A' + (int)((time(0) >> 6 * st) % 26);
  2433.   strncpy(Password, crypt(Password, salt), sizeof(Password));
  2434.   if (CheckPassword)
  2435.     {
  2436. #ifdef COPY_PASTE
  2437.       if (d_copybuffer)
  2438.     free(d_copybuffer);
  2439.       d_copylen = strlen(Password);
  2440.       if ((d_copybuffer = (char *) malloc(d_copylen + 1)) == NULL)
  2441.     {
  2442.       Msg(0, strnomem);
  2443.           d_copylen = 0;
  2444.     }
  2445.       else
  2446.     {
  2447.       strcpy(d_copybuffer, Password);
  2448.       Msg(0, "[ Password moved into copybuffer ]");
  2449.     }
  2450. #else                /* COPY_PASTE */
  2451.       Msg(0, "[ Crypted password is \"%s\" ]", Password);
  2452. #endif                /* COPY_PASTE */
  2453.     }
  2454.   if (buf)
  2455.     bzero(buf, strlen(buf));
  2456. }
  2457. #endif /* PASSWORD */
  2458.  
  2459.