/* $Id: mlink.c,v 1.15 1996/07/19 20:16:31 tf2005 Exp $ */
#undef __vax /* This line may not be needed on some machines */
#include <strings.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
char *strtok();
typedef struct {
char *hostname;
char *hostip;
int port;
char *charname;
char *password;
/* here we define the type of mush; this determines the type of output
* in some cases. The number is set in the link.worlds file, and should
* be one digit after the port as follows:
* 0 - PennMUSHes
* 1 - TinyMUSHes
* 2 - DarkZone
* 3 - TinyMUX
* 4 - MUSE
*/
int mushtype;
/* We're going to add support for mailtype so we don't have to define a
* new mushtype for each kind of mail system
* 0 - Penn extended mailer with subject (@mail person=subj/msg)
* 1 - Penn basic @mail (@mail person=msg)
* 2 - Tiny basic +mail (+mail person=msg)
* 3 - Tiny BrandyMailer (+mail person=subj;-msg;+send)
* 4 - Tiny SeawolfMailer (+smail person=msg)
* 5 - MUX @mailer (@mail person=subj;-msg;@mail/send)
*/
int mailtype;
/* Pemittype will allow us to tailor output nicely.
* 0 - PennMUSH standard: @pemit + lit()
* 1 - TinyMUSH standard: @pemit, no lit()
* 2 - MUX/MUSE/DZ standard: @npemit
*/
int pemittype;
int socket;
int status;
time_t upsince;
time_t idle;
} host_type;
#define VERSION "1.0" /* the version number of MushLink */
#define RLINKNAME "MushLink" /* The name of the robot character */
#define MAXHOSTS 90 /* Maximum number of worlds */
/* Define the MU* server commands the robot needs to use
*
* Please be sure to put in the associated softcode commands
* included in mlink.txt before running this robot on
* that MUSH.
*
*/
#define PEMITCMD "@pemit"
#define DZPEMIT "@npemit"
#define WFILE "mlink.config" /* Configuration file for rlink */
/* Modify the first 5 fields of each line with appropriate host information */
/* but leave the last four fields alone. Add additional lines as needed. */
host_type hosts[MAXHOSTS] = {
NULL, NULL, 0, NULL, NULL, 0, 0, 0, 0, 0, 0
};
#define DISCONNECT "QUIT\n"
/* Replace 'God' here with the owner's name (and make sure all rlink
* characters are pagelocked to the appropriate characters)
*/
#define DISCMSG "God pages: Shutdown operations"
#define SUSPMSG "God pages: Suspend operations"
#define RESUMEMSG "God pages: Resume operations"
#define RECONNMSG "God pages: Reconnect"
#define STAT_DEAD 0
#define STAT_PAUSE 1
#define STAT_OK 2
#define STAT_ON 3
#define SENDSYNCMSG "prtyxnonsense\n"
#define ACKSYNCMSG "Huh? (Type \"help\" for help.)"
#define RWHOKEY "RWHOrequest:"
#define RWHOKEYLEN 12
#define RFINGERKEY "RFINGERrequest:"
#define RFINGERKEYLEN 15
#define RINFOKEY "RINFOrequest:"
#define RINFOKEYLEN 13
#define RPAGEKEY "RPAGErequest:"
#define RPAGEKEYLEN 13
#define RWORLDSKEY "RWORLDSrequest:"
#define RWORLDSKEYLEN 15
#define RMAILKEY "RMAILrequest:"
#define RMAILKEYLEN 13
#define INPREFIX "ghoti"
#define INPREFIXLEN 5
#define PREFIXTEXT ">>..RemoteLink PrefixText..<<"
#define SUFFIXTEXT ">>..RemoteLink SuffixText..<<"
#define SOFTPREFIX "START"
#define SOFTSUFFIX "END"
#define MAXSTRLEN 4096
#define RECON_TIME 300 /* Number of seconds to wait before reconnecting */
#define IBUF_LINES 50
/* Add elements at the tail, remove them from the head */
int ibufhead = 0, ibuftail = 0;
int ibufwrld[IBUF_LINES];
char ibuftxt[IBUF_LINES][MAXSTRLEN];
int num_worlds = 0;
int maxd = 0;
int debug_flg;
void do_alarm();
#define LAG_TIMEOUT 10
#define CONNECT_TIMEOUT 30
time_t timer;
/* The main program sets up the socket connection to the MU*s and
* then calls link_worlds.
*/
main(argc,argv)
int argc;
char **argv;
{
int i;
int n = 0;
if (argc > 1 && argv[1][0]=='-' && argv[1][1]=='d') {
fprintf(stderr, "Dbg: Debugging on.\n");
debug_flg++;
}
if (signal(SIGALRM, do_alarm) < 0) {
fprintf(stderr, "Error in signal()\n");
exit(0);
}
if ((n = load_worlds()) == 0) {
exit(0);
} else
fprintf(stderr, "Init: Read in %d worlds\n", n);
if(debug_flg)
for (i=0; hosts[i].hostname != NULL; i++) {
fprintf(stderr, "Init: Read world %s as %d\n",
hosts[i].hostname, i);
}
for (i=0; hosts[i].hostname != NULL; i++) {
if (!open_socket(i)) {
fprintf(stderr,"Sock: Can't connect to %s\n",hosts[i].hostname);
hosts[i].upsince = time(0);
hosts[i].status = STAT_DEAD;
}
else
hosts[i].status = STAT_OK;
}
for (i=0; hosts[i].hostname != NULL; i++) {
if (hosts[i].status == STAT_OK)
log_in(i);
}
do_alarm();
link_worlds();
/* All worlds closed*/
fprintf(stderr, "Exit: exiting, all worlds closed\n");
exit(0);
}
/* The open_socket routine sets up a socket connection over the Internet
to the MUD, using the appropriate Unix system incantations. */
int open_socket(host)
int host;
{
struct sockaddr_in sin;
int n;
/* Set up socket and connect to designated host and port*/
bzero((char *) &sin, sizeof(sin));
sin.sin_port = htons(hosts[host].port);
sin.sin_addr.s_addr = inet_addr(hosts[host].hostip);
sin.sin_family = AF_INET;
hosts[host].socket = socket(AF_INET, SOCK_STREAM, 0);
fprintf(stderr,"Socket: %d",hosts[host].socket);
if (hosts[host].socket < 0)
return 0;
fprintf(stderr,"Sock: %d\n",hosts[host].socket);
n = connect(hosts[host].socket, (struct sockaddr *) &sin, sizeof(sin));
if (n < 0) {
fprintf(stderr,"Sock Connect: %d\n",n);
close (hosts[host].socket);
return 0;
}
fprintf(stderr,"Sock Connect: %d\n",n);
if (fcntl(hosts[host].socket, F_SETFL, O_NDELAY) == -1) {
close (hosts[host].socket);
return 0;
}
fprintf(stderr,"Sock: [%s] [%s %d] socket %d\n",
hosts[host].hostname, hosts[host].hostip,
hosts[host].port ,hosts[host].socket);
hosts[host].status = STAT_OK;
num_worlds++;
if (hosts[host].socket > (maxd - 1)) {
maxd = hosts[host].socket + 1;
}
return 1;
}
/* Connects to a given world */
log_in(i)
int i;
{
char buf[MAXSTRLEN];
if (hosts[i].status == STAT_OK) {
fcntl (hosts[i].socket, F_SETFL, FNDELAY);
sleep(15);
fprintf(stderr,"Conn: [%s] %s\n",
hosts[i].hostname, hosts[i].charname);
sprintf(buf,"connect %s %s\n", hosts[i].charname, hosts[i].password);
send_host(i, buf);
wait(1);
send_host(i, "\n\r");
wait(1);
send_host(i, "\n\r");
if (sync_bot(i,buf)) {
sprintf(buf,"OUTPUTPREFIX %s\n", PREFIXTEXT);
send_host(i,buf);
sprintf(buf,"OUTPUTSUFFIX %s\n", SUFFIXTEXT);
send_host(i,buf);
hosts[i].upsince = time(0);
hosts[i].status = STAT_OK;
return(1);
}
else {
fprintf(stderr,"Conn: [%s] Error: problem synching robot.\n",
hosts[i].hostname);
close(hosts[i].socket);
hosts[i].status = STAT_DEAD;
hosts[i].upsince = time(0);
num_worlds--;
return(0);
}
}
}
/* The link_worlds routine is the main loop of the program. */
link_worlds()
{
int wi;
struct timeval tval;
char inbuf[MAXSTRLEN];
fd_set rfd, wfd;
while (num_worlds > 0) {
if (ibufhead != ibuftail) {
if (hosts[ibufwrld[ibufhead]].status != STAT_DEAD)
do_one_line(ibuftxt[ibufhead],ibufwrld[ibufhead]);
ibufhead = (ibufhead + 1) % IBUF_LINES;
}
else {
FD_ZERO(&rfd);
FD_ZERO(&wfd);
for (wi = 0; hosts[wi].hostname != NULL; wi++) {
if (hosts[wi].status != STAT_DEAD) {
FD_SET(hosts[wi].socket, &rfd);
FD_SET(hosts[wi].socket, &wfd);
}
}
tval.tv_sec=10;
tval.tv_usec=0;
select(maxd, &rfd, (fd_set *)NULL, (fd_set *)NULL, &tval);
for (wi = 0; hosts[wi].hostname != NULL; wi++) {
if (hosts[wi].status != STAT_DEAD) {
if ((getline(inbuf, wi) != 0) && (strlen(inbuf) > 0))
do_one_line(inbuf,wi);
}
}
}
}
}
do_one_line(inbuf,wi)
char *inbuf;
int wi;
{
int wo;
char tmp1[MAXSTRLEN];
char tmp2[MAXSTRLEN];
if (inbuf[strlen(inbuf)-1] == '\n' || inbuf[strlen(inbuf)-1] == '\r')
inbuf[strlen(inbuf)-1] = 0;
if (debug_flg)
fprintf(stderr,"In [%s]: %s\n",
hosts[wi].hostname, inbuf);
if (strcmp(inbuf,DISCMSG)==0) {
fprintf(stderr,"Conn: [%s] closing on command\n", hosts[wi].hostname);
send_host(wi,"page God=Quitting\n");
send_host(wi,DISCONNECT);
close(hosts[wi].socket);
hosts[wi].status = STAT_DEAD;
num_worlds--;
hosts[wi].upsince = time(0);
}
else if (strcmp(inbuf,SUSPMSG)==0) {
fprintf(stderr,"Conn: [%s] suspending\n", hosts[wi].hostname);
send_host(wi,"page God=Suspending\n");
hosts[wi].status = STAT_PAUSE;
}
else if (strcmp(inbuf,RESUMEMSG)==0) {
fprintf(stderr,"Conn: [%s] resuming\n", hosts[wi].hostname);
send_host(wi,"page God=Resuming\n");
hosts[wi].status = STAT_OK;
}
else if (strncmp(inbuf,RECONNMSG,strlen(RECONNMSG)) == 0) {
for (wo=0; hosts[wo].hostname != NULL; wo++) {
if (substring(&(inbuf[strlen(RECONNMSG)+1]),
hosts[wo].hostname)) {
if (hosts[wo].status != STAT_DEAD) {
sprintf(tmp1,"page God=Already connected to %s\n",
hosts[wo].hostname);
send_host(wi,tmp1);
}
else if (open_socket(wo) && log_in(wo)) {
fprintf(stderr,
"Conn: [%s] Reconnecting on command from %s\n",
hosts[wo].hostname, hosts[wi].hostname);
sprintf(tmp1,"page God=Ok, now connected to %s\n",
hosts[wo].hostname);
send_host(wi,tmp1);
}
else {
sprintf(tmp1,"page God=Can't connect to %s\n",
hosts[wo].hostname);
send_host(wi,tmp1);
}
break;
}
}
/* if (wo >= MAXHOSTS) {
sprintf(tmp1,"page God=I don't know world %s\n",
&(inbuf[strlen(RECONNMSG)+1]));
send_host(wi, tmp1);
} Is this really necesssary now? */
}
else if (hosts[wi].status == STAT_OK) {
if (strncmp(inbuf, RWHOKEY,RWHOKEYLEN)==0)
do_rwho(wi, &(inbuf[RWHOKEYLEN]));
else if (strncmp(inbuf, RFINGERKEY, RFINGERKEYLEN)==0)
do_rfinger(wi, &(inbuf[RFINGERKEYLEN]));
else if (strncmp(inbuf, RINFOKEY,RINFOKEYLEN)==0)
do_rinfo(wi, &(inbuf[RINFOKEYLEN]));
else if (strncmp(inbuf, RPAGEKEY,RPAGEKEYLEN)==0)
do_rpage(wi, &(inbuf[RPAGEKEYLEN]));
else if (strncmp(inbuf, RWORLDSKEY,RWORLDSKEYLEN)==0)
do_rworlds(wi, &(inbuf[RWORLDSKEYLEN]));
else if (strncmp(inbuf, RMAILKEY,RMAILKEYLEN)==0)
do_rmail(wi, &(inbuf[RMAILKEYLEN]));
}
}
do_rwho(wi, inbuf)
int wi;
char *inbuf;
{
char *name;
char *world;
char outbuf[MAXSTRLEN];
char tmpbuf[MAXSTRLEN];
int i;
hosts[wi].idle = time(0);
name = strtok(inbuf,":");
if (name == 0) {
fprintf(stderr,"Rwho: bad RWHOrequest '%s'\n", inbuf);
return(0);
}
world = strtok(0,":");
if (world == 0) {
fprintf(stderr,"Rwho: bad RWHOrequest '%s'\n", inbuf);
return(0);
}
for (i = 0; hosts[i].hostname != NULL; i++) {
if (substring(world,hosts[i].hostname) &&
hosts[i].status == STAT_OK) {
fprintf(stderr,"Rwho: [%s@%s] asked '%s'; found [%s]\n",
name, hosts[wi].hostname, world, hosts[i].hostname);
sprintf(outbuf,"WHO\n");
send_host(i,outbuf);
set_timer();
bzero(tmpbuf,MAXSTRLEN);
while (strncmp(tmpbuf,PREFIXTEXT,strlen(PREFIXTEXT)) != 0) {
if (lagging(i,name,wi,tmpbuf))
return(0);
getline(tmpbuf, i);
buffer_line(i,tmpbuf);
}
set_timer();
while (strncmp(tmpbuf,SUFFIXTEXT,strlen(SUFFIXTEXT)) != 0) {
if (lagging(i,name,wi,tmpbuf))
return(0);
getline(tmpbuf, i);
if (strncmp(tmpbuf,SUFFIXTEXT,strlen(SUFFIXTEXT)) &&
!buffer_line(i,tmpbuf)) {
if (strlen(tmpbuf) > 1) {
bzero(outbuf,MAXSTRLEN);
/* Send the right type of output depending on the MUSH */
switch (hosts[wi].pemittype) {
case 0:
sprintf(outbuf,"%s *%s=<%s> [mid({[lit(%s)]},0,70)]\n", PEMITCMD,
name, hosts[i].hostname, tmpbuf);
break;
case 2:
sprintf(outbuf,"%s *%s=<%s> %s\n",
DZPEMIT, name, hosts[i].hostname, tmpbuf);
break;
case 1:
default:
sprintf(outbuf,"%s *%s=<%s> [mid({%s},0,70)]\n",
PEMITCMD, name, hosts[i].hostname, tmpbuf);
break;
}
send_host(wi,outbuf);
}
}
}
sprintf(outbuf,"%s *%s=Done.\n",PEMITCMD, name);
send_host(wi,outbuf);
return(1);
}
}
fprintf(stderr,"Rwho: [%s@%s] World '%s' not found\n",
name, hosts[wi].hostname, world);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s *%s=Sorry, there is no link to world %s.\n",
PEMITCMD, name, world);
send_host(wi,outbuf);
}
do_rfinger(wi, inbuf)
int wi;
char *inbuf;
{
char *name;
char *player;
char *world;
char outbuf[MAXSTRLEN];
char tmpbuf[MAXSTRLEN];
int i;
hosts[wi].idle = time(0);
name = strtok(inbuf,":");
if (name == 0) {
fprintf(stderr,"Rfinger: bad RFINGERrequest '%s'\n", inbuf);
return(0);
}
player = strtok(0,":");
if (player == 0) {
fprintf(stderr,"Rfinger: bad RFINGERrequest '%s'\n", inbuf);
return(0);
}
world = strtok(0,":");
if (world == 0) {
fprintf(stderr,"Rfinger: bad RFINGERrequest '%s'\n", inbuf);
return(0);
}
for (i = 0; hosts[i].hostname != NULL; i++) {
if (substring(world,hosts[i].hostname) &&
hosts[i].status == STAT_OK) {
fprintf(stderr,"Rfinger: [%s@%s] asked '%s'; found [%s]\n",
name, hosts[wi].hostname, world, hosts[i].hostname);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"+mlfinger %s\n", player);
send_host(i,outbuf);
set_timer();
bzero(tmpbuf,MAXSTRLEN);
while (strncmp(tmpbuf,SOFTPREFIX,strlen(SOFTPREFIX)) != 0) {
if (lagging(i,name,wi,tmpbuf)) {
fprintf(stderr,"Rfinger: lagged out at 1\n");
return(0);
}
getline(tmpbuf, i);
buffer_line(i,tmpbuf);
}
set_timer();
bzero(tmpbuf,MAXSTRLEN);
while (strncmp(tmpbuf,SOFTSUFFIX,strlen(SOFTSUFFIX)) != 0) {
if (lagging(i,name,wi,tmpbuf)) {
fprintf(stderr,"Rfinger: lagged out at 2\n");
return(0);
}
getline(tmpbuf, i);
if (strncmp(tmpbuf,SOFTSUFFIX,strlen(SOFTSUFFIX)) &&
!buffer_line(i,tmpbuf)) {
if (strlen(tmpbuf) > 1 && strncmp(tmpbuf,"Notified.",strlen("Notified.")) &&
strncmp(tmpbuf,PREFIXTEXT,strlen(PREFIXTEXT)) &&
strncmp(tmpbuf,SUFFIXTEXT,strlen(SUFFIXTEXT))) {
bzero(outbuf,MAXSTRLEN);
/* send right type of output based on type of MUSH */
switch (hosts[wi].pemittype) {
case 0:
sprintf(outbuf,"%s *%s=[lit(%s)]\n", PEMITCMD, name, tmpbuf);
break;
case 2:
sprintf(outbuf,"%s *%s=%s\n", DZPEMIT, name, tmpbuf);
break;
case 1:
default:
sprintf(outbuf,"%s *%s=%s\n", PEMITCMD, name, tmpbuf);
break;
}
send_host(wi,outbuf);
}
}
}
sprintf(outbuf,"%s *%s=Done.\n",PEMITCMD, name);
send_host(wi,outbuf);
return(1);
}
}
fprintf(stderr,"Rfinger: [%s@%s] World '%s' not found\n",
name, hosts[wi].hostname, world);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s *%s=Sorry, there is no link to world %s.\n",
PEMITCMD, name, world);
send_host(wi,outbuf);
}
do_rinfo(wi, inbuf)
int wi;
char *inbuf;
{
char *name;
char *world;
char outbuf[MAXSTRLEN];
char tmpbuf[MAXSTRLEN];
int i;
hosts[wi].idle = time(0);
name = strtok(inbuf,":");
if (name == 0) {
fprintf(stderr,"Rinfo: bad RINFOrequest '%s'\n", inbuf);
return(0);
}
world = strtok(0,":");
if (world == 0) {
fprintf(stderr,"Rinfo: bad RINFOrequest '%s'\n", inbuf);
return(0);
}
for (i = 0; hosts[i].hostname != NULL; i++) {
if (substring(world,hosts[i].hostname) &&
hosts[i].status == STAT_OK) {
fprintf(stderr,"Rinfo: [%s@%s] asked '%s'; found [%s]\n",
name, hosts[wi].hostname, world, hosts[i].hostname);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"+mlinfo\n");
send_host(i,outbuf);
set_timer();
bzero(tmpbuf,MAXSTRLEN);
while (strncmp(tmpbuf,SOFTPREFIX,strlen(SOFTPREFIX)) != 0) {
if (lagging(i,name,wi,tmpbuf)) {
fprintf(stderr,"Rinfo: lagged out at 1\n");
return(0);
}
getline(tmpbuf, i);
buffer_line(i,tmpbuf);
}
set_timer();
bzero(tmpbuf,MAXSTRLEN);
while (strncmp(tmpbuf,SOFTSUFFIX,strlen(SOFTSUFFIX)) != 0) {
if (lagging(i,name,wi,tmpbuf)) {
fprintf(stderr,"Rinfo: lagged out at 2\n");
return(0);
}
getline(tmpbuf, i);
if (strncmp(tmpbuf,SOFTSUFFIX,strlen(SOFTSUFFIX)) &&
!buffer_line(i,tmpbuf)) {
if (strlen(tmpbuf) > 1 && strncmp(tmpbuf,"Notified.",strlen("Notified.")) &&
strncmp(tmpbuf,PREFIXTEXT,strlen(PREFIXTEXT)) &&
strncmp(tmpbuf,SUFFIXTEXT,strlen(SUFFIXTEXT))) {
bzero(outbuf,MAXSTRLEN);
/* send right type of output based on type of MUSH */
switch (hosts[wi].pemittype) {
case 0:
sprintf(outbuf,"%s *%s=[lit(%s)]\n", PEMITCMD, name, tmpbuf);
break;
case 2:
sprintf(outbuf,"%s *%s=%s\n", DZPEMIT, name, tmpbuf);
break;
case 1:
default:
sprintf(outbuf,"%s *%s=%s\n", PEMITCMD, name, tmpbuf);
break;
}
send_host(wi,outbuf);
}
}
}
sprintf(outbuf,"%s *%s=Done.\n",PEMITCMD, name);
send_host(wi,outbuf);
return(1);
}
}
fprintf(stderr,"Rinfo: [%s@%s] World '%s' not found\n",
name, hosts[wi].hostname, world);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s *%s=Sorry, there is no link to world %s.\n",
PEMITCMD, name, world);
send_host(wi,outbuf);
}
do_rpage(wi, inbuf)
int wi;
char *inbuf;
{
char *from;
char *to;
char *world;
char *msg;
char outbuf[MAXSTRLEN];
char tmpbuf[MAXSTRLEN];
int i;
hosts[wi].idle = time(0);
from = strtok(inbuf,":");
if (from == 0) {
fprintf(stderr,"Page: bad RPAGErequest '%s'\n", inbuf);
return(0);
}
to = strtok(0,":");
if (to == 0) {
fprintf(stderr,"Page: bad RPAGErequest '%s'\n", inbuf);
return(0);
}
world = strtok(0,":");
if (world == 0) {
fprintf(stderr,"Page: bad RPAGErequest '%s'\n", inbuf);
return(0);
}
if (world[strlen(world)-1] == ' ')
world[strlen(world)-1] = '\0';
msg = strtok(0,"\0");
if(!msg || !*msg) {
sprintf(outbuf, "%s *%s=No message to page (%s@%s)\n",
PEMITCMD, from, to, world);
send_host(wi,outbuf);
return;
}
if (debug_flg)
fprintf(stderr,"Page: [%s@%s] %s@%s = %s\n",
from, hosts[wi].hostname, to, world, msg);
else
fprintf(stderr,"Page: [%s@%s] %s@%s\n",
from, hosts[wi].hostname, to, world);
for (i = 0; hosts[i].hostname != NULL; i++) {
if (substring(world,hosts[i].hostname) &&
hosts[i].status == STAT_OK) {
sprintf(outbuf,"@emit %s [flags(*%s)]\n",INPREFIX, to);
send_host(i,outbuf);
set_timer();
bzero(tmpbuf,MAXSTRLEN);
while (strncmp(tmpbuf,INPREFIX,strlen(INPREFIX)) != 0) {
if (lagging(i,from,wi,tmpbuf))
return(0);
getline(tmpbuf, i);
buffer_line(i,tmpbuf);
}
if (tmpbuf[INPREFIXLEN+1] != 'P') {
sprintf(outbuf,"%s *%s=Sorry, %s does not exist on %s.\n", PEMITCMD,
from,to,world);
send_host(wi,outbuf);
return(0);
}
sprintf(outbuf,"@emit %s [u(onfor, %s)]\n",INPREFIX, to);
send_host(i,outbuf);
set_timer();
bzero(tmpbuf,MAXSTRLEN);
while (strncmp(tmpbuf,INPREFIX,strlen(INPREFIX)) != 0) {
if (lagging(i,from,wi,tmpbuf))
return(0);
getline(tmpbuf, i);
buffer_line(i,tmpbuf);
}
if (tmpbuf[INPREFIXLEN+1] == '#') {
send_host(wi,outbuf);
}
switch(msg[0]) {
case ':':
sprintf(outbuf,"%s *%s=From afar, %s@%s %s\n", PEMITCMD,
to,from,hosts[wi].hostname,msg + 1);
send_host(i,outbuf);
sprintf(outbuf,"%s *%s=Long distance to %s@%s: \"%s %s\".\n", PEMITCMD,
from,to,hosts[i].hostname,from,msg + 1);
send_host(wi,outbuf);
break;
case ';':
sprintf(outbuf,"%s *%s=From afar, %s@%s%s\n", PEMITCMD,
to,from,hosts[wi].hostname,msg + 1);
send_host(i,outbuf);
sprintf(outbuf,"%s *%s=Long distance to %s@%s: \"%s%s\".\n", PEMITCMD,
from,to,hosts[i].hostname,from,msg + 1);
send_host(wi,outbuf);
break;
default:
sprintf(outbuf,"%s *%s=%s@%s pages: %s\n", PEMITCMD,
to,from,hosts[wi].hostname,msg);
send_host(i,outbuf);
sprintf(outbuf,"%s *%s=You paged %s@%s with \"%s\".\n", PEMITCMD,
from,to,hosts[i].hostname,msg);
send_host(wi,outbuf);
}
return(1);
}
}
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s *%s=Sorry, there is no link to world %s.\n",
PEMITCMD, from, world);
send_host(wi,outbuf);
}
do_rmail(wi, inbuf)
int wi;
char *inbuf;
{
char *from;
char *to;
char *world;
char *msg;
char outbuf[MAXSTRLEN];
char tmpbuf[MAXSTRLEN];
int i;
hosts[wi].idle = time(0);
from = strtok(inbuf,":");
if (from == 0) {
fprintf(stderr,"Mail: bad RMAILrequest '%s'\n", inbuf);
return(0);
}
to = strtok(0,":");
if (to == 0) {
fprintf(stderr,"Mail: bad RMAILrequest '%s'\n", inbuf);
return(0);
}
world = strtok(0,":");
if (world == 0) {
fprintf(stderr,"Mail: bad RMAILrequest '%s'\n", inbuf);
return(0);
}
if (world[strlen(world)-1] == ' ')
world[strlen(world)-1] = '\0';
msg = strtok(0,"\0");
if (debug_flg)
fprintf(stderr,"Mail: [%s@%s] %s@%s = %s\n",
from, hosts[wi].hostname, to, world, msg);
else
fprintf(stderr,"Mail: [%s@%s] %s@%s\n",
from, hosts[wi].hostname, to, world);
for (i = 0; hosts[i].hostname != NULL; i++) {
if (substring(world,hosts[i].hostname) &&
hosts[i].status == STAT_OK) {
sprintf(outbuf,"@emit %s [flags(*%s)]\n",INPREFIX, to);
send_host(i,outbuf);
set_timer();
bzero(tmpbuf,MAXSTRLEN);
while (strncmp(tmpbuf,INPREFIX,strlen(INPREFIX)) != 0) {
if (lagging(i,from,wi,tmpbuf))
return(0);
getline(tmpbuf, i);
buffer_line(i,tmpbuf);
}
if (tmpbuf[INPREFIXLEN+1] != 'P') {
sprintf(outbuf,"%s *%s=Sorry, %s does not exist on %s.\n", PEMITCMD,
from,to,world);
send_host(wi,outbuf);
return(0);
}
bzero(outbuf,MAXSTRLEN);
/* Send right type of output based on type of MUSH */
switch (hosts[i].mailtype) {
case 0:
sprintf(outbuf,"@mail %s=MushLink Mail from %s@%s/", to, from, hosts[wi].hostname);
send_host(i, outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s", msg);
send_host(i, outbuf);
bzero(outbuf, MAXSTRLEN);
sprintf(outbuf,"%r** reply using \"mlmail\". See +help mushlink for help. **\n");
break;
case 2:
sprintf(outbuf,"+mail %s=MushLink Mail from %s@%s %R", to, from, hosts[wi].hostname);
send_host(i, outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s", msg);
send_host(i, outbuf);
bzero(outbuf, MAXSTRLEN);
sprintf(outbuf,"%r** reply using \"mlmail\". See +help mushlink for help. **\n");
break;
case 3:
sprintf(outbuf,"+mail %s=MushLink Mail from %s@%s\n",
to, from, hosts[wi].hostname);
send_host(i, outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"-%s\n",msg);
send_host(i, outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"+send\n");
break;
case 4:
sprintf(outbuf,"+smail %s=MushLink Mail from %s@%s %R", to, from, hosts[wi].hostname);
send_host(i, outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s", msg);
send_host(i, outbuf);
bzero(outbuf, MAXSTRLEN);
sprintf(outbuf,"%r** reply using \"mlmail\". See +help mushlink for help. **\n");
break;
case 5:
sprintf(outbuf,"@mail %s=MushLink Mail from %s@%s\n",
to, from, hosts[wi].hostname);
send_host(i, outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"-%s\n",msg);
send_host(i, outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"@mail/send\n");
break;
case 1:
default:
sprintf(outbuf,"@mail %s=MushLink Mail from %s@%s %R", to, from, hosts[wi].hostname);
send_host(i, outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s", msg);
send_host(i, outbuf);
bzero(outbuf, MAXSTRLEN);
sprintf(outbuf,"%r** reply using \"mlmail\". See +help mushlink for help. **\n");
break;
}
send_host(i,outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s *%s=Your mail message, \"%s\", has been sent to %s@%s.\n",
PEMITCMD, from,msg,to,world);
send_host(wi,outbuf);
return(1);
}
}
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s *%s=Sorry, there is no link to world %s.\n",
PEMITCMD, from, world);
send_host(wi,outbuf);
}
do_rworlds(wi, inbuf)
int wi;
char *inbuf;
{
char *name;
char outbuf[MAXSTRLEN];
int i;
char mtype;
hosts[wi].idle = time(0);
name = inbuf;
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf, "%s *%s=[center(%s Version %s,79)]%R[repeat(-,79)]\n",PEMITCMD, name, RLINKNAME, VERSION);
send_host(wi,outbuf);
sprintf(outbuf, "%s *%s=[ljust(World,13)] [ljust(IP Address,24)] Status\n", PEMITCMD, name);
send_host(wi,outbuf);
sprintf(outbuf, "%s *%s=[repeat(-,79)]\n",
PEMITCMD, name);
send_host(wi,outbuf);
for (i=0; hosts[i].hostname != NULL; i++) {
bzero(outbuf,MAXSTRLEN);
switch (hosts[i].mushtype) {
case 0: mtype='P'; break;
case 1: mtype='T'; break;
case 2: mtype='D'; break;
case 3: mtype='X'; break;
case 4: mtype='S'; break;
default: mtype='?'; break;
}
if (hosts[i].status == STAT_OK) {
sprintf(outbuf,"%s *%s=[ljust(%s,9)] <%c> [ljust(%s %d,24)] [ljust(UP,5)] for [u(csecs, %d)]\n",
PEMITCMD, name, hosts[i].hostname, mtype, hosts[i].hostip, hosts[i].port,
time(0)-hosts[i].upsince);
send_host(wi,outbuf);
}
else if (hosts[i].status == STAT_PAUSE) {
sprintf(outbuf, "%s *%s=[ljust(%s,9)] <%c> [ljust(%s %d,24)] [ljust(UP,5)] % % for [u(csecs, %d)] but PAUSED\n",
PEMITCMD, name,hosts[i].hostname, mtype, hosts[i].hostip, hosts[i].port, time(0) - hosts[i].upsince);
send_host(wi,outbuf);
}
else if (hosts[i].status == STAT_DEAD) {
sprintf(outbuf,
"%s *%s=[ljust(%s,9)] <%c> [ljust(%s %d,24)] [ljust(DOWN,5)] for [u(csecs, %d)]\n",
PEMITCMD, name,hosts[i].hostname, mtype, hosts[i].hostip, hosts[i].port, time(0) - hosts[i].upsince);
send_host(wi,outbuf);
}
}
sprintf(outbuf,"%s *%s=[repeat(-,79)]\n",PEMITCMD, name);
send_host(wi,outbuf);
bzero(outbuf,MAXSTRLEN);
sprintf(outbuf,"%s *%s=%B%B%BP - PennMUSH%B%B%BT - TinyMUSH%B%B%BD - DarkZone%B%B%BX - TinyMUX%B%B%BS - MUSE\n",
PEMITCMD, name);
send_host(wi,outbuf);
}
/* sync_bot sends a garbage message and waits for the HUH? to come back.
This is useful for synchronizing dialogue. */
sync_bot(host, buf)
char *buf;
{
int count;
count = 0;
send_host(host, SENDSYNCMSG);
bzero (buf, MAXSTRLEN);
do {
sleep(1);
read (hosts[host].socket, buf, MAXSTRLEN);
if (count++ > 30)
return(0);
}
while(strstr(buf,ACKSYNCMSG)==0);
return(1);
}
/* Getline takes a line from specified file descriptor and */
/* stuffs it into inbuf. */
int getline(inbuf, world)
char *inbuf;
int world;
{
char c, buf[MAXSTRLEN];
int noise, i;
bzero (inbuf, MAXSTRLEN);
noise = read(hosts[world].socket,inbuf,1);
if (noise == 0) {
close(hosts[world].socket);
hosts[world].status = STAT_DEAD;
fprintf(stderr,"Conn: [%s] involuntarily closed.\n",
hosts[world].hostname);
num_worlds--;
hosts[world].upsince = time(0);
inbuf[0] = 0;
return(0);
}
else if (noise == -1 || inbuf[0] == '\n') {
inbuf[0] = 0;
return(0);
}
else {
i = 1;
do {
noise = read(hosts[world].socket,&(inbuf[i++]), 1);
if (inbuf[i] == '\r') i--;
} while ((inbuf[i-1] != '\n') && (i != MAXSTRLEN-1));
inbuf[i-1] = 0;
return(1);
}
}
send_host (host,message)
int host;
char *message;
{
if (debug_flg)
fprintf(stderr,"Send [%s]: %s\n", hosts[host].hostname,message);
write (hosts[host].socket, message, strlen(message));
}
substring(s1, s2)
char *s1, *s2;
{
int i;
if (strlen(s1) > strlen(s2))
return(0);
for (i = 0; i < strlen(s1); i++) {
if (s1[i] == '\r' || s1[i] == '\n') break;
if (tolower(s1[i]) != tolower(s2[i]))
return(0);
}
return(1);
}
reconnect_world(w)
int w;
{
if (open_socket(w)) {
if (log_in(w)) {
fprintf(stderr,"Conn: [%s] Reconnecting on alarm\n",
hosts[w].hostname);
return(1);
}
}
else {
fprintf(stderr,"Conn: [%s] Can't reconnect on alarm\n",
hosts[w].hostname);
return(0);
}
}
void do_alarm()
{
int w;
struct itimerval itime;
struct timeval interval;
fprintf(stderr,"Alrm: timeout (%d seconds with a world down)\n",
RECON_TIME);
for (w = 0; hosts[w].hostname != NULL ; w++)
if (hosts[w].status == STAT_DEAD)
reconnect_world(w);
signal(SIGALRM, do_alarm);
interval.tv_sec = RECON_TIME;
interval.tv_usec = 0;
itime.it_interval = interval;
itime.it_value = interval;
setitimer(ITIMER_REAL, &itime, 0);
}
buffer_line(w,s)
int w;
char *s;
{
if (
strncmp(s, RWHOKEY,RWHOKEYLEN)==0 ||
strncmp(s, RFINGERKEY, RFINGERKEYLEN)==0 ||
strncmp(s, RINFOKEY,RINFOKEYLEN)==0 ||
strncmp(s, RPAGEKEY,RPAGEKEYLEN)==0 ||
strncmp(s, RWORLDSKEY,RWORLDSKEYLEN)==0) {
if (ibufhead == (ibuftail + 1) % IBUF_LINES)
return(-1);
else {
ibufwrld[ibuftail] = w;
strcpy(ibuftxt[ibuftail],s);
ibuftail = (ibuftail+1) % IBUF_LINES;
if (debug_flg)
fprintf(stderr,"Buff: [%s] %s\n",
hosts[w].hostname, s);
else
fprintf(stderr,"Buff: [%s]\n", hosts[w].hostname);
}
}
else
return(0);
}
set_timer()
{
timer = time(0);
}
lagging(world,name,orig,buff)
int world,orig;
char *name,*buff;
{
char buf[MAXSTRLEN];
if (!strncmp(buff, "Huh", 3))
return(1);
else if (time(0) - timer > LAG_TIMEOUT) {
sprintf(buf,
"%s *%s=Sorry, world '%s' is lagging; command halted.\n",
PEMITCMD, name,hosts[world].hostname);
send_host(orig,buf);
fprintf(stderr,"Lag: On [%s], reported to %s@%s\n",
hosts[world].hostname,name,hosts[orig].hostname);
return(1);
}
else
return(0);
}
int timeout()
{
char buf[MAXSTRLEN];
if (time(0) - timer > CONNECT_TIMEOUT) {
fprintf(stderr,"Connect Timeout\n");
return(1);
} else {
return(0);
}
int load_worlds() {
FILE *fp;
int i = 0, j = 0;
int p1, p2, p3, p4;
int nworlds;
char buffer[200];
nworlds = 0;
if (!(fp = fopen(WFILE,"r")))
{
fprintf(stderr, "Init: Cannot read %s.\n", WFILE);
return 0;
} else {
fscanf(fp, "%d\n", &nworlds);
if(nworlds < 1) {
fprintf(stderr, "Init: No worlds to read in\n");
fclose (fp);
return 0;
} else if (nworlds > MAXHOSTS) {
fprintf(stderr, "Init: Number of Worlds greater than define");
fclose (fp);
return 0;
}
for(i = 0; i < nworlds; i++) {
/* Init the port Ip's */
p1 = p2 = p3 = p4 = 0;
hosts[i].upsince = time(0);
hosts[i].port = hosts[i].mushtype = hosts[i].mailtype = hosts[i].pemittype
= hosts[i].socket = hosts[i].status = 0;
/* Read in the name of the world */
fscanf(fp,"%[^\n]\n",&buffer);
hosts[i].hostname = (char *)malloc(sizeof(char)*strlen(buffer)+1);
strcpy(hosts[i].hostname, buffer);
/* Read in the Password for the account */
fscanf(fp,"%[^\n]\n",&buffer);
hosts[i].password = (char *)malloc(sizeof(char)*strlen(buffer)+1);
strcpy(hosts[i].password, buffer);
/* Read in the various #'s */
fscanf(fp,"%d.%d.%d.%d %d %d %d %d\n",&p1, &p2, &p3, &p4,
&(hosts[i].port), &(hosts[i].mushtype), &(hosts[i].mailtype), &(hosts[i].pemittype));
hosts[i].charname = (char *)malloc(sizeof(char)*strlen(RLINKNAME)+1);
strcpy(hosts[i].charname, RLINKNAME);
sprintf(buffer, "%d.%d.%d.%d", p1, p2, p3, p4);
hosts[i].hostip = (char *)malloc(sizeof(char)*strlen(buffer)+1);
strcpy(hosts[i].hostip,buffer);
}
hosts[i].hostname = hosts[i].hostip = hosts[i].password =
hosts[i].charname = NULL;
hosts[i].port = hosts[i].mushtype = hosts[i].mailtype = hosts[i].pemittype =
hosts[i].upsince = hosts[i].status = hosts[i].idle = 0;
}
fclose (fp);
return nworlds;
}