~dannf/ubuntu/saucy/screen/lp1213278-from-debian

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