in sys/vms/vmsmail.c [42:293]
extern unsigned long smg$create_pasteboard(), smg$get_broadcast_message(),
smg$set_broadcast_trapping(), smg$disable_broadcast_trapping();
extern volatile int broadcasts; /* defining declaration in mail.c */
static long pasteboard_id = 0; /* SMG's magic cookie */
/*
* Mail (et al) overview:
*
* When a broadcast is asynchronously captured, a volatile counter
* ('broadcasts') is incremented. Each player turn, ckmailstatus() polls
* the counter and calls parse_next_broadcast() if it's positive; this
* returns some display text, object name, and response command, which is
* passed to newmail(). Routine newmail() generates a mail-daemon monster
* who approaches the character, "speaks" the display text, and delivers
* a scroll of mail pre-named to the object name; the response command is
* also attached to the scroll's oextra->omailcmd field.
* Unrecognized broadcasts result in the mail-daemon
* arriving and announcing the display text, but no scroll being created.
* If SHELL is undefined, then all broadcasts are treated as 'other'; since
* no subproceses are allowed, there'd be no way to respond to the scroll.
*
* When a scroll of mail is read by the character, readmail() extracts
* the command string and uses it for the default when prompting the
* player for a system command to spawn. The player may enter any command
* he or she chooses, or just <return> to accept the default or <escape> to
* avoid executing any command. If the command is "SPAWN", a regular shell
* escape to DCL is performed; otherwise, the indicated single command is
* spawned. Either way, NetHack resumes play when the subprocess terminates
* or explicitly reattaches to its parent.
*
* Broadcast parsing:
*
* The following broadcast messages are [attempted to be] recognized:
* text fragment name for scroll default command
* New mail VMSmail MAIL
* New ALL-IN-1 MAIL A1mail A1M
* Software Tools mail STmail MSG [+folder]
* MM mail MMmail MM
* WPmail: New mail WPmail OFFICE/MAIL
* **M400 mail M400mail M400
* " mail", ^"mail " unknown mail SPAWN
* " phoning" Phone call PHONE ANSWER
* talk-daemon...by...foo Talk request TALK[/OLD] foo@bar
* (node)user - Bitnet noise XYZZY user@node
* Anything else results in just the message text being passed along, no
* scroll of mail so consequently no command to execute when scroll read.
* The user can set up ``$ XYZZY :== SEND'' prior to invoking NetHack if
* vanilla JNET responses to Bitnet messages are prefered.
*
* Static return buffers are used because only one broadcast gets
* processed at a time, and the essential information in each one is
* either displayed and discarded or copied into a scroll-of-mail object.
*
* The test driver code below can be used to check out potential new
* entries without rebuilding NetHack itself. CC/DEFINE="TEST_DRIVER"
* Link it with hacklib.obj or nethack.olb/incl=hacklib (not nethack/lib).
*/
static struct mail_info msg; /* parse_*()'s return buffer */
static char nam_buf[63], /* maximum onamelth, size of ONAME(object) */
cmd_buf[99], /* arbitrary */
txt_buf[255 + 1]; /* same size as used for message buf[] */
/* try to decipher and categorize broadcast message text
*/
static struct mail_info *
parse_brdcst(buf) /* called by parse_next_broadcast() */
char *buf; /* input: filtered broadcast text */
{
int typ;
char *txt;
const char *nam, *cmd;
#ifdef SHELL /* only parse if spawned commands are enabled */
register char *p, *q;
boolean is_jnet_send;
char user[127 + 1], node[127 + 1], sentinel;
/* Check these first; otherwise, their arbitrary text would enable
easy spoofing of some other message patterns. Unfortunately,
any home-grown broadcast delivery program poses a similar risk. */
if (!strncmpi(buf, "reply received", 14))
goto other;
is_jnet_send = (sscanf(buf, "(%[^)])%s -%c", node, user, &sentinel) == 3);
if (is_jnet_send)
goto jnet_send;
/* scan the text more or less by brute force */
if ((q = strstri(buf, " mail")) != 0 || /* all known mail broadcasts */
!strncmpi(q = buf, "mail ", 5)) { /* unexpected alternative */
typ = MSG_MAIL;
p = strstri(q, " from");
txt = p ? strcat(strcpy(txt_buf, "Mail for you"), p) : (char *) 0;
if (!strncmpi(buf, "new mail", 8)) {
/*
* New mail [on node FOO] from [SPAM::]BAR
* [\"personal_name\"] [\(HH:MM:SS\)]
*/
nam = "VMSmail"; /* assume VMSmail */
cmd = "MAIL";
if (txt && (p = strrchr(txt, '(')) > txt && /* discard time */
(--p, strspn(p, "0123456789( :.)") == strlen(p)))
*p = '\0';
} else if (!strncmpi(buf, "new all-in-1", 12)) {
int i;
/*
* New ALL-IN-1 MAIL message [on node FOO] from Personal Name
* \(BAR@SPAM\) [\(DD-MMM-YYYY HH:MM:SS\)]
*/
nam = "A1mail";
cmd = "A1M";
if (txt && (p = strrchr(txt, '(')) > txt
&& /* discard date+time */
sscanf(p - 1, " (%*d-%*[^-]-%*d %*d:%*d:%d) %c", &i,
&sentinel) == 1)
*--p = '\0';
} else if (!strncmpi(buf, "software tools", 14)) {
/*
* Software Tools mail has arrived on FOO from \'BAR\' [in SPAM]
*/
nam = "STmail";
cmd = "MSG";
if (txt && (p = strstri(p, " in ")) != 0) /* specific folder */
cmd = strcat(strcpy(cmd_buf, "MSG +"), p + 4);
} else if (q - 2 >= buf && !strncmpi(q - 2, "mm", 2)) {
/*
* {MultiNet\ |PMDF\/}MM mail has arrived on FOO from BAR\n
* [Subject: subject_text] (PMDF only)
*/
nam = "MMmail"; /* MultiNet's version of MM */
cmd = "MM"; /*{ perhaps "MM READ"? }*/
} else if (!strncmpi(buf, "wpmail:", 7)) {
/*
* WPmail: New mail from BAR. subject_text
*/
nam = "WPmail"; /* WordPerfect [sic] Office */
cmd = "OFFICE/MAIL";
} else if (!strncmpi(buf, "**m400 mail", 7)) {
/*
* **M400 mail waiting**
*/
nam = "M400mail"; /* Messenger 400 [not seen] */
cmd = "M400";
} else {
/* not recognized, but presumed to be mail */
nam = "unknown mail";
cmd = "SPAWN"; /* generic escape back to DCL */
txt = (char *) 0; /* don't rely on "from" info here */
}
if (!txt)
txt = strcat(strcpy(txt_buf, "Mail for you: "), buf);
/*
* end of mail recognition; now check for call-type interruptions...
*/
} else if ((q = strstri(buf, " phoning")) != 0) {
/*
* BAR is phoning you [on FOO] \(HH:MM:SS\)
*/
typ = MSG_CALL;
nam = "Phone call";
cmd = "PHONE ANSWER";
if (!strncmpi(q + 8, " you", 4))
q += (8 + 4), *q = '\0';
txt = strcat(strcpy(txt_buf, "Do you hear ringing? "), buf);
} else if ((q = strstri(buf, " talk-daemon")) != 0
|| (q = strstri(buf, " talk_daemon")) != 0) {
/*
* Message from TALK-DAEMON@FOO at HH:MM:SS\n
* Connection request by BAR@SPAM\n
* \[Respond with: TALK[/OLD] BAR@SPAM\]
*/
typ = MSG_CALL;
nam = "Talk request"; /* MultiNet's TALK and/or TALK/OLD */
cmd = "TALK";
if ((p = strstri(q, " by ")) != 0) {
txt = strcat(strcpy(txt_buf, "Talk request from"), p + 3);
if ((p = strstri(p, "respond with")) != 0) {
if (*(p - 1) == '[')
*(p - 1) = '\0';
else
*p = '\0'; /* terminate */
p += (sizeof "respond with" - sizeof "");
if (*p == ':')
p++;
if (*p == ' ')
p++;
cmd = strcpy(cmd_buf, p); /* "TALK[/OLD] bar@spam" */
p = eos(cmd_buf);
if (*--p == ']')
*p = '\0';
}
} else
txt = strcat(strcpy(txt_buf, "Pardon the interruption: "), buf);
} else if (is_jnet_send) { /* sscanf(,"(%[^)])%s -%c",,,)==3 */
jnet_send:
/*
* \(SPAM\)BAR - arbitrary_message_text (from BAR@SPAM)
*/
typ = MSG_CALL;
nam = "Bitnet noise"; /* RSCS/NJE message received via JNET */
Sprintf(cmd_buf, "XYZZY %s@%s", user, node);
cmd = cmd_buf;
/*{ perhaps just vanilla SEND instead of XYZZY? }*/
Sprintf(txt_buf, "Message from %s@%s:%s", user, node,
/* "(node)user -" */
&buf[1 + strlen(node) + 1 + strlen(user) + 2 - 1]);
txt = txt_buf;
/*
* end of call recognition; anything else is none-of-the-above...
*/
} else {
other:
#endif /* SHELL */
/* arbitrary broadcast: batch job completed, system shutdown
* imminent, &c
*/
typ = MSG_OTHER;
nam = (char *) 0; /*"captured broadcast message"*/
cmd = (char *) 0;
txt = strcat(strcpy(txt_buf, "Message for you: "), buf);
#ifdef SHELL
}
/* Daemon in newmail() will append period when the text is displayed */
if ((p = eos(txt)) > txt && *--p == '.')
*p = '\0';
/* newmail() and readmail() used to assume that nam and cmd are
concatenated but that is no longer the case */
if (nam && nam != nam_buf) {
(void) strncpy(nam_buf, nam, sizeof nam_buf - 1);
nam_buf[sizeof nam_buf - 1] = '\0';
}
if (cmd && cmd != cmd_buf) {
(void) strncpy(cmd_buf, cmd, sizeof cmd_buf - 1);
cmd_buf[sizeof cmd_buf - 1] = '\0';
}
#endif /* SHELL */
/* truncate really long messages to prevent verbalize() from blowing up */
if (txt && strlen(txt) > BUFSZ - 50)
txt[BUFSZ - 50] = '\0';
msg.message_typ = typ; /* simple index */
msg.display_txt = txt; /* text for daemon to pline() */
msg.object_nam = nam; /* 'name' for mail scroll */
msg.response_cmd = cmd; /* command to spawn when scroll read */
return &msg;
}