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

« back to all changes in this revision

Viewing changes to screen.c

  • Committer: Bazaar Package Importer
  • Author(s): Nathaniel McCallum
  • Date: 2004-09-03 15:15:33 UTC
  • Revision ID: james.westby@ubuntu.com-20040903151533-px02yqlrchs4fv2t
Tags: upstream-4.0.2
ImportĀ upstreamĀ versionĀ 4.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#ifdef HAVE_BRAILLE
 
6
 * Modified by:
 
7
 *      Authors:  Hadi Bargi Rangin  bargi@dots.physics.orst.edu
 
8
 *                Bill Barry         barryb@dots.physics.orst.edu
 
9
 *                Randy Lundquist    randyl@dots.physics.orst.edu
 
10
 *
 
11
 * Modifications Copyright (c) 1995 by
 
12
 * Science Access Project, Oregon State University.
 
13
#endif
 
14
 *
 
15
 * This program is free software; you can redistribute it and/or modify
 
16
 * it under the terms of the GNU General Public License as published by
 
17
 * the Free Software Foundation; either version 2, or (at your option)
 
18
 * any later version.
 
19
 *
 
20
 * This program is distributed in the hope that it will be useful,
 
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
23
 * GNU General Public License for more details.
 
24
 *
 
25
 * You should have received a copy of the GNU General Public License
 
26
 * along with this program (see the file COPYING); if not, write to the
 
27
 * Free Software Foundation, Inc.,
 
28
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 
29
 *
 
30
 ****************************************************************
 
31
 */
 
32
 
 
33
#include <sys/types.h>
 
34
#include <ctype.h>
 
35
 
 
36
#include <fcntl.h>
 
37
 
 
38
#ifdef sgi
 
39
# include <sys/sysmacros.h>
 
40
#endif
 
41
 
 
42
#include <sys/stat.h>
 
43
#ifndef sun
 
44
# include <sys/ioctl.h>
 
45
#endif
 
46
 
 
47
#ifndef SIGINT
 
48
# include <signal.h>
 
49
#endif
 
50
 
 
51
#include "config.h"
 
52
 
 
53
#ifdef SVR4
 
54
# include <sys/stropts.h>
 
55
#endif
 
56
 
 
57
#if defined(SYSV) && !defined(ISC)
 
58
# include <sys/utsname.h>
 
59
#endif
 
60
 
 
61
#if defined(sequent) || defined(SVR4)
 
62
# include <sys/resource.h>
 
63
#endif /* sequent || SVR4 */
 
64
 
 
65
#ifdef ISC
 
66
# include <sys/tty.h>
 
67
# include <sys/sioctl.h>
 
68
# include <sys/pty.h>
 
69
#endif /* ISC */
 
70
 
 
71
#if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX)
 
72
# include <compat.h>
 
73
#endif
 
74
#if defined(USE_LOCALE) || defined(ENCODINGS)
 
75
# include <locale.h>
 
76
#endif
 
77
#if defined(HAVE_NL_LANGINFO) && defined(ENCODINGS)
 
78
# include <langinfo.h>
 
79
#endif
 
80
 
 
81
#include "screen.h"
 
82
#ifdef HAVE_BRAILLE
 
83
# include "braille.h"
 
84
#endif
 
85
 
 
86
#include "patchlevel.h"
 
87
 
 
88
/*
 
89
 *  At the moment we only need the real password if the
 
90
 *  builtin lock is used. Therefore disable SHADOWPW if
 
91
 *  we do not really need it (kind of security thing).
 
92
 */
 
93
#ifndef LOCK
 
94
# undef SHADOWPW
 
95
#endif
 
96
 
 
97
#include <pwd.h>
 
98
#ifdef SHADOWPW
 
99
# include <shadow.h>
 
100
#endif /* SHADOWPW */
 
101
 
 
102
#include "logfile.h"    /* islogfile, logfflush */
 
103
 
 
104
#ifdef DEBUG
 
105
FILE *dfp;
 
106
#endif
 
107
 
 
108
 
 
109
extern char Term[], screenterm[], **environ, Termcap[];
 
110
int force_vt = 1;
 
111
int VBellWait, MsgWait, MsgMinWait, SilenceWait;
 
112
 
 
113
extern struct acluser *users;
 
114
extern struct display *displays, *display; 
 
115
 
 
116
 
 
117
extern int visual_bell;
 
118
#ifdef COPY_PASTE
 
119
extern unsigned char mark_key_tab[];
 
120
#endif
 
121
extern char version[];
 
122
extern char DefaultShell[];
 
123
#ifdef ZMODEM
 
124
extern char *zmodem_sendcmd;
 
125
extern char *zmodem_recvcmd;
 
126
#endif
 
127
 
 
128
 
 
129
char *ShellProg;
 
130
char *ShellArgs[2];
 
131
 
 
132
extern struct NewWindow nwin_undef, nwin_default, nwin_options;
 
133
struct backtick;
 
134
 
 
135
static struct passwd *getpwbyname __P((char *, struct passwd *));
 
136
static void  SigChldHandler __P((void));
 
137
static sigret_t SigChld __P(SIGPROTOARG);
 
138
static sigret_t SigInt __P(SIGPROTOARG);
 
139
static sigret_t CoreDump __P(SIGPROTOARG);
 
140
static sigret_t FinitHandler __P(SIGPROTOARG);
 
141
static void  DoWait __P((void));
 
142
static void  serv_read_fn __P((struct event *, char *));
 
143
static void  serv_select_fn __P((struct event *, char *));
 
144
static void  logflush_fn __P((struct event *, char *));
 
145
static void  backtick_filter __P((struct backtick *));
 
146
static void  backtick_fn __P((struct event *, char *));
 
147
static char *runbacktick __P((struct backtick *, int *, time_t));
 
148
static int   IsSymbol __P((char *, char *));
 
149
static char *ParseChar __P((char *, char *));
 
150
static int   ParseEscape __P((char *));
 
151
static char *pad_expand __P((char *, char *, int, int));
 
152
#ifdef DEBUG
 
153
static void  fds __P((void));
 
154
#endif
 
155
 
 
156
int nversion;   /* numerical version, used for secondary DA */
 
157
 
 
158
/* the attacher */
 
159
struct passwd *ppp;
 
160
char *attach_tty;
 
161
char *attach_term;
 
162
char *LoginName;
 
163
struct mode attach_Mode;
 
164
 
 
165
char SockPath[MAXPATHLEN + 2 * MAXSTR];
 
166
char *SockName;                 /* SockName is pointer in SockPath */
 
167
char *SockMatch = NULL;         /* session id command line argument */
 
168
int ServerSocket = -1;
 
169
struct event serv_read;
 
170
struct event serv_select;
 
171
struct event logflushev;
 
172
 
 
173
char **NewEnv = NULL;
 
174
 
 
175
char *RcFileName = NULL;
 
176
char *home;
 
177
 
 
178
char *screenlogfile;                    /* filename layout */
 
179
int log_flush = 10;                     /* flush interval in seconds */
 
180
int logtstamp_on = 0;                   /* tstamp disabled */
 
181
char *logtstamp_string;                 /* stamp layout */
 
182
int logtstamp_after = 120;              /* first tstamp after 120s */
 
183
char *hardcopydir = NULL;
 
184
char *BellString;
 
185
char *VisualBellString;
 
186
char *ActivityString;
 
187
#ifdef COPY_PASTE
 
188
char *BufferFile;
 
189
#endif
 
190
#ifdef POW_DETACH
 
191
char *PowDetachString;
 
192
#endif
 
193
char *hstatusstring;
 
194
char *captionstring;
 
195
char *timestring;
 
196
char *wliststr;
 
197
char *wlisttit;
 
198
int auto_detach = 1;
 
199
int iflag, rflag, dflag, lsflag, quietflag, wipeflag, xflag;
 
200
int cmdflag;
 
201
int adaptflag;
 
202
 
 
203
#ifdef MULTIUSER
 
204
char *multi;
 
205
char *multi_home;
 
206
int multi_uid;
 
207
int own_uid;
 
208
int multiattach;
 
209
int tty_mode;
 
210
int tty_oldmode = -1;
 
211
#endif
 
212
 
 
213
char HostName[MAXSTR];
 
214
int MasterPid;
 
215
int real_uid, real_gid, eff_uid, eff_gid;
 
216
int default_startup;
 
217
int ZombieKey_destroy, ZombieKey_resurrect;
 
218
char *preselect = NULL;         /* only used in Attach() */
 
219
 
 
220
#ifdef UTF8
 
221
char *screenencodings;
 
222
#endif
 
223
 
 
224
#ifdef NETHACK
 
225
int nethackflag = 0;
 
226
#endif
 
227
int maxwin = MAXWIN;
 
228
 
 
229
 
 
230
struct layer *flayer;
 
231
struct win *fore;
 
232
struct win *windows;
 
233
struct win *console_window;
 
234
 
 
235
 
 
236
 
 
237
/*
 
238
 * Do this last
 
239
 */
 
240
#include "extern.h"
 
241
 
 
242
char strnomem[] = "Out of memory.";
 
243
 
 
244
 
 
245
static int InterruptPlease;
 
246
static int GotSigChld;
 
247
 
 
248
static int 
 
249
lf_secreopen(name, wantfd, l)
 
250
char *name;
 
251
int wantfd;
 
252
struct logfile *l;
 
253
{
 
254
  int got_fd;
 
255
 
 
256
  close(wantfd);
 
257
  if (((got_fd = secopen(name, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) ||
 
258
      lf_move_fd(got_fd, wantfd) < 0)
 
259
    {
 
260
      logfclose(l);
 
261
      debug1("lf_secreopen: failed for %s\n", name);
 
262
      return -1;
 
263
    }
 
264
  l->st->st_ino = l->st->st_dev = 0;
 
265
  debug2("lf_secreopen: %d = %s\n", wantfd, name);
 
266
  return 0;
 
267
}
 
268
 
 
269
/********************************************************************/
 
270
/********************************************************************/
 
271
/********************************************************************/
 
272
 
 
273
 
 
274
static struct passwd *
 
275
getpwbyname(name, ppp)
 
276
char *name;
 
277
struct passwd *ppp;
 
278
{
 
279
  int n;
 
280
#ifdef SHADOWPW
 
281
  struct spwd *sss = NULL;
 
282
  static char *spw = NULL;
 
283
#endif
 
284
 
 
285
  if (!ppp && !(ppp = getpwnam(name)))
 
286
    return NULL;
 
287
 
 
288
  /* Do password sanity check..., allow ##user for SUN_C2 security */
 
289
#ifdef SHADOWPW
 
290
pw_try_again:
 
291
#endif
 
292
  n = 0;
 
293
  if (ppp->pw_passwd[0] == '#' && ppp->pw_passwd[1] == '#' &&
 
294
      strcmp(ppp->pw_passwd + 2, ppp->pw_name) == 0)
 
295
    n = 13;
 
296
  for (; n < 13; n++)
 
297
    {
 
298
      char c = ppp->pw_passwd[n];
 
299
      if (!(c == '.' || c == '/' || c == '$' ||
 
300
            (c >= '0' && c <= '9') || 
 
301
            (c >= 'a' && c <= 'z') || 
 
302
            (c >= 'A' && c <= 'Z'))) 
 
303
        break;
 
304
    }
 
305
 
 
306
#ifdef SHADOWPW
 
307
  /* try to determine real password */
 
308
  if (n < 13 && sss == 0)
 
309
    {
 
310
      sss = getspnam(ppp->pw_name);
 
311
      if (sss)
 
312
        {
 
313
          if (spw)
 
314
            free(spw);
 
315
          ppp->pw_passwd = spw = SaveStr(sss->sp_pwdp);
 
316
          endspent();   /* this should delete all buffers ... */
 
317
          goto pw_try_again;
 
318
        }
 
319
      endspent();       /* this should delete all buffers ... */
 
320
    }
 
321
#endif
 
322
  if (n < 13)
 
323
    ppp->pw_passwd = 0;
 
324
#ifdef linux
 
325
  if (ppp->pw_passwd && strlen(ppp->pw_passwd) == 13 + 11)
 
326
    ppp->pw_passwd[13] = 0;     /* beware of linux's long passwords */
 
327
#endif
 
328
 
 
329
  return ppp;
 
330
}
 
331
 
 
332
 
 
333
int
 
334
main(ac, av)
 
335
int ac;
 
336
char **av;
 
337
{
 
338
  register int n;
 
339
  char *ap;
 
340
  char *av0;
 
341
  char socknamebuf[2 * MAXSTR];
 
342
  int mflag = 0;
 
343
  char *myname = (ac == 0) ? "screen" : av[0];
 
344
  char *SockDir;
 
345
  struct stat st;
 
346
#ifdef _MODE_T                  /* (jw) */
 
347
  mode_t oumask;
 
348
#else
 
349
  int oumask;
 
350
#endif
 
351
#if defined(SYSV) && !defined(ISC)
 
352
  struct utsname utsnam;
 
353
#endif
 
354
  struct NewWindow nwin;
 
355
  int detached = 0;             /* start up detached */
 
356
#ifdef MULTIUSER
 
357
  char *sockp;
 
358
#endif
 
359
 
 
360
#if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX)
 
361
  setcompat(COMPAT_POSIX|COMPAT_BSDPROT); /* turn on seteuid support */
 
362
#endif
 
363
#if defined(sun) && defined(SVR4)
 
364
  {
 
365
    /* Solaris' login blocks SIGHUP! This is _very bad_ */
 
366
    sigset_t sset;
 
367
    sigemptyset(&sset);
 
368
    sigprocmask(SIG_SETMASK, &sset, 0);
 
369
  }
 
370
#endif
 
371
 
 
372
  /*
 
373
   *  First, close all unused descriptors
 
374
   *  (otherwise, we might have problems with the select() call)
 
375
   */
 
376
  closeallfiles(0);
 
377
#ifdef DEBUG
 
378
  opendebug(1, 0);
 
379
#endif
 
380
  sprintf(version, "%d.%.2d.%.2d%s (%s) %s", REV, VERS,
 
381
          PATCHLEVEL, STATE, ORIGIN, DATE);
 
382
  nversion = REV * 10000 + VERS * 100 + PATCHLEVEL;
 
383
  debug2("-- screen debug started %s (%s)\n", *av, version);
 
384
#ifdef POSIX
 
385
  debug("POSIX\n");
 
386
#endif
 
387
#ifdef TERMIO
 
388
  debug("TERMIO\n");
 
389
#endif
 
390
#ifdef SYSV
 
391
  debug("SYSV\n");
 
392
#endif
 
393
#ifdef SYSVSIGS
 
394
  debug("SYSVSIGS\n");
 
395
#endif
 
396
#ifdef NAMEDPIPE
 
397
  debug("NAMEDPIPE\n");
 
398
#endif
 
399
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
 
400
  debug("Window size changing enabled\n");
 
401
#endif
 
402
#ifdef HAVE_SETREUID
 
403
  debug("SETREUID\n");
 
404
#endif
 
405
#ifdef HAVE_SETEUID
 
406
  debug("SETEUID\n");
 
407
#endif
 
408
#ifdef hpux
 
409
  debug("hpux\n");
 
410
#endif
 
411
#ifdef USEBCOPY
 
412
  debug("USEBCOPY\n");
 
413
#endif
 
414
#ifdef UTMPOK
 
415
  debug("UTMPOK\n");
 
416
#endif
 
417
#ifdef LOADAV
 
418
  debug("LOADAV\n");
 
419
#endif
 
420
#ifdef NETHACK
 
421
  debug("NETHACK\n");
 
422
#endif
 
423
#ifdef TERMINFO
 
424
  debug("TERMINFO\n");
 
425
#endif
 
426
#ifdef SHADOWPW
 
427
  debug("SHADOWPW\n");
 
428
#endif
 
429
#ifdef NAME_MAX
 
430
  debug1("NAME_MAX = %d\n", NAME_MAX);
 
431
#endif
 
432
 
 
433
  BellString = SaveStr("Bell in window %n");
 
434
  VisualBellString = SaveStr("   Wuff,  Wuff!!  ");
 
435
  ActivityString = SaveStr("Activity in window %n");
 
436
  screenlogfile = SaveStr("screenlog.%n");
 
437
  logtstamp_string = SaveStr("-- %n:%t -- time-stamp -- %M/%d/%y %c:%s --\n");
 
438
  hstatusstring = SaveStr("%h");
 
439
  captionstring = SaveStr("%3n %t");
 
440
  timestring = SaveStr("%c:%s %M %d %H%? %l%?");
 
441
  wlisttit = SaveStr("Num Name%=Flags");
 
442
  wliststr = SaveStr("%3n %t%=%f");
 
443
#ifdef COPY_PASTE
 
444
  BufferFile = SaveStr(DEFAULT_BUFFERFILE);
 
445
#endif
 
446
  ShellProg = NULL;
 
447
#ifdef POW_DETACH
 
448
  PowDetachString = 0;
 
449
#endif
 
450
  default_startup = (ac > 1) ? 0 : 1;
 
451
  adaptflag = 0;
 
452
  VBellWait = VBELLWAIT * 1000;
 
453
  MsgWait = MSGWAIT * 1000;
 
454
  MsgMinWait = MSGMINWAIT * 1000;
 
455
  SilenceWait = SILENCEWAIT;
 
456
#ifdef HAVE_BRAILLE
 
457
  InitBraille();
 
458
#endif
 
459
#ifdef ZMODEM
 
460
  zmodem_sendcmd = SaveStr("!!! sz -vv -b ");
 
461
  zmodem_recvcmd = SaveStr("!!! rz -vv -b -E");
 
462
#endif
 
463
 
 
464
#ifdef COPY_PASTE
 
465
  CompileKeys((char *)0, 0, mark_key_tab);
 
466
#endif
 
467
#ifdef UTF8
 
468
  InitBuiltinTabs();
 
469
  screenencodings = SaveStr(SCREENENCODINGS);
 
470
#endif
 
471
  nwin = nwin_undef;
 
472
  nwin_options = nwin_undef;
 
473
  strcpy(screenterm, "screen");
 
474
 
 
475
  logreopen_register(lf_secreopen);
 
476
 
 
477
  av0 = *av;
 
478
  /* if this is a login screen, assume -RR */
 
479
  if (*av0 == '-')
 
480
    {
 
481
      rflag = 4;
 
482
#ifdef MULTI
 
483
      xflag = 1;
 
484
#else
 
485
      dflag = 1;
 
486
#endif
 
487
      ShellProg = SaveStr(DefaultShell); /* to prevent nasty circles */
 
488
    }
 
489
  while (ac > 0)
 
490
    {
 
491
      ap = *++av;
 
492
      if (--ac > 0 && *ap == '-')
 
493
        {
 
494
          if (ap[1] == '-' && ap[2] == 0)
 
495
            {
 
496
              av++;
 
497
              ac--;
 
498
              break;
 
499
            }
 
500
          if (ap[1] == '-' && !strcmp(ap, "--version"))
 
501
            Panic(0, "Screen version %s", version);
 
502
          if (ap[1] == '-' && !strcmp(ap, "--help"))
 
503
            exit_with_usage(myname, NULL, NULL);
 
504
          while (ap && *ap && *++ap)
 
505
            {
 
506
              switch (*ap)
 
507
                {
 
508
                case 'a':
 
509
                  nwin_options.aflag = 1;
 
510
                  break;
 
511
                case 'A':
 
512
                  adaptflag = 1;
 
513
                  break;
 
514
                case 'p': /* preselect */
 
515
                  if (*++ap)
 
516
                    preselect = ap;
 
517
                  else
 
518
                    {
 
519
                      if (!--ac)
 
520
                        exit_with_usage(myname, "Specify a window to preselect with -p", NULL);
 
521
                      preselect = *++av;
 
522
                    }
 
523
                  ap = NULL;
 
524
                  break;
 
525
#ifdef HAVE_BRAILLE
 
526
                case 'B':
 
527
                  bd.bd_start_braille = 1;
 
528
                  break;
 
529
#endif
 
530
                case 'c':
 
531
                  if (*++ap)
 
532
                    RcFileName = ap;
 
533
                  else
 
534
                    {
 
535
                      if (--ac == 0)
 
536
                        exit_with_usage(myname, "Specify an alternate rc-filename with -c", NULL);
 
537
                      RcFileName = *++av;
 
538
                    }
 
539
                  ap = NULL;
 
540
                  break;
 
541
                case 'e':
 
542
                  if (!*++ap)
 
543
                    {
 
544
                      if (--ac == 0)
 
545
                        exit_with_usage(myname, "Specify command characters with -e", NULL);
 
546
                      ap = *++av;
 
547
                    }
 
548
                  if (ParseEscape(ap))
 
549
                    Panic(0, "Two characters are required with -e option, not '%s'.", ap);
 
550
                  ap = NULL;
 
551
                  break;
 
552
                case 'f':
 
553
                  ap++;
 
554
                  switch (*ap++)
 
555
                    {
 
556
                    case 'n':
 
557
                    case '0':
 
558
                      nwin_options.flowflag = FLOW_NOW * 0;
 
559
                      break;
 
560
                    case '\0':
 
561
                      ap--;
 
562
                      /* FALLTHROUGH */
 
563
                    case 'y':
 
564
                    case '1':
 
565
                      nwin_options.flowflag = FLOW_NOW * 1;
 
566
                      break;
 
567
                    case 'a':
 
568
                      nwin_options.flowflag = FLOW_AUTOFLAG;
 
569
                      break;
 
570
                    default:
 
571
                      exit_with_usage(myname, "Unknown flow option -%s", --ap);
 
572
                    }
 
573
                  break;
 
574
                case 'h':
 
575
                  if (--ac == 0)
 
576
                    exit_with_usage(myname, NULL, NULL);
 
577
                  nwin_options.histheight = atoi(*++av);
 
578
                  if (nwin_options.histheight < 0)
 
579
                    exit_with_usage(myname, "-h: %s: negative scrollback size?", *av);
 
580
                  break;
 
581
                case 'i':
 
582
                  iflag = 1;
 
583
                  break;
 
584
                case 't': /* title, the former AkA == -k */
 
585
                  if (--ac == 0)
 
586
                    exit_with_usage(myname, "Specify a new window-name with -t", NULL);
 
587
                  nwin_options.aka = *++av;
 
588
                  break;
 
589
                case 'l':
 
590
                  ap++;
 
591
                  switch (*ap++)
 
592
                    {
 
593
                    case 'n':
 
594
                    case '0':
 
595
                      nwin_options.lflag = 0;
 
596
                      break;
 
597
                    case '\0':
 
598
                      ap--;
 
599
                      /* FALLTHROUGH */
 
600
                    case 'y':
 
601
                    case '1':
 
602
                      nwin_options.lflag = 1;
 
603
                      break;
 
604
                    case 'a':
 
605
                      nwin_options.lflag = 3;
 
606
                      break;
 
607
                    case 's':   /* -ls */
 
608
                    case 'i':   /* -list */
 
609
                      lsflag = 1;
 
610
                      if (ac > 1 && !SockMatch)
 
611
                        {
 
612
                          SockMatch = *++av;
 
613
                          ac--;
 
614
                        }
 
615
                      ap = NULL;
 
616
                      break;
 
617
                    default:
 
618
                      exit_with_usage(myname, "%s: Unknown suboption to -l", --ap);
 
619
                    }
 
620
                  break;
 
621
                case 'w':
 
622
                  lsflag = 1;
 
623
                  wipeflag = 1;
 
624
                  if (ac > 1 && !SockMatch)
 
625
                    {
 
626
                      SockMatch = *++av;
 
627
                      ac--;
 
628
                    }
 
629
                  break;
 
630
                case 'L':
 
631
                  nwin_options.Lflag = 1;
 
632
                  break;
 
633
                case 'm':
 
634
                  mflag = 1;
 
635
                  break;
 
636
                case 'O':               /* to be (or not to be?) deleted. jw. */
 
637
                  force_vt = 0;
 
638
                  break;
 
639
                case 'T':
 
640
                  if (--ac == 0)
 
641
                    exit_with_usage(myname, "Specify terminal-type with -T", NULL);
 
642
                  if (strlen(*++av) < 20)
 
643
                    strcpy(screenterm, *av);
 
644
                  else
 
645
                    Panic(0, "-T: terminal name too long. (max. 20 char)");
 
646
                  nwin_options.term = screenterm;
 
647
                  break;
 
648
                case 'q':
 
649
                  quietflag = 1;
 
650
                  break;
 
651
                case 'r':
 
652
                case 'R':
 
653
#ifdef MULTI
 
654
                case 'x':
 
655
#endif
 
656
                  if (ac > 1 && *av[1] != '-' && !SockMatch)
 
657
                    {
 
658
                      SockMatch = *++av;
 
659
                      ac--;
 
660
                      debug2("rflag=%d, SockMatch=%s\n", dflag, SockMatch);
 
661
                    }
 
662
#ifdef MULTI
 
663
                  if (*ap == 'x')
 
664
                    xflag = 1;
 
665
#endif
 
666
                  if (rflag)
 
667
                    rflag = 2;
 
668
                  rflag += (*ap == 'R') ? 2 : 1;
 
669
                  break;
 
670
#ifdef REMOTE_DETACH
 
671
                case 'd':
 
672
                  dflag = 1;
 
673
                  /* FALLTHROUGH */
 
674
                case 'D':
 
675
                  if (!dflag)
 
676
                    dflag = 2;
 
677
                  if (ac == 2)
 
678
                    {
 
679
                      if (*av[1] != '-' && !SockMatch)
 
680
                        {
 
681
                          SockMatch = *++av;
 
682
                          ac--;
 
683
                          debug2("dflag=%d, SockMatch=%s\n", dflag, SockMatch);
 
684
                        }
 
685
                    }
 
686
                  break;
 
687
#endif
 
688
                case 's':
 
689
                  if (--ac == 0)
 
690
                    exit_with_usage(myname, "Specify shell with -s", NULL);
 
691
                  if (ShellProg)
 
692
                    free(ShellProg);
 
693
                  ShellProg = SaveStr(*++av);
 
694
                  debug1("ShellProg: '%s'\n", ShellProg);
 
695
                  break;
 
696
                case 'S':
 
697
                  if (!SockMatch)
 
698
                    {
 
699
                      if (--ac == 0)
 
700
                        exit_with_usage(myname, "Specify session-name with -S", NULL);
 
701
                      SockMatch = *++av;
 
702
                    }
 
703
                  if (!*SockMatch)
 
704
                    exit_with_usage(myname, "Empty session-name?", NULL);
 
705
                  break;
 
706
                case 'X':
 
707
                  cmdflag = 1;
 
708
                  break;
 
709
                case 'v':
 
710
                  Panic(0, "Screen version %s", version);
 
711
                  /* NOTREACHED */
 
712
#ifdef UTF8
 
713
                case 'U':
 
714
                  nwin_options.encoding = nwin_options.encoding == -1 ? UTF8 : 0;
 
715
                  break;
 
716
#endif
 
717
                default:
 
718
                  exit_with_usage(myname, "Unknown option %s", --ap);
 
719
                }
 
720
            }
 
721
        }
 
722
      else
 
723
        break;
 
724
    }
 
725
 
 
726
  real_uid = getuid();
 
727
  real_gid = getgid();
 
728
  eff_uid = geteuid();
 
729
  eff_gid = getegid();
 
730
  if (eff_uid != real_uid)
 
731
    {           
 
732
      /* if running with s-bit, we must install a special signal
 
733
       * handler routine that resets the s-bit, so that we get a
 
734
       * core file anyway.
 
735
       */
 
736
#ifdef SIGBUS /* OOPS, linux has no bus errors! */
 
737
      signal(SIGBUS, CoreDump);
 
738
#endif /* SIGBUS */
 
739
      signal(SIGSEGV, CoreDump);
 
740
    }
 
741
 
 
742
#ifdef USE_LOCALE
 
743
  setlocale(LC_ALL, "");
 
744
#endif
 
745
#ifdef ENCODINGS
 
746
  if (nwin_options.encoding == -1)
 
747
    {
 
748
      /* ask locale if we should start in UTF-8 mode */
 
749
# ifdef HAVE_NL_LANGINFO
 
750
#  ifndef USE_LOCALE
 
751
      setlocale(LC_CTYPE, "");
 
752
#  endif
 
753
      nwin_options.encoding = FindEncoding(nl_langinfo(CODESET));
 
754
      debug1("locale says encoding = %d\n", nwin_options.encoding);
 
755
# else
 
756
#  ifdef UTF8
 
757
      char *s;
 
758
      if (((s = getenv("LC_ALL")) || (s = getenv("LC_CTYPE")) ||
 
759
          (s = getenv("LANG"))) && InStr(s, "UTF-8"))
 
760
        nwin_options.encoding = UTF8;
 
761
#  endif
 
762
      debug1("environment says encoding=%d\n", nwin_options.encoding);
 
763
#endif
 
764
    }
 
765
#endif
 
766
  if (SockMatch && strlen(SockMatch) >= MAXSTR)
 
767
    Panic(0, "Ridiculously long socketname - try again.");
 
768
  if (cmdflag && !rflag && !dflag && !xflag)
 
769
    xflag = 1;
 
770
  if (!cmdflag && dflag && mflag && !(rflag || xflag))
 
771
    detached = 1;
 
772
  nwin = nwin_options;
 
773
#ifdef ENCODINGS
 
774
  nwin.encoding = nwin_undef.encoding;  /* let screenrc overwrite it */
 
775
#endif
 
776
  if (ac)
 
777
    nwin.args = av;
 
778
 
 
779
  /* make the write() calls return -1 on all errors */
 
780
#ifdef SIGXFSZ
 
781
  /*
 
782
   * Ronald F. Guilmette, Oct 29 '94, bug-gnu-utils@prep.ai.mit.edu:
 
783
   * It appears that in System V Release 4, UNIX, if you are writing
 
784
   * an output file and you exceed the currently set file size limit,
 
785
   * you _don't_ just get the call to `write' returning with a
 
786
   * failure code.  Rather, you get a signal called `SIGXFSZ' which,
 
787
   * if neither handled nor ignored, will cause your program to crash
 
788
   * with a core dump.
 
789
   */
 
790
  signal(SIGXFSZ, SIG_IGN);
 
791
#endif /* SIGXFSZ */
 
792
 
 
793
#ifdef SIGPIPE
 
794
  signal(SIGPIPE, SIG_IGN);
 
795
#endif
 
796
 
 
797
  if (!ShellProg)
 
798
    {
 
799
      register char *sh;
 
800
 
 
801
      sh = getenv("SHELL");
 
802
      ShellProg = SaveStr(sh ? sh : DefaultShell);
 
803
    }
 
804
  ShellArgs[0] = ShellProg;
 
805
  home = getenv("HOME");
 
806
 
 
807
#ifdef NETHACK
 
808
  if (!(nethackflag = (getenv("NETHACKOPTIONS") != NULL)))
 
809
    {
 
810
      char nethackrc[MAXPATHLEN];
 
811
 
 
812
      if (home && (strlen(home) < (MAXPATHLEN - 20)))
 
813
        {
 
814
          sprintf(nethackrc,"%s/.nethackrc", home);
 
815
          nethackflag = !access(nethackrc, F_OK);
 
816
        }
 
817
    }
 
818
#endif
 
819
 
 
820
#ifdef MULTIUSER
 
821
  own_uid = multi_uid = real_uid;
 
822
  if (SockMatch && (sockp = index(SockMatch, '/')))
 
823
    {
 
824
      if (eff_uid)
 
825
        Panic(0, "Must run suid root for multiuser support.");
 
826
      *sockp = 0;
 
827
      multi = SockMatch;
 
828
      SockMatch = sockp + 1;
 
829
      if (*multi)
 
830
        {
 
831
          struct passwd *mppp;
 
832
          if ((mppp = getpwnam(multi)) == (struct passwd *)0)
 
833
            Panic(0, "Cannot identify account '%s'.", multi);
 
834
          multi_uid = mppp->pw_uid;
 
835
          multi_home = SaveStr(mppp->pw_dir);
 
836
          if (strlen(multi_home) > MAXPATHLEN - 10)
 
837
            Panic(0, "home directory path too long");
 
838
# ifdef MULTI
 
839
          /* always fake multi attach mode */
 
840
          if (rflag || lsflag)
 
841
            xflag = 1;
 
842
# endif /* MULTI */
 
843
          detached = 0;
 
844
          multiattach = 1;
 
845
        }
 
846
    }
 
847
  if (SockMatch && *SockMatch == 0)
 
848
    SockMatch = 0;
 
849
#endif /* MULTIUSER */
 
850
 
 
851
  if ((LoginName = getlogin()) && LoginName[0] != '\0')
 
852
    {
 
853
      if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
 
854
        if ((int)ppp->pw_uid != real_uid)
 
855
          ppp = (struct passwd *) 0;
 
856
    }
 
857
  if (ppp == 0)
 
858
    {
 
859
      if ((ppp = getpwuid(real_uid)) == 0)
 
860
        {
 
861
          Panic(0, "getpwuid() can't identify your account!");
 
862
          exit(1);
 
863
        }
 
864
      LoginName = ppp->pw_name;
 
865
    }
 
866
  LoginName = SaveStr(LoginName);
 
867
 
 
868
  ppp = getpwbyname(LoginName, ppp);
 
869
 
 
870
#if !defined(SOCKDIR) && defined(MULTIUSER)
 
871
  if (multi && !multiattach)
 
872
    {
 
873
      if (home && strcmp(home, ppp->pw_dir))
 
874
        Panic(0, "$HOME must match passwd entry for multiuser screens.");
 
875
    }
 
876
#endif
 
877
 
 
878
  if (home == 0 || *home == '\0')
 
879
    home = ppp->pw_dir;
 
880
  if (strlen(LoginName) > 20)
 
881
    Panic(0, "LoginName too long - sorry.");
 
882
#ifdef MULTIUSER
 
883
  if (multi && strlen(multi) > 20)
 
884
    Panic(0, "Screen owner name too long - sorry.");
 
885
#endif
 
886
  if (strlen(home) > MAXPATHLEN - 25)
 
887
    Panic(0, "$HOME too long - sorry.");
 
888
 
 
889
  attach_tty = "";
 
890
  if (!detached && !lsflag && !cmdflag && !(dflag && !mflag && !rflag && !xflag))
 
891
    {
 
892
      /* ttyname implies isatty */
 
893
      if (!(attach_tty = ttyname(0)))
 
894
        Panic(0, "Must be connected to a terminal.");
 
895
      if (strlen(attach_tty) >= MAXPATHLEN)
 
896
        Panic(0, "TtyName too long - sorry.");
 
897
      if (stat(attach_tty, &st))
 
898
        Panic(errno, "Cannot access '%s'", attach_tty);
 
899
#ifdef MULTIUSER
 
900
      tty_mode = (int)st.st_mode & 0777;
 
901
#endif
 
902
      if ((n = secopen(attach_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
 
903
        Panic(0, "Cannot open your terminal '%s' - please check.", attach_tty);
 
904
      close(n);
 
905
      debug1("attach_tty is %s\n", attach_tty);
 
906
      if ((attach_term = getenv("TERM")) == 0 || *attach_term == 0)
 
907
        Panic(0, "Please set a terminal type.");
 
908
      if (strlen(attach_term) > sizeof(D_termname) - 1)
 
909
        Panic(0, "$TERM too long - sorry.");
 
910
      GetTTY(0, &attach_Mode);
 
911
#ifdef DEBUGGGGGGGGGGGGGGG
 
912
      DebugTTY(&attach_Mode);
 
913
#endif /* DEBUG */
 
914
    }
 
915
 
 
916
#ifdef _MODE_T
 
917
  oumask = umask(0);            /* well, unsigned never fails? jw. */
 
918
#else
 
919
  if ((oumask = (int)umask(0)) == -1)
 
920
    Panic(errno, "Cannot change umask to zero");
 
921
#endif
 
922
  SockDir = getenv("SCREENDIR");
 
923
  if (SockDir)
 
924
    {
 
925
      if (strlen(SockDir) >= MAXPATHLEN - 1)
 
926
        Panic(0, "Ridiculously long $SCREENDIR - try again.");
 
927
#ifdef MULTIUSER
 
928
      if (multi)
 
929
        Panic(0, "No $SCREENDIR with multi screens, please.");
 
930
#endif
 
931
    }
 
932
#ifdef MULTIUSER
 
933
  if (multiattach)
 
934
    {
 
935
# ifndef SOCKDIR
 
936
      sprintf(SockPath, "%s/.screen", multi_home);
 
937
      SockDir = SockPath;
 
938
# else
 
939
      SockDir = SOCKDIR;
 
940
      sprintf(SockPath, "%s/S-%s", SockDir, multi);
 
941
# endif
 
942
    }
 
943
  else
 
944
#endif
 
945
    {
 
946
#ifndef SOCKDIR
 
947
      if (SockDir == 0)
 
948
        {
 
949
          sprintf(SockPath, "%s/.screen", home);
 
950
          SockDir = SockPath;
 
951
        }
 
952
#endif
 
953
      if (SockDir)
 
954
        {
 
955
          if (access(SockDir, F_OK))
 
956
            {
 
957
              debug1("SockDir '%s' missing ...\n", SockDir);
 
958
              if (UserContext() > 0)
 
959
                {
 
960
                  if (mkdir(SockDir, 0700))
 
961
                    UserReturn(0);
 
962
                  UserReturn(1);
 
963
                }
 
964
              if (UserStatus() <= 0)
 
965
                Panic(0, "Cannot make directory '%s'.", SockDir);
 
966
            }
 
967
          if (SockDir != SockPath)
 
968
            strcpy(SockPath, SockDir);
 
969
        }
 
970
#ifdef SOCKDIR
 
971
      else
 
972
        {
 
973
          SockDir = SOCKDIR;
 
974
          if (lstat(SockDir, &st))
 
975
            {
 
976
              n = (eff_uid == 0 && (real_uid || eff_gid == real_gid)) ? 0755 :
 
977
                  (eff_gid != real_gid) ? 0775 :
 
978
#ifdef S_ISVTX
 
979
                  0777|S_ISVTX;
 
980
#else
 
981
                  0777;
 
982
#endif
 
983
              if (mkdir(SockDir, n) == -1)
 
984
                Panic(errno, "Cannot make directory '%s'", SockDir);
 
985
            }
 
986
          else
 
987
            {
 
988
              if (!S_ISDIR(st.st_mode))
 
989
                Panic(0, "'%s' must be a directory.", SockDir);
 
990
              if (eff_uid == 0 && real_uid && (int)st.st_uid != eff_uid)
 
991
                Panic(0, "Directory '%s' must be owned by root.", SockDir);
 
992
              n = (eff_uid == 0 && (real_uid || (st.st_mode & 0775) != 0775)) ? 0755 :
 
993
                  (eff_gid == (int)st.st_gid && eff_gid != real_gid) ? 0775 :
 
994
                  0777;
 
995
              if (((int)st.st_mode & 0777) != n)
 
996
                Panic(0, "Directory '%s' must have mode %03o.", SockDir, n);
 
997
            }
 
998
          sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
 
999
          if (access(SockPath, F_OK))
 
1000
            {
 
1001
              if (mkdir(SockPath, 0700) == -1)
 
1002
                Panic(errno, "Cannot make directory '%s'", SockPath);
 
1003
              (void) chown(SockPath, real_uid, real_gid);
 
1004
            }
 
1005
        }
 
1006
#endif
 
1007
    }
 
1008
 
 
1009
  if (stat(SockPath, &st) == -1)
 
1010
    Panic(errno, "Cannot access %s", SockPath);
 
1011
  else
 
1012
  if (!S_ISDIR(st.st_mode))
 
1013
    Panic(0, "%s is not a directory.", SockPath);
 
1014
#ifdef MULTIUSER
 
1015
  if (multi)
 
1016
    {
 
1017
      if ((int)st.st_uid != multi_uid)
 
1018
        Panic(0, "%s is not the owner of %s.", multi, SockPath);
 
1019
    }
 
1020
  else
 
1021
#endif
 
1022
    {
 
1023
      if ((int)st.st_uid != real_uid)
 
1024
        Panic(0, "You are not the owner of %s.", SockPath);
 
1025
    }
 
1026
  if ((st.st_mode & 0777) != 0700)
 
1027
    Panic(0, "Directory %s must have mode 700.", SockPath);
 
1028
  if (SockMatch && index(SockMatch, '/'))
 
1029
    Panic(0, "Bad session name '%s'", SockMatch);
 
1030
  SockName = SockPath + strlen(SockPath) + 1;
 
1031
  *SockName = 0;
 
1032
  (void) umask(oumask);
 
1033
  debug2("SockPath: %s  SockMatch: %s\n", SockPath, SockMatch ? SockMatch : "NULL");
 
1034
 
 
1035
#if defined(SYSV) && !defined(ISC)
 
1036
  if (uname(&utsnam) == -1)
 
1037
    Panic(errno, "uname");
 
1038
  strncpy(HostName, utsnam.nodename, sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1);
 
1039
  HostName[sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1] = '\0';
 
1040
#else
 
1041
  (void) gethostname(HostName, MAXSTR);
 
1042
  HostName[MAXSTR - 1] = '\0';
 
1043
#endif
 
1044
  if ((ap = index(HostName, '.')) != NULL)
 
1045
    *ap = '\0';
 
1046
 
 
1047
  if (lsflag)
 
1048
    {
 
1049
      int i, fo, oth;
 
1050
 
 
1051
#ifdef MULTIUSER
 
1052
      if (multi)
 
1053
        real_uid = multi_uid;
 
1054
#endif
 
1055
      setgid(real_gid);
 
1056
      setuid(real_uid);
 
1057
      eff_uid = real_uid;
 
1058
      eff_gid = real_gid;
 
1059
      i = FindSocket((int *)NULL, &fo, &oth, SockMatch);
 
1060
      if (quietflag)
 
1061
        exit(8 + (fo ? ((oth || i) ? 2 : 1) : 0) + i);
 
1062
      if (fo == 0)
 
1063
        Panic(0, "No Sockets found in %s.\n", SockPath);
 
1064
      Panic(0, "%d Socket%s in %s.\n", fo, fo > 1 ? "s" : "", SockPath);
 
1065
      /* NOTREACHED */
 
1066
    }
 
1067
  signal(SIG_BYE, AttacherFinit);       /* prevent races */
 
1068
  if (cmdflag)
 
1069
    {
 
1070
      char *sty = 0;
 
1071
 
 
1072
      /* attach_tty is not mandatory */
 
1073
      if ((attach_tty = ttyname(0)) == 0)
 
1074
        attach_tty = "";
 
1075
      if (strlen(attach_tty) >= MAXPATHLEN)
 
1076
        Panic(0, "TtyName too long - sorry.");
 
1077
      if (!*av)
 
1078
        Panic(0, "Please specify a command.");
 
1079
      setgid(real_gid);
 
1080
      setuid(real_uid);
 
1081
      eff_uid = real_uid;
 
1082
      eff_gid = real_gid;
 
1083
      if (!mflag && !SockMatch)
 
1084
        {
 
1085
          sty = getenv("STY");
 
1086
          if (sty && *sty == 0)
 
1087
            sty = 0;
 
1088
        }
 
1089
      SendCmdMessage(sty, SockMatch, av);
 
1090
      exit(0);
 
1091
    }
 
1092
  else if (rflag || xflag)
 
1093
    {
 
1094
      debug("screen -r: - is there anybody out there?\n");
 
1095
      if (Attach(MSG_ATTACH))
 
1096
        {
 
1097
          Attacher();
 
1098
          /* NOTREACHED */
 
1099
        }
 
1100
#ifdef MULTIUSER
 
1101
      if (multiattach)
 
1102
        Panic(0, "Can't create sessions of other users.");
 
1103
#endif
 
1104
      debug("screen -r: backend not responding -- still crying\n");
 
1105
    }
 
1106
  else if (dflag && !mflag)
 
1107
    {
 
1108
      (void) Attach(MSG_DETACH);
 
1109
      Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
 
1110
      eexit(0);
 
1111
      /* NOTREACHED */
 
1112
    }
 
1113
  if (!SockMatch && !mflag)
 
1114
    {
 
1115
      register char *sty;
 
1116
 
 
1117
      if ((sty = getenv("STY")) != 0 && *sty != '\0')
 
1118
        {
 
1119
          setgid(real_gid);
 
1120
          setuid(real_uid);
 
1121
          eff_uid = real_uid;
 
1122
          eff_gid = real_gid;
 
1123
          nwin_options.args = av;
 
1124
          SendCreateMsg(sty, &nwin);
 
1125
          exit(0);
 
1126
          /* NOTREACHED */
 
1127
        }
 
1128
    }
 
1129
  nwin_compose(&nwin_default, &nwin_options, &nwin_default);
 
1130
 
 
1131
  if (!detached || dflag != 2)
 
1132
    MasterPid = fork();
 
1133
  else
 
1134
    MasterPid = 0;
 
1135
 
 
1136
  switch (MasterPid)
 
1137
    {
 
1138
    case -1:
 
1139
      Panic(errno, "fork");
 
1140
      /* NOTREACHED */
 
1141
    case 0:
 
1142
      break;
 
1143
    default:
 
1144
      if (detached)
 
1145
        exit(0);
 
1146
      if (SockMatch)
 
1147
        sprintf(socknamebuf, "%d.%s", MasterPid, SockMatch);
 
1148
      else
 
1149
        sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty), HostName);
 
1150
      for (ap = socknamebuf; *ap; ap++)
 
1151
        if (*ap == '/')
 
1152
          *ap = '-';
 
1153
#ifdef NAME_MAX
 
1154
      if (strlen(socknamebuf) > NAME_MAX)
 
1155
        socknamebuf[NAME_MAX] = 0;
 
1156
#endif
 
1157
      sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf);
 
1158
      setgid(real_gid);
 
1159
      setuid(real_uid);
 
1160
      eff_uid = real_uid;
 
1161
      eff_gid = real_gid;
 
1162
      Attacher();
 
1163
      /* NOTREACHED */
 
1164
    }
 
1165
 
 
1166
  if (DefaultEsc == -1)
 
1167
    DefaultEsc = Ctrl('a');
 
1168
  if (DefaultMetaEsc == -1)
 
1169
    DefaultMetaEsc = 'a';
 
1170
 
 
1171
  ap = av0 + strlen(av0) - 1;
 
1172
  while (ap >= av0)
 
1173
    {
 
1174
      if (!strncmp("screen", ap, 6))
 
1175
        {
 
1176
          strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
 
1177
          break;
 
1178
        }
 
1179
      ap--;
 
1180
    }
 
1181
  if (ap < av0)
 
1182
    *av0 = 'S';
 
1183
 
 
1184
#ifdef DEBUG
 
1185
  {
 
1186
    char buf[256];
 
1187
 
 
1188
    if (dfp && dfp != stderr)
 
1189
      fclose(dfp);
 
1190
    sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, (int)getpid());
 
1191
    if ((dfp = fopen(buf, "w")) == NULL)
 
1192
      dfp = stderr;
 
1193
    else
 
1194
      (void) chmod(buf, 0666);
 
1195
  }
 
1196
#endif
 
1197
  if (!detached)
 
1198
    {
 
1199
      /* reopen tty. must do this, because fd 0 may be RDONLY */
 
1200
      if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
 
1201
        Panic(0, "Cannot reopen '%s' - please check.", attach_tty);
 
1202
    }
 
1203
  else
 
1204
    n = -1;
 
1205
  freopen("/dev/null", "r", stdin);
 
1206
  freopen("/dev/null", "w", stdout);
 
1207
 
 
1208
#ifdef DEBUG
 
1209
  if (dfp != stderr)
 
1210
#endif
 
1211
  freopen("/dev/null", "w", stderr);
 
1212
  debug("-- screen.back debug started\n");
 
1213
 
 
1214
  /* 
 
1215
   * This guarantees that the session owner is listed, even when we
 
1216
   * start detached. From now on we should not refer to 'LoginName'
 
1217
   * any more, use users->u_name instead.
 
1218
   */
 
1219
  if (UserAdd(LoginName, (char *)0, (struct acluser **)0) < 0)
 
1220
    Panic(0, "Could not create user info");
 
1221
  if (!detached)
 
1222
    {
 
1223
      if (MakeDisplay(LoginName, attach_tty, attach_term, n, getppid(), &attach_Mode) == 0)
 
1224
        Panic(0, "Could not alloc display");
 
1225
#ifdef ENCODINGS
 
1226
      D_encoding = nwin_options.encoding > 0 ? nwin_options.encoding : 0;
 
1227
      debug1("D_encoding = %d\n", D_encoding);
 
1228
#endif
 
1229
    }
 
1230
 
 
1231
  if (SockMatch)
 
1232
    {
 
1233
      /* user started us with -S option */
 
1234
      sprintf(socknamebuf, "%d.%s", (int)getpid(), SockMatch);
 
1235
    }
 
1236
  else
 
1237
    {
 
1238
      sprintf(socknamebuf, "%d.%s.%s", (int)getpid(), stripdev(attach_tty),
 
1239
              HostName);
 
1240
    }
 
1241
  for (ap = socknamebuf; *ap; ap++)
 
1242
    if (*ap == '/')
 
1243
      *ap = '-';
 
1244
#ifdef NAME_MAX
 
1245
  if (strlen(socknamebuf) > NAME_MAX)
 
1246
    {
 
1247
      debug2("Socketname %s truncated to %d chars\n", socknamebuf, NAME_MAX);
 
1248
      socknamebuf[NAME_MAX] = 0;
 
1249
    }
 
1250
#endif
 
1251
  sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf);
 
1252
  
 
1253
  ServerSocket = MakeServerSocket();
 
1254
  InitKeytab();
 
1255
#ifdef ETCSCREENRC
 
1256
# ifdef ALLOW_SYSSCREENRC
 
1257
  if ((ap = getenv("SYSSCREENRC")))
 
1258
    StartRc(ap);
 
1259
  else
 
1260
# endif
 
1261
    StartRc(ETCSCREENRC);
 
1262
#endif
 
1263
  StartRc(RcFileName);
 
1264
# ifdef UTMPOK
 
1265
#  ifndef UTNOKEEP
 
1266
  InitUtmp(); 
 
1267
#  endif /* UTNOKEEP */
 
1268
# endif /* UTMPOK */
 
1269
  if (display)
 
1270
    {
 
1271
      if (InitTermcap(0, 0))
 
1272
        {
 
1273
          debug("Could not init termcap - exiting\n");
 
1274
          fcntl(D_userfd, F_SETFL, 0);  /* Flush sets FNBLOCK */
 
1275
          freetty();
 
1276
          if (D_userpid)
 
1277
            Kill(D_userpid, SIG_BYE);
 
1278
          eexit(1);
 
1279
        }
 
1280
      MakeDefaultCanvas();
 
1281
      InitTerm(0);
 
1282
#ifdef UTMPOK
 
1283
      RemoveLoginSlot();
 
1284
#endif
 
1285
    }
 
1286
  else
 
1287
    MakeTermcap(1);
 
1288
#ifdef LOADAV
 
1289
  InitLoadav();
 
1290
#endif /* LOADAV */
 
1291
  MakeNewEnv();
 
1292
  signal(SIGHUP, SigHup);
 
1293
  signal(SIGINT, FinitHandler);
 
1294
  signal(SIGQUIT, FinitHandler);
 
1295
  signal(SIGTERM, FinitHandler);
 
1296
#ifdef BSDJOBS
 
1297
  signal(SIGTTIN, SIG_IGN);
 
1298
  signal(SIGTTOU, SIG_IGN);
 
1299
#endif
 
1300
 
 
1301
  if (display)
 
1302
    {
 
1303
      brktty(D_userfd);
 
1304
      SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
 
1305
      /* Note: SetMode must be called _before_ FinishRc. */
 
1306
      SetTTY(D_userfd, &D_NewMode);
 
1307
      if (fcntl(D_userfd, F_SETFL, FNBLOCK))
 
1308
        Msg(errno, "Warning: NBLOCK fcntl failed");
 
1309
    }
 
1310
  else
 
1311
    brktty(-1);         /* just try */
 
1312
  signal(SIGCHLD, SigChld);
 
1313
#ifdef ETCSCREENRC
 
1314
# ifdef ALLOW_SYSSCREENRC
 
1315
  if ((ap = getenv("SYSSCREENRC")))
 
1316
    FinishRc(ap);
 
1317
  else
 
1318
# endif
 
1319
    FinishRc(ETCSCREENRC);
 
1320
#endif
 
1321
  FinishRc(RcFileName);
 
1322
 
 
1323
  debug2("UID %d  EUID %d\n", (int)getuid(), (int)geteuid());
 
1324
  if (windows == NULL)
 
1325
    {
 
1326
      debug("We open one default window, as screenrc did not specify one.\n");
 
1327
      if (MakeWindow(&nwin) == -1)
 
1328
        {
 
1329
          Msg(0, "Sorry, could not find a PTY.");
 
1330
          sleep(5);
 
1331
          Finit(0);
 
1332
          /* NOTREACHED */
 
1333
        }
 
1334
    }
 
1335
 
 
1336
#ifdef HAVE_BRAILLE
 
1337
  StartBraille();
 
1338
#endif
 
1339
  
 
1340
  if (display && default_startup)
 
1341
    display_copyright();
 
1342
  signal(SIGINT, SigInt);
 
1343
  if (rflag && (rflag & 1) == 0)
 
1344
    {
 
1345
      Msg(0, "New screen...");
 
1346
      rflag = 0;
 
1347
    }
 
1348
 
 
1349
  serv_read.type = EV_READ;
 
1350
  serv_read.fd = ServerSocket;
 
1351
  serv_read.handler = serv_read_fn;
 
1352
  evenq(&serv_read);
 
1353
 
 
1354
  serv_select.pri = -10;
 
1355
  serv_select.type = EV_ALWAYS;
 
1356
  serv_select.handler = serv_select_fn;
 
1357
  evenq(&serv_select);
 
1358
 
 
1359
  logflushev.type = EV_TIMEOUT;
 
1360
  logflushev.handler = logflush_fn;
 
1361
 
 
1362
  sched();
 
1363
  /* NOTREACHED */
 
1364
  return 0;
 
1365
}
 
1366
 
 
1367
void
 
1368
WindowDied(p)
 
1369
struct win *p;
 
1370
{
 
1371
  if (ZombieKey_destroy)
 
1372
    {
 
1373
      char buf[100], *s;
 
1374
      time_t now;
 
1375
 
 
1376
      (void) time(&now);
 
1377
      s = ctime(&now);
 
1378
      if (s && *s)
 
1379
        s[strlen(s) - 1] = '\0';
 
1380
      debug3("window %d (%s) going into zombie state fd %d",
 
1381
             p->w_number, p->w_title, p->w_ptyfd);
 
1382
#ifdef UTMPOK
 
1383
      if (p->w_slot != (slot_t)0 && p->w_slot != (slot_t)-1)
 
1384
        {
 
1385
          RemoveUtmp(p);
 
1386
          p->w_slot = 0;        /* "detached" */
 
1387
        }
 
1388
#endif
 
1389
      CloseDevice(p);
 
1390
 
 
1391
      p->w_pid = 0;
 
1392
      ResetWindow(p);
 
1393
      /* p->w_y = p->w_bot; */
 
1394
      p->w_y = MFindUsedLine(p, p->w_bot, 1);
 
1395
      sprintf(buf, "\n\r=== Window terminated (%s) ===", s ? s : "?");
 
1396
      WriteString(p, buf, strlen(buf));
 
1397
      WindowChanged(p, 'f');
 
1398
    }
 
1399
  else
 
1400
    KillWindow(p);
 
1401
#ifdef UTMPOK
 
1402
  CarefulUtmp();
 
1403
#endif
 
1404
}
 
1405
 
 
1406
static void
 
1407
SigChldHandler()
 
1408
{
 
1409
  struct stat st;
 
1410
#ifdef DEBUG
 
1411
  fds();
 
1412
#endif
 
1413
  while (GotSigChld)
 
1414
    {
 
1415
      GotSigChld = 0;
 
1416
      DoWait();
 
1417
#ifdef SYSVSIGS
 
1418
      signal(SIGCHLD, SigChld);
 
1419
#endif
 
1420
    }
 
1421
  if (stat(SockPath, &st) == -1)
 
1422
    {
 
1423
      debug1("SigChldHandler: Yuck! cannot stat '%s'\n", SockPath);
 
1424
      if (!RecoverSocket())
 
1425
        {
 
1426
          debug("SCREEN cannot recover from corrupt Socket, bye\n");
 
1427
          Finit(1);
 
1428
        }
 
1429
      else
 
1430
        debug1("'%s' reconstructed\n", SockPath);
 
1431
    }
 
1432
  else
 
1433
    debug2("SigChldHandler: stat '%s' o.k. (%03o)\n", SockPath, (int)st.st_mode);
 
1434
}
 
1435
 
 
1436
static sigret_t
 
1437
SigChld SIGDEFARG
 
1438
{
 
1439
  debug("SigChld()\n");
 
1440
  GotSigChld = 1;
 
1441
  SIGRETURN;
 
1442
}
 
1443
 
 
1444
sigret_t
 
1445
SigHup SIGDEFARG
 
1446
{
 
1447
  /* Hangup all displays */
 
1448
  while ((display = displays) != 0)
 
1449
    Hangup();
 
1450
  SIGRETURN;
 
1451
}
 
1452
 
 
1453
/* 
 
1454
 * the backend's Interrupt handler
 
1455
 * we cannot insert the intrc directly, as we never know
 
1456
 * if fore is valid.
 
1457
 */
 
1458
static sigret_t
 
1459
SigInt SIGDEFARG
 
1460
{
 
1461
#if HAZARDOUS
 
1462
  char ibuf;
 
1463
 
 
1464
  debug("SigInt()\n");
 
1465
  if (fore && displays)
 
1466
    {
 
1467
# if defined(TERMIO) || defined(POSIX)
 
1468
      ibuf = displays->d_OldMode.tio.c_cc[VINTR];
 
1469
# else
 
1470
      ibuf = displays->d_OldMode.m_tchars.t_intrc;
 
1471
# endif
 
1472
      fore->w_inlen = 0;
 
1473
      write(fore->w_ptyfd, &ibuf, 1);
 
1474
    }
 
1475
#else
 
1476
  signal(SIGINT, SigInt);
 
1477
  debug("SigInt() careful\n");
 
1478
  InterruptPlease = 1;
 
1479
#endif
 
1480
  SIGRETURN;
 
1481
}
 
1482
 
 
1483
static sigret_t
 
1484
CoreDump SIGDEFARG
 
1485
{
 
1486
  struct display *disp;
 
1487
  char buf[80];
 
1488
 
 
1489
#if defined(SYSVSIGS) && defined(SIGHASARG)
 
1490
  signal(sigsig, SIG_IGN);
 
1491
#endif
 
1492
  setgid(getgid());
 
1493
  setuid(getuid());
 
1494
  unlink("core");
 
1495
#ifdef SIGHASARG
 
1496
  sprintf(buf, "\r\n[screen caught signal %d.%s]\r\n", sigsig,
 
1497
#else
 
1498
  sprintf(buf, "\r\n[screen caught a fatal signal.%s]\r\n",
 
1499
#endif
 
1500
#if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
 
1501
              ""
 
1502
#else /* SHADOWPW  && !DEBUG */
 
1503
              " (core dumped)"
 
1504
#endif /* SHADOWPW  && !DEBUG */
 
1505
              );
 
1506
  for (disp = displays; disp; disp = disp->d_next)
 
1507
    {
 
1508
      fcntl(disp->d_userfd, F_SETFL, 0);
 
1509
      SetTTY(disp->d_userfd, &D_OldMode);
 
1510
      write(disp->d_userfd, buf, strlen(buf));
 
1511
      Kill(disp->d_userpid, SIG_BYE);
 
1512
    }
 
1513
#if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
 
1514
  Kill(getpid(), SIGKILL);
 
1515
  eexit(11);
 
1516
#else /* SHADOWPW && !DEBUG */
 
1517
  abort();
 
1518
#endif /* SHADOWPW  && !DEBUG */
 
1519
  SIGRETURN;
 
1520
}
 
1521
 
 
1522
static void
 
1523
DoWait()
 
1524
{
 
1525
  register int pid;
 
1526
  struct win *p, *next;
 
1527
#ifdef BSDWAIT
 
1528
  union wait wstat;
 
1529
#else
 
1530
  int wstat;
 
1531
#endif
 
1532
 
 
1533
#ifdef BSDJOBS
 
1534
# ifndef BSDWAIT
 
1535
  while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
 
1536
# else
 
1537
# ifdef USE_WAIT2
 
1538
  /* 
 
1539
   * From: rouilj@sni-usa.com (John Rouillard) 
 
1540
   * note that WUNTRACED is not documented to work, but it is defined in
 
1541
   * /usr/include/sys/wait.h, so it may work 
 
1542
   */
 
1543
  while ((pid = wait2(&wstat, WNOHANG | WUNTRACED )) > 0)
 
1544
#  else /* USE_WAIT2 */
 
1545
  while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
 
1546
#  endif /* USE_WAIT2 */
 
1547
# endif
 
1548
#else   /* BSDJOBS */
 
1549
  while ((pid = wait(&wstat)) < 0)
 
1550
    if (errno != EINTR)
 
1551
      break;
 
1552
  if (pid > 0)
 
1553
#endif  /* BSDJOBS */
 
1554
    {
 
1555
      for (p = windows; p; p = next)
 
1556
        {
 
1557
          next = p->w_next;
 
1558
          if (pid == p->w_pid)
 
1559
            {
 
1560
#ifdef BSDJOBS
 
1561
              if (WIFSTOPPED(wstat))
 
1562
                {
 
1563
                  debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, p->w_pid, WSTOPSIG(wstat));
 
1564
#ifdef SIGTTIN
 
1565
                  if (WSTOPSIG(wstat) == SIGTTIN)
 
1566
                    {
 
1567
                      Msg(0, "Suspended (tty input)");
 
1568
                      continue;
 
1569
                    }
 
1570
#endif
 
1571
#ifdef SIGTTOU
 
1572
                  if (WSTOPSIG(wstat) == SIGTTOU)
 
1573
                    {
 
1574
                      Msg(0, "Suspended (tty output)");
 
1575
                      continue;
 
1576
                    }
 
1577
#endif
 
1578
                  /* Try to restart process */
 
1579
                  Msg(0, "Child has been stopped, restarting.");
 
1580
                  if (killpg(p->w_pid, SIGCONT))
 
1581
                    kill(p->w_pid, SIGCONT);
 
1582
                }
 
1583
              else
 
1584
#endif
 
1585
                {
 
1586
                  WindowDied(p);
 
1587
                }
 
1588
              break;
 
1589
            }
 
1590
#ifdef PSEUDOS
 
1591
          if (p->w_pwin && pid == p->w_pwin->p_pid)
 
1592
            {
 
1593
              debug2("pseudo of win Nr %d died. pid == %d\n", p->w_number, p->w_pwin->p_pid);
 
1594
              FreePseudowin(p);
 
1595
              break;
 
1596
            }
 
1597
#endif
 
1598
        }
 
1599
      if (p == 0)
 
1600
        {
 
1601
          debug1("pid %d not found - hope that's ok\n", pid);
 
1602
        }
 
1603
    }
 
1604
}
 
1605
 
 
1606
 
 
1607
static sigret_t
 
1608
FinitHandler SIGDEFARG
 
1609
{
 
1610
#ifdef SIGHASARG
 
1611
  debug1("FinitHandler called, sig %d.\n", sigsig);
 
1612
#else
 
1613
  debug("FinitHandler called.\n");
 
1614
#endif
 
1615
  Finit(1);
 
1616
  SIGRETURN;
 
1617
}
 
1618
 
 
1619
void
 
1620
Finit(i)
 
1621
int i;
 
1622
{
 
1623
  struct win *p, *next;
 
1624
 
 
1625
  signal(SIGCHLD, SIG_DFL);
 
1626
  signal(SIGHUP, SIG_IGN);
 
1627
  debug1("Finit(%d);\n", i);
 
1628
  for (p = windows; p; p = next)
 
1629
    {
 
1630
      next = p->w_next;
 
1631
      FreeWindow(p);
 
1632
    }
 
1633
  if (ServerSocket != -1)
 
1634
    {
 
1635
      debug1("we unlink(%s)\n", SockPath);
 
1636
#ifdef USE_SETEUID
 
1637
      xseteuid(real_uid);
 
1638
      xsetegid(real_gid);
 
1639
#endif
 
1640
      (void) unlink(SockPath);
 
1641
#ifdef USE_SETEUID
 
1642
      xseteuid(eff_uid);
 
1643
      xsetegid(eff_gid);
 
1644
#endif
 
1645
    }
 
1646
  for (display = displays; display; display = display->d_next)
 
1647
    {
 
1648
      if (D_status)
 
1649
        RemoveStatus();
 
1650
      FinitTerm();
 
1651
#ifdef UTMPOK
 
1652
      RestoreLoginSlot();
 
1653
#endif
 
1654
      AddStr("[screen is terminating]\r\n");
 
1655
      Flush();
 
1656
      SetTTY(D_userfd, &D_OldMode);
 
1657
      fcntl(D_userfd, F_SETFL, 0);
 
1658
      freetty();
 
1659
      Kill(D_userpid, SIG_BYE);
 
1660
    }
 
1661
  /*
 
1662
   * we _cannot_ call eexit(i) here, 
 
1663
   * instead of playing with the Socket above. Sigh.
 
1664
   */
 
1665
  exit(i);
 
1666
}
 
1667
 
 
1668
void
 
1669
eexit(e)
 
1670
int e;
 
1671
{
 
1672
  debug("eexit\n");
 
1673
  if (ServerSocket != -1)
 
1674
    {
 
1675
      debug1("we unlink(%s)\n", SockPath);
 
1676
      setgid(real_gid);
 
1677
      setuid(real_uid);
 
1678
      (void) unlink(SockPath);
 
1679
    }
 
1680
  exit(e);
 
1681
}
 
1682
 
 
1683
void
 
1684
Hangup()
 
1685
{
 
1686
  if (display == 0)
 
1687
    return;
 
1688
  debug1("Hangup %x\n", display);
 
1689
  if (D_userfd >= 0)
 
1690
    {
 
1691
      close(D_userfd);
 
1692
      D_userfd = -1;
 
1693
    }
 
1694
  if (auto_detach || displays->d_next)
 
1695
    Detach(D_HANGUP);
 
1696
  else
 
1697
    Finit(0);
 
1698
}
 
1699
 
 
1700
/*
 
1701
 * Detach now has the following modes:
 
1702
 *D_DETACH       SIG_BYE        detach backend and exit attacher
 
1703
 *D_HANGUP       SIG_BYE        detach backend and exit attacher
 
1704
 *D_STOP         SIG_STOP       stop attacher (and detach backend)
 
1705
 *D_REMOTE       SIG_BYE        remote detach -- reattach to new attacher
 
1706
 *D_POWER        SIG_POWER_BYE  power detach -- attacher kills his parent
 
1707
 *D_REMOTE_POWER SIG_POWER_BYE  remote power detach -- both
 
1708
 *D_LOCK         SIG_LOCK       lock the attacher
 
1709
 * (jw)
 
1710
 * we always remove our utmp slots. (even when "lock" or "stop")
 
1711
 * Note: Take extra care here, we may be called by interrupt!
 
1712
 */
 
1713
void
 
1714
Detach(mode)
 
1715
int mode;
 
1716
{
 
1717
  int sign = 0, pid;
 
1718
  struct canvas *cv;
 
1719
  struct win *p;
 
1720
 
 
1721
  if (display == 0)
 
1722
    return;
 
1723
 
 
1724
  signal(SIGHUP, SIG_IGN);
 
1725
  debug1("Detach(%d)\n", mode);
 
1726
  if (D_status)
 
1727
    RemoveStatus();
 
1728
  FinitTerm();
 
1729
  if (!display)
 
1730
    return;
 
1731
  switch (mode)
 
1732
    {
 
1733
    case D_HANGUP:
 
1734
      sign = SIG_BYE;
 
1735
      break;
 
1736
    case D_DETACH:
 
1737
      AddStr("[detached]\r\n");
 
1738
      sign = SIG_BYE;
 
1739
      break;
 
1740
#ifdef BSDJOBS
 
1741
    case D_STOP:
 
1742
      sign = SIG_STOP;
 
1743
      break;
 
1744
#endif
 
1745
#ifdef REMOTE_DETACH
 
1746
    case D_REMOTE:
 
1747
      AddStr("[remote detached]\r\n");
 
1748
      sign = SIG_BYE;
 
1749
      break;
 
1750
#endif
 
1751
#ifdef POW_DETACH
 
1752
    case D_POWER:
 
1753
      AddStr("[power detached]\r\n");
 
1754
      if (PowDetachString) 
 
1755
        {
 
1756
          AddStr(PowDetachString);
 
1757
          AddStr("\r\n");
 
1758
        }
 
1759
      sign = SIG_POWER_BYE;
 
1760
      break;
 
1761
#ifdef REMOTE_DETACH
 
1762
    case D_REMOTE_POWER:
 
1763
      AddStr("[remote power detached]\r\n");
 
1764
      if (PowDetachString) 
 
1765
        {
 
1766
          AddStr(PowDetachString);
 
1767
          AddStr("\r\n");
 
1768
        }
 
1769
      sign = SIG_POWER_BYE;
 
1770
      break;
 
1771
#endif
 
1772
#endif
 
1773
    case D_LOCK:
 
1774
      ClearAll();
 
1775
      sign = SIG_LOCK;
 
1776
      /* tell attacher to lock terminal with a lockprg. */
 
1777
      break;
 
1778
    }
 
1779
#ifdef UTMPOK
 
1780
  if (displays->d_next == 0)
 
1781
    {
 
1782
      for (p = windows; p; p = p->w_next)
 
1783
        {
 
1784
          if (p->w_slot != (slot_t) -1 && !(p->w_lflag & 2))
 
1785
            {
 
1786
              RemoveUtmp(p);
 
1787
              /*
 
1788
               * Set the slot to 0 to get the window
 
1789
               * logged in again.
 
1790
               */
 
1791
              p->w_slot = (slot_t) 0;
 
1792
            }
 
1793
        }
 
1794
    }
 
1795
  if (mode != D_HANGUP)
 
1796
    RestoreLoginSlot();
 
1797
#endif
 
1798
  if (displays->d_next == 0 && console_window)
 
1799
    {
 
1800
      if (TtyGrabConsole(console_window->w_ptyfd, 0, "detach"))
 
1801
        {
 
1802
          debug("could not release console - killing window\n");
 
1803
          KillWindow(console_window);
 
1804
          display = displays;           /* restore display */
 
1805
        }
 
1806
    }
 
1807
  if (D_fore)
 
1808
    {
 
1809
#ifdef MULTIUSER
 
1810
      ReleaseAutoWritelock(display, D_fore);
 
1811
#endif
 
1812
      D_user->u_detachwin = D_fore->w_number;
 
1813
      D_user->u_detachotherwin = D_other ? D_other->w_number : -1;
 
1814
    }
 
1815
  for (cv = D_cvlist; cv; cv = cv->c_next)
 
1816
    {
 
1817
      p = Layer2Window(cv->c_layer);
 
1818
      SetCanvasWindow(cv, 0);
 
1819
      if (p)
 
1820
        WindowChanged(p, 'u');
 
1821
    }
 
1822
 
 
1823
  pid = D_userpid;
 
1824
  debug2("display: %#x displays: %#x\n", (unsigned int)display, (unsigned int)displays);
 
1825
  FreeDisplay();
 
1826
  if (displays == 0)
 
1827
    /* Flag detached-ness */
 
1828
    (void) chsock();
 
1829
  /*
 
1830
   * tell father what to do. We do that after we
 
1831
   * freed the tty, thus getty feels more comfortable on hpux
 
1832
   * if it was a power detach.
 
1833
   */
 
1834
  Kill(pid, sign);
 
1835
  debug2("Detach: Signal %d to Attacher(%d)!\n", sign, pid);
 
1836
  debug("Detach returns, we are successfully detached.\n");
 
1837
  signal(SIGHUP, SigHup);
 
1838
}
 
1839
 
 
1840
static int
 
1841
IsSymbol(e, s)
 
1842
char *e, *s;
 
1843
{
 
1844
  register int l;
 
1845
 
 
1846
  l = strlen(s);
 
1847
  return strncmp(e, s, l) == 0 && e[l] == '=';
 
1848
}
 
1849
 
 
1850
void
 
1851
MakeNewEnv()
 
1852
{
 
1853
  register char **op, **np;
 
1854
  static char stybuf[MAXSTR];
 
1855
 
 
1856
  for (op = environ; *op; ++op)
 
1857
    ;
 
1858
  if (NewEnv)
 
1859
    free((char *)NewEnv);
 
1860
  NewEnv = np = (char **) malloc((unsigned) (op - environ + 7 + 1) * sizeof(char **));
 
1861
  if (!NewEnv)
 
1862
    Panic(0, strnomem);
 
1863
  sprintf(stybuf, "STY=%s", strlen(SockName) <= MAXSTR - 5 ? SockName : "?");
 
1864
  *np++ = stybuf;                       /* NewEnv[0] */
 
1865
  *np++ = Term;                 /* NewEnv[1] */
 
1866
  np++;         /* room for SHELL */
 
1867
#ifdef TIOCSWINSZ
 
1868
  np += 2;      /* room for TERMCAP and WINDOW */
 
1869
#else
 
1870
  np += 4;      /* room for TERMCAP WINDOW LINES COLUMNS */
 
1871
#endif
 
1872
 
 
1873
  for (op = environ; *op; ++op)
 
1874
    {
 
1875
      if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
 
1876
          && !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
 
1877
          && !IsSymbol(*op, "SCREENCAP") && !IsSymbol(*op, "SHELL")
 
1878
          && !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
 
1879
         )
 
1880
        *np++ = *op;
 
1881
    }
 
1882
  *np = 0;
 
1883
}
 
1884
 
 
1885
void
 
1886
/*VARARGS2*/
 
1887
#if defined(USEVARARGS) && defined(__STDC__)
 
1888
Msg(int err, char *fmt, VA_DOTS)
 
1889
#else
 
1890
Msg(err, fmt, VA_DOTS)
 
1891
int err;
 
1892
char *fmt;
 
1893
VA_DECL
 
1894
#endif
 
1895
{
 
1896
  VA_LIST(ap)
 
1897
  char buf[MAXPATHLEN*2];
 
1898
  char *p = buf;
 
1899
 
 
1900
  VA_START(ap, fmt);
 
1901
  fmt = DoNLS(fmt);
 
1902
  (void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap));
 
1903
  VA_END(ap);
 
1904
  if (err)
 
1905
    {
 
1906
      p += strlen(p);
 
1907
      *p++ = ':';
 
1908
      *p++ = ' ';
 
1909
      strncpy(p, strerror(err), buf + sizeof(buf) - p - 1);
 
1910
      buf[sizeof(buf) - 1] = 0;
 
1911
    }
 
1912
  debug2("Msg('%s') (%#x);\n", buf, (unsigned int)display);
 
1913
 
 
1914
  if (display && displays)
 
1915
    MakeStatus(buf);
 
1916
  else if (displays)
 
1917
    {
 
1918
      for (display = displays; display; display = display->d_next)
 
1919
        MakeStatus(buf);
 
1920
    }
 
1921
  else if (display)
 
1922
    {
 
1923
      /* no displays but a display - must have forked.
 
1924
       * send message to backend!
 
1925
       */
 
1926
      char *tty = D_usertty;
 
1927
      struct display *olddisplay = display;
 
1928
      display = 0;      /* only send once */
 
1929
      SendErrorMsg(tty, buf);
 
1930
      display = olddisplay;
 
1931
    }
 
1932
  else
 
1933
    printf("%s\r\n", buf);
 
1934
}
 
1935
 
 
1936
/*
 
1937
 * Call FinitTerm for all displays, write a message to each and call eexit();
 
1938
 */
 
1939
void
 
1940
/*VARARGS2*/
 
1941
#if defined(USEVARARGS) && defined(__STDC__)
 
1942
Panic(int err, char *fmt, VA_DOTS)
 
1943
#else
 
1944
Panic(err, fmt, VA_DOTS)
 
1945
int err;
 
1946
char *fmt;
 
1947
VA_DECL
 
1948
#endif
 
1949
{
 
1950
  VA_LIST(ap)
 
1951
  char buf[MAXPATHLEN*2];
 
1952
  char *p = buf;
 
1953
 
 
1954
  VA_START(ap, fmt);
 
1955
  fmt = DoNLS(fmt);
 
1956
  (void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap));
 
1957
  VA_END(ap);
 
1958
  if (err)
 
1959
    {
 
1960
      p += strlen(p);
 
1961
      *p++ = ':';
 
1962
      *p++ = ' ';
 
1963
      strncpy(p, strerror(err), buf + sizeof(buf) - p - 1);
 
1964
      buf[sizeof(buf) - 1] = 0;
 
1965
    }
 
1966
  debug3("Panic('%s'); display=%x displays=%x\n", buf, display, displays);
 
1967
  if (displays == 0 && display == 0)
 
1968
    printf("%s\r\n", buf);
 
1969
  else if (displays == 0)
 
1970
    {
 
1971
      /* no displays but a display - must have forked.
 
1972
       * send message to backend!
 
1973
       */
 
1974
      char *tty = D_usertty;
 
1975
      display = 0;
 
1976
      SendErrorMsg(tty, buf);
 
1977
      sleep(2);
 
1978
      _exit(1);
 
1979
    }
 
1980
  else
 
1981
    for (display = displays; display; display = display->d_next)
 
1982
      {
 
1983
        if (D_status)
 
1984
          RemoveStatus();
 
1985
        FinitTerm();
 
1986
        Flush();
 
1987
#ifdef UTMPOK
 
1988
        RestoreLoginSlot();
 
1989
#endif
 
1990
        SetTTY(D_userfd, &D_OldMode);
 
1991
        fcntl(D_userfd, F_SETFL, 0);
 
1992
        write(D_userfd, buf, strlen(buf));
 
1993
        write(D_userfd, "\n", 1);
 
1994
        freetty();
 
1995
        if (D_userpid)
 
1996
          Kill(D_userpid, SIG_BYE);
 
1997
      }
 
1998
#ifdef MULTIUSER
 
1999
  if (tty_oldmode >= 0)
 
2000
    {
 
2001
# ifdef USE_SETEUID
 
2002
      if (setuid(own_uid))
 
2003
        xseteuid(own_uid);      /* may be a loop. sigh. */
 
2004
# else
 
2005
      setuid(own_uid);
 
2006
# endif
 
2007
      debug1("Panic: changing back modes from %s\n", attach_tty);
 
2008
      chmod(attach_tty, tty_oldmode);
 
2009
    }
 
2010
#endif
 
2011
  eexit(1);
 
2012
}
 
2013
 
 
2014
 
 
2015
/*
 
2016
 * '^' is allowed as an escape mechanism for control characters. jw.
 
2017
 * 
 
2018
 * Added time insertion using ideas/code from /\ndy Jones
 
2019
 *   (andy@lingua.cltr.uq.OZ.AU) - thanks a lot!
 
2020
 *
 
2021
 */
 
2022
 
 
2023
#ifndef USE_LOCALE
 
2024
static const char days[]   = "SunMonTueWedThuFriSat";
 
2025
static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
 
2026
#endif
 
2027
 
 
2028
static char winmsg_buf[MAXSTR];
 
2029
#define MAX_WINMSG_REND 16      /* rendition changes */
 
2030
static int winmsg_rend[MAX_WINMSG_REND];
 
2031
static int winmsg_rendpos[MAX_WINMSG_REND];
 
2032
static int winmsg_numrend;
 
2033
 
 
2034
static char *
 
2035
pad_expand(buf, p, numpad, padlen)
 
2036
char *buf;
 
2037
char *p;
 
2038
int numpad;
 
2039
int padlen;
 
2040
{
 
2041
  char *pn, *pn2;
 
2042
  int i, r;
 
2043
 
 
2044
  padlen = padlen - (p - buf);  /* space for rent */
 
2045
  if (padlen < 0)
 
2046
    padlen = 0;
 
2047
  pn2 = pn = p + padlen;
 
2048
  r = winmsg_numrend;
 
2049
  while (p >= buf)
 
2050
    {
 
2051
      if (r && p - buf == winmsg_rendpos[r - 1])
 
2052
        {
 
2053
          winmsg_rendpos[--r] = pn - buf;
 
2054
          continue;
 
2055
        }
 
2056
      *pn-- = *p;
 
2057
      if (*p-- == 127)
 
2058
        {
 
2059
          pn[1] = ' ';
 
2060
          i = numpad > 0 ? (padlen + numpad - 1) / numpad : 0;
 
2061
          padlen -= i;
 
2062
          while (i-- > 0)
 
2063
            *pn-- = ' ';
 
2064
          numpad--;
 
2065
        }
 
2066
    }
 
2067
  return pn2;
 
2068
}
 
2069
 
 
2070
struct backtick {
 
2071
  struct backtick *next;
 
2072
  int num;
 
2073
  int tick;
 
2074
  int lifespan;
 
2075
  time_t bestbefore;
 
2076
  char result[MAXSTR];
 
2077
  char **cmdv;
 
2078
  struct event ev;
 
2079
  char *buf;
 
2080
  int bufi;
 
2081
};
 
2082
 
 
2083
struct backtick *backticks;
 
2084
 
 
2085
static void
 
2086
backtick_filter(bt)
 
2087
struct backtick *bt;
 
2088
{
 
2089
  char *p, *q;
 
2090
  int c;
 
2091
 
 
2092
  for (p = q = bt->result; (c = (unsigned char)*p++) != 0;)
 
2093
    {
 
2094
      if (c == '\t')
 
2095
        c = ' ';
 
2096
      if (c >= ' ' || c == '\005')
 
2097
        *q++ = c;
 
2098
    }
 
2099
  *q = 0;
 
2100
}
 
2101
 
 
2102
static void
 
2103
backtick_fn(ev, data)
 
2104
struct event *ev;
 
2105
char *data;
 
2106
{
 
2107
  struct backtick *bt;
 
2108
  int i, j, k, l;
 
2109
 
 
2110
  bt = (struct backtick *)data;
 
2111
  debug1("backtick_fn for #%d\n", bt->num);
 
2112
  i = bt->bufi;
 
2113
  l = read(ev->fd, bt->buf + i, MAXSTR - i);
 
2114
  if (l <= 0)
 
2115
    {
 
2116
      debug1("EOF on backtick #%d\n", bt->num);
 
2117
      evdeq(ev);
 
2118
      close(ev->fd);
 
2119
      ev->fd = -1;
 
2120
      return;
 
2121
    }
 
2122
  debug1("read %d bytes\n", l);
 
2123
  i += l;
 
2124
  for (j = 0; j < l; j++)
 
2125
    if (bt->buf[i - j - 1] == '\n')
 
2126
      break;
 
2127
  if (j < l)
 
2128
    {
 
2129
      for (k = i - j - 2; k >= 0; k--)
 
2130
        if (bt->buf[k] == '\n')
 
2131
          break;
 
2132
      k++;
 
2133
      bcopy(bt->buf + k, bt->result, i - j - k);
 
2134
      bt->result[i - j - k - 1] = 0;
 
2135
      backtick_filter(bt);
 
2136
      WindowChanged(0, '`');
 
2137
    }
 
2138
  if (j == l && i == MAXSTR)
 
2139
    {
 
2140
      j = MAXSTR/2;
 
2141
      l = j + 1;
 
2142
    }
 
2143
  if (j < l)
 
2144
    {
 
2145
      if (j)
 
2146
        bcopy(bt->buf + i - j, bt->buf, j);
 
2147
      i = j;
 
2148
    }
 
2149
  bt->bufi = i;
 
2150
}
 
2151
 
 
2152
void
 
2153
setbacktick(num, lifespan, tick, cmdv)
 
2154
int num;
 
2155
int lifespan;
 
2156
int tick;
 
2157
char **cmdv;
 
2158
{
 
2159
  struct backtick **btp, *bt;
 
2160
  char **v;
 
2161
 
 
2162
  debug1("setbacktick called for backtick #%d\n", num);
 
2163
  for (btp = &backticks; (bt = *btp) != 0; btp = &bt->next)
 
2164
    if (bt->num == num)
 
2165
      break;
 
2166
  if (!bt && !cmdv)
 
2167
    return;
 
2168
  if (bt)
 
2169
    {
 
2170
      for (v = bt->cmdv; *v; v++)
 
2171
        free(*v);
 
2172
      free(bt->cmdv);
 
2173
      if (bt->buf)
 
2174
        free(bt->buf);
 
2175
      if (bt->ev.fd >= 0)
 
2176
        close(bt->ev.fd);
 
2177
      evdeq(&bt->ev);
 
2178
    }
 
2179
  if (bt && !cmdv)
 
2180
    {
 
2181
      *btp = bt->next;
 
2182
      free(bt);
 
2183
      return;
 
2184
    }
 
2185
  if (!bt)
 
2186
    {
 
2187
      bt = (struct backtick *)malloc(sizeof *bt);
 
2188
      if (!bt)
 
2189
        {
 
2190
          Msg(0, strnomem);
 
2191
          return;
 
2192
        }
 
2193
      bzero(bt, sizeof(*bt));
 
2194
      bt->next = 0;
 
2195
      *btp = bt;
 
2196
    }
 
2197
  bt->num = num;
 
2198
  bt->tick = tick;
 
2199
  bt->lifespan = lifespan;
 
2200
  bt->bestbefore = 0;
 
2201
  bt->result[0] = 0;
 
2202
  bt->buf = 0;
 
2203
  bt->bufi = 0;
 
2204
  bt->cmdv = cmdv;
 
2205
  bt->ev.fd = -1;
 
2206
  if (bt->tick == 0 && bt->lifespan == 0)
 
2207
    {
 
2208
      debug("setbacktick: continuous mode\n");
 
2209
      bt->buf = (char *)malloc(MAXSTR);
 
2210
      if (bt->buf == 0)
 
2211
        {
 
2212
          Msg(0, strnomem);
 
2213
          setbacktick(num, 0, 0, (char **)0);
 
2214
          return;
 
2215
        }
 
2216
      bt->ev.type = EV_READ;
 
2217
      bt->ev.fd = readpipe(bt->cmdv);
 
2218
      bt->ev.handler = backtick_fn;
 
2219
      bt->ev.data = (char *)bt;
 
2220
      if (bt->ev.fd >= 0)
 
2221
        evenq(&bt->ev);
 
2222
    }
 
2223
}
 
2224
 
 
2225
static char *
 
2226
runbacktick(bt, tickp, now)
 
2227
struct backtick *bt;
 
2228
int *tickp;
 
2229
time_t now;
 
2230
{
 
2231
  int f, i, l, j;
 
2232
  time_t now2;
 
2233
 
 
2234
  debug1("runbacktick called for backtick #%d\n", bt->num);
 
2235
  if (bt->tick && (!*tickp || bt->tick < *tickp))
 
2236
    *tickp = bt->tick;
 
2237
  if ((bt->lifespan == 0 && bt->tick == 0) || now < bt->bestbefore)
 
2238
    {
 
2239
      debug1("returning old result (%d)\n", bt->lifespan);
 
2240
      return bt->result;
 
2241
    }
 
2242
  f = readpipe(bt->cmdv);
 
2243
  if (f == -1)
 
2244
    return bt->result;
 
2245
  i = 0;
 
2246
  while ((l = read(f, bt->result + i, sizeof(bt->result) - i)) > 0)
 
2247
    {
 
2248
      debug1("runbacktick: read %d bytes\n", l);
 
2249
      i += l;
 
2250
      for (j = 1; j < l; j++)
 
2251
        if (bt->result[i - j - 1] == '\n')
 
2252
          break;
 
2253
      if (j == l && i == sizeof(bt->result))
 
2254
        {
 
2255
          j = sizeof(bt->result) / 2;
 
2256
          l = j + 1;
 
2257
        }
 
2258
      if (j < l)
 
2259
        {
 
2260
          bcopy(bt->result + i - j, bt->result, j);
 
2261
          i = j;
 
2262
        }
 
2263
    }
 
2264
  close(f);
 
2265
  bt->result[sizeof(bt->result) - 1] = '\n';
 
2266
  if (i && bt->result[i - 1] == '\n')
 
2267
    i--;
 
2268
  debug1("runbacktick: finished, %d bytes\n", i);
 
2269
  bt->result[i] = 0;
 
2270
  backtick_filter(bt);
 
2271
  (void)time(&now2);
 
2272
  bt->bestbefore = now2 + bt->lifespan;
 
2273
  return bt->result;
 
2274
}
 
2275
 
 
2276
char *
 
2277
MakeWinMsgEv(str, win, esc, padlen, ev, rec)
 
2278
char *str;
 
2279
struct win *win;
 
2280
int esc;
 
2281
int padlen;
 
2282
struct event *ev;
 
2283
int rec;
 
2284
{
 
2285
  static int tick;
 
2286
  char *s = str;
 
2287
  register char *p = winmsg_buf;
 
2288
  register int ctrl;
 
2289
  struct timeval now;
 
2290
  struct tm *tm;
 
2291
  int l, i, r;
 
2292
  int num;
 
2293
  int zeroflg;
 
2294
  int longflg;
 
2295
  int minusflg;
 
2296
  int plusflg;
 
2297
  int qmflag = 0, omflag = 0, qmnumrend = 0;
 
2298
  char *qmpos = 0;
 
2299
  int numpad = 0;
 
2300
  int lastpad = 0;
 
2301
  int truncpos = -1;
 
2302
  int truncper = 0;
 
2303
  int trunclong = 0;
 
2304
  struct backtick *bt;
 
2305
 
 
2306
  if (winmsg_numrend >= 0)
 
2307
    winmsg_numrend = 0;
 
2308
  else
 
2309
    winmsg_numrend = -winmsg_numrend;
 
2310
    
 
2311
  tick = 0;
 
2312
  tm = 0;
 
2313
  ctrl = 0;
 
2314
  gettimeofday(&now, NULL);
 
2315
  for (; *s && (l = winmsg_buf + MAXSTR - 1 - p) > 0; s++, p++)
 
2316
    {
 
2317
      *p = *s;
 
2318
      if (ctrl)
 
2319
        {
 
2320
          ctrl = 0;
 
2321
          if (*s != '^' && *s >= 64)
 
2322
            *p &= 0x1f;
 
2323
          continue;
 
2324
        }
 
2325
      if (*s != esc)
 
2326
        {
 
2327
          if (esc == '%')
 
2328
            {
 
2329
              switch (*s)
 
2330
                {
 
2331
#if 0
 
2332
                case '~':
 
2333
                  *p = BELL;
 
2334
                  break;
 
2335
#endif
 
2336
                case '^':
 
2337
                  ctrl = 1;
 
2338
                  *p-- = '^';
 
2339
                  break;
 
2340
                default:
 
2341
                  break;
 
2342
                }
 
2343
            }
 
2344
          continue;
 
2345
        }
 
2346
      if (*++s == esc)  /* double escape ? */
 
2347
        continue;
 
2348
      if ((plusflg = *s == '+') != 0)
 
2349
        s++;
 
2350
      if ((minusflg = *s == '-') != 0)
 
2351
        s++;
 
2352
      if ((zeroflg = *s == '0') != 0)
 
2353
        s++;
 
2354
      num = 0;
 
2355
      while(*s >= '0' && *s <= '9')
 
2356
        num = num * 10 + (*s++ - '0');
 
2357
      if ((longflg = *s == 'L') != 0)
 
2358
        s++;
 
2359
      switch (*s)
 
2360
        {
 
2361
        case '?':
 
2362
          p--;
 
2363
          if (qmpos)
 
2364
            {
 
2365
              if ((!qmflag && !omflag) || omflag == 1)
 
2366
                {
 
2367
                  p = qmpos;
 
2368
                  if (qmnumrend < winmsg_numrend)
 
2369
                    winmsg_numrend = qmnumrend;
 
2370
                }
 
2371
              qmpos = 0;
 
2372
              break;
 
2373
            }
 
2374
          qmpos = p;
 
2375
          qmnumrend = winmsg_numrend;
 
2376
          qmflag = omflag = 0;
 
2377
          break;
 
2378
        case ':':
 
2379
          p--;
 
2380
          if (!qmpos)
 
2381
            break;
 
2382
          if (qmflag && omflag != 1)
 
2383
            {
 
2384
              omflag = 1;
 
2385
              qmpos = p;
 
2386
              qmnumrend = winmsg_numrend;
 
2387
            }
 
2388
          else
 
2389
            {
 
2390
              p = qmpos;
 
2391
              if (qmnumrend < winmsg_numrend)
 
2392
                winmsg_numrend = qmnumrend;
 
2393
              omflag = -1;
 
2394
            }
 
2395
          break;
 
2396
        case 'd': case 'D': case 'm': case 'M': case 'y': case 'Y':
 
2397
        case 'a': case 'A': case 's': case 'c': case 'C':
 
2398
          if (l < 4)
 
2399
            break;
 
2400
          if (tm == 0)
 
2401
            {
 
2402
              time_t nowsec = now.tv_sec;
 
2403
              tm = localtime(&nowsec);
 
2404
            }
 
2405
          qmflag = 1;
 
2406
          if (!tick || tick > 3600)
 
2407
            tick = 3600;
 
2408
          switch (*s)
 
2409
            {
 
2410
            case 'd':
 
2411
              sprintf(p, "%02d", tm->tm_mday % 100);
 
2412
              break;
 
2413
            case 'D':
 
2414
#ifdef USE_LOCALE
 
2415
              strftime(p, l, (longflg ? "%A" : "%a"), tm);
 
2416
#else
 
2417
              sprintf(p, "%3.3s", days + 3 * tm->tm_wday);
 
2418
#endif
 
2419
              break;
 
2420
            case 'm':
 
2421
              sprintf(p, "%02d", tm->tm_mon + 1);
 
2422
              break;
 
2423
            case 'M':
 
2424
#ifdef USE_LOCALE
 
2425
              strftime(p, l, (longflg ? "%B" : "%b"), tm);
 
2426
#else
 
2427
              sprintf(p, "%3.3s", months + 3 * tm->tm_mon);
 
2428
#endif
 
2429
              break;
 
2430
            case 'y':
 
2431
              sprintf(p, "%02d", tm->tm_year % 100);
 
2432
              break;
 
2433
            case 'Y':
 
2434
              sprintf(p, "%04d", tm->tm_year + 1900);
 
2435
              break;
 
2436
            case 'a':
 
2437
              sprintf(p, tm->tm_hour >= 12 ? "pm" : "am");
 
2438
              break;
 
2439
            case 'A':
 
2440
              sprintf(p, tm->tm_hour >= 12 ? "PM" : "AM");
 
2441
              break;
 
2442
            case 's':
 
2443
              sprintf(p, "%02d", tm->tm_sec);
 
2444
              tick = 1;
 
2445
              break;
 
2446
            case 'c':
 
2447
              sprintf(p, zeroflg ? "%02d:%02d" : "%2d:%02d", tm->tm_hour, tm->tm_min);
 
2448
              if (!tick || tick > 60)
 
2449
                tick = 60;
 
2450
              break;
 
2451
            case 'C':
 
2452
              sprintf(p, zeroflg ? "%02d:%02d" : "%2d:%02d", (tm->tm_hour + 11) % 12 + 1, tm->tm_min);
 
2453
              if (!tick || tick > 60)
 
2454
                tick = 60;
 
2455
              break;
 
2456
            default:
 
2457
              break;
 
2458
            }
 
2459
          p += strlen(p) - 1;
 
2460
          break;
 
2461
        case 'l':
 
2462
#ifdef LOADAV
 
2463
          *p = 0;
 
2464
          if (l > 20)
 
2465
            AddLoadav(p);
 
2466
          if (*p)
 
2467
            {
 
2468
              qmflag = 1;
 
2469
              p += strlen(p) - 1;
 
2470
            }
 
2471
          else
 
2472
            *p = '?';
 
2473
          if (!tick || tick > 60)
 
2474
            tick = 60;
 
2475
#else
 
2476
          *p = '?';
 
2477
#endif
 
2478
          p += strlen(p) - 1;
 
2479
          break;
 
2480
        case '`':
 
2481
        case 'h':
 
2482
          if (rec >= 10 || (*s == 'h' && (win == 0 || win->w_hstatus == 0 || *win->w_hstatus == 0)))
 
2483
            {
 
2484
              p--;
 
2485
              break;
 
2486
            }
 
2487
          if (*s == '`')
 
2488
            {
 
2489
              for (bt = backticks; bt; bt = bt->next)
 
2490
                if (bt->num == num)
 
2491
                  break;
 
2492
              if (bt == 0)
 
2493
                {
 
2494
                  p--;
 
2495
                  break;
 
2496
                }
 
2497
            }
 
2498
            {
 
2499
              char savebuf[sizeof(winmsg_buf)];
 
2500
              int oldtick = tick;
 
2501
              int oldnumrend = winmsg_numrend;
 
2502
 
 
2503
              *p = 0;
 
2504
              strcpy(savebuf, winmsg_buf);
 
2505
              winmsg_numrend = -winmsg_numrend;
 
2506
              MakeWinMsgEv(*s == 'h' ? win->w_hstatus : runbacktick(bt, &oldtick, now.tv_sec), win, '\005', 0, (struct event *)0, rec + 1);
 
2507
              debug2("oldtick=%d tick=%d\n", oldtick, tick);
 
2508
              if (!tick || oldtick < tick)
 
2509
                tick = oldtick;
 
2510
              if ((int)strlen(winmsg_buf) < l)
 
2511
                strcat(savebuf, winmsg_buf);
 
2512
              strcpy(winmsg_buf, savebuf);
 
2513
              while (oldnumrend < winmsg_numrend)
 
2514
                winmsg_rendpos[oldnumrend++] += p - winmsg_buf;
 
2515
              if (*p)
 
2516
                qmflag = 1;
 
2517
              p += strlen(p) - 1;
 
2518
            }
 
2519
          break;
 
2520
        case 'w':
 
2521
        case 'W':
 
2522
          {
 
2523
            struct win *oldfore = 0;
 
2524
            char *ss;
 
2525
 
 
2526
            if (display)
 
2527
              {
 
2528
                oldfore = D_fore;
 
2529
                D_fore = win;
 
2530
              }
 
2531
            ss = AddWindows(p, l - 1, (*s == 'w' ? 0 : 1) | (longflg ? 0 : 2) | (plusflg ? 4 : 0), win ? win->w_number : -1);
 
2532
            if (minusflg)
 
2533
               *ss = 0;
 
2534
            if (display)
 
2535
              D_fore = oldfore;
 
2536
          }
 
2537
          if (*p)
 
2538
            qmflag = 1;
 
2539
          p += strlen(p) - 1;
 
2540
          break;
 
2541
        case 'u':
 
2542
          *p = 0;
 
2543
          if (win)
 
2544
            AddOtherUsers(p, l - 1, win);
 
2545
          if (*p)
 
2546
            qmflag = 1;
 
2547
          p += strlen(p) - 1;
 
2548
          break;
 
2549
        case 'f':
 
2550
          *p = 0;
 
2551
          if (win)
 
2552
            AddWindowFlags(p, l - 1, win);
 
2553
          if (*p)
 
2554
            qmflag = 1;
 
2555
          p += strlen(p) - 1;
 
2556
          break;
 
2557
        case 't':
 
2558
          *p = 0;
 
2559
          if (win && (int)strlen(win->w_title) < l)
 
2560
            {
 
2561
              strcpy(p, win->w_title);
 
2562
              if (*p)
 
2563
                qmflag = 1;
 
2564
            }
 
2565
          p += strlen(p) - 1;
 
2566
          break;
 
2567
        case '{':
 
2568
          {
 
2569
            char rbuf[128];
 
2570
            s++;
 
2571
            for (i = 0; i < 127; i++)
 
2572
              if (s[i] && s[i] != '}')
 
2573
                rbuf[i] = s[i];
 
2574
              else
 
2575
                break;
 
2576
            if (s[i] == '}' && winmsg_numrend < MAX_WINMSG_REND)
 
2577
              {
 
2578
                r = -1;
 
2579
                rbuf[i] = 0;
 
2580
                debug1("MakeWinMsg attrcolor %s\n", rbuf);
 
2581
                if (i != 1 || rbuf[0] != '-')
 
2582
                  r = ParseAttrColor(rbuf, (char *)0, 0);
 
2583
                if (r != -1 || (i == 1 && rbuf[0] == '-'))
 
2584
                  {
 
2585
                    winmsg_rend[winmsg_numrend] = r;
 
2586
                    winmsg_rendpos[winmsg_numrend] = p - winmsg_buf;
 
2587
                    winmsg_numrend++;
 
2588
                  }
 
2589
              }
 
2590
            s += i;
 
2591
            p--;
 
2592
          }
 
2593
          break;
 
2594
        case 'H':
 
2595
          *p = 0;
 
2596
          if ((int)strlen(HostName) < l)
 
2597
            {
 
2598
              strcpy(p, HostName);
 
2599
              if (*p)
 
2600
                qmflag = 1;
 
2601
            }
 
2602
          p += strlen(p) - 1;
 
2603
          break;
 
2604
        case 'F':
 
2605
          p--;
 
2606
          /* small hack */
 
2607
          if (display && ((ev && ev == &D_forecv->c_captev) || (!ev && win && win == D_fore)))
 
2608
            qmflag = 1;
 
2609
          break;
 
2610
        case '>':
 
2611
          truncpos = p - winmsg_buf;
 
2612
          truncper = num > 100 ? 100 : num;
 
2613
          trunclong = longflg;
 
2614
          p--;
 
2615
          break;
 
2616
        case '=':
 
2617
        case '<':
 
2618
          *p = ' ';
 
2619
          if (num || zeroflg || plusflg || longflg || (*s != '='))
 
2620
            {
 
2621
              /* expand all pads */
 
2622
              if (minusflg)
 
2623
                {
 
2624
                  num = (plusflg ? lastpad : padlen) - num;
 
2625
                  if (!plusflg && padlen == 0)
 
2626
                    num = p - winmsg_buf;
 
2627
                  plusflg = 0;
 
2628
                }
 
2629
              else if (!zeroflg)
 
2630
                {
 
2631
                  if (*s != '=' && num == 0 && !plusflg)
 
2632
                    num = 100;
 
2633
                  if (num > 100)
 
2634
                    num = 100;
 
2635
                  if (padlen == 0)
 
2636
                    num = p - winmsg_buf;
 
2637
                  else
 
2638
                    num = (padlen - (plusflg ? lastpad : 0)) * num / 100;
 
2639
                }
 
2640
              if (num < 0)
 
2641
                num = 0;
 
2642
              if (plusflg)
 
2643
                num += lastpad;
 
2644
              if (num > MAXSTR - 1)
 
2645
                num = MAXSTR - 1;
 
2646
              if (numpad)
 
2647
                p = pad_expand(winmsg_buf, p, numpad, num);
 
2648
              numpad = 0;
 
2649
              if (p - winmsg_buf > num && !longflg)
 
2650
                {
 
2651
                  int left, trunc;
 
2652
 
 
2653
                  if (truncpos == -1)
 
2654
                    {
 
2655
                      truncpos = lastpad;
 
2656
                      truncper = 0;
 
2657
                    }
 
2658
                  trunc = lastpad + truncper * (num - lastpad) / 100;
 
2659
                  if (trunc > num)
 
2660
                    trunc = num;
 
2661
                  if (trunc < lastpad)
 
2662
                    trunc = lastpad;
 
2663
                  left = truncpos - trunc;
 
2664
                  if (left > p - winmsg_buf - num)
 
2665
                    left = p - winmsg_buf - num;
 
2666
                  debug1("lastpad = %d, ", lastpad);
 
2667
                  debug3("truncpos = %d, trunc = %d, left = %d\n", truncpos, trunc, left);
 
2668
                  if (left > 0)
 
2669
                    {
 
2670
                      if (left + lastpad > p - winmsg_buf)
 
2671
                        left = p - winmsg_buf - lastpad;
 
2672
                      if (p - winmsg_buf - lastpad - left > 0)
 
2673
                        bcopy(winmsg_buf + lastpad + left, winmsg_buf + lastpad,  p - winmsg_buf - lastpad - left);
 
2674
                      p -= left;
 
2675
                      r = winmsg_numrend;
 
2676
                      while (r && winmsg_rendpos[r - 1] > lastpad)
 
2677
                        {
 
2678
                          r--;
 
2679
                          winmsg_rendpos[r] -= left;
 
2680
                          if (winmsg_rendpos[r] < lastpad)
 
2681
                            winmsg_rendpos[r] = lastpad;
 
2682
                        }
 
2683
                      if (trunclong)
 
2684
                        {
 
2685
                          if (p - winmsg_buf > lastpad)
 
2686
                            winmsg_buf[lastpad] = '.';
 
2687
                          if (p - winmsg_buf > lastpad + 1)
 
2688
                            winmsg_buf[lastpad + 1] = '.';
 
2689
                          if (p - winmsg_buf > lastpad + 2)
 
2690
                            winmsg_buf[lastpad + 2] = '.';
 
2691
                        }
 
2692
                    }
 
2693
                  if (p - winmsg_buf > num)
 
2694
                    {
 
2695
                      p = winmsg_buf + num;
 
2696
                      if (trunclong)
 
2697
                        {
 
2698
                          if (num - 1 >= lastpad)
 
2699
                            p[-1] = '.';
 
2700
                          if (num - 2 >= lastpad)
 
2701
                            p[-2] = '.';
 
2702
                          if (num - 3 >= lastpad)
 
2703
                            p[-3] = '.';
 
2704
                        }
 
2705
                      r = winmsg_numrend;
 
2706
                      while (r && winmsg_rendpos[r - 1] > num)
 
2707
                        winmsg_rendpos[--r] = num;
 
2708
                    }
 
2709
                  truncpos = -1;
 
2710
                  trunclong = 0;
 
2711
                  if (lastpad > p - winmsg_buf)
 
2712
                    lastpad = p - winmsg_buf;
 
2713
                  debug1("lastpad now %d\n", lastpad);
 
2714
                }
 
2715
              if (*s == '=')
 
2716
                {
 
2717
                  while (p - winmsg_buf < num)
 
2718
                    *p++ = ' ';
 
2719
                  lastpad = p - winmsg_buf;
 
2720
                  truncpos = -1;
 
2721
                  trunclong = 0;
 
2722
                  debug1("lastpad2 now %d\n", lastpad);
 
2723
                }
 
2724
              p--;
 
2725
            }
 
2726
          else if (padlen)
 
2727
            {
 
2728
              *p = 127;         /* internal pad representation */
 
2729
              numpad++;
 
2730
            }
 
2731
          break;
 
2732
        case 'n':
 
2733
          s++;
 
2734
          /* FALLTHROUGH */
 
2735
        default:
 
2736
          s--;
 
2737
          if (l > 10 + num)
 
2738
            {
 
2739
              if (num == 0)
 
2740
                num = 1;
 
2741
              if (!win)
 
2742
                sprintf(p, "%*s", num, num > 1 ? "--" : "-");
 
2743
              else
 
2744
                sprintf(p, "%*d", num, win->w_number);
 
2745
              qmflag = 1;
 
2746
              p += strlen(p) - 1;
 
2747
            }
 
2748
          break;
 
2749
        }
 
2750
    }
 
2751
  if (qmpos && !qmflag)
 
2752
    p = qmpos + 1;
 
2753
  *p = '\0';
 
2754
  if (numpad)
 
2755
    {
 
2756
      if (padlen > MAXSTR - 1)
 
2757
        padlen = MAXSTR - 1;
 
2758
      p = pad_expand(winmsg_buf, p, numpad, padlen);
 
2759
    }
 
2760
  if (ev)
 
2761
    {
 
2762
      evdeq(ev);                /* just in case */
 
2763
      ev->timeout.tv_sec = 0;
 
2764
      ev->timeout.tv_usec = 0;
 
2765
    }
 
2766
  if (ev && tick)
 
2767
    {
 
2768
      now.tv_usec = 100000;
 
2769
      if (tick == 1)
 
2770
        now.tv_sec++;
 
2771
      else
 
2772
        now.tv_sec += tick - (now.tv_sec % tick);
 
2773
      ev->timeout = now;
 
2774
      debug2("NEW timeout %d %d\n", ev->timeout.tv_sec, tick);
 
2775
    }
 
2776
  return winmsg_buf;
 
2777
}
 
2778
 
 
2779
char *
 
2780
MakeWinMsg(s, win, esc)
 
2781
char *s;
 
2782
struct win *win;
 
2783
int esc;
 
2784
{
 
2785
  return MakeWinMsgEv(s, win, esc, 0, (struct event *)0, 0);
 
2786
}
 
2787
 
 
2788
int
 
2789
PutWinMsg(s, start, max)
 
2790
char *s;
 
2791
int start, max;
 
2792
{
 
2793
  int i, p, l, r, n;
 
2794
  struct mchar rend;
 
2795
  struct mchar rendstack[MAX_WINMSG_REND];
 
2796
  int rendstackn = 0;
 
2797
 
 
2798
  if (s != winmsg_buf)
 
2799
    return 0;
 
2800
  rend = D_rend;
 
2801
  p = 0;
 
2802
  l = strlen(s);
 
2803
  debug2("PutWinMsg %s start attr %x\n", s, rend.attr);
 
2804
  for (i = 0; i < winmsg_numrend && max > 0; i++)
 
2805
    {
 
2806
      if (p > winmsg_rendpos[i] || winmsg_rendpos[i] > l)
 
2807
        break;
 
2808
      if (p < winmsg_rendpos[i])
 
2809
        {
 
2810
          n = winmsg_rendpos[i] - p;
 
2811
          if (n > max)
 
2812
            n = max;
 
2813
          max -= n;
 
2814
          p += n;
 
2815
          while(n-- > 0)
 
2816
            {
 
2817
              if (start-- > 0)
 
2818
                s++;
 
2819
              else
 
2820
                PUTCHARLP(*s++);
 
2821
            }
 
2822
        }
 
2823
      r = winmsg_rend[i];
 
2824
      if (r == -1)
 
2825
        {
 
2826
          if (rendstackn > 0)
 
2827
            rend = rendstack[--rendstackn];
 
2828
        }
 
2829
      else
 
2830
        {
 
2831
          rendstack[rendstackn++] = rend;
 
2832
          ApplyAttrColor(r, &rend);
 
2833
        }
 
2834
      SetRendition(&rend);
 
2835
    }
 
2836
  if (p < l)
 
2837
    {
 
2838
      n = l - p;
 
2839
      if (n > max)
 
2840
        n = max;
 
2841
      while(n-- > 0)
 
2842
        {
 
2843
          if (start-- > 0)
 
2844
            s++;
 
2845
          else
 
2846
            PUTCHARLP(*s++);
 
2847
        }
 
2848
    }
 
2849
  return 1;
 
2850
}
 
2851
 
 
2852
 
 
2853
#ifdef DEBUG
 
2854
static void
 
2855
fds1(i, j)
 
2856
int i, j;
 
2857
{
 
2858
  while (i < j)
 
2859
    {
 
2860
      debug1("%d ", i);
 
2861
      i++;
 
2862
    }
 
2863
  if ((j = open("/dev/null", 0)) >= 0)
 
2864
    {
 
2865
      fds1(i + 1, j);
 
2866
      close(j);
 
2867
    }
 
2868
  else
 
2869
    {
 
2870
      while (dup(++i) < 0 && errno != EBADF)
 
2871
        debug1("%d ", i);
 
2872
      debug1(" [%d]\n", i);
 
2873
    }
 
2874
}
 
2875
 
 
2876
static void
 
2877
fds()
 
2878
{
 
2879
  debug("fds: ");
 
2880
  fds1(-1, -1);
 
2881
}
 
2882
#endif
 
2883
 
 
2884
static void
 
2885
serv_read_fn(ev, data)
 
2886
struct event *ev;
 
2887
char *data;
 
2888
{
 
2889
  debug("Knock - knock!\n");
 
2890
  ReceiveMsg();
 
2891
}
 
2892
 
 
2893
static void
 
2894
serv_select_fn(ev, data)
 
2895
struct event *ev;
 
2896
char *data;
 
2897
{
 
2898
  struct win *p;
 
2899
 
 
2900
  debug("serv_select_fn called\n");
 
2901
  /* XXX: messages?? */
 
2902
  if (GotSigChld)
 
2903
    {
 
2904
      SigChldHandler();
 
2905
    }
 
2906
  if (InterruptPlease)
 
2907
    {
 
2908
      debug("Backend received interrupt\n");
 
2909
      /* This approach is rather questionable in a multi-display
 
2910
       * environment */
 
2911
      if (fore && displays)
 
2912
        {
 
2913
#if defined(TERMIO) || defined(POSIX)
 
2914
          char ibuf = displays->d_OldMode.tio.c_cc[VINTR];
 
2915
#else
 
2916
          char ibuf = displays->d_OldMode.m_tchars.t_intrc;
 
2917
#endif
 
2918
#ifdef PSEUDOS
 
2919
          write(W_UWP(fore) ? fore->w_pwin->p_ptyfd : fore->w_ptyfd, 
 
2920
                &ibuf, 1);
 
2921
          debug1("Backend wrote interrupt to %d", fore->w_number);
 
2922
          debug1("%s\n", W_UWP(fore) ? " (pseudowin)" : "");
 
2923
#else
 
2924
          write(fore->w_ptyfd, &ibuf, 1);
 
2925
          debug1("Backend wrote interrupt to %d\n", fore->w_number);
 
2926
#endif
 
2927
        }
 
2928
      InterruptPlease = 0;
 
2929
    }
 
2930
 
 
2931
  for (p = windows; p; p = p->w_next)
 
2932
    {
 
2933
      if (p->w_bell == BELL_FOUND || p->w_bell == BELL_VISUAL)
 
2934
        {
 
2935
          struct canvas *cv;
 
2936
          int visual = p->w_bell == BELL_VISUAL || visual_bell;
 
2937
          p->w_bell = BELL_ON;
 
2938
          for (display = displays; display; display = display->d_next)
 
2939
            {
 
2940
              for (cv = D_cvlist; cv; cv = cv->c_next)
 
2941
                if (cv->c_layer->l_bottom == &p->w_layer)
 
2942
                  break;
 
2943
              if (cv == 0)
 
2944
                {
 
2945
                  p->w_bell = BELL_DONE;
 
2946
                  Msg(0, "%s", MakeWinMsg(BellString, p, '%'));
 
2947
                }
 
2948
              else if (visual && !D_VB && (!D_status || !D_status_bell))
 
2949
                {
 
2950
                  Msg(0, "%s", VisualBellString);
 
2951
                  if (D_status)
 
2952
                    {
 
2953
                      D_status_bell = 1;
 
2954
                      debug1("using vbell timeout %d\n", VBellWait);
 
2955
                      SetTimeout(&D_statusev, VBellWait );
 
2956
                    }
 
2957
                }
 
2958
            }
 
2959
          /* don't annoy the user with two messages */
 
2960
          if (p->w_monitor == MON_FOUND)
 
2961
            p->w_monitor = MON_DONE;
 
2962
          WindowChanged(p, 'f');
 
2963
        }
 
2964
      if (p->w_monitor == MON_FOUND)
 
2965
        {
 
2966
          struct canvas *cv;
 
2967
          p->w_monitor = MON_ON;
 
2968
          for (display = displays; display; display = display->d_next)
 
2969
            {
 
2970
              for (cv = D_cvlist; cv; cv = cv->c_next)
 
2971
                if (cv->c_layer->l_bottom == &p->w_layer)
 
2972
                  break;
 
2973
              if (cv)
 
2974
                continue;       /* user already sees window */
 
2975
#ifdef MULTIUSER
 
2976
              if (!(ACLBYTE(p->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
 
2977
                continue;       /* user doesn't care */
 
2978
#endif
 
2979
              Msg(0, "%s", MakeWinMsg(ActivityString, p, '%'));
 
2980
              p->w_monitor = MON_DONE;
 
2981
            }
 
2982
          WindowChanged(p, 'f');
 
2983
        }
 
2984
    }
 
2985
 
 
2986
  for (display = displays; display; display = display->d_next)
 
2987
    {
 
2988
      struct canvas *cv;
 
2989
      if (D_status == STATUS_ON_WIN)
 
2990
        continue;
 
2991
      /* XXX: should use display functions! */
 
2992
      for (cv = D_cvlist; cv; cv = cv->c_next)
 
2993
        {
 
2994
          int lx, ly;
 
2995
 
 
2996
          /* normalize window, see resize.c */
 
2997
          lx = cv->c_layer->l_x;
 
2998
          ly = cv->c_layer->l_y;
 
2999
          if (lx == cv->c_layer->l_width)
 
3000
            lx--;
 
3001
          if (ly + cv->c_yoff < cv->c_ys)
 
3002
            {
 
3003
              int i, n = cv->c_ys - (ly + cv->c_yoff);
 
3004
              cv->c_yoff = cv->c_ys - ly;
 
3005
              RethinkViewportOffsets(cv);
 
3006
              if (n > cv->c_layer->l_height)
 
3007
                n = cv->c_layer->l_height;
 
3008
              CV_CALL(cv, 
 
3009
                LScrollV(flayer, -n, 0, flayer->l_height - 1, 0);
 
3010
                LayRedisplayLine(-1, -1, -1, 1);
 
3011
                for (i = 0; i < n; i++)
 
3012
                  LayRedisplayLine(i, 0, flayer->l_width - 1, 1);
 
3013
                if (cv == cv->c_display->d_forecv)
 
3014
                  LaySetCursor();
 
3015
              );
 
3016
            }
 
3017
          else if (ly + cv->c_yoff > cv->c_ye)
 
3018
            {
 
3019
              int i, n = ly + cv->c_yoff - cv->c_ye;
 
3020
              cv->c_yoff = cv->c_ye - ly;
 
3021
              RethinkViewportOffsets(cv);
 
3022
              if (n > cv->c_layer->l_height)
 
3023
                n = cv->c_layer->l_height;
 
3024
              CV_CALL(cv, 
 
3025
                LScrollV(flayer, n, 0, cv->c_layer->l_height - 1, 0);
 
3026
                LayRedisplayLine(-1, -1, -1, 1);
 
3027
                for (i = 0; i < n; i++)
 
3028
                  LayRedisplayLine(i + flayer->l_height - n, 0, flayer->l_width - 1, 1);
 
3029
                if (cv == cv->c_display->d_forecv)
 
3030
                  LaySetCursor();
 
3031
              );
 
3032
            }
 
3033
          if (lx + cv->c_xoff < cv->c_xs)
 
3034
            {
 
3035
              int i, n = cv->c_xs - (lx + cv->c_xoff);
 
3036
              if (n < (cv->c_xe - cv->c_xs + 1) / 2)
 
3037
                n = (cv->c_xe - cv->c_xs + 1) / 2;
 
3038
              if (cv->c_xoff + n > cv->c_xs)
 
3039
                n = cv->c_xs - cv->c_xoff;
 
3040
              cv->c_xoff += n;
 
3041
              RethinkViewportOffsets(cv);
 
3042
              if (n > cv->c_layer->l_width)
 
3043
                n = cv->c_layer->l_width;
 
3044
              CV_CALL(cv, 
 
3045
                LayRedisplayLine(-1, -1, -1, 1);
 
3046
                for (i = 0; i < flayer->l_height; i++)
 
3047
                  {
 
3048
                    LScrollH(flayer, -n, i, 0, flayer->l_width - 1, 0, 0);
 
3049
                    LayRedisplayLine(i, 0, n - 1, 1);
 
3050
                  }
 
3051
                if (cv == cv->c_display->d_forecv)
 
3052
                  LaySetCursor();
 
3053
              );
 
3054
            }
 
3055
          else if (lx + cv->c_xoff > cv->c_xe)
 
3056
            {
 
3057
              int i, n = lx + cv->c_xoff - cv->c_xe;
 
3058
              if (n < (cv->c_xe - cv->c_xs + 1) / 2)
 
3059
                n = (cv->c_xe - cv->c_xs + 1) / 2;
 
3060
              if (cv->c_xoff - n + cv->c_layer->l_width - 1 < cv->c_xe)
 
3061
                n = cv->c_xoff + cv->c_layer->l_width - 1 - cv->c_xe;
 
3062
              cv->c_xoff -= n;
 
3063
              RethinkViewportOffsets(cv);
 
3064
              if (n > cv->c_layer->l_width)
 
3065
                n = cv->c_layer->l_width;
 
3066
              CV_CALL(cv, 
 
3067
                LayRedisplayLine(-1, -1, -1, 1);
 
3068
                for (i = 0; i < flayer->l_height; i++)
 
3069
                  {
 
3070
                    LScrollH(flayer, n, i, 0, flayer->l_width - 1, 0, 0);
 
3071
                    LayRedisplayLine(i, flayer->l_width - n, flayer->l_width - 1, 1);
 
3072
                  }
 
3073
                if (cv == cv->c_display->d_forecv)
 
3074
                  LaySetCursor();
 
3075
              );
 
3076
            }
 
3077
        }
 
3078
    }
 
3079
 
 
3080
  for (display = displays; display; display = display->d_next)
 
3081
    {
 
3082
      if (D_status == STATUS_ON_WIN || D_cvlist == 0 || D_cvlist->c_next == 0)
 
3083
        continue;
 
3084
      debug1("serv_select_fn: Restore on cv %#x\n", (int)D_forecv);
 
3085
      CV_CALL(D_forecv, LayRestore();LaySetCursor());
 
3086
    }
 
3087
}
 
3088
 
 
3089
static void
 
3090
logflush_fn(ev, data)
 
3091
struct event *ev;
 
3092
char *data;
 
3093
{
 
3094
  struct win *p;
 
3095
  char *buf;
 
3096
  int n;
 
3097
 
 
3098
  if (!islogfile(NULL))
 
3099
    return;             /* no more logfiles */
 
3100
  logfflush(NULL);
 
3101
  n = log_flush ? log_flush : (logtstamp_after + 4) / 5;
 
3102
  if (n)
 
3103
    {
 
3104
      SetTimeout(ev, n * 1000);
 
3105
      evenq(ev);        /* re-enqueue ourself */
 
3106
    }
 
3107
  if (!logtstamp_on)
 
3108
    return;
 
3109
  /* write fancy time-stamp */
 
3110
  for (p = windows; p; p = p->w_next)
 
3111
    {
 
3112
      if (!p->w_log)
 
3113
        continue;
 
3114
      p->w_logsilence += n;
 
3115
      if (p->w_logsilence < logtstamp_after)
 
3116
        continue;
 
3117
      if (p->w_logsilence - n >= logtstamp_after)
 
3118
        continue;
 
3119
      buf = MakeWinMsg(logtstamp_string, p, '%');
 
3120
      logfwrite(p->w_log, buf, strlen(buf));
 
3121
    }
 
3122
}
 
3123
 
 
3124
/*
 
3125
 * Interprets ^?, ^@ and other ^-control-char notation.
 
3126
 * Interprets \ddd octal notation
 
3127
 * 
 
3128
 * The result is placed in *cp, p is advanced behind the parsed expression and 
 
3129
 * returned. 
 
3130
 */
 
3131
static char *
 
3132
ParseChar(p, cp)
 
3133
char *p, *cp;
 
3134
{
 
3135
  if (*p == 0)
 
3136
    return 0;
 
3137
  if (*p == '^' && p[1])
 
3138
    {
 
3139
      if (*++p == '?')
 
3140
        *cp = '\177';
 
3141
      else if (*p >= '@')
 
3142
        *cp = Ctrl(*p);
 
3143
      else
 
3144
        return 0;
 
3145
      ++p;
 
3146
    }
 
3147
  else if (*p == '\\' && *++p <= '7' && *p >= '0')
 
3148
    {
 
3149
      *cp = 0;
 
3150
      do
 
3151
        *cp = *cp * 8 + *p - '0';
 
3152
      while (*++p <= '7' && *p >= '0');
 
3153
    }
 
3154
  else
 
3155
    *cp = *p++;
 
3156
  return p;
 
3157
}
 
3158
 
 
3159
static int 
 
3160
ParseEscape(p)
 
3161
char *p;
 
3162
{
 
3163
  unsigned char buf[2];
 
3164
 
 
3165
  if (*p == 0)
 
3166
    SetEscape((struct acluser *)0, -1, -1);
 
3167
  else
 
3168
    {
 
3169
      if ((p = ParseChar(p, (char *)buf)) == NULL ||
 
3170
          (p = ParseChar(p, (char *)buf+1)) == NULL || *p)
 
3171
        return -1;
 
3172
      SetEscape((struct acluser *)0, buf[0], buf[1]);
 
3173
    }
 
3174
  return 0;
 
3175
}
 
3176