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