OSDN Git Service

add translation
[jnethack/source.git] / src / mail.c
1 /* NetHack 3.6  mail.c  $NHDT-Date: 1545597424 2018/12/23 20:37:04 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.39 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Pasi Kallinen, 2018. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #include "hack.h"
12
13 #ifdef MAIL
14 #ifdef SIMPLE_MAIL
15 # include <fcntl.h>
16 # include <errno.h>
17 #endif /* SIMPLE_MAIL */
18 #include "mail.h"
19
20 /*
21  * Notify user when new mail has arrived.  Idea by Merlyn Leroy.
22  *
23  * The mail daemon can move with less than usual restraint.  It can:
24  *      - move diagonally from a door
25  *      - use secret and closed doors
26  *      - run through a monster ("Gangway!", etc.)
27  *      - run over pools & traps
28  *
29  * Possible extensions:
30  *      - Open the file MAIL and do fstat instead of stat for efficiency.
31  *        (But sh uses stat, so this cannot be too bad.)
32  *      - Examine the mail and produce a scroll of mail named "From somebody".
33  *      - Invoke MAILREADER in such a way that only this single mail is read.
34  *      - Do something to the text when the scroll is enchanted or cancelled.
35  *      - Make the daemon always appear at a stairwell, and have it find a
36  *        path to the hero.
37  *
38  * Note by Olaf Seibert: On the Amiga, we usually don't get mail.  So we go
39  *                       through most of the effects at 'random' moments.
40  * Note by Paul Winner:  The MSDOS port also 'fakes' the mail daemon at
41  *                       random intervals.
42  */
43
44 STATIC_DCL boolean FDECL(md_start, (coord *));
45 STATIC_DCL boolean FDECL(md_stop, (coord *, coord *));
46 STATIC_DCL boolean FDECL(md_rush, (struct monst *, int, int));
47 STATIC_DCL void FDECL(newmail, (struct mail_info *));
48
49 extern char *viz_rmin, *viz_rmax; /* line-of-sight limits (vision.c) */
50
51 #if !defined(UNIX) && !defined(VMS)
52 int mustgetmail = -1;
53 #endif
54
55 #ifdef UNIX
56 #include <sys/stat.h>
57 #include <pwd.h>
58 /* DON'T trust all Unices to declare getpwuid() in <pwd.h> */
59 #if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX)
60 #if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__))
61 /* DO trust all SVR4 to typedef uid_t in <sys/types.h> (probably to a long) */
62 #if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX)
63 extern struct passwd *FDECL(getpwuid, (uid_t));
64 #else
65 extern struct passwd *FDECL(getpwuid, (int));
66 #endif
67 #endif
68 #endif
69 static struct stat omstat, nmstat;
70 static char *mailbox = (char *) 0;
71 static long laststattime;
72
73 #if !defined(MAILPATH) && defined(AMS) /* Just a placeholder for AMS */
74 #define MAILPATH "/dev/null"
75 #endif
76 #if !defined(MAILPATH) && (defined(LINUX) || defined(__osf__))
77 #define MAILPATH "/var/spool/mail/"
78 #endif
79 #if !defined(MAILPATH) && defined(__FreeBSD__)
80 #define MAILPATH "/var/mail/"
81 #endif
82 #if !defined(MAILPATH) && (defined(BSD) || defined(ULTRIX))
83 #define MAILPATH "/usr/spool/mail/"
84 #endif
85 #if !defined(MAILPATH) && (defined(SYSV) || defined(HPUX))
86 #define MAILPATH "/usr/mail/"
87 #endif
88
89 void
90 free_maildata()
91 {
92     if (mailbox)
93         free((genericptr_t) mailbox), mailbox = (char *) 0;
94 }
95
96 void
97 getmailstatus()
98 {
99     if (mailbox) {
100         ; /* no need to repeat the setup */
101     } else if ((mailbox = nh_getenv("MAIL")) != 0) {
102         mailbox = dupstr(mailbox);
103 #ifdef MAILPATH
104     } else  {
105 #ifdef AMS
106         struct passwd ppasswd;
107
108         (void) memcpy(&ppasswd, getpwuid(getuid()), sizeof (struct passwd));
109         if (ppasswd.pw_dir) {
110             /* note: 'sizeof "LITERAL"' includes +1 for terminating '\0' */
111             mailbox = (char *) alloc((unsigned) (strlen(ppasswd.pw_dir)
112                                                  + sizeof AMS_MAILBOX));
113             Strcpy(mailbox, ppasswd.pw_dir);
114             Strcat(mailbox, AMS_MAILBOX);
115         }
116 #else
117         const char *pw_name = getpwuid(getuid())->pw_name;
118
119         /* note: 'sizeof "LITERAL"' includes +1 for terminating '\0' */
120         mailbox = (char *) alloc((unsigned) (strlen(pw_name)
121                                              + sizeof MAILPATH));
122         Strcpy(mailbox, MAILPATH);
123         Strcat(mailbox, pw_name);
124 #endif /* AMS */
125 #endif /* MAILPATH */
126     }
127
128     debugpline3("mailbox=%c%s%c",
129                 mailbox ? '\"' : '<',
130                 mailbox ? mailbox : "null",
131                 mailbox ? '\"' : '>');
132
133     if (mailbox && stat(mailbox, &omstat)) {
134 #ifdef PERMANENT_MAILBOX
135         pline("Cannot get status of MAIL=\"%s\".", mailbox);
136         free_maildata(); /* set 'mailbox' to Null */
137 #else
138         omstat.st_mtime = 0;
139 #endif
140     }
141 }
142 #endif /* UNIX */
143
144 /*
145  * Pick coordinates for a starting position for the mail daemon.  Called
146  * from newmail() and newphone().
147  */
148 STATIC_OVL boolean
149 md_start(startp)
150 coord *startp;
151 {
152     coord testcc;     /* scratch coordinates */
153     int row;          /* current row we are checking */
154     int lax;          /* if TRUE, pick a position in sight. */
155     int dd;           /* distance to current point */
156     int max_distance; /* max distance found so far */
157
158     /*
159      * If blind and not telepathic, then it doesn't matter what we pick ---
160      * the hero is not going to see it anyway.  So pick a nearby position.
161      */
162     if (Blind && !Blind_telepat) {
163         if (!enexto(startp, u.ux, u.uy, (struct permonst *) 0))
164             return FALSE; /* no good positions */
165         return TRUE;
166     }
167
168     /*
169      * Arrive at an up or down stairwell if it is in line of sight from the
170      * hero.
171      */
172     if (couldsee(upstair.sx, upstair.sy)) {
173         startp->x = upstair.sx;
174         startp->y = upstair.sy;
175         return TRUE;
176     }
177     if (couldsee(dnstair.sx, dnstair.sy)) {
178         startp->x = dnstair.sx;
179         startp->y = dnstair.sy;
180         return TRUE;
181     }
182
183     /*
184      * Try to pick a location out of sight next to the farthest position away
185      * from the hero.  If this fails, try again, just picking the farthest
186      * position that could be seen.  What we really ought to be doing is
187      * finding a path from a stairwell...
188      *
189      * The arrays viz_rmin[] and viz_rmax[] are set even when blind.  These
190      * are the LOS limits for each row.
191      */
192     lax = 0; /* be picky */
193     max_distance = -1;
194  retry:
195     for (row = 0; row < ROWNO; row++) {
196         if (viz_rmin[row] < viz_rmax[row]) {
197             /* There are valid positions on this row. */
198             dd = distu(viz_rmin[row], row);
199             if (dd > max_distance) {
200                 if (lax) {
201                     max_distance = dd;
202                     startp->y = row;
203                     startp->x = viz_rmin[row];
204
205                 } else if (enexto(&testcc, (xchar) viz_rmin[row], row,
206                                   (struct permonst *) 0)
207                            && !cansee(testcc.x, testcc.y)
208                            && couldsee(testcc.x, testcc.y)) {
209                     max_distance = dd;
210                     *startp = testcc;
211                 }
212             }
213             dd = distu(viz_rmax[row], row);
214             if (dd > max_distance) {
215                 if (lax) {
216                     max_distance = dd;
217                     startp->y = row;
218                     startp->x = viz_rmax[row];
219
220                 } else if (enexto(&testcc, (xchar) viz_rmax[row], row,
221                                   (struct permonst *) 0)
222                            && !cansee(testcc.x, testcc.y)
223                            && couldsee(testcc.x, testcc.y)) {
224                     max_distance = dd;
225                     *startp = testcc;
226                 }
227             }
228         }
229     }
230
231     if (max_distance < 0) {
232         if (!lax) {
233             lax = 1; /* just find a position */
234             goto retry;
235         }
236         return FALSE;
237     }
238
239     return TRUE;
240 }
241
242 /*
243  * Try to choose a stopping point as near as possible to the starting
244  * position while still adjacent to the hero.  If all else fails, try
245  * enexto().  Use enexto() as a last resort because enexto() chooses
246  * its point randomly, which is not what we want.
247  */
248 STATIC_OVL boolean
249 md_stop(stopp, startp)
250 coord *stopp;  /* stopping position (we fill it in) */
251 coord *startp; /* starting position (read only) */
252 {
253     int x, y, distance, min_distance = -1;
254
255     for (x = u.ux - 1; x <= u.ux + 1; x++)
256         for (y = u.uy - 1; y <= u.uy + 1; y++) {
257             if (!isok(x, y) || (x == u.ux && y == u.uy))
258                 continue;
259
260             if (accessible(x, y) && !MON_AT(x, y)) {
261                 distance = dist2(x, y, startp->x, startp->y);
262                 if (min_distance < 0 || distance < min_distance
263                     || (distance == min_distance && rn2(2))) {
264                     stopp->x = x;
265                     stopp->y = y;
266                     min_distance = distance;
267                 }
268             }
269         }
270
271     /* If we didn't find a good spot, try enexto(). */
272     if (min_distance < 0 && !enexto(stopp, u.ux, u.uy, &mons[PM_MAIL_DAEMON]))
273         return FALSE;
274
275     return TRUE;
276 }
277
278 /* Let the mail daemon have a larger vocabulary. */
279 #if 0 /*JP*/
280 static NEARDATA const char *mail_text[] = { "Gangway!", "Look out!",
281                                             "Pardon me!" };
282 #else
283 static NEARDATA const char *mail_text[] = { "\82Ç\82¢\82½\82Ç\82¢\82½\81I", "\8bC\82ð\82Â\82¯\82ë\81I",
284                                             "\82\82á\82Ü\82·\82é\82æ\81I" };
285 #endif
286 #define md_exclamations() (mail_text[rn2(3)])
287
288 /*
289  * Make the mail daemon run through the dungeon.  The daemon will run over
290  * any monsters that are in its path, but will replace them later.  Return
291  * FALSE if the md gets stuck in a position where there is a monster.  Return
292  * TRUE otherwise.
293  */
294 STATIC_OVL boolean
295 md_rush(md, tx, ty)
296 struct monst *md;
297 register int tx, ty; /* destination of mail daemon */
298 {
299     struct monst *mon;            /* displaced monster */
300     register int dx, dy;          /* direction counters */
301     int fx = md->mx, fy = md->my; /* current location */
302     int nfx = fx, nfy = fy,       /* new location */
303         d1, d2;                   /* shortest distances */
304
305     /*
306      * It is possible that the monster at (fx,fy) is not the md when:
307      * the md rushed the hero and failed, and is now starting back.
308      */
309     if (m_at(fx, fy) == md) {
310         remove_monster(fx, fy); /* pick up from orig position */
311         newsym(fx, fy);
312     }
313
314     /*
315      * At the beginning and exit of this loop, md is not placed in the
316      * dungeon.
317      */
318     while (1) {
319         /* Find a good location next to (fx,fy) closest to (tx,ty). */
320         d1 = dist2(fx, fy, tx, ty);
321         for (dx = -1; dx <= 1; dx++)
322             for (dy = -1; dy <= 1; dy++)
323                 if ((dx || dy) && isok(fx + dx, fy + dy)
324                     && !IS_STWALL(levl[fx + dx][fy + dy].typ)) {
325                     d2 = dist2(fx + dx, fy + dy, tx, ty);
326                     if (d2 < d1) {
327                         d1 = d2;
328                         nfx = fx + dx;
329                         nfy = fy + dy;
330                     }
331                 }
332
333         /* Break if the md couldn't find a new position. */
334         if (nfx == fx && nfy == fy)
335             break;
336
337         fx = nfx; /* this is our new position */
338         fy = nfy;
339
340         /* Break if the md reaches its destination. */
341         if (fx == tx && fy == ty)
342             break;
343
344         if ((mon = m_at(fx, fy)) != 0) /* save monster at this position */
345             verbalize1(md_exclamations());
346         else if (fx == u.ux && fy == u.uy)
347 /*JP
348             verbalize("Excuse me.");
349 */
350             verbalize("\82¿\82å\82Á\82Æ\82µ\82Â\82ê\82¢\81D");
351
352         if (mon)
353             remove_monster(fx, fy);
354         place_monster(md, fx, fy); /* put md down */
355         newsym(fx, fy);            /* see it */
356         flush_screen(0);           /* make sure md shows up */
357         delay_output();            /* wait a little bit */
358
359         /* Remove md from the dungeon.  Restore original mon, if necessary. */
360         remove_monster(fx, fy);
361         if (mon) {
362             if ((mon->mx != fx) || (mon->my != fy))
363                 place_worm_seg(mon, fx, fy);
364             else
365                 place_monster(mon, fx, fy);
366         }
367         newsym(fx, fy);
368     }
369
370     /*
371      * Check for a monster at our stopping position (this is possible, but
372      * very unlikely).  If one exists, then have the md leave in disgust.
373      */
374     if ((mon = m_at(fx, fy)) != 0) {
375         remove_monster(fx, fy);
376         place_monster(md, fx, fy); /* display md with text below */
377         newsym(fx, fy);
378 /*JP
379         verbalize("This place's too crowded.  I'm outta here.");
380 */
381         verbalize("\82±\82±\82Í\8d¬\82Ý\82·\82¬\81D\82±\82±\82Å\91Ò\82Á\82Ä\82é\82æ\81D");
382         remove_monster(fx, fy);
383
384         if ((mon->mx != fx) || (mon->my != fy)) /* put mon back */
385             place_worm_seg(mon, fx, fy);
386         else
387             place_monster(mon, fx, fy);
388
389         newsym(fx, fy);
390         return FALSE;
391     }
392
393     place_monster(md, fx, fy); /* place at final spot */
394     newsym(fx, fy);
395     flush_screen(0);
396     delay_output(); /* wait a little bit */
397
398     return TRUE;
399 }
400
401 /* Deliver a scroll of mail. */
402 /*ARGSUSED*/
403 STATIC_OVL void
404 newmail(info)
405 struct mail_info *info;
406 {
407     struct monst *md;
408     coord start, stop;
409     boolean message_seen = FALSE;
410
411     /* Try to find good starting and stopping places. */
412     if (!md_start(&start) || !md_stop(&stop, &start))
413         goto give_up;
414
415     /* Make the daemon.  Have it rush towards the hero. */
416     if (!(md = makemon(&mons[PM_MAIL_DAEMON], start.x, start.y, NO_MM_FLAGS)))
417         goto give_up;
418     if (!md_rush(md, stop.x, stop.y))
419         goto go_back;
420
421     message_seen = TRUE;
422 #if 0 /*JP*/
423     verbalize("%s, %s!  %s.", Hello(md), plname, info->display_txt);
424 #else
425     verbalize("%s\81I%s\81D", Hello(md), info->display_txt);
426 #endif
427
428     if (info->message_typ) {
429         struct obj *obj = mksobj(SCR_MAIL, FALSE, FALSE);
430
431         if (info->object_nam)
432             obj = oname(obj, info->object_nam);
433         if (info->response_cmd)
434             new_omailcmd(obj, info->response_cmd);
435
436         if (distu(md->mx, md->my) > 2)
437 /*JP
438             verbalize("Catch!");
439 */
440             verbalize("\82Ù\82ç\82æ\81I");
441         display_nhwindow(WIN_MESSAGE, FALSE);
442 #if 0 /*JP*/
443         obj = hold_another_object(obj, "Oops!", (const char *) 0,
444                                   (const char *) 0);
445 #else
446         obj = hold_another_object(obj, "\82¨\82Á\82Æ\81I", (const char *) 0,
447                                   (const char *) 0);
448 #endif
449         nhUse(obj);
450     }
451
452  go_back:
453     /* zip back to starting location */
454     if (!md_rush(md, start.x, start.y))
455         md->mx = md->my = 0; /* for mongone, md is not on map */
456     mongone(md);
457
458  give_up:
459     /* deliver some classes of messages even if no daemon ever shows up */
460     if (!message_seen && info->message_typ == MSG_OTHER)
461 /*JP
462         pline("Hark!  \"%s.\"", info->display_txt);
463 */
464         pline("\81u%s\81D\81v\82Æ\8c¾\82¤\82±\82Æ\82¾\81I", info->display_txt);
465 }
466
467 #if !defined(UNIX) && !defined(VMS)
468
469 void
470 ckmailstatus()
471 {
472     if (u.uswallow || !flags.biff)
473         return;
474     if (mustgetmail < 0) {
475 #if defined(AMIGA) || defined(MSDOS) || defined(TOS)
476         mustgetmail = (moves < 2000) ? (100 + rn2(2000)) : (2000 + rn2(3000));
477 #endif
478         return;
479     }
480     if (--mustgetmail <= 0) {
481         static struct mail_info deliver = {
482 /*JP
483             MSG_MAIL, "I have some mail for you", 0, 0
484 */
485             MSG_MAIL, "\83\81\81[\83\8b\82ð\8e\9d\82Á\82Ä\82«\82½\82æ", 0, 0
486         };
487         newmail(&deliver);
488         mustgetmail = -1;
489     }
490 }
491
492 /*ARGSUSED*/
493 void
494 readmail(otmp)
495 struct obj *otmp UNUSED;
496 {
497     static char *junk[] = {
498         NULL, /* placeholder for "Report bugs to <devteam@nethack.org>.", */
499 /*JP
500         "Please disregard previous letter.", "Welcome to NetHack.",
501 */
502         "\91O\82Ì\83\81\81[\83\8b\82Í\96Y\82ê\82Ä\82­\82¾\82³\82¢\81D", "JNetHack\82Ö\82æ\82¤\82±\82»\81I",
503 #ifdef AMIGA
504         "Only Amiga makes it possible.", "CATS have all the answers.",
505 #endif
506 /*JP
507         "This mail complies with the Yendorian Anti-Spam Act (YASA)",
508 */
509         "\82±\82Ì\83\81\81[\83\8b\82Í\83C\83F\83\93\83_\81[\83X\83p\83\80\91Î\8dô\96@(YASA)\82É\8f\80\8b\92\82µ\82Ä\82¢\82Ü\82·\81D",
510 /*JP
511         "Please find enclosed a small token to represent your Owlbear",
512 */
513         "\82 \82È\82½\82Ì\83A\83E\83\8b\83x\83A\82ð\95\\8c»\82·\82é\82½\82ß\82É\93¯\95\95\82µ\82½\8f¬\82³\82¢\83g\81[\83N\83\93\82ð\92T\82µ\82Ä\82­\82¾\82³\82¢",
514 /*JP
515         "**FR33 P0T10N 0F FULL H34L1NG**",
516 */
517         "**\8a®\91S\89ñ\95\9c\82Ì\96ò\83v\83\8c\83[\83\93\83g**",
518 /*JP
519         "Please return to sender (Asmodeus)",
520 */
521         "\91\97\90M\8eÒ(\83A\83X\83\82\83f\83E\83X)\82É\91\97\82è\95Ô\82µ\82Ä\82­\82¾\82³\82¢",
522 /*JP
523      "Buy a potion of gain level for only $19.99!  Guaranteed to be blessed!",
524 */
525       "\83\8c\83x\83\8b\83A\83b\83v\82Ì\96ò\82ª\82½\82Á\82½\82Ì1980\89~!\8fj\95\9f\95Û\8fØ!",
526 /*JP
527         "Invitation: Visit the NetHack web site at http://www.nethack.org!"
528 */
529         "\8fµ\91Ò\8fó: NetHack \83E\83F\83u\83T\83C\83g http://www.nethack.org \82É\97\88\82Ä\82Ë!"
530     };
531
532     /* XXX replace with more general substitution code and add local
533      * contact message.  Also use DEVTEAM_URL */
534     if (junk[0] == NULL) {
535 #define BUGS_FORMAT "Report bugs to <%s>."
536         /* +2 from '%s' suffices as substitute for usual +1 for terminator */
537         junk[0] = (char *) alloc(strlen(BUGS_FORMAT) + strlen(DEVTEAM_EMAIL));
538         Sprintf(junk[0], BUGS_FORMAT, DEVTEAM_EMAIL);
539 #undef BUGS_FORMAT
540     }
541     if (Blind) {
542 /*JP
543         pline("Unfortunately you cannot see what it says.");
544 */
545         pline("\8ec\94O\82È\82ª\82ç\89½\82Æ\8f\91\82¢\82Ä\82 \82é\82Ì\82©\8c©\82é\82±\82Æ\82ª\82Å\82«\82È\82¢\81D");
546     } else
547 /*JP
548         pline("It reads:  \"%s\"", junk[rn2(SIZE(junk))]);
549 */
550         pline("\82»\82ê\82ð\93Ç\82ñ\82¾\81F\"%s\"", junk[rn2(SIZE(junk))]);
551 }
552
553 #endif /* !UNIX && !VMS */
554
555 #ifdef UNIX
556
557 void
558 ckmailstatus()
559 {
560     ck_server_admin_msg();
561
562     if (!mailbox || u.uswallow || !flags.biff
563 #ifdef MAILCKFREQ
564         || moves < laststattime + MAILCKFREQ
565 #endif
566         )
567         return;
568
569     laststattime = moves;
570     if (stat(mailbox, &nmstat)) {
571 #ifdef PERMANENT_MAILBOX
572         pline("Cannot get status of MAIL=\"%s\" anymore.", mailbox);
573         free_maildata();
574 #else
575         nmstat.st_mtime = 0;
576 #endif
577     } else if (nmstat.st_mtime > omstat.st_mtime) {
578         if (nmstat.st_size) {
579             static struct mail_info deliver = {
580 #ifndef NO_MAILREADER
581 /*JP
582                 MSG_MAIL, "I have some mail for you",
583 */
584                 MSG_MAIL, "\83\81\83C\83\8b\82ð\8e\9d\82Á\82Ä\82«\82½\82æ",
585 #else
586                 /* suppress creation and delivery of scroll of mail */
587 /*JP
588                 MSG_OTHER, "You have some mail in the outside world",
589 */
590                 MSG_OTHER, "\8aO\82Ì\90¢\8aE\82©\82ç\82Ì\83\81\81[\83\8b\82¾",
591 #endif
592                 0, 0
593             };
594             newmail(&deliver);
595         }
596         getmailstatus(); /* might be too late ... */
597     }
598 }
599
600 #if defined(SIMPLE_MAIL) || defined(SERVER_ADMIN_MSG)
601 void
602 read_simplemail(mbox, adminmsg)
603 char *mbox;
604 boolean adminmsg;
605 {
606     FILE* mb = fopen(mbox, "r");
607     char curline[128], *msg;
608     boolean seen_one_already = FALSE;
609 #ifdef SIMPLE_MAIL
610     struct flock fl = { 0 };
611 #endif
612     const char *msgfrom = adminmsg
613 #if 0 /*JP*/
614         ? "The voice of %s booms through the caverns:"
615         : "This message is from '%s'.";
616 #else
617         ? "%s\82Ì\90º\82ª\93´\8cA\82É\8b¿\82«\82í\82½\82Á\82½:"
618         : "\82±\82ê\82Í'%s'\82©\82ç\82Ì\83\81\83b\83Z\81[\83W\82¾\81D";
619 #endif
620
621     if (!mb)
622         goto bail;
623
624 #ifdef SIMPLE_MAIL
625     fl.l_type = F_RDLCK;
626     fl.l_whence = SEEK_SET;
627     fl.l_start = 0;
628     fl.l_len = 0;
629     errno = 0;
630 #endif
631
632     /* Allow this call to block. */
633     if (!adminmsg
634 #ifdef SIMPLE_MAIL
635         && fcntl (fileno (mb), F_SETLKW, &fl) == -1
636 #endif
637         )
638         goto bail;
639
640     while (fgets(curline, 128, mb) != NULL) {
641         if (!adminmsg) {
642 #ifdef SIMPLE_MAIL
643             fl.l_type = F_UNLCK;
644             fcntl (fileno(mb), F_UNLCK, &fl);
645 #endif
646 #if 0 /*JP*/
647             pline("There is a%s message on this scroll.",
648                   seen_one_already ? "nother" : "");
649 #else
650             pline("\82±\82Ì\8aª\95¨\82É\82Í%s\83\81\83b\83Z\81[\83W\82ª\82 \82é\81D",
651                   seen_one_already ? "\82Ü\82¾" : "");
652 #endif
653         }
654         msg = strchr(curline, ':');
655
656         if (!msg)
657             goto bail;
658
659         *msg = '\0';
660         msg++;
661         msg[strlen(msg) - 1] = '\0'; /* kill newline */
662
663         pline(msgfrom, curline);
664         if (adminmsg)
665             verbalize(msg);
666         else
667 /*JP
668             pline("It reads: \"%s\".", msg);
669 */
670             pline("\82»\82ê\82ð\93Ç\82ñ\82¾\81F\81u%s\81v", msg);
671
672         seen_one_already = TRUE;
673 #ifdef SIMPLE_MAIL
674         errno = 0;
675         if (!adminmsg) {
676             fl.l_type = F_RDLCK;
677             fcntl(fileno(mb), F_SETLKW, &fl);
678         }
679 #endif
680     }
681
682 #ifdef SIMPLE_MAIL
683     if (!adminmsg) {
684         fl.l_type = F_UNLCK;
685         fcntl(fileno(mb), F_UNLCK, &fl);
686     }
687 #endif
688     fclose(mb);
689     if (adminmsg)
690         display_nhwindow(WIN_MESSAGE, TRUE);
691     else
692         unlink(mailbox);
693     return;
694  bail:
695     /* bail out _professionally_ */
696     if (!adminmsg)
697 /*JP
698         pline("It appears to be all gibberish.");
699 */
700         pline("\82±\82ê\82Í\82Ü\82Á\82½\82­\82¿\82ñ\82Õ\82ñ\82©\82ñ\82Õ\82ñ\82¾\81D");
701 }
702 #endif /* SIMPLE_MAIL */
703
704 void
705 ck_server_admin_msg()
706 {
707 #ifdef SERVER_ADMIN_MSG
708     static struct stat ost,nst;
709     static long lastchk = 0;
710
711     if (moves < lastchk + SERVER_ADMIN_MSG_CKFREQ) return;
712     lastchk = moves;
713
714     if (!stat(SERVER_ADMIN_MSG, &nst)) {
715         if (nst.st_mtime > ost.st_mtime)
716             read_simplemail(SERVER_ADMIN_MSG, TRUE);
717         ost.st_mtime = nst.st_mtime;
718     }
719 #endif /* SERVER_ADMIN_MSG */
720 }
721
722 /*ARGSUSED*/
723 void
724 readmail(otmp)
725 struct obj *otmp UNUSED;
726 {
727 #ifdef DEF_MAILREADER /* This implies that UNIX is defined */
728     register const char *mr = 0;
729 #endif /* DEF_MAILREADER */
730 #ifdef SIMPLE_MAIL
731     read_simplemail(mailbox, FALSE);
732     return;
733 #endif /* SIMPLE_MAIL */
734 #ifdef DEF_MAILREADER /* This implies that UNIX is defined */
735     if (iflags.debug_fuzzer)
736         return;
737     display_nhwindow(WIN_MESSAGE, FALSE);
738     if (!(mr = nh_getenv("MAILREADER")))
739         mr = DEF_MAILREADER;
740
741     if (child(1)) {
742         (void) execl(mr, mr, (char *) 0);
743         nh_terminate(EXIT_FAILURE);
744     }
745 #else
746 #ifndef AMS /* AMS mailboxes are directories */
747     display_file(mailbox, TRUE);
748 #endif /* AMS */
749 #endif /* DEF_MAILREADER */
750
751     /* get new stat; not entirely correct: there is a small time
752        window where we do not see new mail */
753     getmailstatus();
754 }
755
756 #endif /* UNIX */
757
758 #ifdef VMS
759
760 extern NDECL(struct mail_info *parse_next_broadcast);
761
762 volatile int broadcasts = 0;
763
764 void
765 ckmailstatus()
766 {
767     struct mail_info *brdcst;
768
769     if (iflags.debug_fuzzer)
770         return;
771     if (u.uswallow || !flags.biff)
772         return;
773
774     while (broadcasts > 0) { /* process all trapped broadcasts [until] */
775         broadcasts--;
776         if ((brdcst = parse_next_broadcast()) != 0) {
777             newmail(brdcst);
778             break; /* only handle one real message at a time */
779         }
780     }
781 }
782
783 void
784 readmail(otmp)
785 struct obj *otmp;
786 {
787 #ifdef SHELL /* can't access mail reader without spawning subprocess */
788     const char *txt, *cmd;
789     char *p, buf[BUFSZ] = DUMMY, qbuf[BUFSZ];
790     int len;
791
792     /* there should be a command in OMAILCMD */
793     if (has_oname(otmp))
794         txt = ONAME(otmp);
795     else
796         txt = "";
797     len = strlen(txt);
798     if (has_omailcmd(otmp))
799         cmd = OMAILCMD(otmp);
800     if (!cmd || !*cmd)
801         cmd = "SPAWN";
802
803     Sprintf(qbuf, "System command (%s)", cmd);
804     getlin(qbuf, buf);
805     if (*buf != '\033') {
806         for (p = eos(buf); p > buf; *p = '\0')
807             if (*--p != ' ')
808                 break; /* strip trailing spaces */
809         if (*buf)
810             cmd = buf; /* use user entered command */
811         if (!strcmpi(cmd, "SPAWN") || !strcmp(cmd, "!"))
812             cmd = (char *) 0; /* interactive escape */
813
814         vms_doshell(cmd, TRUE);
815         (void) sleep(1);
816     }
817 #else
818     nhUse(otmp);
819 #endif /* SHELL */
820 }
821
822 #endif /* VMS */
823 #endif /* MAIL */
824
825 /*mail.c*/