Wikia

Wikihack

Source:Mail.c

2,032pages on
this wiki
Talk0

Below is the full text to src/mail.c from NetHack 3.4.3. To link to a particular line, write [[mail.c#line123]], for example.

Top of file Edit

1.    /*	SCCS Id: @(#)mail.c	3.4	2002/01/13	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
5.    #include "hack.h"
6.    
7.    #ifdef MAIL
8.    #include "mail.h"
9.    
10.   /*
11.    * Notify user when new mail has arrived.  Idea by Merlyn Leroy.
12.    *
13.    * The mail daemon can move with less than usual restraint.  It can:
14.    *	- move diagonally from a door
15.    *	- use secret and closed doors
16.    *	- run through a monster ("Gangway!", etc.)
17.    *	- run over pools & traps
18.    *
19.    * Possible extensions:
20.    *	- Open the file MAIL and do fstat instead of stat for efficiency.
21.    *	  (But sh uses stat, so this cannot be too bad.)
22.    *	- Examine the mail and produce a scroll of mail named "From somebody".
23.    *	- Invoke MAILREADER in such a way that only this single letter is read.
24.    *	- Do something to the text when the scroll is enchanted or cancelled.
25.    *	- Make the daemon always appear at a stairwell, and have it find a
26.    *	  path to the hero.
27.    *
28.    * Note by Olaf Seibert: On the Amiga, we usually don't get mail.  So we go
29.    *			 through most of the effects at 'random' moments.
30.    * Note by Paul Winner:  The MSDOS port also 'fakes' the mail daemon at
31.    *			 random intervals.
32.    */
33.   
34.   STATIC_DCL boolean FDECL(md_start,(coord *));
35.   STATIC_DCL boolean FDECL(md_stop,(coord *, coord *));
36.   STATIC_DCL boolean FDECL(md_rush,(struct monst *,int,int));
37.   STATIC_DCL void FDECL(newmail, (struct mail_info *));
38.   
39.   extern char *viz_rmin, *viz_rmax;	/* line-of-sight limits (vision.c) */
40.   
41.   #ifdef OVL0
42.   
43.   # if !defined(UNIX) && !defined(VMS) && !defined(LAN_MAIL)
44.   int mustgetmail = -1;
45.   # endif
46.   
47.   #endif /* OVL0 */
48.   #ifdef OVLB
49.   
50.   # ifdef UNIX
51.   #include <sys/stat.h>
52.   #include <pwd.h>
53.   /* DON'T trust all Unices to declare getpwuid() in <pwd.h> */
54.   #  if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX)
55.   #   if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__))
56.   /* DO trust all SVR4 to typedef uid_t in <sys/types.h> (probably to a long) */
57.   #    if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX)
58.   extern struct passwd *FDECL(getpwuid,(uid_t));
59.   #    else
60.   extern struct passwd *FDECL(getpwuid,(int));
61.   #    endif
62.   #   endif
63.   #  endif
64.   static struct stat omstat,nmstat;
65.   static char *mailbox = (char *)0;
66.   static long laststattime;
67.   
68.   # if !defined(MAILPATH) && defined(AMS)	/* Just a placeholder for AMS */
69.   #  define MAILPATH "/dev/null"
70.   # endif
71.   # if !defined(MAILPATH) && (defined(LINUX) || defined(__osf__))
72.   #  define MAILPATH "/var/spool/mail/"
73.   # endif
74.   # if !defined(MAILPATH) && defined(__FreeBSD__)
75.   #  define MAILPATH "/var/mail/"
76.   # endif
77.   # if !defined(MAILPATH) && (defined(BSD) || defined(ULTRIX))
78.   #  define MAILPATH "/usr/spool/mail/"
79.   # endif
80.   # if !defined(MAILPATH) && (defined(SYSV) || defined(HPUX))
81.   #  define MAILPATH "/usr/mail/"
82.   # endif
83.   

getmailstatus Edit

84.   void
85.   getmailstatus()
86.   {
87.   	if(!mailbox && !(mailbox = nh_getenv("MAIL"))) {
88.   #  ifdef MAILPATH
89.   #   ifdef AMS
90.   	        struct passwd ppasswd;
91.   
92.   		(void) memcpy(&ppasswd, getpwuid(getuid()), sizeof(struct passwd));
93.   		if (ppasswd.pw_dir) {
94.   		     mailbox = (char *) alloc((unsigned) strlen(ppasswd.pw_dir)+sizeof(AMS_MAILBOX));
95.   		     Strcpy(mailbox, ppasswd.pw_dir);
96.   		     Strcat(mailbox, AMS_MAILBOX);
97.   		} else
98.   		  return;
99.   #   else
100.  		const char *pw_name = getpwuid(getuid())->pw_name;
101.  		mailbox = (char *) alloc(sizeof(MAILPATH)+strlen(pw_name));
102.  		Strcpy(mailbox, MAILPATH);
103.  		Strcat(mailbox, pw_name);
104.  #  endif /* AMS */
105.  #  else
106.  		return;
107.  #  endif
108.  	}
109.  	if(stat(mailbox, &omstat)){
110.  #  ifdef PERMANENT_MAILBOX
111.  		pline("Cannot get status of MAIL=\"%s\".", mailbox);
112.  		mailbox = 0;
113.  #  else
114.  		omstat.st_mtime = 0;
115.  #  endif
116.  	}
117.  }
118.  # endif /* UNIX */
119.  
120.  #endif /* OVLB */

md_start Edit

121.  #ifdef OVL0
122.  
123.  /*
124.   * Pick coordinates for a starting position for the mail daemon.  Called
125.   * from newmail() and newphone().
126.   */
127.  STATIC_OVL boolean
128.  md_start(startp)
129.      coord *startp;
130.  {
131.      coord testcc;	/* scratch coordinates */
132.      int row;		/* current row we are checking */
133.      int lax;		/* if TRUE, pick a position in sight. */
134.      int dd;		/* distance to current point */
135.      int max_distance;	/* max distance found so far */
136.  
137.      /*
138.       * If blind and not telepathic, then it doesn't matter what we pick ---
139.       * the hero is not going to see it anyway.  So pick a nearby position.
140.       */
141.      if (Blind && !Blind_telepat) {
142.  	if (!enexto(startp, u.ux, u.uy, (struct permonst *) 0))
143.  	    return FALSE;	/* no good posiitons */
144.  	return TRUE;
145.      }
146.  
147.      /*
148.       * Arrive at an up or down stairwell if it is in line of sight from the
149.       * hero.
150.       */
151.      if (couldsee(upstair.sx, upstair.sy)) {
152.  	startp->x = upstair.sx;
153.  	startp->y = upstair.sy;
154.  	return TRUE;
155.      }
156.      if (couldsee(dnstair.sx, dnstair.sy)) {
157.  	startp->x = dnstair.sx;
158.  	startp->y = dnstair.sy;
159.  	return TRUE;
160.      }
161.  
162.      /*
163.       * Try to pick a location out of sight next to the farthest position away
164.       * from the hero.  If this fails, try again, just picking the farthest
165.       * position that could be seen.  What we really ought to be doing is
166.       * finding a path from a stairwell...
167.       *
168.       * The arrays viz_rmin[] and viz_rmax[] are set even when blind.  These
169.       * are the LOS limits for each row.
170.       */
171.      lax = 0;	/* be picky */
172.      max_distance = -1;
173.  retry:
174.      for (row = 0; row < ROWNO; row++) {
175.  	if (viz_rmin[row] < viz_rmax[row]) {
176.  	    /* There are valid positions on this row. */
177.  	    dd = distu(viz_rmin[row],row);
178.  	    if (dd > max_distance) {
179.  		if (lax) {
180.  		    max_distance = dd;
181.  		    startp->y = row;
182.  		    startp->x = viz_rmin[row];
183.  		
184.  		} else if (enexto(&testcc, (xchar)viz_rmin[row], row,
185.  						(struct permonst *) 0) &&
186.  			   !cansee(testcc.x, testcc.y) &&
187.  			   couldsee(testcc.x, testcc.y)) {
188.  		    max_distance = dd;
189.  		    *startp = testcc;
190.  		}
191.  	    }
192.  	    dd = distu(viz_rmax[row],row);
193.  	    if (dd > max_distance) {
194.  		if (lax) {
195.  		    max_distance = dd;
196.  		    startp->y = row;
197.  		    startp->x = viz_rmax[row];
198.  		
199.  		} else if (enexto(&testcc, (xchar)viz_rmax[row], row,
200.  						(struct permonst *) 0) &&
201.  			   !cansee(testcc.x,testcc.y) &&
202.  			   couldsee(testcc.x, testcc.y)) {
203.  
204.  		    max_distance = dd;
205.  		    *startp = testcc;
206.  		}
207.  	    }
208.  	}
209.      }
210.  
211.      if (max_distance < 0) {
212.  	if (!lax) {
213.  	    lax = 1;		/* just find a position */
214.  	    goto retry;
215.  	}
216.  	return FALSE;
217.      }
218.  
219.      return TRUE;
220.  }
221.  

md_stop Edit

222.  /*
223.   * Try to choose a stopping point as near as possible to the starting
224.   * position while still adjacent to the hero.  If all else fails, try
225.   * enexto().  Use enexto() as a last resort because enexto() chooses
226.   * its point randomly, which is not what we want.
227.   */
228.  STATIC_OVL boolean
229.  md_stop(stopp, startp)
230.      coord *stopp;	/* stopping position (we fill it in) */
231.      coord *startp;	/* starting positon (read only) */
232.  {
233.      int x, y, distance, min_distance = -1;
234.  
235.      for (x = u.ux-1; x <= u.ux+1; x++)
236.  	for (y = u.uy-1; y <= u.uy+1; y++) {
237.  	    if (!isok(x, y) || (x == u.ux && y == u.uy)) continue;
238.  
239.  	    if (ACCESSIBLE(levl[x][y].typ) && !MON_AT(x,y)) {
240.  		distance = dist2(x,y,startp->x,startp->y);
241.  		if (min_distance < 0 || distance < min_distance ||
242.  			(distance == min_distance && rn2(2))) {
243.  		    stopp->x = x;
244.  		    stopp->y = y;
245.  		    min_distance = distance;
246.  		}
247.  	    }
248.  	}
249.  
250.      /* If we didn't find a good spot, try enexto(). */
251.      if (min_distance < 0 &&
252.  		!enexto(stopp, u.ux, u.uy, &mons[PM_MAIL_DAEMON]))
253.  	return FALSE;
254.  
255.      return TRUE;
256.  }
257.  

md_rush Edit

258.  /* Let the mail daemon have a larger vocabulary. */
259.  static NEARDATA const char *mail_text[] = {
260.      "Gangway!",
261.      "Look out!",
262.      "Pardon me!"
263.  };
264.  #define md_exclamations()	(mail_text[rn2(3)])
265.  
266.  /*
267.   * Make the mail daemon run through the dungeon.  The daemon will run over
268.   * any monsters that are in its path, but will replace them later.  Return
269.   * FALSE if the md gets stuck in a position where there is a monster.  Return
270.   * TRUE otherwise.
271.   */
272.  STATIC_OVL boolean
273.  md_rush(md,tx,ty)
274.      struct monst *md;
275.      register int tx, ty;		/* destination of mail daemon */
276.  {
277.      struct monst *mon;			/* displaced monster */
278.      register int dx, dy;		/* direction counters */
279.      int fx = md->mx, fy = md->my;	/* current location */
280.      int nfx = fx, nfy = fy,		/* new location */
281.  	d1, d2;				/* shortest distances */
282.  
283.      /*
284.       * It is possible that the monster at (fx,fy) is not the md when:
285.       * the md rushed the hero and failed, and is now starting back.
286.       */
287.      if (m_at(fx, fy) == md) {
288.  	remove_monster(fx, fy);		/* pick up from orig position */
289.  	newsym(fx, fy);
290.      }
291.  
292.      /*
293.       * At the beginning and exit of this loop, md is not placed in the
294.       * dungeon.
295.       */
296.      while (1) {
297.  	/* Find a good location next to (fx,fy) closest to (tx,ty). */
298.  	d1 = dist2(fx,fy,tx,ty);
299.  	for (dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
300.  	    if ((dx || dy) && isok(fx+dx,fy+dy) &&
301.  				       !IS_STWALL(levl[fx+dx][fy+dy].typ)) {
302.  		d2 = dist2(fx+dx,fy+dy,tx,ty);
303.  		if (d2 < d1) {
304.  		    d1 = d2;
305.  		    nfx = fx+dx;
306.  		    nfy = fy+dy;
307.  		}
308.  	    }
309.  
310.  	/* Break if the md couldn't find a new position. */
311.  	if (nfx == fx && nfy == fy) break;
312.  
313.  	fx = nfx;			/* this is our new position */
314.  	fy = nfy;
315.  
316.  	/* Break if the md reaches its destination. */
317.  	if (fx == tx && fy == ty) break;
318.  
319.  	if ((mon = m_at(fx,fy)) != 0)	/* save monster at this position */
320.  	    verbalize(md_exclamations());
321.  	else if (fx == u.ux && fy == u.uy)
322.  	    verbalize("Excuse me.");
323.  
324.  	place_monster(md,fx,fy);	/* put md down */
325.  	newsym(fx,fy);			/* see it */
326.  	flush_screen(0);		/* make sure md shows up */
327.  	delay_output();			/* wait a little bit */
328.  
329.  	/* Remove md from the dungeon.  Restore original mon, if necessary. */
330.  	if (mon) {
331.  	    if ((mon->mx != fx) || (mon->my != fy))
332.  		place_worm_seg(mon, fx, fy);
333.  	    else
334.  		place_monster(mon, fx, fy);
335.  	} else
336.  	    remove_monster(fx, fy);
337.  	newsym(fx,fy);
338.      }
339.  
340.      /*
341.       * Check for a monster at our stopping position (this is possible, but
342.       * very unlikely).  If one exists, then have the md leave in disgust.
343.       */
344.      if ((mon = m_at(fx, fy)) != 0) {
345.  	place_monster(md, fx, fy);	/* display md with text below */
346.  	newsym(fx, fy);
347.  	verbalize("This place's too crowded.  I'm outta here.");
348.  
349.  	if ((mon->mx != fx) || (mon->my != fy))	/* put mon back */
350.  	    place_worm_seg(mon, fx, fy);
351.  	else
352.  	    place_monster(mon, fx, fy);
353.  
354.  	newsym(fx, fy);
355.  	return FALSE;
356.      }
357.  
358.      place_monster(md, fx, fy);	/* place at final spot */
359.      newsym(fx, fy);
360.      flush_screen(0);
361.      delay_output();			/* wait a little bit */
362.  
363.      return TRUE;
364.  }
365.  

newmail Edit

366.  /* Deliver a scroll of mail. */
367.  /*ARGSUSED*/
368.  STATIC_OVL void
369.  newmail(info)
370.  struct mail_info *info;
371.  {
372.      struct monst *md;
373.      coord start, stop;
374.      boolean message_seen = FALSE;
375.  
376.      /* Try to find good starting and stopping places. */
377.      if (!md_start(&start) || !md_stop(&stop,&start)) goto give_up;
378.  
379.      /* Make the daemon.  Have it rush towards the hero. */
380.      if (!(md = makemon(&mons[PM_MAIL_DAEMON], start.x, start.y, NO_MM_FLAGS)))
381.  	 goto give_up;
382.      if (!md_rush(md, stop.x, stop.y)) goto go_back;
383.  
384.      message_seen = TRUE;
385.      verbalize("%s, %s!  %s.", Hello(md), plname, info->display_txt);
386.  
387.      if (info->message_typ) {
388.  	struct obj *obj = mksobj(SCR_MAIL, FALSE, FALSE);
389.  	if (distu(md->mx,md->my) > 2)
390.  	    verbalize("Catch!");
391.  	display_nhwindow(WIN_MESSAGE, FALSE);
392.  	if (info->object_nam) {
393.  	    obj = oname(obj, info->object_nam);
394.  	    if (info->response_cmd) {	/*(hide extension of the obj name)*/
395.  		int namelth = info->response_cmd - info->object_nam - 1;
396.  		if ( namelth <= 0 || namelth >= (int) obj->onamelth )
397.  		    impossible("mail delivery screwed up");
398.  		else
399.  		    *(ONAME(obj) + namelth) = '\0';
400.  		/* Note: renaming object will discard the hidden command. */
401.  	    }
402.  	}
403.  	obj = hold_another_object(obj, "Oops!",
404.  				  (const char *)0, (const char *)0);
405.      }
406.  
407.      /* zip back to starting location */
408.  go_back:
409.      (void) md_rush(md, start.x, start.y);
410.      mongone(md);
411.      /* deliver some classes of messages even if no daemon ever shows up */
412.  give_up:
413.      if (!message_seen && info->message_typ == MSG_OTHER)
414.  	pline("Hark!  \"%s.\"", info->display_txt);
415.  }
416.  

Miscellaneous systems Edit

417.  # if !defined(UNIX) && !defined(VMS) && !defined(LAN_MAIL)
418.  

ckmailstatus on miscellaneous systems Edit

419.  void
420.  ckmailstatus()
421.  {
422.  	if (u.uswallow || !flags.biff) return;
423.  	if (mustgetmail < 0) {
424.  #if defined(AMIGA) || defined(MSDOS) || defined(TOS)
425.  	    mustgetmail=(moves<2000)?(100+rn2(2000)):(2000+rn2(3000));
426.  #endif
427.  	    return;
428.  	}
429.  	if (--mustgetmail <= 0) {
430.  		static struct mail_info
431.  			deliver = {MSG_MAIL,"I have some mail for you",0,0};
432.  		newmail(&deliver);
433.  		mustgetmail = -1;
434.  	}
435.  }
436.  

readmail on miscellaneous systems Edit

437.  /*ARGSUSED*/
438.  void
439.  readmail(otmp)
440.  struct obj *otmp;
441.  {
442.      static char *junk[] = {
443.      "Please disregard previous letter.",
444.      "Welcome to NetHack.",
445.  #ifdef AMIGA
446.      "Only Amiga makes it possible.",
447.      "CATS have all the answers.",
448.  #endif
449.      "Report bugs to <devteam@nethack.org>.",
450.      "Invitation: Visit the NetHack web site at http://www.nethack.org!"
451.      };
452.  
453.      if (Blind) {
454.  	pline("Unfortunately you cannot see what it says.");
455.      } else
456.  	pline("It reads:  \"%s\"", junk[rn2(SIZE(junk))]);
457.  
458.  }
459.  
460.  # endif /* !UNIX && !VMS && !LAN_MAIL */
461.  

UNIX Edit

462.  # ifdef UNIX
463.  

ckmailstatus on UNIX Edit

464.  void
465.  ckmailstatus()
466.  {
467.  	if(!mailbox || u.uswallow || !flags.biff
468.  #  ifdef MAILCKFREQ
469.  		    || moves < laststattime + MAILCKFREQ
470.  #  endif
471.  							)
472.  		return;
473.  
474.  	laststattime = moves;
475.  	if(stat(mailbox, &nmstat)){
476.  #  ifdef PERMANENT_MAILBOX
477.  		pline("Cannot get status of MAIL=\"%s\" anymore.", mailbox);
478.  		mailbox = 0;
479.  #  else
480.  		nmstat.st_mtime = 0;
481.  #  endif
482.  	} else if(nmstat.st_mtime > omstat.st_mtime) {
483.  		if (nmstat.st_size) {
484.  		    static struct mail_info deliver = {
485.  #  ifndef NO_MAILREADER
486.  			MSG_MAIL, "I have some mail for you",
487.  #  else
488.  			/* suppress creation and delivery of scroll of mail */
489.  			MSG_OTHER, "You have some mail in the outside world",
490.  #  endif
491.  			0, 0
492.  		    };
493.  		    newmail(&deliver);
494.  		}
495.  		getmailstatus();	/* might be too late ... */
496.  	}
497.  }
498.  

readmail on UNIX Edit

499.  /*ARGSUSED*/
500.  void
501.  readmail(otmp)
502.  struct obj *otmp;
503.  {
504.  #  ifdef DEF_MAILREADER			/* This implies that UNIX is defined */
505.  	register const char *mr = 0;
506.  
507.  	display_nhwindow(WIN_MESSAGE, FALSE);
508.  	if(!(mr = nh_getenv("MAILREADER")))
509.  		mr = DEF_MAILREADER;
510.  
511.  	if(child(1)){
512.  		(void) execl(mr, mr, (char *)0);
513.  		terminate(EXIT_FAILURE);
514.  	}
515.  #  else
516.  #   ifndef AMS				/* AMS mailboxes are directories */
517.  	display_file(mailbox, TRUE);
518.  #   endif /* AMS */
519.  #  endif /* DEF_MAILREADER */
520.  
521.  	/* get new stat; not entirely correct: there is a small time
522.  	   window where we do not see new mail */
523.  	getmailstatus();
524.  }
525.  
526.  # endif /* UNIX */
527.  

VMS Edit

528.  # ifdef VMS
529.  
530.  extern NDECL(struct mail_info *parse_next_broadcast);
531.  
532.  volatile int broadcasts = 0;
533.  

ckmailstatus on VMS Edit

534.  void
535.  ckmailstatus()
536.  {
537.      struct mail_info *brdcst;
538.  
539.      if (u.uswallow || !flags.biff) return;
540.  
541.      while (broadcasts > 0) {	/* process all trapped broadcasts [until] */
542.  	broadcasts--;
543.  	if ((brdcst = parse_next_broadcast()) != 0) {
544.  	    newmail(brdcst);
545.  	    break;		/* only handle one real message at a time */
546.  	}
547.      }
548.  }
549.  

readmail on VMS Edit

550.  void
551.  readmail(otmp)
552.  struct obj *otmp;
553.  {
554.  #  ifdef SHELL	/* can't access mail reader without spawning subprocess */
555.      const char *txt, *cmd;
556.      char *p, buf[BUFSZ], qbuf[BUFSZ];
557.      int len;
558.  
559.      /* there should be a command hidden beyond the object name */
560.      txt = otmp->onamelth ? ONAME(otmp) : "";
561.      len = strlen(txt);
562.      cmd = (len + 1 < otmp->onamelth) ? txt + len + 1 : (char *) 0;
563.      if (!cmd || !*cmd) cmd = "SPAWN";
564.  
565.      Sprintf(qbuf, "System command (%s)", cmd);
566.      getlin(qbuf, buf);
567.      if (*buf != '\033') {
568.  	for (p = eos(buf); p > buf; *p = '\0')
569.  	    if (*--p != ' ') break;	/* strip trailing spaces */
570.  	if (*buf) cmd = buf;		/* use user entered command */
571.  	if (!strcmpi(cmd, "SPAWN") || !strcmp(cmd, "!"))
572.  	    cmd = (char *) 0;		/* interactive escape */
573.  
574.  	vms_doshell(cmd, TRUE);
575.  	(void) sleep(1);
576.      }
577.  #  endif /* SHELL */
578.  }
579.  
580.  # endif /* VMS */
581.  

LAN mail Edit

582.  # ifdef LAN_MAIL
583.  

ckmailstatus with LAN mail Edit

584.  void
585.  ckmailstatus()
586.  {
587.  	static int laststattime = 0;
588.  	
589.  	if(u.uswallow || !flags.biff
590.  #  ifdef MAILCKFREQ
591.  		    || moves < laststattime + MAILCKFREQ
592.  #  endif
593.  							)
594.  		return;
595.  
596.  	laststattime = moves;
597.  	if (lan_mail_check()) {
598.  		    static struct mail_info deliver = {
599.  #  ifndef NO_MAILREADER
600.  			MSG_MAIL, "I have some mail for you",
601.  #  else
602.  			/* suppress creation and delivery of scroll of mail */
603.  			MSG_OTHER, "You have some mail in the outside world",
604.  #  endif
605.  			0, 0
606.  		    };
607.  		    newmail(&deliver);
608.  	}
609.  }
610.  

readmail with LAN mail Edit

611.  /*ARGSUSED*/
612.  void
613.  readmail(otmp)
614.  struct obj *otmp;
615.  {
616.  	lan_mail_read(otmp);
617.  }
618.  
619.  # endif /* LAN_MAIL */
620.  
621.  #endif /* OVL0 */
622.  
623.  #endif /* MAIL */
624.  
625.  /*mail.c*/

Around Wikia's network

Random Wiki