1*37649e40Smrg /* $NetBSD: hack.unix.c,v 1.18 2019/02/03 10:48:46 mrg Exp $ */
23ea4a95cSchristos
3210cab45Smycroft /*
41c7f94e5Sjsm * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
51c7f94e5Sjsm * Amsterdam
61c7f94e5Sjsm * All rights reserved.
71c7f94e5Sjsm *
81c7f94e5Sjsm * Redistribution and use in source and binary forms, with or without
91c7f94e5Sjsm * modification, are permitted provided that the following conditions are
101c7f94e5Sjsm * met:
111c7f94e5Sjsm *
121c7f94e5Sjsm * - Redistributions of source code must retain the above copyright notice,
131c7f94e5Sjsm * this list of conditions and the following disclaimer.
141c7f94e5Sjsm *
151c7f94e5Sjsm * - Redistributions in binary form must reproduce the above copyright
161c7f94e5Sjsm * notice, this list of conditions and the following disclaimer in the
171c7f94e5Sjsm * documentation and/or other materials provided with the distribution.
181c7f94e5Sjsm *
191c7f94e5Sjsm * - Neither the name of the Stichting Centrum voor Wiskunde en
201c7f94e5Sjsm * Informatica, nor the names of its contributors may be used to endorse or
211c7f94e5Sjsm * promote products derived from this software without specific prior
221c7f94e5Sjsm * written permission.
231c7f94e5Sjsm *
241c7f94e5Sjsm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
251c7f94e5Sjsm * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
261c7f94e5Sjsm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
271c7f94e5Sjsm * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
281c7f94e5Sjsm * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
291c7f94e5Sjsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
301c7f94e5Sjsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
311c7f94e5Sjsm * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
321c7f94e5Sjsm * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
331c7f94e5Sjsm * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
341c7f94e5Sjsm * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
351c7f94e5Sjsm */
361c7f94e5Sjsm
371c7f94e5Sjsm /*
381c7f94e5Sjsm * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
391c7f94e5Sjsm * All rights reserved.
401c7f94e5Sjsm *
411c7f94e5Sjsm * Redistribution and use in source and binary forms, with or without
421c7f94e5Sjsm * modification, are permitted provided that the following conditions
431c7f94e5Sjsm * are met:
441c7f94e5Sjsm * 1. Redistributions of source code must retain the above copyright
451c7f94e5Sjsm * notice, this list of conditions and the following disclaimer.
461c7f94e5Sjsm * 2. Redistributions in binary form must reproduce the above copyright
471c7f94e5Sjsm * notice, this list of conditions and the following disclaimer in the
481c7f94e5Sjsm * documentation and/or other materials provided with the distribution.
491c7f94e5Sjsm * 3. The name of the author may not be used to endorse or promote products
501c7f94e5Sjsm * derived from this software without specific prior written permission.
511c7f94e5Sjsm *
521c7f94e5Sjsm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
531c7f94e5Sjsm * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
541c7f94e5Sjsm * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
551c7f94e5Sjsm * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
561c7f94e5Sjsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
571c7f94e5Sjsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
581c7f94e5Sjsm * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
591c7f94e5Sjsm * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
601c7f94e5Sjsm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
611c7f94e5Sjsm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62210cab45Smycroft */
63210cab45Smycroft
643ea4a95cSchristos #include <sys/cdefs.h>
65210cab45Smycroft #ifndef lint
66*37649e40Smrg __RCSID("$NetBSD: hack.unix.c,v 1.18 2019/02/03 10:48:46 mrg Exp $");
67210cab45Smycroft #endif /* not lint */
6861f28255Scgd
6961f28255Scgd /* This file collects some Unix dependencies; hack.pager.c contains some more */
7061f28255Scgd
7161f28255Scgd /*
7261f28255Scgd * The time is used for:
7361f28255Scgd * - seed for random()
7461f28255Scgd * - year on tombstone and yymmdd in record file
7561f28255Scgd * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
7661f28255Scgd * - night and midnight (the undead are dangerous at midnight)
7761f28255Scgd * - determination of what files are "very old"
7861f28255Scgd */
7961f28255Scgd
8061f28255Scgd #include <errno.h>
8161f28255Scgd #include <sys/types.h> /* for time_t and stat */
8261f28255Scgd #include <sys/stat.h>
8361f28255Scgd #ifdef BSD
8461f28255Scgd #include <sys/time.h>
8561f28255Scgd #else
8661f28255Scgd #include <time.h>
873ea4a95cSchristos #endif /* BSD */
883ea4a95cSchristos #include <stdlib.h>
893ea4a95cSchristos #include <unistd.h>
903ea4a95cSchristos #include <signal.h>
913ea4a95cSchristos #include <fcntl.h>
9261f28255Scgd
933ea4a95cSchristos #include "hack.h" /* mainly for strchr() which depends on BSD */
943ea4a95cSchristos #include "extern.h"
9561f28255Scgd
96bc32159dSchristos extern int locknum;
97bc32159dSchristos
989b92b189Sdholland static struct tm *getlt(void);
999b92b189Sdholland static int veryold(int);
1009b92b189Sdholland
1013ea4a95cSchristos
1023ea4a95cSchristos void
setrandom(void)1031fa8a9a6Sdholland setrandom(void)
10461f28255Scgd {
10561f28255Scgd (void) srandom((int) time((time_t *) 0));
10661f28255Scgd }
10761f28255Scgd
1089b92b189Sdholland static struct tm *
getlt(void)1091fa8a9a6Sdholland getlt(void)
11061f28255Scgd {
11161f28255Scgd time_t date;
11261f28255Scgd
11361f28255Scgd (void) time(&date);
11461f28255Scgd return (localtime(&date));
11561f28255Scgd }
11661f28255Scgd
1173ea4a95cSchristos int
getyear(void)1181fa8a9a6Sdholland getyear(void)
11961f28255Scgd {
12061f28255Scgd return (1900 + getlt()->tm_year);
12161f28255Scgd }
12261f28255Scgd
12361f28255Scgd char *
getdatestr(void)1241fa8a9a6Sdholland getdatestr(void)
12561f28255Scgd {
126*37649e40Smrg static char datestr[32];
1273ea4a95cSchristos struct tm *lt = getlt();
12861f28255Scgd
129907fca1bSdholland (void) snprintf(datestr, sizeof(datestr), "%02d%02d%02d",
1308e5038f0Skristerw lt->tm_year % 100, lt->tm_mon + 1, lt->tm_mday);
13161f28255Scgd return (datestr);
13261f28255Scgd }
13361f28255Scgd
1343ea4a95cSchristos int
phase_of_the_moon(void)1351fa8a9a6Sdholland phase_of_the_moon(void)
1363ea4a95cSchristos { /* 0-7, with 0: new, 4: full *//* moon
1373ea4a95cSchristos * period: 29.5306 days */
13861f28255Scgd /* year: 365.2422 days */
1393ea4a95cSchristos struct tm *lt = getlt();
1403ea4a95cSchristos int epact, diy, golden;
14161f28255Scgd
14261f28255Scgd diy = lt->tm_yday;
14361f28255Scgd golden = (lt->tm_year % 19) + 1;
14461f28255Scgd epact = (11 * golden + 18) % 30;
14561f28255Scgd if ((epact == 25 && golden > 11) || epact == 24)
14661f28255Scgd epact++;
14761f28255Scgd
14861f28255Scgd return ((((((diy + epact) * 6) + 11) % 177) / 22) & 7);
14961f28255Scgd }
15061f28255Scgd
1513ea4a95cSchristos int
night(void)1521fa8a9a6Sdholland night(void)
15361f28255Scgd {
1543ea4a95cSchristos int hour = getlt()->tm_hour;
15561f28255Scgd
15661f28255Scgd return (hour < 6 || hour > 21);
15761f28255Scgd }
15861f28255Scgd
1593ea4a95cSchristos int
midnight(void)1601fa8a9a6Sdholland midnight(void)
16161f28255Scgd {
16261f28255Scgd return (getlt()->tm_hour == 0);
16361f28255Scgd }
16461f28255Scgd
1659b92b189Sdholland static struct stat buf, hbuf;
16661f28255Scgd
1673ea4a95cSchristos void
gethdate(char * name)1681fa8a9a6Sdholland gethdate(char *name)
1693ea4a95cSchristos {
1703ea4a95cSchristos #if 0
17161f28255Scgd /* old version - for people short of space */
1723ea4a95cSchristos
1733ea4a95cSchristos char *np;
1743ea4a95cSchristos
1753ea4a95cSchristos if(stat(name, &hbuf))
1763ea4a95cSchristos error("Cannot get status of %s.",
1773ea4a95cSchristos (np = strrchr(name, '/')) ? np+1 : name);
1783ea4a95cSchristos #else
17961f28255Scgd /* version using PATH from: seismo!gregc@ucsf-cgl.ARPA (Greg Couch) */
18061f28255Scgd
18161f28255Scgd
18261f28255Scgd /*
18361f28255Scgd * The problem with #include <sys/param.h> is that this include file
18461f28255Scgd * does not exist on all systems, and moreover, that it sometimes includes
18561f28255Scgd * <sys/types.h> again, so that the compiler sees these typedefs twice.
18661f28255Scgd */
18761f28255Scgd #define MAXPATHLEN 1024
18861f28255Scgd
189ab8b6343Sjsm const char *np, *path;
19061f28255Scgd char filename[MAXPATHLEN + 1];
1913ea4a95cSchristos if (strchr(name, '/') != NULL || (path = getenv("PATH")) == NULL)
19261f28255Scgd path = "";
19361f28255Scgd
19461f28255Scgd for (;;) {
1953ea4a95cSchristos if ((np = strchr(path, ':')) == NULL)
19661f28255Scgd np = path + strlen(path); /* point to end str */
19761f28255Scgd if (np - path <= 1) /* %% */
198165c915bSdholland (void) strlcpy(filename, name, sizeof(filename));
19961f28255Scgd else {
200165c915bSdholland (void) snprintf(filename, sizeof(filename),
201165c915bSdholland "%.*s/%s",
202165c915bSdholland (int)(np - path), path, name);
20361f28255Scgd }
20461f28255Scgd if (stat(filename, &hbuf) == 0)
20561f28255Scgd return;
20661f28255Scgd if (*np == '\0')
20761f28255Scgd break;
20861f28255Scgd path = np + 1;
20961f28255Scgd }
21061f28255Scgd error("Cannot get status of %s.",
2113ea4a95cSchristos (np = strrchr(name, '/')) ? np + 1 : name);
2123ea4a95cSchristos #endif
21361f28255Scgd }
21461f28255Scgd
2153ea4a95cSchristos int
uptodate(int fd)216ab8b6343Sjsm uptodate(int fd)
2173ea4a95cSchristos {
21861f28255Scgd if (fstat(fd, &buf)) {
21961f28255Scgd pline("Cannot get status of saved level? ");
22061f28255Scgd return (0);
22161f28255Scgd }
22261f28255Scgd if (buf.st_mtime < hbuf.st_mtime) {
22361f28255Scgd pline("Saved level is out of date. ");
22461f28255Scgd return (0);
22561f28255Scgd }
22661f28255Scgd return (1);
22761f28255Scgd }
22861f28255Scgd
22961f28255Scgd /* see whether we should throw away this xlock file */
2309b92b189Sdholland static int
veryold(int fd)2311fa8a9a6Sdholland veryold(int fd)
2323ea4a95cSchristos {
2333ea4a95cSchristos int i;
23461f28255Scgd time_t date;
23561f28255Scgd
2363ea4a95cSchristos if (fstat(fd, &buf))
2373ea4a95cSchristos return (0); /* cannot get status */
2383ea4a95cSchristos if (buf.st_size != sizeof(int))
2393ea4a95cSchristos return (0); /* not an xlock file */
24061f28255Scgd (void) time(&date);
24161f28255Scgd if (date - buf.st_mtime < 3L * 24L * 60L * 60L) { /* recent */
2423ea4a95cSchristos int lockedpid; /* should be the same size as
2433ea4a95cSchristos * hackpid */
24461f28255Scgd
2452c0ecb1aSdholland if (read(fd, &lockedpid, sizeof(lockedpid)) !=
24661f28255Scgd sizeof(lockedpid))
24761f28255Scgd /* strange ... */
24861f28255Scgd return (0);
24961f28255Scgd
2503ea4a95cSchristos /*
2513ea4a95cSchristos * From: Rick Adams <seismo!rick> This will work on
2523ea4a95cSchristos * 4.1cbsd, 4.2bsd and system 3? & 5. It will do nothing
2533ea4a95cSchristos * on V7 or 4.1bsd.
2543ea4a95cSchristos */
25561f28255Scgd if (!(kill(lockedpid, 0) == -1 && errno == ESRCH))
25661f28255Scgd return (0);
25761f28255Scgd }
25861f28255Scgd (void) close(fd);
25961f28255Scgd for (i = 1; i <= MAXLEVEL; i++) { /* try to remove all */
26061f28255Scgd glo(i);
26161f28255Scgd (void) unlink(lock);
26261f28255Scgd }
26361f28255Scgd glo(0);
2643ea4a95cSchristos if (unlink(lock))
2653ea4a95cSchristos return (0); /* cannot remove it */
26661f28255Scgd return (1); /* success! */
26761f28255Scgd }
26861f28255Scgd
2693ea4a95cSchristos void
getlock(void)2701fa8a9a6Sdholland getlock(void)
27161f28255Scgd {
2723ea4a95cSchristos int i = 0, fd;
27361f28255Scgd
27461f28255Scgd (void) fflush(stdout);
27561f28255Scgd
27661f28255Scgd /* we ignore QUIT and INT at this point */
27761f28255Scgd if (link(HLOCK, LLOCK) == -1) {
2783ea4a95cSchristos int errnosv = errno;
27961f28255Scgd
28061f28255Scgd perror(HLOCK);
28161f28255Scgd printf("Cannot link %s to %s\n", LLOCK, HLOCK);
28261f28255Scgd switch (errnosv) {
28361f28255Scgd case ENOENT:
28461f28255Scgd printf("Perhaps there is no (empty) file %s ?\n", HLOCK);
28561f28255Scgd break;
28661f28255Scgd case EACCES:
28761f28255Scgd printf("It seems you don't have write permission here.\n");
28861f28255Scgd break;
28961f28255Scgd case EEXIST:
29061f28255Scgd printf("(Try again or rm %s.)\n", LLOCK);
29161f28255Scgd break;
29261f28255Scgd default:
29361f28255Scgd printf("I don't know what is wrong.");
29461f28255Scgd }
29561f28255Scgd getret();
2963ea4a95cSchristos error("%s", "");
29761f28255Scgd /* NOTREACHED */
29861f28255Scgd }
29961f28255Scgd regularize(lock);
30061f28255Scgd glo(0);
3013ea4a95cSchristos if (locknum > 25)
3023ea4a95cSchristos locknum = 25;
30361f28255Scgd
30461f28255Scgd do {
3053ea4a95cSchristos if (locknum)
3063ea4a95cSchristos lock[0] = 'a' + i++;
30761f28255Scgd
308ab8b6343Sjsm if ((fd = open(lock, O_RDONLY)) == -1) {
3093ea4a95cSchristos if (errno == ENOENT)
3103ea4a95cSchristos goto gotlock; /* no such file */
31161f28255Scgd perror(lock);
31261f28255Scgd (void) unlink(LLOCK);
31361f28255Scgd error("Cannot open %s", lock);
31461f28255Scgd }
31561f28255Scgd if (veryold(fd))/* if true, this closes fd and unlinks lock */
31661f28255Scgd goto gotlock;
31761f28255Scgd (void) close(fd);
31861f28255Scgd } while (i < locknum);
31961f28255Scgd
32061f28255Scgd (void) unlink(LLOCK);
32161f28255Scgd error(locknum ? "Too many hacks running now."
32261f28255Scgd : "There is a game in progress under your name.");
32361f28255Scgd gotlock:
32461f28255Scgd fd = creat(lock, FMASK);
32561f28255Scgd if (unlink(LLOCK) == -1)
32661f28255Scgd error("Cannot unlink %s.", LLOCK);
32761f28255Scgd if (fd == -1) {
32861f28255Scgd error("cannot creat lock file.");
32961f28255Scgd } else {
3302c0ecb1aSdholland if (write(fd, &hackpid, sizeof(hackpid))
33161f28255Scgd != sizeof(hackpid)) {
33261f28255Scgd error("cannot write lock");
33361f28255Scgd }
33461f28255Scgd if (close(fd) == -1) {
33561f28255Scgd error("cannot close lock");
33661f28255Scgd }
33761f28255Scgd }
33861f28255Scgd }
33961f28255Scgd
34061f28255Scgd #ifdef MAIL
34161f28255Scgd
34261f28255Scgd /*
34361f28255Scgd * Notify user when new mail has arrived. [Idea from Merlyn Leroy, but
34461f28255Scgd * I don't know the details of his implementation.]
34561f28255Scgd * { Later note: he disliked my calling a general mailreader and felt that
34661f28255Scgd * hack should do the paging itself. But when I get mail, I want to put it
34761f28255Scgd * in some folder, reply, etc. - it would be unreasonable to put all these
34861f28255Scgd * functions in hack. }
34961f28255Scgd * The mail daemon '2' is at present not a real monster, but only a visual
35061f28255Scgd * effect. Thus, makemon() is superfluous. This might become otherwise,
35161f28255Scgd * however. The motion of '2' is less restrained than usual: diagonal moves
35261f28255Scgd * from a DOOR are possible. He might also use SDOOR's. Also, '2' is visible
35361f28255Scgd * in a ROOM, even when you are Blind.
35461f28255Scgd * Its path should be longer when you are Telepat-hic and Blind.
35561f28255Scgd *
35661f28255Scgd * Interesting side effects:
35761f28255Scgd * - You can get rich by sending yourself a lot of mail and selling
35861f28255Scgd * it to the shopkeeper. Unfortunately mail isn't very valuable.
35961f28255Scgd * - You might die in case '2' comes along at a critical moment during
36061f28255Scgd * a fight and delivers a scroll the weight of which causes you to
36161f28255Scgd * collapse.
36261f28255Scgd *
36361f28255Scgd * Possible extensions:
36461f28255Scgd * - Open the file MAIL and do fstat instead of stat for efficiency.
36561f28255Scgd * (But sh uses stat, so this cannot be too bad.)
36661f28255Scgd * - Examine the mail and produce a scroll of mail called "From somebody".
36761f28255Scgd * - Invoke MAILREADER in such a way that only this single letter is read.
36861f28255Scgd *
36961f28255Scgd * - Make him lose his mail when a Nymph steals the letter.
37061f28255Scgd * - Do something to the text when the scroll is enchanted or cancelled.
37161f28255Scgd */
37261f28255Scgd #include "def.mkroom.h"
37361f28255Scgd static struct stat omstat, nmstat;
37461f28255Scgd static char *mailbox;
37561f28255Scgd static long laststattime;
37661f28255Scgd
3773ea4a95cSchristos void
getmailstatus(void)3781fa8a9a6Sdholland getmailstatus(void)
3793ea4a95cSchristos {
38061f28255Scgd if (!(mailbox = getenv("MAIL")))
38161f28255Scgd return;
38261f28255Scgd if (stat(mailbox, &omstat)) {
38361f28255Scgd #ifdef PERMANENT_MAILBOX
38461f28255Scgd pline("Cannot get status of MAIL=%s .", mailbox);
38561f28255Scgd mailbox = 0;
38661f28255Scgd #else
38761f28255Scgd omstat.st_mtime = 0;
3883ea4a95cSchristos #endif /* PERMANENT_MAILBOX */
38961f28255Scgd }
39061f28255Scgd }
39161f28255Scgd
3923ea4a95cSchristos void
ckmailstatus(void)3931fa8a9a6Sdholland ckmailstatus(void)
3943ea4a95cSchristos {
39561f28255Scgd if (!mailbox
39661f28255Scgd #ifdef MAILCKFREQ
39761f28255Scgd || moves < laststattime + MAILCKFREQ
3983ea4a95cSchristos #endif /* MAILCKFREQ */
39961f28255Scgd )
40061f28255Scgd return;
40161f28255Scgd laststattime = moves;
40261f28255Scgd if (stat(mailbox, &nmstat)) {
40361f28255Scgd #ifdef PERMANENT_MAILBOX
40461f28255Scgd pline("Cannot get status of MAIL=%s anymore.", mailbox);
40561f28255Scgd mailbox = 0;
40661f28255Scgd #else
40761f28255Scgd nmstat.st_mtime = 0;
4083ea4a95cSchristos #endif /* PERMANENT_MAILBOX */
40961f28255Scgd } else if (nmstat.st_mtime > omstat.st_mtime) {
41061f28255Scgd if (nmstat.st_size)
41161f28255Scgd newmail();
41261f28255Scgd getmailstatus();/* might be too late ... */
41361f28255Scgd }
41461f28255Scgd }
41561f28255Scgd
4163ea4a95cSchristos void
newmail(void)4171fa8a9a6Sdholland newmail(void)
4183ea4a95cSchristos {
41961f28255Scgd /* produce a scroll of mail */
4203ea4a95cSchristos struct obj *obj;
4213ea4a95cSchristos struct monst *md;
42261f28255Scgd
42361f28255Scgd obj = mksobj(SCR_MAIL);
42461f28255Scgd if (md = makemon(&pm_mail_daemon, u.ux, u.uy)) /* always succeeds */
42561f28255Scgd mdrush(md, 0);
42661f28255Scgd
42761f28255Scgd pline("\"Hello, %s! I have some mail for you.\"", plname);
42861f28255Scgd if (md) {
42961f28255Scgd if (dist(md->mx, md->my) > 2)
43061f28255Scgd pline("\"Catch!\"");
43161f28255Scgd more();
43261f28255Scgd
43361f28255Scgd /* let him disappear again */
43461f28255Scgd mdrush(md, 1);
43561f28255Scgd mondead(md);
43661f28255Scgd }
43761f28255Scgd obj = addinv(obj);
43861f28255Scgd (void) identify(obj); /* set known and do prinv() */
43961f28255Scgd }
44061f28255Scgd
44161f28255Scgd /* make md run through the cave */
4423ea4a95cSchristos void
mdrush(struct monst * md,boolean away)4431fa8a9a6Sdholland mdrush(struct monst *md, boolean away)
44461f28255Scgd {
4453ea4a95cSchristos int uroom = inroom(u.ux, u.uy);
44661f28255Scgd if (uroom >= 0) {
4473ea4a95cSchristos int tmp = rooms[uroom].fdoor;
4483ea4a95cSchristos int cnt = rooms[uroom].doorct;
4493ea4a95cSchristos int fx = u.ux, fy = u.uy;
45061f28255Scgd while (cnt--) {
45161f28255Scgd if (dist(fx, fy) < dist(doors[tmp].x, doors[tmp].y)) {
45261f28255Scgd fx = doors[tmp].x;
45361f28255Scgd fy = doors[tmp].y;
45461f28255Scgd }
45561f28255Scgd tmp++;
45661f28255Scgd }
45761f28255Scgd tmp_at(-1, md->data->mlet); /* open call */
45861f28255Scgd if (away) { /* interchange origin and destination */
45961f28255Scgd unpmon(md);
4603ea4a95cSchristos tmp = fx;
4613ea4a95cSchristos fx = md->mx;
4623ea4a95cSchristos md->mx = tmp;
4633ea4a95cSchristos tmp = fy;
4643ea4a95cSchristos fy = md->my;
4653ea4a95cSchristos md->my = tmp;
46661f28255Scgd }
46761f28255Scgd while (fx != md->mx || fy != md->my) {
4683ea4a95cSchristos int dx, dy, nfx = fx, nfy = fy, d1,
4693ea4a95cSchristos d2;
47061f28255Scgd
47161f28255Scgd tmp_at(fx, fy);
47261f28255Scgd d1 = DIST(fx, fy, md->mx, md->my);
4733ea4a95cSchristos for (dx = -1; dx <= 1; dx++)
4743ea4a95cSchristos for (dy = -1; dy <= 1; dy++)
47561f28255Scgd if (dx || dy) {
47661f28255Scgd d2 = DIST(fx + dx, fy + dy, md->mx, md->my);
47761f28255Scgd if (d2 < d1) {
47861f28255Scgd d1 = d2;
47961f28255Scgd nfx = fx + dx;
48061f28255Scgd nfy = fy + dy;
48161f28255Scgd }
48261f28255Scgd }
48361f28255Scgd if (nfx != fx || nfy != fy) {
48461f28255Scgd fx = nfx;
48561f28255Scgd fy = nfy;
48661f28255Scgd } else {
48761f28255Scgd if (!away) {
48861f28255Scgd md->mx = fx;
48961f28255Scgd md->my = fy;
49061f28255Scgd }
49161f28255Scgd break;
49261f28255Scgd }
49361f28255Scgd }
49461f28255Scgd tmp_at(-1, -1); /* close call */
49561f28255Scgd }
49661f28255Scgd if (!away)
49761f28255Scgd pmon(md);
49861f28255Scgd }
49961f28255Scgd
5003ea4a95cSchristos void
readmail(void)5011fa8a9a6Sdholland readmail(void)
5023ea4a95cSchristos {
50361f28255Scgd #ifdef DEF_MAILREADER /* This implies that UNIX is defined */
5043ea4a95cSchristos char *mr = 0;
50561f28255Scgd more();
50661f28255Scgd if (!(mr = getenv("MAILREADER")))
50761f28255Scgd mr = DEF_MAILREADER;
50861f28255Scgd if (child(1)) {
509acae6852Splunky execl(mr, mr, (char *)NULL);
51061f28255Scgd exit(1);
51161f28255Scgd }
5123ea4a95cSchristos #else /* DEF_MAILREADER */
51361f28255Scgd (void) page_file(mailbox, FALSE);
5143ea4a95cSchristos #endif /* DEF_MAILREADER */
5153ea4a95cSchristos /*
5163ea4a95cSchristos * get new stat; not entirely correct: there is a small time window
5173ea4a95cSchristos * where we do not see new mail
5183ea4a95cSchristos */
51961f28255Scgd getmailstatus();
52061f28255Scgd }
5213ea4a95cSchristos #endif /* MAIL */
52261f28255Scgd
5231fa8a9a6Sdholland /*
5241fa8a9a6Sdholland * normalize file name - we don't like ..'s or /'s
5251fa8a9a6Sdholland */
5263ea4a95cSchristos void
regularize(char * s)5271fa8a9a6Sdholland regularize(char *s)
52861f28255Scgd {
5293ea4a95cSchristos char *lp;
53061f28255Scgd
5313ea4a95cSchristos while ((lp = strchr(s, '.')) || (lp = strchr(s, '/')))
53261f28255Scgd *lp = '_';
53361f28255Scgd }
534