/*
 * Copyright (C) 2004-2005 BarkerJr
 *
 * This module 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 Anope; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#include "module.h"
#define VERSION "1.0.1"

/*
 * ircd_ctcpping
 *   by BarkerJr <http://barkerjr.net>
 *
 * This module has been written to block Bottler bots which reply to CTCP PING.
 * Bottlers reply to two-part pings (1102439028 1234) with only
 * the first part, but also mising the last digit (110243902).
 *
 * It has been tested on SolidIRCd 3.4.6 (based on Bahamut) and Anope 1.7.7svn.
 */

/* Akill Reason.  According to the Bottler forum, the default reason should
 * cause the bot to remove the server from its list. */
#define REASON "no bottler clients please"

/* Akill time in seconds (if applicable).  Minimum is 60.  Maximum is 2147483647.
 * 604800 = 1 week */
#define AKILL_TIME 604800

/* PingServ information */
#define s_PingServ "PingServ"
#define PINGSERV_FULL "Ping Server"

/* Run in gebug mode */
#undef DEBUG_MODE



/* End of configuration */



#if AKILL_TIME < 60
  #define AKILL_TIME 60
#elif AKILL_TIME > 2147483647
  #define AKILL_TIME 2147483647
#endif

#ifdef IRC_ULTIMATE3
  #define CONNECT_NOTICE "CLIENT"
#elif defined (IRC_RAGE2)
  #define CONNECT_NOTICE "SNICK"
#else
  #define CONNECT_NOTICE send_token("NICK", "&")
#endif

#if defined (IRC_SOLID) || defined (IRC_BAHAMUT)
  #define USE_IP
#endif

int gotNotice(char*, int, char**);
int gotConnect(char*, int, char**);

int AnopeInit(int argc, char **argv)
{
  Message *msg;
  int reply;
  msg = createMessage(send_token("NOTICE", "B"), gotNotice);
  reply = moduleAddMessage(msg, MOD_TAIL);
  if (reply != MOD_ERR_OK)
  {
    alog("ircd_ctcpping error adding message \"%s\": %i", send_token("NOTICE", "B"), reply);
    return MOD_STOP;
  }
  msg = createMessage(CONNECT_NOTICE, gotConnect);
  reply = moduleAddMessage(msg, MOD_TAIL);
  if (reply != MOD_ERR_OK)
  {
    alog("ircd_ctcpping error adding message \"%s\": %i", CONNECT_NOTICE, reply);
    return MOD_STOP;
  }
  anope_cmd_bot_nick(s_PingServ, ServiceUser, ServiceHost, PINGSERV_FULL, "+i");
  moduleAddAuthor("BarkerJr");
  moduleAddVersion(VERSION);
  alog("ircd_ctcpping v%s by BarkerJr loaded", VERSION);
#if AKILL_TIME < 3600
  alog("ircd_ctcpping akills expire after %u minutes", AKILL_TIME / 60);
#elif AKILL_TIME == 3600
  alog("ircd_ctcpping akills expire after 1 hour");
#elif AKILL_TIME < 86400
  alog("ircd_ctcpping akills expire after %.1f hours", AKILL_TIME / 3600.0);
#elif AKILL_TIME == 86400
  alog("ircd_ctcpping akills expire after 1 day");
#else
  alog("ircd_ctcpping akills expire after %.1f days", AKILL_TIME / 86400.0);
#endif
  return MOD_CONT;
}

void AnopeFini(void)
{
  anope_cmd_quit(s_PingServ, "Help!  I'm being unloaded!");
}

int gotNotice(char *source, int ac, char **av)
{
  if (*av[0] == '#') return MOD_CONT; /* Channel Notice */
  if (strcmp(av[0], s_PingServ)) return MOD_CONT; /* Not for me */
  if (strcmp(av[1], "\1PING BottlerTes\1")) return MOD_CONT; /* Not a Bottler */
  {
    User *u;
    if (!(u = finduser(source))) return MOD_CONT; /* Not a user */
    {
      char *mask;
      char *host;
#ifdef USE_IP
      if (!(host = moduleGetData(&u->moduleData, "ip")))
#endif
        host = u->host;
      if (!(mask = (char *)malloc(strlen(host) + 3))) /* Out of memory */
      {
        alog("ircd_ctcpping error allocating memory to akill %s", u->nick);
        return MOD_CONT;
      }
      sprintf(mask, "*@%s", host);
#ifdef DEBUG_MODE
      alog("%s: Sending akill for %s", s_PingServ, mask);
#endif
      add_akill(NULL, mask, s_PingServ, time(NULL) + AKILL_TIME, REASON);
      free(mask);
      alog("%s: Akilling %s!%s@%s [%s] for malformed CTCP \"PING\" reply (Bottler)", s_PingServ, u->nick, u->username, u->host, u->realname);
    }
  }
  return MOD_STOP;
}

int gotConnect(char *source, int ac, char **av)
{
  if (ac < 2) return MOD_CONT;
#ifndef IRC_ULTIMATE3
  if (*source) return MOD_CONT;
#endif
#ifdef USE_IP
  {
    User *u;
    if (!(u = finduser(av[0]))) return MOD_CONT; /* Not a user */
    {
      int reply;
      char ipbuf[16];
      struct in_addr addr;

      addr.s_addr = htonl(strtoul(av[8], NULL, 10));
      ntoa(addr, ipbuf, sizeof(ipbuf));
  #ifdef DEBUG_MODE
      alog("ircd_ctcpping storing %s for %s", ipbuf, av[0]);
  #endif
      reply = moduleAddData(&u->moduleData, "ip", ipbuf);

      if (reply != MOD_ERR_OK)
        alog("ircd_ctcpping error storing IP for %s: %i", av[0], reply);
    }
  }
#endif
  anope_cmd_privmsg2(s_PingServ, av[0], "\1PING BottlerTest PleaseIgnore\1");
  return MOD_CONT;
}

