musicmud-2.1.6/data/
musicmud-2.1.6/data/help/
musicmud-2.1.6/data/policy/
musicmud-2.1.6/data/wild/
musicmud-2.1.6/data/world/
musicmud-2.1.6/doc/
musicmud-2.1.6/src/ident/
musicmud-2.1.6/src/lua/
musicmud-2.1.6/src/lua/include/
musicmud-2.1.6/src/lua/src/lib/
musicmud-2.1.6/src/lua/src/lua/
musicmud-2.1.6/src/lua/src/luac/
/*
 * 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);
}