/* * MusicMUD Daemon, AberChat Module. * Copyright (C) 1997 Giancarlo Castrataro. * Copyright (C) 1998 Jo Dillon * Copyright (C) 1998-2003 Abigail Brady * Copyright (C) 2001 Robert Rescorla * Copyright (C) 2001 Paul Lettington * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include <ctype.h> #include <unistd.h> #include <errno.h> #include <set> #include "musicmud.h" #include "Socket.h" #include "util.h" #include "verbs.h" #include "State.h" #include "Player.h" #include "misc.h" #include "levels.h" #include "aberchat.h" #include "client_int.h" #include "flags.h" #include "misc.h" #include "pflags.h" #include "vsprintf.h" #include "util.h" #include "emsg.h" #include "musictok.h" #include "actions.h" #include "pipe-ident.h" #define MYMUD MUDNAME #include <time.h> #include <sys/types.h> #include <sys/socket.h> #include <fcntl.h> #include <netinet/in.h> #include <arpa/inet.h> static string dirt_to_music(const char *blah, int s=0); #define MODULE "aberchat" extern bool achat_auto_run; extern int achat_fuckup_timeout;//used to store time to try to start again. extern int pending_achat_socket;//used as part-time store for achat connection extern int achat_ping_delay;//do a mudlist every 60 seconds. extern int achat_ping_sched;//time of next ping. extern int last_achat;//time since last aberchat thing happened. extern char * achat_crash_mat; extern char * achat_crash_err; extern set<string> achat_list; extern Socket *primary; #define PORT (primary->port) const char *chat_chat = "^W[^%XAChat^W]^n ^Z^p%s^R@^B%s^n says ^`^{%X%s\2^}^'\n"; const char *chat_emote = "^W[^%XAChat^W]^n ^Z^p%s^R@^B%s^n %s^n\n"; const char *coder_chat = "^W[^%XACode^W]^n ^Z^p%s^R@^B%s^n says ^`^{%X%s\2^}^'\n"; const char *coder_emote = "^W[^%XACode^W]^n ^Z^p%s^R@^B%s^n %s^n\n"; const char *god_chat = "^W[^%XAGod^W]^n ^Z^p%s^R@^B%s^n says ^`^{%X%s\2^}^'\n"; const char *god_emote = "^W[^%XAGod^W]^n ^Z^p%s^R@^B%s^n %s^n\n"; string subfmt(const char *s, const char *col) { string b = ""; while (*s) { if (s[0]=='%' && s[1]=='X') { b += col; s += 2; } else { b += *s; s++; } } return b; } const char *atell_fmt = "^p%s^R@^B%s^n tells you, ^{W^`^n%s\2^n^'^}\n"; const char *atell_send_fmt = "You tell ^p%s^R@^B%s^n, ^{W^`^n%s\2^n^'^}\n"; const char *atell_emote_send_fmt = "You aberemote to ^p%s^R@^B%s^n: %s\2^n\n"; const char *atell_emote_fmt = "^p%s^R@^B%s^n %s\2^n\n"; const char *ainfo_fmt = "^b[^WAberchat info from ^B%s^W: ^n%s\2^b]^n\n"; const char *areply_send_fmt = "You reply to ^p%s^R@^B%s^n, ^W^`^n%s\2^W^'^n\n"; const char *areply_emote_send_fmt = "You emote at ^p%s^R@^B%s^n, ^W^`^n%s\2^W^'^n\n"; Flag chat_option = FL_NOACHAT; Flag coder_option = FL_NOACODE; Flag god_option = FL_NOAGOD; static void ainfo(bool, const char *, const char *); static Player *get_player(const char *whoto) { return players->get(make_lower(whoto).c_str()); } char aberchat_pass[256]; char aberchat_server[256]; int aberchat_port; struct sockaddr_in achat_addr; //modify this to write direct into an address struct. static bool get_which() { char myhost[256]; char hostname[256]; int myport; achat_addr.sin_family = AF_INET; FILE *f = xopen(".", DATA_ABERCHAT, "r"); if (!f) { log(PFL_CODER, 0, "aberchat", "can't open file %s",DATA_ABERCHAT); return false; } gethostname(myhost, sizeof myhost); log(PFL_CODER,0, "aberchat","host name %s",myhost); log(PFL_CODER,0, "aberchat","mud port is %d",PORT); while (fscanf(f, "%s %i %s %i %s\n", hostname, &myport, aberchat_server, &aberchat_port, aberchat_pass)!=EOF) { if (streq(hostname, myhost) && myport == PORT) { achat_addr.sin_port=htons(aberchat_port); inet_aton(aberchat_server,&achat_addr.sin_addr); xclose(f); return true; } log(PFL_CODER,0,"aberchat","read a line "); } xclose(f); return false; } static char lookup_classic(char w) { if (w=='S') return 'G'; if (w=='o') return 'c'; if (w=='p') return 'C'; if (w=='P') return 'B'; if (w=='t') return 'y'; if (w=='s') return 'g'; if (w=='k') return 'y'; if (w=='i') return 'Y'; if (w=='d') return 'W'; if (w=='D') return 'C'; return w; } static void send_msg(const char *to, const char *tomud, const char *what); static void send_msg(const char *to, const char *tomud, const string &what) { return send_msg(to, tomud, what.c_str()); } static string music_to_dirt(const char *buffer) { string ptr; char normal[4] = "&*"; while (*buffer) { if (*buffer != '^') { ptr += *buffer; buffer++; continue; } if (buffer[1]=='#') { if (strncmp(buffer, "^#9834;", 7)==0) { ptr+= 'o'; ptr+= '/'; ptr+= '~'; buffer += 7; continue; } while (*buffer && *buffer != ';') { buffer++; } buffer++; ptr += '?'; continue; } buffer++; if (buffer[0]=='\'' || buffer[0]=='`') { ptr += '\''; buffer++; continue; } if (buffer[0]=='^') { ptr += '^'; buffer++; continue; } if (buffer[0]=='Z' || buffer[1]=='}') { buffer++; continue; } if (buffer[0]=='n') { ptr += normal; buffer ++; continue; } if (buffer[0]=='{') { buffer++; if (!buffer[0]) continue; char col = lookup_classic(buffer[0]); normal[0] = '&'; normal[1] = '+'; normal[2] = col; normal[3] = 0; ptr += normal; buffer++; continue; } if (buffer[0]=='}') { buffer++; normal[0] = '&'; normal[1] = '*'; normal[2] = 0; ptr += normal; continue; } if (!buffer[0]) { continue; } char col = lookup_classic(buffer[0]); ptr += '&'; ptr += '+'; ptr += col; buffer++; continue; } return ptr; } static void aprintf(const char *,const char *, ...) __attribute__((format(printf, 2, 3))); static void aprintf(const char *user,const char *fmt, ...) { va_list va; va_start(va, fmt); static char buffer[4096]; vsprintf(buffer, fmt, va); va_end(va); if (aberchat_socket) { aberchat_socket->write(buffer, strlen(buffer)+1); } } static void send_abermail(const char *from2, const char *to, const char *at, const char *subject, const char *date, const char *data) { char from[256]; if(!aberchat_auth) { MudObject* o=get_player(from2); if (o) o->printf("^RError!^n Aberchat is off line, your message was discarded.\n"); return; } strncpy(from, from2, 256); from[0] = toupper(from[0]); aprintf(from2,"%c" D "%s" D "%c" D "%s" D "%s" D "%s" D "%s" D "%s" D "%s", TO_MUD, at, ABERMAIL, from, MYMUD, to, subject, date, data); } #include "mailboard.h" static void make_lower(char *to) { while (*to) { *to = tolower(*to); to++; } } static void recieve_abermail(const char *from, const char *frommud, const char *to, const char *subject, const char *date, const char *data) { if (!data) return; string tos = make_lower(to); to = tos.c_str(); if (!player_exist(to)) { send_msg(from, frommud, ssprintf("No such player as %s.", to)); return; } string fromname = ssprintf("%s@%s", from, frommud); sendmail(to, fromname.c_str(), subject, date, data); send_msg(from, frommud, "Mail successfully delivered."); } static void kill_mud_list() { set<string> s; achat_list = s; } static const char * mud_name_expand(const char*,bool); static bool verb_aignore(MudObject *who,int argc,const char** argv) { if (argc==1) { int f=0; who->spec_printf("%s\n", title_for("AIgnore", who).c_str()); Object::intit i = who->ints.begin(); while (i != who->ints.end()) { const char *key = i->first.c_str(); if (strncmp(key, "aignore.",8)==0) { who->printf("^G %s\n", key+8); f=1; } i++; } if(f==0) { who->cancel_printf(); who->printf("You are not ignoring anyone on aberchat.\n"); } else who->spec_printf("%s\n", footer_for(who).c_str()); return(true); } if(argc==2) { char card[512]; char hold[512]; char * at; const char * ata; strncpy(hold,argv[1],400); make_lower(hold); if(!(at=strchr(hold,'@'))) { who->printf("Where is the @ sign?\n"); return true; } *at=0; ata=mud_name_expand(at+1,true); sprintf(card,"aignore.%s@%s",hold,ata); if (who->get_int(card)!=-1) { who->unset(card); who->printf("You no longer ignore %s.\n",card+8); log(PFL_GOD, 0, "aberchat", "no longer ignores %s.", card+8); } else { if(!ata) { who->printf("No match for \"%s\" in current amudlist\n",at+1); } else { who->set(card,1); who->printf("You now ignore %s.\n",card+8); log(PFL_GOD, 0, "aberchat", "now ignores %s.", card+8); } } return true; } who->printf("Syntax : aignore, aignore player@mud, aignore *@mud\n"); return true; } static const char* mud_name_expand(const char* mud,bool check) { int thislen = strlen(mud); for (set<string>::iterator i=achat_list.begin();i!=achat_list.end();i++) { const char *s = i->c_str(); if (strncasecmp(s, mud, thislen)==0) return s; } if (check) return mud; return 0; } static const char* aber_ignored(MudObject * target,const char * mud,const char * from,bool expand) { char wild[256]; char spec[256]; sprintf(wild, "aignore.*@%s", mud); sprintf(spec, "aignore.%s@%s", from, mud); make_lower(spec); make_lower(wild); if (target->get_int(spec,0)) { return "that person"; } if (target->get_int(wild,0)) { return "that entire mud"; } return NULL; } static bool aignore_polite(MudObject * who,char * mud, char * to) { const char * pol=aber_ignored(who,mud,to,true); if (pol) { who->printf("You are ignoring %s\n",pol); return true; } return false; } static bool aignored(MudObject *target, const char *mud, const char *from) { if(aber_ignored(target,mud,from,false)) { send_msg(from,mud,ssprintf("%s is ignoring you.", bwname(target))); return true; } return false; } static void send_tell(const char *from, const char *to, const char *at, const char *text) { aprintf(from,"%c" D "%s" D "%c" D "%s" D "%s" D "%s" D "%s", TO_MUD, at, TELL, from, to, MYMUD, text); } static void send_chat(char channel, const char *from, const char *text) { aprintf(from,"%c" D "%c" D "%s" D "%s" D "%s", TO_ALL, channel, MYMUD, from, text); } static void send_info(const char *text) { aprintf(NULL,"%c" D "%c" D "%s" D "%s", TO_ALL, INFOMSG, MYMUD, text); } static void send_who(const char *from, const char *which) { aprintf(from,"%c" D "%s" D "%c" D "%s" D "%s", TO_MUD, which, WHO, MYMUD, from); } static void send_mudlist(const char *from) { aprintf(from,"%c" D "%s" D "%c" D "%s", TO_MUD, MYMUD, MUDLIST, from); } #define CLIENT_VERSION "AberChat Client 4.2.7 " \ "(compatible ; Music 1.0.0; X-AberMail)" static void send_aversion(const char *who, const char *which) { if (which && *which) aprintf(NULL,"%c" D "%s" D "%c" D "%s" D "%s", TO_MUD, which, AVERREQ, MYMUD, who); else aprintf(NULL,"%c" D "%s" D "%c" D "%s" D "%s", TO_MUD, MYMUD, AVERSION, who, CLIENT_VERSION); } static void send_kick(const char *from, char *who) { char *mudn = strchr(who, '@'); *(mudn++)=0; aprintf(from,"%c" D "%s" D "%c" D "%s" D "%s" D "%s", TO_MUD, mudn, KICK, from, who, MYMUD); } static void send_auth() { aprintf(NULL,"%c" D "%s" D "%c" D "%s" D "%s" D "%i" D "%s", TO_MUD, MYMUD, AUTH, MYMUD, MUDLIB, PORT, crypt(aberchat_pass, "Ac")); } static void send_msg(const char *to, const char *tomud, const char *what) { aprintf(NULL,"%c" D "%s" D "%c" D "%s" D "%s" D "%s", TO_MUD, tomud, MSG, to, MYMUD, what); } // this socket code not through the library, who cares? // aberchat was kludged long before I got here! static void achat_init() { int e; socklen_t size = sizeof achat_addr; if(-1==pending_achat_socket) { if (get_which()==false) { log(PFL_SEEINFO, 0, "aberchat", "no server details in %s", DATA_ABERCHAT); achat_auto_run=false;//no point in trying to re-start //achat_dead(); return; } log(PFL_SEEINFO, 0, "aberchat", "connecting"); pending_achat_socket=socket(AF_INET,SOCK_STREAM,0); fcntl(pending_achat_socket,F_SETFL,O_NONBLOCK); achat_fuckup_timeout=0;//poll us again soon! achat_auto_run=true;//enable polling. } aberchat_auth=false; if(connect(pending_achat_socket,(struct sockaddr *)&achat_addr, size)) { if(((e=errno)!=EINPROGRESS)&&(e!=EALREADY)) { close(pending_achat_socket); pending_achat_socket=-1; //this probably means wrong details in file, or server fucked, achat_fuckup_timeout=time(NULL)+600;//try again in ten minutes, pl598 says this okay! log(PFL_SEEINFO, 0, "aberchat", "cannot connect : %s",strerror(e)); //achat_dead(); } return; } aberchat_socket = new Socket(); aberchat_socket->connect(pending_achat_socket); aberchat_isup=true; pending_achat_socket=-1; achat_auto_run=false;//we've started! send_auth(); log(PFL_SEEINFO, 0, "aberchat", "connected"); } static void achat_shutdown() { if (aberchat_socket) { ainfo(true,MYMUD, "Exited Network"); } aberchat_auth = false; if (aberchat_socket) delete aberchat_socket; aberchat_socket = 0; aberchat_isup=false; if(pending_achat_socket!=-1) { close(pending_achat_socket); pending_achat_socket=-1; } kill_mud_list(); } static void kick_player(const char *from, const char *to, const char *frommud) { MudObject *who = get_player(to); if (!who) { send_msg(from, frommud, ssprintf("%s is not online.", to)); return; } if (who->get_priv(PFL_GOD)) { send_msg(from, frommud, ssprintf("%s is too powerful.", to)); return; } //who->set_bflag(FL_BANNEDABERCHAT, 1); //who->printf("You have been banned from Aberchat.\n"); log(PFL_SEEINFO, 0, "aberchat", "%s has been kicked by %s@%s", to, from, frommud); return; } static void aversion(const char *player, const char *server, const char *client) { MudObject *who = get_player(player); if (!who) return; who->printf("Client is : %s\n" "Server is : %s\n" "All code Copyright G. Castrataro (gcastrat@indiana.edu)\n", server, client); } static void amessage(const char *player, const char *frommud, const char *reply) { MudObject *who = get_player(player); if (!who) { return; } who->printf("Reply from server %s : %s\n", frommud, dirt_to_music(reply).c_str()); } const char *namefix(const char *c) { return c; } static void atell(const char *whofrom, const char *whoto, const char *frommud, const char *text) { Player *who = get_player(namefix(whoto)); if (!who || !is_player(who) || invis(who)) { char buffer[256]; sprintf(buffer, "No such player (%s)", whoto); send_msg(whofrom, frommud, buffer); return; } if (aignored(who,frommud,whofrom)) return; Player *p = who; if (!p->p) { char buffer[256]; sprintf(buffer, "%s is linkdead.", whoto); send_msg(whofrom, frommud, buffer); return; } if (p->get_flag(FL_NOABERCHAT) || p->get_flag(FL_NOATELL)) { char buffer[256]; sprintf(buffer, "You can't ATell %s at the moment.", bwname(p)); send_msg(whofrom, frommud, buffer); return; } if (p->get("away")) { char buffer[1024]; if (streq(p->get("away"), ".")) { sprintf(buffer, "%s is away and might not respond.", whoto); } else { sprintf(buffer, "%s is away : %s, and might not respond.", whoto, p->get("away")); buffer[1000] = 0; } send_msg(whofrom, frommud, buffer); //return; } char buffer[256]; sprintf(buffer, "%s@%s", whofrom, frommud); who->set("areply.target", buffer); if (text[0]==':') { text++; while (*text==' ') text++; who->printf(atell_emote_fmt, whofrom, frommud, dirt_to_music(text).c_str()); } else who->printf(atell_fmt, whofrom, frommud, dirt_to_music(text).c_str()); } static void aver_reply(const char *frommud, const char *player) { aprintf(NULL,"%c" D "%s" D "%c" D "%s" D "%s", TO_MUD, frommud, AVERSION, player, CLIENT_VERSION); } static string dirt_to_music(const char *blah, int spaces) { string a = ""; while (*blah) { unsigned char q = *blah; if (blah[0]=='&' && blah[1]=='>') { if (spaces) { a += '\v'; for (int i=0;i<spaces;i++) a += ' '; } blah+=2; continue; } if (blah[0]=='&' && blah[1]=='+' && blah[2]) { a += '^'; a += blah[2]; blah += 3; continue; } if (blah[0]=='&' && (blah[1]=='N'||blah[1]=='*')) { a += "^n"; blah += 2; continue; } if ((q>=0x20 && q<=0x7e) || (q>=0xa0||q<=0xff)) a += *blah; else a += "?"; if (*blah=='^') a += *blah; blah++; } return a; } static string gendersub(const char *t, MudObject *me) { string s; while (*t) { if (t[0]=='$') { if (t[1]=='x' && me) { s += his_or_her(me); t+=2; continue; } if (t[1]=='y' && me) { s += he_or_she(me); t+=2; continue; } if (t[1]=='z' && me) { s += him_or_her(me); t+=2; continue; } } s += *t; t++; } return s; } static string sub(const char *t, const char *from, const char *frommud, const char *to=0, const char *tomud=0) { string s; while (*t) { if (t[0]=='$') { if (t[1]=='a' && from) { s += ssprintf("^p%s^R@^B%s^n", from, frommud); t+=2; continue; } if (t[1]=='t' && to) { s += ssprintf("^p%s^R@^B%s^n", to, tomud); t+=2; continue; } } s += *t; t++; } return s; } static void handle_act(const char *arg1, const char *arg2, const char *arg3, const char *arg4, const char *text) { int i; MudObject *m; foreach(players, m, i) if (m->get_flag(FL_LOGGEDIN)) { if (!text || !*text) m->printf("^W[AAct^W]^n ^Z%s\n", sub(dirt_to_music(arg3).c_str(), arg1, arg2)); else m->printf("^W[AAct^W]^n ^Z%s\n", sub(dirt_to_music(text).c_str(), arg1, arg3, arg2, arg4)); } } static string convert_to_aact(const string &ss, MudObject *who, const char *txt=0) { const char *s = ss.c_str(); string b; int pct = 0, mode = 0, cap = 0; while (*s) { if (*s=='\n') { return b; } if (mode) { if (s[0]==']') mode = 0; else if (s[0]=='/') mode = 2; else if (mode==1) { b += *s; } s++; continue; } /* $a actor's name/mud $t target's name/mud $x his/her (target) $y he/she (target) $z him/her (target) */ if (pct) { if (s[0]=='1') { b += "$a"; } else if (s[0]>='2' && s[0]<='9') { if (cap) { string p = pronoun[s[0]-'2'][get_gender(who)]; p[0] = toupper(p[0]); b += p; } else b += pronoun[s[0]-'2'][get_gender(who)]; } else if (s[0]=='%') { b += "%"; } else if (s[0]=='a') { b += "$t"; } else if (s[0]=='b' || s[0]=='B') {// he/she b += "$y"; } else if (s[0]=='c' || s[0]=='C') {// him/her b += "$z"; } else if (s[0]=='d' || s[0]=='D') {// his/her b += "$x"; } else if (s[0]=='e') { b += "$<his$/hers$>"; } else if (s[0]=='f') { b += "$<himself$/herself$>"; } else if (s[0]=='g') { b += "$<man$/woman$>"; } else if (s[0]=='s') { b += txt?txt:"???"; } else if (s[0]=='[') { mode = 1; } else if (s[0]=='#') { cap = 1; s++; continue; } pct=0; s++; continue; } if (!pct) { if (s[0]=='%') pct = 1, cap = 0; else b += *s; s++; } } return b; } static bool verb_aaction(MudObject *who, int argc, const char **argv) { if (!argv[1]) { who->printf("Need an arg.\n"); return true; } Action a(argv[1]); if (a.u_rest.length() && !argv[2]) { aprintf(who->id, "%c\a%c\a%s\a%s\a%s\a%s\a%s", TO_ALL, SOCIALREQ, bwname(who), "", MYMUD, "", convert_to_aact(music_to_dirt(a.u_rest.c_str()), who).c_str()); return true; } if (a.x_rest.length() && argv[2]) { aprintf(who->id, "%c\a%c\a%s\a%s\a%s\a%s\a%s", TO_ALL, SOCIALREQ, bwname(who), "", MYMUD, "", convert_to_aact(music_to_dirt(a.x_rest.c_str()), who, the_rest(argc, argv, 2) .c_str()).c_str()); return true; } if (a.t_rest.length() && argv[2]) { if (!strchr(argv[2], '@')) { who->printf("Need an at.\n"); return true; } string victname = argv[2]; string victmud = victname.substr(victname.find('@')+1); victname = victname.substr(0, victname.find('@')); aprintf(who->id, "%c\a%s\a%c\a%s\a%s\a%s\a%s", TO_MUD, victmud.c_str(), SOCIALANS, bwname(who), victname.c_str(), MYMUD, convert_to_aact(music_to_dirt(a.t_rest.c_str()), who).c_str()); return true; } who->printf("Not handled.\n"); return true; } static void handle_areq(const char *arg1, const char *arg2, const char *arg3, const char *text) { MudObject *rec = get_player(arg2); if (rec) { aprintf(rec->id, "%c\a%c\a%s\a%s\a%s\a%s\a%s", TO_ALL, SOCIALREQ, arg1, bwname(rec), arg3, MYMUD, gendersub(text, rec).c_str()); } } static void achat(int type, const char *mudfrom, const char *from, const char *text) { Flag option = FL_NONE; PFlag req = PFL_NONE; const char *colprop = "col.achat"; const char *defcol = "^c"; const char *ctl = "%s - %s - %s^n\n"; switch(type) { case CHAT: ctl = (*text == ':') ? chat_emote:chat_chat; option = chat_option; req = PFL_ABERCHAT; break; case ACODE: ctl = (*text == ':') ? coder_emote:coder_chat; option = coder_option; colprop = "col.acode"; defcol = "^y"; req = PFL_CODER; break; case AGOD: ctl = (*text == ':') ? god_emote:god_chat; option = god_option; colprop = "col.agod"; defcol = "^R"; req = PFL_GOD; break; default: ctl = "%s - %s - %s^n\n"; /* dummy format in case something goes wrong :) */ break; } if (*text == ':') { text++; while (*text==' ') text++; } MudObject *m; int i; foreach(players, m, i) { if (!m->get_flag(FL_LOGGEDIN)) continue; if (m->get_flag(FL_NOABERCHAT)) continue; if (option != FL_NONE && m->get_flag(option)) continue; if (!(req == PFL_NONE || m->get_priv(req))) continue; if (aber_ignored(m, mudfrom, from, false)) continue; const char *rcol = m->get(colprop); string myfmt = subfmt(ctl, (rcol?:defcol)+1); string buf = ssprintf(myfmt.c_str(), from, mudfrom, dirt_to_music(text).c_str()); m->printf("%s", buf.c_str()); } } static void ainfo(bool music, const char *from, const char *text) { MudObject *m; int i; foreach(players, m, i) { if (!m->get_flag(FL_NOAINFO) && m->get_flag(FL_LOGGEDIN)) { m->printf(ainfo_fmt, from, dirt_to_music(text).c_str()); } } } static void auth_recieved(bool t) { if (t) { ainfo(true,MYMUD, "Authenticated/Joined Network"); aberchat_auth = true; } else { log(PFL_SEEINFO, 0, "aberchat", "didn't authenticate"); achat_shutdown(); } } static void send_awho(const char *mudn, const char *player) { string ptr; Player *obj; int i; ptr += ssprintf("%c" D "%s" D "%c" D "%s" D "%s", TO_MUD, mudn, RWHO, player, MYMUD); int pc = players->getsize(); if (pc) { Player *pls[pc]; int c = 0; foreach(players, obj, i) pls[c++] = obj; qsort(pls, pc, sizeof (Player *), player_rank); for (i=0;i<pc;i++) { MudObject *obj = pls[i]; if (obj->get_flag(FL_LOGGEDIN) && !obj->get_flag(FL_NOABERCHAT) && invis(obj)<=0) ptr += ssprintf(D "%s" D "%s" D "%s", bwname(obj), get_rank(obj), music_to_dirt(object_title(obj).c_str()).c_str()); } } aberchat_socket->write(ptr.c_str(), ptr.length()+1); last_achat=time(NULL); } static bool start_filepage(MudObject *who, const char *fn) { if (!is_player(who)) { who->printf("Players only.\n"); return true; } Player *p = (Player *)who; p->push_state("apager"); p->set("apager.line", 0); p->set("apager.which", fn); aprintf(who->id,"%c" D "%s" D "%c" D "%s" D "%s" D "%d", TO_MUD, MYMUD, FILEPAGE, bwname(who), fn, 0); return true; } static void afilepage(const char *player, const char *txt, const char *more) { Player *p = get_player(player); if (!p) return; if(p->get_int("apager.line")<0)return; p->set("style", 0); p->printf("%s", dirt_to_music(txt).c_str()); if (*more=='1') { p->printf("[AberPager : enter to continue, q to quit]"); int line = p->get_int("apager.line")+1; p->set("apager.line", line); } else { p->pop_state(); p->set("style", 2); p->set("apager.line",-1); p->need_prompt = 1; p->had_prompt = 0; } p->tryio(0); } static void state_aberpager(Player *who, const char *txt) { if (*txt == 'q' || *txt=='Q') { who->set("apager.line",-1); who->pop_state(); } else { int line = who->get_int("apager.line"); aprintf(who->id,"%c" D "%s" D "%c" D "%s" D "%s" D "%d", TO_MUD, MYMUD, FILEPAGE, bwname(who), who->get("apager.which"), line); } } static bool verb_aping(MudObject *who,int argc,const char **argv) { if(argc!=2) { who->printf("Syntax: aping <time in seconds>, or aping 0 to stop.\n"); return true; } int foo=atoi(argv[1]);//crude! if(foo) { if(foo>0) achat_ping_delay=foo; else who->printf("An unusual time, is that :%d",foo); } else { if(*argv[1]!='0') return true; else log(PFL_CODER,0,"aberchat","pinging turned off by %s",who->get("name")); achat_ping_delay=0; kill_mud_list(); } return true; } static bool verb_astate(MudObject *who,int argc,const char ** argv) { who->printf("^B=================================\n^n"); who->printf("^GAberchat is %s\n",(aberchat_socket)?"up":"down"); if(aberchat_socket) { if(aberchat_auth==true) { who->printf("^GAuthenticated\n"); if(achat_ping_delay) who->printf("^GPing interval is: %d.\n",achat_ping_delay); else who->printf("^RPinging is disabled.\n"); who->printf("^GTime since last Network usage %d.\n",time(NULL)-last_achat); } else who->printf("^RNOT authenticated\n"); } else { who->printf("^GPending Socket Number = %d\n",pending_achat_socket); who->printf("^GAuto starting is %sabled\n",(achat_auto_run==true)?"en":"dis"); if(achat_auto_run)who->printf("^GRetry Time is %d current time is %d\n",achat_fuckup_timeout,time(NULL)); } who->printf("^B=================================\n^n"); return true; } extern string esc(const char*, int); class magicvector { vector<string> v; public: void push_back(const string &s) { v.push_back(s); } string operator[](size_t i) { if (i>=size()) return ""; return v[i]; } size_t size() { return v.size(); } }; namespace ident { string dnslookup(const string &host); } struct mudrec { string name; string addr; string port; string lib; bool operator<(const mudrec &m) const { return name < m.name; } }; void dealwith(string sofar) { magicvector hmm; StrTok t(sofar.c_str()); while (const char *s=t.next("\a")) { hmm.push_back(s); } sofar = ""; if(achat_ping_delay) achat_ping_sched = now + achat_ping_delay; if (hmm[0]=="0" && hmm.size()>1) { auth_recieved(hmm[1]=="Y"); return; } if (hmm[0]=="1") { MudObject *dest = get_player(hmm[1].c_str()); if (dest) dest->printf("^WMudname ^CAddress " "^MPort ^GCode Base\n" DASHES); kill_mud_list(); int muds = 0; set<mudrec> allmuds; for (size_t i=0;i<(hmm.size()-2)/5;i++) { const char *mudname = hmm[i*5 + 2].c_str(); const char *mudaddr = hmm[i*5 + 3].c_str(); const char *mudport = hmm[i*5 + 5].c_str(); const char *mudlib = hmm[i*5 + 6].c_str(); mudrec m = {mudname, mudaddr, mudport, mudlib }; allmuds.insert(m); achat_list.insert(make_lower(mudname).c_str()); muds++; } if (dest) { iforeach(m, allmuds) dest->printf("%-16.14s%-43.41s%-6s%s\n", m->name, ident::dnslookup(m->addr), m->port, m->lib); dest->printf(DASHES); string h = ident::dnslookup(aberchat_socket->get_addr()); string i = aberchat_socket->get_addr()->tostring(); dest->printf("There %s %i %s on %s:%i.\n", muds==1?"is":"are", muds, muds==1?"mud":"muds", h.length()?h:i, aberchat_socket->get_addr()->get_port()); if (Player *p=dynamic_cast<Player*>(dest)) { p->tryio(0); } } return; } if (hmm[0]=="4" || hmm[0]=="<" || hmm[0]=="=") { achat(hmm[0][0], hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str()); return; } if (hmm[0]=="6") { MudObject *who = get_player(hmm[1].c_str()); if (!who) return; if (hmm.size()==3) { who->printf("There are no players online at %s.\n", hmm[2].c_str()); if (Player *p=dynamic_cast<Player*>(who)) { p->tryio(0); } return; } int c = 0; who->printf("^WLevel ^CName ^YTitle\n" DASHES); for (size_t i=0;i<(hmm.size()-3)/3;i++) { const char *level = hmm[i*3 + 3].c_str(); const char *name = hmm[i*3 + 4].c_str(); const char *title = hmm[i*3 + 5].c_str(); who->printf("%-14s%-15s^Z%s\n", name, level, dirt_to_music(title, 14+15).c_str()); c++; } who->printf(DASHES "There %s %d player%s on %s.\n", (c > 1) ? "are" : "is", c, (c > 1) ? "s" : "", hmm[2].c_str()); if (Player *p=dynamic_cast<Player*>(who)) { p->tryio(0); } return; } if (hmm[0]=="3") { atell(hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str(), hmm[4].c_str()); return; } if (hmm[0]=="8") { amessage(hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str()); return; } if (hmm[0]=="5") { send_awho(hmm[1].c_str(), hmm[2].c_str()); return; } if (hmm[0]=="7") { ainfo(false, hmm[1].c_str(), hmm[2].c_str()); return; } if (hmm[0]=="9") { kick_player(hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str()); return; } if (hmm[0]=="?") { recieve_abermail(hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str(), hmm[4].c_str(), hmm[5].c_str(), hmm[6].c_str()); return; } if (hmm[0]==":") { aversion(hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str()); return; } if (hmm[0]==">") { aver_reply(hmm[1].c_str(), hmm[2].c_str()); return; } if (hmm[0]=="@") { handle_act(hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str(), hmm[4].c_str(), hmm[5].c_str()); } if (hmm[0]=="A") { handle_areq(hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str(), hmm[4].c_str()); } if (hmm[0]==";") { afilepage(hmm[1].c_str(), hmm[2].c_str(), hmm[3].c_str()); } return; } static void achat_process() { if (achat_auto_run) { if (!aberchat_socket) { if(time(NULL)>achat_fuckup_timeout) achat_init(); } else { achat_auto_run=false; log(PFL_CODER,0,"aberchat","If that wasn't a code reload or a reboot, something is bad."); } } if (!aberchat_socket) return; static string sofar = ""; string s = aberchat_socket->read_data(); if (aberchat_socket->get_dead()) { log(PFL_CODER, 0, "aberchat", "network error, shutting down."); achat_fuckup_timeout=0; achat_auto_run=true; achat_shutdown(); return; } for (size_t i=0;i<s.length();i++) { char c = s[i]; if (c) { sofar += c; } else { dealwith(sofar); sofar = ""; } } if (achat_ping_delay && (now>achat_ping_sched) && aberchat_auth) { send_mudlist("flubsey"); achat_ping_sched = now + achat_ping_delay; } } #define MODULE "aberchat" void achat_check(MudObject *who, Flag flag=FL_NONE, const char *what=NULL) { if (!aberchat_socket) throw emsg("Aberchat isn't up at the moment."); if (!aberchat_auth) throw emsg("Aberchat isn't authenticated at the moment."); if (who->get_flag(FL_BANNEDABERCHAT)) throw emsg("You are banned from AberChat."); if (who->get_flag(FL_NOABERCHAT)) throw emsg("You have aberchat turned off."); if (flag != FL_NONE && who->get_flag(flag)) { who->printf("You had %s turned off.\n", what); who->set_bflag(flag, 0); } } static bool verb_acopyright(MudObject *who, int, const char **) { achat_check(who); return start_filepage(who, "copyright"); } static bool verb_amasslist(MudObject *who, int, const char **) { achat_check(who); return start_filepage(who, "masslist"); } static bool verb_apolicy(MudObject *who, int argc, const char **argv) { achat_check(who); string buffer = "policy"; if (argc>1) buffer = buffer + "." + argv[1]; return start_filepage(who, buffer.c_str()); } #define TOGGLE(what) ({ bool current = !who->get_flag(what); who->set_bflag(what, current); current; }) static bool verb_noaberchat(MudObject *who, int, const char **) { who->printf("AberChat now %s\n", !TOGGLE(FL_NOABERCHAT) ? "on" : "off"); return true; } static bool verb_noachat(MudObject *who, int, const char **) { who->printf("AChat now %s\n", !TOGGLE(FL_NOACHAT) ? "on" : "off"); return true; } static bool verb_noacode(MudObject *who, int, const char **) { who->printf("ACode now %s\n", !TOGGLE(FL_NOACODE) ? "on" : "off"); return true; } static bool verb_noagod(MudObject *who, int, const char **) { who->printf("AGod now %s\n", !TOGGLE(FL_NOAGOD) ? "on" : "off"); return true; } static bool verb_noatell(MudObject *who, int, const char **) { who->printf("ATell is now %s\n", !TOGGLE(FL_NOATELL) ? "on" : "off"); return true; } static bool verb_noainfo(MudObject *who, int, const char **) { who->printf("AInfo now %s\n", !TOGGLE(FL_NOAINFO) ? "on" : "off"); return true; } class UnInvis { MudObject *who; int oldinvis; public: UnInvis(MudObject *who) : who(who), oldinvis(invis(who)) { who->unset("invis"); } ~UnInvis() { who->set("invis", oldinvis); } }; string format_action(MudObject *who, const char *str) { parsedact a = parse_action(who, str, 0); return sprinta(mud, a.a_rest.c_str(), who, a.targ, a.txt.c_str(), 0, a.prop); } static bool verb_achat(MudObject *who, int argc, const char **argv) { achat_check(who, FL_NOACHAT, "achat"); string what2 = the_rest(argc, argv, 1); const char *what = what2.c_str(); string la; if (*what == '#') { UnInvis u(who); la = format_action(who, what+1); string expected_name = sprinta(who, "%1", who, who, NULL, 1); if (strncmp(la.c_str(), expected_name.c_str(), strlen(expected_name.c_str()))==0) { la = la.c_str()+strlen(expected_name.c_str())+1; la = ": " + la; what = la.c_str(); } else { who->printf("Can only achat actions that start with your name.\n"); return true; } } else if (what[0]!=':') { what2 = possibly_drunkify(who, what2); what = what2.c_str(); } if (what && *what) { send_chat(CHAT, bwname(who), music_to_dirt(what).c_str()); } else who->printf("Achat what?\n"); return true; } static bool verb_acode(MudObject *who, int argc, const char **argv) { achat_check(who, FL_NOACODE, "acode"); string what2 = the_rest(argc, argv, 1); const char *what = what2.c_str(); string la; if (*what == '#') { UnInvis u(who); la = format_action(who, what+1); string expected_name = sprinta(who, "%1", who, who, NULL, 1); if (strncmp(la.c_str(), expected_name.c_str(), strlen(expected_name.c_str()))==0) { la = la.c_str()+strlen(expected_name.c_str())+1; la = ": " + la; what = la.c_str(); } else { who->printf("Can only achat actions that start with your name.\n"); return true; } } else if (what[0]!=':') { what2 = possibly_drunkify(who, what2); what = what2.c_str(); } if (what && *what) send_chat(ACODE, bwname(who), music_to_dirt(what).c_str()); else who->printf("Acode what?\n"); return true; } static bool verb_agod(MudObject *who, int argc, const char **argv) { achat_check(who, FL_NOAGOD, "agod"); string what2 = the_rest(argc, argv, 1); const char *what = what2.c_str(); string la; if (*what == '#') { UnInvis u(who); la = format_action(who, what+1); string expected_name = sprinta(who, "%1", who, who, NULL, 1); if (strncmp(la.c_str(), expected_name.c_str(), strlen(expected_name.c_str()))==0) { la = la.c_str()+strlen(expected_name.c_str())+1; la = ": " + la; what = la.c_str(); } else { who->printf("Can only achat actions that start with your name.\n"); return true; } } else if (what[0]!=':') { what2 = possibly_drunkify(who, what2); what = what2.c_str(); } if (*what) send_chat(AGOD, bwname(who), music_to_dirt(what).c_str()); else who->printf("Agod what?\n"); return true; } static bool verb_ainfo(MudObject *who, int argc, const char **argv) { achat_check(who, FL_NOAINFO, "ainfo"); string what2 = the_rest(argc, argv, 1); const char *what = what2.c_str(); if (*what) send_info(music_to_dirt(what).c_str()); else who->printf("Ainfo what?\n"); return true; } static bool verb_awho(MudObject *who, int argc, const char ** argv) { achat_check(who); if (argc < 2) { who->printf("syntax: awho mudname\n"); return true; } string what2 = the_rest(argc, argv, 1); const char *q = what2.c_str(); send_who(who->id, q); return true; } static bool verb_amudlist(MudObject *who, int, const char **) { achat_check(who); send_mudlist(who->id); return true; } static bool verb_aversion(MudObject *who, int, const char **argv) { achat_check(who); send_aversion(who->id, argv[1]); return true; } static bool verb_atell(MudObject *who, int argc, const char **argv) { if (argc < 3) { who->printf("syntax: atell who@where what\n"); return true; } achat_check(who, FL_NOATELL, "atell"); if (invis(who)) { who->printf("You may not atell when invisible.\n"); return true; } char to[4096]; strncpy(to, argv[1],4096); char *atsign = strchr(to, '@'); if (!atsign) { who->printf("Where is the @ sign?\n"); return true; } char at[4096]; strcpy(at, atsign+1); *atsign = 0; if(aignore_polite(who,at,to)) return(true); string what2 = the_rest(argc, argv, 2); const char *what = what2.c_str(); send_tell(bwname(who), to, at, music_to_dirt(what).c_str()); const char *txt2 = what; const char *ctl = (*txt2==':') ? atell_emote_send_fmt : atell_send_fmt; if (*txt2==':') txt2++; for (; *txt2 == ' '; txt2++); if (!who->get_flag(FL_NOHEARBACK)) who->printf(ctl, to, at, txt2); return true; } static bool verb_areply(MudObject *who, int argc, const char **argv) { if (argc < 2) { who->printf("syntax: areply what\n"); return true; } achat_check(who, FL_NOATELL, "atell"); const char *whoto = who->get("areply.target"); if (!whoto) { who->printf("You have noone to reply to.\n"); return true; } char to[4096]; strncpy(to, whoto,4096); char *atsign = strchr(to, '@'); if (!atsign) { who->printf("Where is the @ sign?\n"); return true; } char at[4096]; strcpy(at, atsign+1); *atsign = 0; string what2 = the_rest(argc, argv, 1); const char *what = what2.c_str(); send_tell(bwname(who), to, at, music_to_dirt(what).c_str()); const char *txt2 = what; const char *ctl = (*txt2==':') ? areply_emote_send_fmt : areply_send_fmt; if (*txt2==':') txt2++; for (; *txt2 == ' '; txt2++); if (!who->get_flag(FL_NOHEARBACK)) who->printf(ctl, to,at, txt2); return true; } static bool verb_akick(MudObject *who, int argc, const char **argv) { achat_check(who); if (!who->get_priv(PFL_CANAKICK)) { who->printf("You can't do that.\n"); return true; } if (argc < 2) { who->printf("syntax: akick person@mud\n"); return true; } char to[4096]; strncpy(to, argv[1],4096); char *atsign = strchr(to, '@'); if (!atsign) { who->printf("Where is the @ sign?\n"); return true; } send_kick(bwname(who), to); return true; } static bool verb_aboot(MudObject *who, int, const char **) { if (aberchat_socket) { who->printf("Already up.\n"); return true; } if(pending_achat_socket!=-1) close(pending_achat_socket); pending_achat_socket=-1; achat_init(); return true; } static bool verb_ashutdown(MudObject *, int, const char **) { achat_shutdown(); achat_auto_run=false; return true; } #define CLEANUP aberhook = 0; abermail_hook = 0; #include "verbmodule.h" void startup() { extern bool rebooting; if (rebooting) { log(PFL_CODER, 0, "aberchat", "starting reboot"); char name[256]; sprintf(name, VARDATA "/aberfd.%i", getpid()); FILE *f = xopen(".", name, "r"); unlink(name); if (f) { char line[256]; fgets(line, 256, f); if (!feof(f)) { aberchat_socket = new Socket(); aberchat_socket->connect(atoi(line)); aberchat_isup=true; aberchat_auth = true; achat_auto_run = false; last_achat=time(NULL); } xclose(f); } log(PFL_CODER, 0, "aberchat", "done reboot"); } aberhook = achat_process; abermail_hook = send_abermail; AUTO_VERB(aaction, 3, 0, PFL_ABERCHAT); AUTO_VERB(noaberchat, 4, 0, PFL_ABERCHAT); AUTO_VERB(noachat, 4, 0, PFL_ABERCHAT); AUTO_VERB(noatell, 4, 0, PFL_ABERCHAT); AUTO_VERB(noainfo, 4, 0, PFL_ABERCHAT); AUTO_VERB(noacode, 5, 0, PFL_CODER); AUTO_VERB(noagod, 4, 0, PFL_GOD); AUTO_VERB(aignore, 4, 0 ,PFL_ABERCHAT); AUTO_VERB(achat, 3, 0, PFL_ABERCHAT, VFL_MAGICSPACE); AUTO_VERB(acode, 3, 0, PFL_CODER, VFL_MAGICSPACE); AUTO_VERB(agod, 3, 0, PFL_GOD, VFL_MAGICSPACE); AUTO_VERB(ainfo, 3, 0, PFL_GOD, VFL_MAGICSPACE); AUTO_VERB(amudlist, 3, 0, PFL_ABERCHAT); AUTO_VERB(atell, 3, 0, PFL_ABERCHAT, VFL_MAGICSPACE); AUTO_VERB(areply, 4, 0, PFL_ABERCHAT, VFL_MAGICSPACE); AUTO_VERB(awho, 3, 0, PFL_ABERCHAT); AUTO_VERB(aversion, 3, 0, PFL_ABERCHAT); AUTO_VERB(aboot, 3, 0, PFL_CODER); AUTO_VERB(ashutdown, 3, 0, PFL_CODER); AUTO_VERB(aping,5,0,PFL_CODER); AUTO_VERB(astate, 6, 0, PFL_CODER); AUTO_VERB(akick, 3, 0, PFL_CANAKICK); AUTO_VERB(acopyright, 4, 0, PFL_ABERCHAT); AUTO_VERB(apolicy, 5, 0, PFL_ABERCHAT); AUTO_VERB(amasslist, 3, 0, PFL_ABERCHAT); ADD_STATE("apager", "", state_aberpager, false); }