/* $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; }