1
0
mirror of https://github.com/anope/anope.git synced 2026-07-07 11:03:13 +02:00

Added a new database format and sqlite support. Also moved db-convert to a module.

This commit is contained in:
Adam
2011-09-25 04:19:15 -04:00
parent 43201ead95
commit 1f2399de36
75 changed files with 4143 additions and 5880 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
# Only install example.chk and example.conf from this directory
# NOTE: I would've had this just find all files in the directory, but that would include files not needed (like this file)
set(DATA example.chk tables.sql botserv.example.conf example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf)
set(DATA example.chk botserv.example.conf example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf)
install(FILES ${DATA}
DESTINATION data
)
+65 -20
View File
@@ -1032,11 +1032,29 @@ dns
*/
/*
* db_plain
* [DEPRECATED] db_old
*
* This is the default flatfile database format.
* This is the old binary database format from late Anope 1.7.x, Anope 1.8.x, and
* early Anope 1.9.x. This module only loads these databases, and will NOT save them.
* You should only use this to upgrade old databases to a newer database format by loading
* other database modules in addition to this one, which will be used when saving databases.
*/
module { name = "db_plain" }
#module { name = "db_old" }
db_old
{
/*
* This is the encryption type used by the databases. This must be set correctly or
* your passwords will not work. Valid options are: md5, oldmd5, sha1, and plain.
*/
#hash = "md5"
}
/*
* [DEPRECATED] db_plain
*
* This is the flatfile database format from Anope-1.9.2 to Anope-1.9.5.
*/
#module { name = "db_plain" }
db_plain
{
/*
@@ -1046,25 +1064,52 @@ db_plain
}
/*
* db_mysql and db_mysql_live
* db_flatfile
*
* Enables (live) MySQL support.
*
* The db_mysql_live module is an extension to db_mysql, and should only be used if
* db_mysql is being used. This module pulls data in real time from SQL as it is
* requested by the core as a result of someone executing commands.
*
* This effectively allows you to edit your database and have it be immediately
* reflected back in Anope.
*
* At this time db_mysql_live only supports pulling data in real time from the three
* main tables: anope_cs_info, anope_ns_alias, and anope_ns_core.
*
* db_mysql provides the command operserv/sqlsync, which is used for importing other database
* methods into MySQL.
* This is the default flatfile database format.
*/
#module { name = "db_mysql" }
#module { name = "db_mysql_live" }
module { name = "db_flatfile" }
db_flatfile
{
/*
* The database name db_flatfile should use
*/
database = "anope.db"
}
/*
* db_sql
*
* This module allows saving and loading databases using one of the SQL engines.
*/
#module { name = "db_sql" }
db_sql
{
/*
* The SQL service db_sql should use, these are configured in modules.conf.
* For MySQL, this should probably be mysql/main.
*/
engine = "sqlite/main"
}
/*
* db_sql_live_read, db_sql_live_write
*
* Enables (live) SQL support.
*
* The db_sql_live modules are an extension to db_sql, and should only be used if
* db_sql is being used.
*
* The db_sql_live_read module pulls data in real time from
* SQL as it is needed by the core.
* At this time this three main tables: ChannelInfo, NickAlias, and NickCore.
*
* The db_sql_live_write module writes data to SQL in real time as it is modified by
* the core.
*
*/
#module { name = "db_sql_live_read" }
#module { name = "db_sql_live_write" }
/*
* [REQUIRED] Encryption modules.
+17 -3
View File
@@ -197,13 +197,13 @@ m_ldap_oper
/*
* m_mysql
*
* This module allows other modules (db_mysql/db_mysql_live) to use MySQL.
* Be sure you have imported the table schema with mydbgen before
* trying to use MySQL
* This module allows other modules to use MySQL.
*/
#module { name = "m_mysql" }
mysql
{
/* The name of this service */
name = "mysql/main"
database = "anope"
server = "127.0.0.1"
username = "anope"
@@ -296,6 +296,20 @@ proxyscan
reason = "You have an open proxy running on your host (%t:%i:%p)"
}
/*
* m_sqlite
*
* This module allows other modules to use SQLite.
*/
#module { name = "m_sqlite" }
sqlite
{
/* The name of this service */
name = "sqlite/main"
/* The database name, it will be created if it does not exist. */
database = "anope.db"
}
/*
* m_ssl
*
-426
View File
@@ -1,426 +0,0 @@
-- phpMyAdmin SQL Dump
-- version 3.3.5
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Aug 07, 2011 at 03:53 PM
-- Server version: 5.1.50
-- PHP Version: 5.3.6-pl0-gentoo
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
--
-- Database: `anope`
--
-- --------------------------------------------------------
--
-- Table structure for table `anope_bs_badwords`
--
CREATE TABLE IF NOT EXISTS `anope_bs_badwords` (
`channel` varchar(255) NOT NULL DEFAULT '',
`word` varchar(255) NOT NULL,
`type` varchar(50) NOT NULL,
UNIQUE KEY `channel` (`channel`,`word`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_bs_core`
--
CREATE TABLE IF NOT EXISTS `anope_bs_core` (
`nick` varchar(255) NOT NULL DEFAULT '',
`user` varchar(255) NOT NULL DEFAULT '',
`host` text NOT NULL,
`rname` text NOT NULL,
`flags` text NOT NULL,
`created` int(10) unsigned NOT NULL DEFAULT '0',
`chancount` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`nick`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_bs_info_metadata`
--
CREATE TABLE IF NOT EXISTS `anope_bs_info_metadata` (
`botname` varchar(255) NOT NULL DEFAULT '',
`name` varchar(255) NOT NULL DEFAULT '',
`value` text NOT NULL,
KEY `FK_anope_bs_info_metadata_botname` (`botname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_cs_access`
--
CREATE TABLE IF NOT EXISTS `anope_cs_access` (
`provider` varchar(255) NOT NULL DEFAULT '',
`data` varchar(255) NOT NULL DEFAULT '',
`mask` varchar(255) NOT NULL DEFAULT '',
`channel` varchar(255) NOT NULL DEFAULT '',
`last_seen` int(10) unsigned NOT NULL DEFAULT '0',
`creator` varchar(255) NOT NULL DEFAULT '',
`created` int(11) unsigned NOT NULL DEFAULT '0',
UNIQUE KEY `channel` (`channel`,`mask`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_cs_akick`
--
CREATE TABLE IF NOT EXISTS `anope_cs_akick` (
`channel` varchar(255) NOT NULL DEFAULT '',
`flags` varchar(255) NOT NULL DEFAULT '',
`mask` varchar(255) NOT NULL DEFAULT '',
`reason` text NOT NULL,
`creator` varchar(255) NOT NULL DEFAULT '',
`created` int(10) unsigned NOT NULL DEFAULT '0',
`last_used` int(10) unsigned NOT NULL DEFAULT '0',
UNIQUE KEY `channel` (`channel`,`mask`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_cs_info`
--
CREATE TABLE IF NOT EXISTS `anope_cs_info` (
`name` varchar(255) NOT NULL DEFAULT '',
`founder` text NOT NULL,
`successor` text NOT NULL,
`descr` text NOT NULL,
`time_registered` int(10) unsigned NOT NULL DEFAULT '0',
`last_used` int(10) unsigned NOT NULL DEFAULT '0',
`last_topic` text NOT NULL,
`last_topic_setter` text NOT NULL,
`last_topic_time` int(10) unsigned NOT NULL DEFAULT '0',
`flags` text NOT NULL,
`bantype` smallint(6) NOT NULL DEFAULT '0',
`memomax` smallint(5) unsigned NOT NULL DEFAULT '0',
`botnick` varchar(255) NOT NULL DEFAULT '',
`botflags` text NOT NULL,
`capsmin` smallint(6) NOT NULL DEFAULT '0',
`capspercent` smallint(6) NOT NULL DEFAULT '0',
`floodlines` smallint(6) NOT NULL DEFAULT '0',
`floodsecs` smallint(6) NOT NULL DEFAULT '0',
`repeattimes` smallint(6) NOT NULL DEFAULT '0',
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_cs_info_metadata`
--
CREATE TABLE IF NOT EXISTS `anope_cs_info_metadata` (
`channel` varchar(255) NOT NULL DEFAULT '',
`name` varchar(255) NOT NULL DEFAULT '',
`value` text NOT NULL,
KEY `FK_anope_cs_info_metadata_channel` (`channel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_cs_levels`
--
CREATE TABLE IF NOT EXISTS `anope_cs_levels` (
`channel` varchar(255) NOT NULL DEFAULT '',
`name` varchar(255) NOT NULL DEFAULT '',
`level` int(11) NOT NULL DEFAULT '0',
UNIQUE KEY `channel` (`channel`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_cs_mlock`
--
CREATE TABLE IF NOT EXISTS `anope_cs_mlock` (
`channel` varchar(255) NOT NULL,
`mode` varchar(127) NOT NULL,
`status` int(11) NOT NULL,
`setter` varchar(255) NOT NULL,
`created` int(11) NOT NULL,
`param` varchar(255) NOT NULL,
UNIQUE KEY `entry` (`channel`,`mode`,`status`,`setter`,`param`),
KEY `FK_anope_cs_mlock` (`channel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_cs_ttb`
--
CREATE TABLE IF NOT EXISTS `anope_cs_ttb` (
`channel` varchar(255) NOT NULL DEFAULT '',
`ttb_id` int(11) NOT NULL DEFAULT '0',
`value` int(11) NOT NULL DEFAULT '0',
UNIQUE KEY `channel` (`channel`,`ttb_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_extra`
--
CREATE TABLE IF NOT EXISTS `anope_extra` (
`data` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_hs_core`
--
CREATE TABLE IF NOT EXISTS `anope_hs_core` (
`nick` varchar(255) NOT NULL,
`vident` varchar(64) NOT NULL,
`vhost` varchar(255) NOT NULL,
`creator` varchar(255) NOT NULL,
`time` int(11) NOT NULL,
KEY `FK_anope_hs_core_nick` (`nick`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_info`
--
CREATE TABLE IF NOT EXISTS `anope_info` (
`version` int(11) DEFAULT NULL,
`date` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_ms_info`
--
CREATE TABLE IF NOT EXISTS `anope_ms_info` (
`receiver` varchar(255) NOT NULL,
`flags` int(11) NOT NULL DEFAULT '0',
`time` int(10) unsigned NOT NULL DEFAULT '0',
`sender` text NOT NULL,
`text` blob NOT NULL,
`serv` enum('NICK','CHAN') NOT NULL DEFAULT 'NICK',
KEY `FK_anope_ms_info_receiver` (`receiver`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_ns_access`
--
CREATE TABLE IF NOT EXISTS `anope_ns_access` (
`display` varchar(255) NOT NULL DEFAULT '',
`access` varchar(160) NOT NULL,
KEY `FK_anope_ns_access_display` (`display`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_ns_alias`
--
CREATE TABLE IF NOT EXISTS `anope_ns_alias` (
`nick` varchar(255) NOT NULL DEFAULT '',
`last_quit` text NOT NULL,
`last_realname` text NOT NULL,
`last_usermask` text NOT NULL,
`last_realhost` text NOT NULL,
`time_registered` int(10) unsigned NOT NULL DEFAULT '0',
`last_seen` int(10) unsigned NOT NULL DEFAULT '0',
`flags` text NOT NULL,
`display` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`nick`),
KEY `FK_anope_ns_alias_display` (`display`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_ns_alias_metadata`
--
CREATE TABLE IF NOT EXISTS `anope_ns_alias_metadata` (
`nick` varchar(255) NOT NULL DEFAULT '',
`name` varchar(255) NOT NULL DEFAULT '',
`value` text NOT NULL,
KEY `FK_anope_ns_alias_metadata_nick` (`nick`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_ns_core`
--
CREATE TABLE IF NOT EXISTS `anope_ns_core` (
`display` varchar(255) NOT NULL DEFAULT '',
`pass` text NOT NULL,
`email` text NOT NULL,
`greet` text NOT NULL,
`flags` text NOT NULL,
`language` varchar(5) NOT NULL DEFAULT '',
`memomax` smallint(5) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`display`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_ns_core_metadata`
--
CREATE TABLE IF NOT EXISTS `anope_ns_core_metadata` (
`nick` varchar(255) NOT NULL DEFAULT '',
`name` varchar(255) NOT NULL DEFAULT '',
`value` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_os_core`
--
CREATE TABLE IF NOT EXISTS `anope_os_core` (
`maxusercnt` int(11) NOT NULL DEFAULT '0',
`maxusertime` int(10) unsigned NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_os_exceptions`
--
CREATE TABLE IF NOT EXISTS `anope_os_exceptions` (
`mask` varchar(255) NOT NULL,
`slimit` int(11) NOT NULL DEFAULT '0',
`who` text NOT NULL,
`reason` text NOT NULL,
`time` int(10) unsigned NOT NULL DEFAULT '0',
`expires` int(10) unsigned NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `anope_os_xlines`
--
CREATE TABLE IF NOT EXISTS `anope_os_xlines` (
`type` varchar(1) NOT NULL,
`mask` varchar(255) NOT NULL,
`xby` text NOT NULL,
`reason` text NOT NULL,
`seton` int(10) unsigned NOT NULL DEFAULT '0',
`expire` int(10) unsigned NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `anope_bs_badwords`
--
ALTER TABLE `anope_bs_badwords`
ADD CONSTRAINT `FK_anope_bs_badwords_channel` FOREIGN KEY (`channel`) REFERENCES `anope_cs_info` (`name`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_bs_info_metadata`
--
ALTER TABLE `anope_bs_info_metadata`
ADD CONSTRAINT `FK_anope_bs_info_metadata_botname` FOREIGN KEY (`botname`) REFERENCES `anope_bs_core` (`nick`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_cs_access`
--
ALTER TABLE `anope_cs_access`
ADD CONSTRAINT `FK_anope_cs_access_channel` FOREIGN KEY (`channel`) REFERENCES `anope_cs_info` (`name`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_cs_akick`
--
ALTER TABLE `anope_cs_akick`
ADD CONSTRAINT `FK_anope_cs_akick_channel` FOREIGN KEY (`channel`) REFERENCES `anope_cs_info` (`name`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_cs_info_metadata`
--
ALTER TABLE `anope_cs_info_metadata`
ADD CONSTRAINT `FK_anope_cs_info_metadata_channel` FOREIGN KEY (`channel`) REFERENCES `anope_cs_info` (`name`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_cs_levels`
--
ALTER TABLE `anope_cs_levels`
ADD CONSTRAINT `FK_anope_cs_levels_channel` FOREIGN KEY (`channel`) REFERENCES `anope_cs_info` (`name`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_cs_mlock`
--
ALTER TABLE `anope_cs_mlock`
ADD CONSTRAINT `FK_anope_cs_mlock_channel` FOREIGN KEY (`channel`) REFERENCES `anope_cs_info` (`name`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_cs_ttb`
--
ALTER TABLE `anope_cs_ttb`
ADD CONSTRAINT `FK_anope_cs_ttb_channel` FOREIGN KEY (`channel`) REFERENCES `anope_cs_info` (`name`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_hs_core`
--
ALTER TABLE `anope_hs_core`
ADD CONSTRAINT `FK_anope_hs_core_nick` FOREIGN KEY (`nick`) REFERENCES `anope_ns_alias` (`nick`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_ms_info`
--
ALTER TABLE `anope_ms_info`
ADD CONSTRAINT `FK_anope_ms_info_receiver` FOREIGN KEY (`receiver`) REFERENCES `anope_ns_alias` (`nick`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_ns_access`
--
ALTER TABLE `anope_ns_access`
ADD CONSTRAINT `FK_anope_ns_access_display` FOREIGN KEY (`display`) REFERENCES `anope_ns_core` (`display`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_ns_alias`
--
ALTER TABLE `anope_ns_alias`
ADD CONSTRAINT `FK_anope_ns_alias_display` FOREIGN KEY (`display`) REFERENCES `anope_ns_core` (`display`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `anope_ns_alias_metadata`
--
ALTER TABLE `anope_ns_alias_metadata`
ADD CONSTRAINT `FK_anope_ns_alias_metadata_nick` FOREIGN KEY (`nick`) REFERENCES `anope_ns_alias` (`nick`) ON DELETE CASCADE ON UPDATE CASCADE;
+3
View File
@@ -41,6 +41,9 @@ class CoreExport ChanAccess
time_t last_seen;
time_t created;
virtual Anope::string serialize_name() = 0;
virtual SerializableBase::serialized_data serialize() = 0;
ChanAccess(AccessProvider *p);
virtual ~ChanAccess();
virtual bool Matches(User *u, NickCore *nc) = 0;
+9 -5
View File
@@ -93,9 +93,7 @@ const Anope::string NickCoreFlagStrings[] = {
"MEMO_MAIL", "HIDE_STATUS", "SUSPENDED", "AUTOOP", "FORBIDDEN", "UNCONFIRMED", ""
};
class NickCore;
class CoreExport NickAlias : public Extensible, public Flags<NickNameFlag, NS_END>
class CoreExport NickAlias : public Extensible, public Flags<NickNameFlag, NS_END>, public Serializable<NickAlias>
{
public:
/** Default constructor
@@ -118,6 +116,9 @@ class CoreExport NickAlias : public Extensible, public Flags<NickNameFlag, NS_EN
NickCore *nc; /* I'm an alias of this */
HostInfo hostinfo;
serialized_data serialize();
static void unserialize(serialized_data &);
/** Release a nick
* See the comment in users.cpp
*/
@@ -131,7 +132,7 @@ class CoreExport NickAlias : public Extensible, public Flags<NickNameFlag, NS_EN
void OnCancel(User *u);
};
class CoreExport NickCore : public Extensible, public Flags<NickCoreFlag, NI_END>
class CoreExport NickCore : public Extensible, public Flags<NickCoreFlag, NI_END>, public Serializable<NickCore>
{
public:
/** Default constructor
@@ -153,14 +154,17 @@ class CoreExport NickCore : public Extensible, public Flags<NickCoreFlag, NI_END
std::vector<Anope::string> access; /* Access list, vector of strings */
std::vector<Anope::string> cert; /* ssl certificate list, vector of strings */
MemoInfo memos;
uint16 channelcount; /* Number of channels currently registered */
Oper *o;
/* Unsaved data */
uint16 channelcount; /* Number of channels currently registered */
time_t lastmail; /* Last time this nick record got a mail */
std::list<NickAlias *> aliases; /* List of aliases */
serialized_data serialize();
static void unserialize(serialized_data &);
/** Checks whether this account is a services oper or not.
* @return True if this account is a services oper, false otherwise.
*/
+4 -1
View File
@@ -32,7 +32,7 @@ enum BotFlag
static const Anope::string BotFlagString[] = { "BEGIN", "CORE", "PRIVATE", "CONF", "" };
class CoreExport BotInfo : public User, public Flags<BotFlag, BI_END>
class CoreExport BotInfo : public User, public Flags<BotFlag, BI_END>, public Serializable<BotInfo>
{
public:
uint32 chancount;
@@ -57,6 +57,9 @@ class CoreExport BotInfo : public User, public Flags<BotFlag, BI_END>
*/
virtual ~BotInfo();
serialized_data serialize();
static void unserialize(serialized_data &);
void GenerateUID();
/** Change the nickname for the bot.
+38 -134
View File
@@ -7,61 +7,28 @@
#ifndef EXTENSIBLE_H
#define EXTENSIBLE_H
#include "anope.h"
#include "hashcomp.h"
/** Dummy base class we use to cast everything to/from
*/
class ExtensibleItemBase
class ExtensibleItem
{
public:
ExtensibleItemBase() { }
virtual ~ExtensibleItemBase() { }
ExtensibleItem();
virtual ~ExtensibleItem();
virtual void OnDelete();
};
/** Class used to represent an extensible item that doesn't hold a pointer
*/
template<typename T> class ExtensibleItemRegular : public ExtensibleItemBase
class ExtensibleString : public Anope::string, public ExtensibleItem
{
protected:
T Item;
public:
ExtensibleItemRegular(T item) : Item(item) { }
virtual ~ExtensibleItemRegular() { }
T &GetItem() { return Item; }
};
/** Class used to represent an extensible item that holds a pointer
*/
template<typename T> class ExtensibleItemPointer : public ExtensibleItemBase
{
protected:
T *Item;
public:
ExtensibleItemPointer(T *item) : Item(item) { }
virtual ~ExtensibleItemPointer() { delete Item; }
T *GetItem() { return Item; }
};
/** Class used to represent an extensible item that holds a pointer to an arrray
*/
template<typename T> class ExtensibleItemPointerArray : public ExtensibleItemBase
{
protected:
T *Item;
public:
ExtensibleItemPointerArray(T *item) : Item(item) { }
virtual ~ExtensibleItemPointerArray() { delete [] Item; }
T *GetItem() { return Item; }
ExtensibleString(const Anope::string &s) : Anope::string(s), ExtensibleItem() { }
};
class CoreExport Extensible : public Base
{
private:
typedef std::map<Anope::string, ExtensibleItemBase *> extensible_map;
extensible_map Extension_Items;
typedef Anope::map<ExtensibleItem *> extensible_map;
extensible_map extension_items;
public:
/** Default constructor, does nothing
@@ -73,9 +40,10 @@ class CoreExport Extensible : public Base
*/
virtual ~Extensible()
{
for (extensible_map::iterator it = Extension_Items.begin(), it_end = Extension_Items.end(); it != it_end; ++it)
delete it->second;
Extension_Items.clear();
for (extensible_map::iterator it = extension_items.begin(), it_end = extension_items.end(); it != it_end; ++it)
if (it->second)
it->second->OnDelete();
extension_items.clear();
}
/** Extend an Extensible class.
@@ -89,26 +57,10 @@ class CoreExport Extensible : public Base
*
* @return Returns true on success, false if otherwise
*/
void Extend(const Anope::string &key, ExtensibleItemBase *p)
void Extend(const Anope::string &key, ExtensibleItem *p)
{
this->Shrink(key);
this->Extension_Items.insert(std::make_pair(key, p));
}
/** Extend an Extensible class.
*
* @param key The key parameter is an arbitary string which identifies the extension data
*
* You must provide a key to store the data as via the parameter 'key', this single-parameter
* version takes no 'data' parameter, this is used purely for boolean values.
* The key will be inserted into the map with a NULL 'data' pointer. If the key already exists
* then you may not insert it twice, Extensible::Extend will return false in this case.
*
* @return Returns true on success, false if otherwise
*/
void Extend(const Anope::string &key)
{
this->Extend(key, new ExtensibleItemPointer<char *>(NULL));
this->extension_items[key] = p;
}
/** Shrink an Extensible class.
@@ -121,91 +73,43 @@ class CoreExport Extensible : public Base
*/
bool Shrink(const Anope::string &key)
{
extensible_map::iterator it = this->Extension_Items.find(key);
if (it != this->Extension_Items.end())
extensible_map::iterator it = this->extension_items.find(key);
if (it != this->extension_items.end())
{
delete it->second;
if (it->second != NULL)
it->second->OnDelete();
/* map::size_type map::erase( const key_type& key );
* returns the number of elements removed, std::map
* is single-associative so this should only be 0 or 1
*/
return this->Extension_Items.erase(key);
return this->extension_items.erase(key) > 0;
}
return false;
}
/** Get an extension item that is not a pointer.
*
* @param key The key parameter is an arbitary string which identifies the extension data
* @param p If you provide a non-existent key, this value will be 0. Otherwise a copy to the item you requested will be placed in this templated parameter.
* @return Returns true if the item was found and false if it was nor, regardless of wether 'p' is NULL. This allows you to store NULL values in Extensible.
*/
template<typename T> bool GetExtRegular(const Anope::string &key, T &p)
{
extensible_map::iterator it = this->Extension_Items.find(key);
if (it != this->Extension_Items.end())
{
p = debug_cast<ExtensibleItemRegular<T> *>(it->second)->GetItem();
return true;
}
return false;
}
/** Get an extension item that is a pointer.
*
* @param key The key parameter is an arbitary string which identifies the extension data
* * @param p If you provide a non-existent key, this value will be NULL. Otherwise a pointer to the item you requested will be placed in this templated parameter.
* @return Returns true if the item was found and false if it was nor, regardless of wether 'p' is NULL. This allows you to store NULL values in Extensible.
*/
template<typename T> bool GetExtPointer(const Anope::string &key, T *&p)
{
extensible_map::iterator it = this->Extension_Items.find(key);
if (it != this->Extension_Items.end())
{
p = debug_cast<ExtensibleItemPointer<T> *>(it->second)->GetItem();
return true;
}
p = NULL;
return false;
}
/** Get an extension item that is a pointer to an array
*
* @param key The key parameter is an arbitary string which identifies the extension data
* @param p If you provide a non-existent key, this value will be NULL. Otherwise a pointer to the item you requested will be placed in this templated parameter.
* @return Returns true if the item was found and false if it was nor, regardless of wether 'p' is NULL. This allows you to store NULL values in Extensible.
*/
template<typename T> bool GetExtArray(const Anope::string &key, T *&p)
{
extensible_map::iterator it = this->Extension_Items.find(key);
if (it != this->Extension_Items.end())
{
p = debug_cast<ExtensibleItemPointerArray<T> *>(it->second)->GetItem();
return true;
}
p = NULL;
return false;
}
/** Get an extension item.
*
* @param key The key parameter is an arbitary string which identifies the extension data
* @return Returns true if the item was found and false if it was not.
*
* This single-parameter version only checks if the key exists, it does nothing with
* the 'data' field and is probably only useful in conjunction with the single-parameter
* version of Extend().
* @return The item found
*/
bool GetExt(const Anope::string &key)
template<typename T> T GetExt(const Anope::string &key)
{
return this->Extension_Items.find(key) != this->Extension_Items.end();
extensible_map::iterator it = this->extension_items.find(key);
if (it != this->extension_items.end())
return debug_cast<T>(it->second);
return NULL;
}
/** Check if an extension item exists.
*
* @param key The key parameter is an arbitary string which identifies the extension data
* @return True if the item was found.
*/
bool HasExt(const Anope::string &key)
{
return this->extension_items.count(key) > 0;
}
/** Get a list of all extension items names.
@@ -215,7 +119,7 @@ class CoreExport Extensible : public Base
*/
void GetExtList(std::deque<Anope::string> &list)
{
for (extensible_map::iterator it = Extension_Items.begin(), it_end = Extension_Items.end(); it != it_end; ++it)
for (extensible_map::iterator it = extension_items.begin(), it_end = extension_items.end(); it != it_end; ++it)
list.push_back(it->first);
}
};
-24
View File
@@ -316,30 +316,6 @@ namespace std
};
}
/* Define operators for using >> and << with irc::string to an ostream on an istream. */
/* This was endless fun. No. Really. */
/* It was also the first core change Ommeh made, if anyone cares */
/** Operator >> for irc::string
*/
inline std::istream &operator>>(std::istream &is, irc::string &str)
{
std::string tmp;
is >> tmp;
str = tmp.c_str();
return is;
}
/** Operator >> for ci::string
*/
inline std::istream &operator>>(std::istream &is, ci::string &str)
{
std::string tmp;
is >> tmp;
str = tmp.c_str();
return is;
}
/* Define operators for + and == with irc::string to std::string for easy assignment
* and comparison
*
+9 -82
View File
@@ -342,11 +342,6 @@ class CoreExport Module : public Extensible
*/
virtual void OnPostCommand(CommandSource &source, Command *command, const std::vector<Anope::string> &params) { }
/** Called after the core has finished loading the databases, but before
* we connect to the server
*/
virtual void OnPostLoadDatabases() { }
/** Called when the databases are saved
* @return EVENT_CONTINUE to let other modules continue saving, EVENT_STOP to stop
*/
@@ -485,73 +480,6 @@ class CoreExport Module : public Extensible
*/
virtual void OnServerDisconnect() { }
/** Called when the flatfile dbs are being written
* @param Write A callback to the function used to insert a line into the database
*/
virtual void OnDatabaseWrite(void (*Write)(const Anope::string &)) { }
/** Called when a line is read from the database
* @param params The params from the database
* @return EVENT_CONTINUE to let other modules decide, EVENT_STOP to stop processing
*/
virtual EventReturn OnDatabaseRead(const std::vector<Anope::string> &params) { return EVENT_CONTINUE; }
/** Called when nickcore metadata is read from the database
* @param nc The nickcore
* @param key The metadata key
* @param params The params from the database
* @return EVENT_CONTINUE to let other modules decide, EVENT_STOP to stop processing
*/
virtual EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> &params) { return EVENT_CONTINUE; }
/** Called when nickcore metadata is read from the database
* @param na The nickalias
* @param key The metadata key
* @param params The params from the database
* @return EVENT_CONTINUE to let other modules decide, EVENT_STOP to stop processing
*/
virtual EventReturn OnDatabaseReadMetadata(NickAlias *na, const Anope::string &key, const std::vector<Anope::string> &params) { return EVENT_CONTINUE; }
/** Called when botinfo metadata is read from the database
* @param bi The botinfo
* @param key The metadata key
* @param params The params from the database
* @return EVENT_CONTINUE to let other modules decide, EVENT_STOP to stop processing
*/
virtual EventReturn OnDatabaseReadMetadata(BotInfo *bi, const Anope::string &key, const std::vector<Anope::string> &params) { return EVENT_CONTINUE; }
/** Called when chaninfo metadata is read from the database
* @param ci The chaninfo
* @param key The metadata key
* @param params The params from the database
* @return EVENT_CONTINUE to let other modules decide, EVENT_STOP to stop processing
*/
virtual EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> &params) { return EVENT_CONTINUE; }
/** Called when we are writing metadata for a nickcore
* @param WriteMetata A callback function used to insert the metadata
* @param nc The nickcore
*/
virtual void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), NickCore *nc) { }
/** Called when we are wrting metadata for a nickalias
* @param WriteMetata A callback function used to insert the metadata
* @param na The nick alias
*/
virtual void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), NickAlias *na) { }
/** Called when we are writing metadata for a botinfo
* @param WriteMetata A callback function used to insert the metadata
* @param bi The botinfo
*/
virtual void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), BotInfo *bi) { }
/** Called when are are writing metadata for a channelinfo
* @param WriteMetata A callback function used to insert the metadata
* @param bi The channelinfo
*/
virtual void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), ChannelInfo *ci) { }
/** Called when services restart
*/
virtual void OnRestart() { }
@@ -673,11 +601,6 @@ class CoreExport Module : public Extensible
*/
virtual void OnChanDrop(const Anope::string &chname) { }
/** Called when a channel is forbidden
* @param ci The channel
*/
virtual void OnChanForbidden(ChannelInfo *ci) { }
/** Called when a channel is registered
* @param ci The channel
*/
@@ -979,10 +902,10 @@ class CoreExport Module : public Extensible
/** Called when a mode is about to be unlocked
* @param ci The channel the mode is being unlocked from
* @param mode The mode being unlocked
* @param lock The mode lock
* @return EVENT_CONTINUE to let other modules decide, EVENT_STOP to deny the mlock.
*/
virtual EventReturn OnUnMLock(ChannelInfo *ci, ChannelMode *mode, const Anope::string &param) { return EVENT_CONTINUE; }
virtual EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) { return EVENT_CONTINUE; }
/** Called after a module is loaded
* @param u The user loading the module, can be NULL
@@ -1042,7 +965,7 @@ enum Implementation
I_OnNickUpdate,
/* ChanServ */
I_OnChanForbidden, I_OnChanSuspend, I_OnChanDrop, I_OnPreChanExpire, I_OnChanExpire, I_OnAccessAdd,
I_OnChanSuspend, I_OnChanDrop, I_OnPreChanExpire, I_OnChanExpire, I_OnAccessAdd,
I_OnAccessDel, I_OnAccessClear, I_OnLevelChange, I_OnChanRegistered, I_OnChanUnsuspend, I_OnCreateChan, I_OnDelChan, I_OnChannelCreate,
I_OnChannelDelete, I_OnAkickAdd, I_OnAkickDel, I_OnCheckKick,
I_OnChanInfo, I_OnFindChan, I_OnCheckPriv, I_OnGroupCheckPriv,
@@ -1066,8 +989,7 @@ enum Implementation
I_OnAddXLine, I_OnDelXLine, I_IsServicesOper,
/* Database */
I_OnPostLoadDatabases, I_OnSaveDatabase, I_OnLoadDatabase,
I_OnDatabaseWrite, I_OnDatabaseRead, I_OnDatabaseReadMetadata, I_OnDatabaseWriteMetadata,
I_OnSaveDatabase, I_OnLoadDatabase,
/* Modules */
I_OnModuleLoad, I_OnModuleUnload,
@@ -1235,6 +1157,11 @@ class service_reference : public dynamic_reference<T>
{
}
inline void operator=(const Anope::string &n)
{
this->name = n;
}
operator bool()
{
if (this->invalid)
+7 -1
View File
@@ -11,14 +11,17 @@
class XLineManager;
class CoreExport XLine
class CoreExport XLine : public Serializable<XLine>
{
protected:
XLine();
public:
Anope::string Mask;
Anope::string By;
time_t Created;
time_t Expires;
Anope::string Reason;
Anope::string Manager;
XLine(const Anope::string &mask, const Anope::string &reason = "");
@@ -28,6 +31,9 @@ class CoreExport XLine
Anope::string GetUser() const;
Anope::string GetHost() const;
sockaddrs GetIP() const;
serialized_data serialize();
static void unserialize(serialized_data &data);
};
class CoreExport XLineManager : public Service<XLineManager>
+44 -5
View File
@@ -60,6 +60,30 @@ const Anope::string ChannelInfoFlagStrings[] = {
"SIGNKICK", "SIGNKICK_LEVEL", "SUSPENDED", "PERSIST", ""
};
/** Flags for badwords
*/
enum BadWordType
{
/* Always kicks if the word is said */
BW_ANY,
/* User must way the entire word */
BW_SINGLE,
/* The word has to start with the badword */
BW_START,
/* The word has to end with the badword */
BW_END
};
/* Structure used to contain bad words. */
struct BadWord : Serializable<BadWord>
{
Anope::string word;
BadWordType type;
serialized_data serialize();
static void unserialize(serialized_data &);
};
/** Flags for auto kick
*/
enum AutoKickFlag
@@ -71,7 +95,7 @@ enum AutoKickFlag
const Anope::string AutoKickFlagString[] = { "AK_ISNICK", "" };
/* AutoKick data. */
class AutoKick : public Flags<AutoKickFlag>
class AutoKick : public Flags<AutoKickFlag>, public Serializable<AutoKick>
{
public:
AutoKick() : Flags<AutoKickFlag>(AutoKickFlagString) { }
@@ -83,20 +107,29 @@ class AutoKick : public Flags<AutoKickFlag>
Anope::string creator;
time_t addtime;
time_t last_used;
serialized_data serialize();
static void unserialize(serialized_data &);
};
struct ModeLock
struct ModeLock : Serializable<ModeLock>
{
ModeLock() { }
public:
ChannelInfo *ci;
bool set;
ChannelModeName name;
Anope::string param;
Anope::string setter;
time_t created;
ModeLock(bool s, ChannelModeName n, const Anope::string &p, const Anope::string &se = "", time_t c = Anope::CurTime) : set(s), name(n), param(p), setter(se), created(c) { }
ModeLock(ChannelInfo *ch, bool s, ChannelModeName n, const Anope::string &p, const Anope::string &se = "", time_t c = Anope::CurTime) : ci(ch), set(s), name(n), param(p), setter(se), created(c) { }
serialized_data serialize();
static void unserialize(serialized_data &);
};
struct LogSetting
struct LogSetting : Serializable<LogSetting>
{
/* Our service name of the command */
Anope::string service_name;
@@ -107,9 +140,12 @@ struct LogSetting
Anope::string method, extra;
Anope::string creator;
time_t created;
serialized_data serialize();
static void unserialize(serialized_data &);
};
class CoreExport ChannelInfo : public Extensible, public Flags<ChannelInfoFlag, CI_END>
class CoreExport ChannelInfo : public Extensible, public Flags<ChannelInfoFlag, CI_END>, public Serializable<ChannelInfo>
{
private:
NickCore *founder; /* Channel founder */
@@ -163,6 +199,9 @@ class CoreExport ChannelInfo : public Extensible, public Flags<ChannelInfoFlag,
int16 floodlines, floodsecs; /* For FLOOD kicker */
int16 repeattimes; /* For REPEAT kicker */
serialized_data serialize();
static void unserialize(serialized_data &);
/** Change the founder of the channek
* @params nc The new founder
*/
+160
View File
@@ -0,0 +1,160 @@
#ifndef SERIALIZE_H
#define SERIALIZE_H
namespace Serialize
{
enum DataType
{
DT_TEXT,
DT_INT
};
class stringstream : public std::stringstream
{
private:
DataType type;
bool key;
unsigned max;
public:
stringstream() : std::stringstream(), type(DT_TEXT), key(false), max(0) { }
stringstream(const stringstream &ss) : std::stringstream(ss.str()), type(DT_TEXT), key(false), max(0) { }
Anope::string astr() const { return this->str(); }
template<typename T> std::istream &operator>>(T &val)
{
std::istringstream is(this->str());
is >> val;
return *this;
}
std::istream &operator>>(Anope::string &val) { return *this >> val.str(); }
stringstream &setType(DataType t)
{
this->type = t;
return *this;
}
DataType getType() const
{
return this->type;
}
stringstream &setKey()
{
this->key = true;
return *this;
}
bool getKey() const
{
return this->key;
}
stringstream &setMax(unsigned m)
{
this->max = m;
return *this;
}
unsigned getMax() const
{
return this->max;
}
};
}
class SerializableBase;
extern std::vector<SerializableBase *> serialized_types;
extern std::list<SerializableBase *> serialized_items;
extern void RegisterTypes();
class SerializableBase
{
public:
typedef std::map<Anope::string, Serialize::stringstream> serialized_data;
virtual Anope::string serialize_name() = 0;
virtual serialized_data serialize() = 0;
virtual void alloc(serialized_data &) = 0;
};
template<typename Type> class Serializable : public SerializableBase
{
public:
static class SerializableAllocator : public SerializableBase
{
Anope::string name;
public:
SerializableAllocator()
{
}
~SerializableAllocator()
{
Unregister();
}
void Register(const Anope::string &n, int pos = -1)
{
this->name = n;
serialized_types.insert(serialized_types.begin() + (pos < 0 ? serialized_types.size() : pos), this);
}
void Unregister()
{
std::vector<SerializableBase *>::iterator it = std::find(serialized_types.begin(), serialized_types.end(), this);
if (it != serialized_types.end())
serialized_types.erase(it);
}
Anope::string serialize_name()
{
if (this->name.empty())
throw CoreException();
return this->name;
}
serialized_data serialize()
{
throw CoreException();
}
void alloc(serialized_data &data)
{
Type::unserialize(data);
}
} Alloc;
private:
std::list<SerializableBase *>::iterator s_iter;
protected:
Serializable()
{
serialized_items.push_front(this);
this->s_iter = serialized_items.begin();
}
Serializable(const Serializable &)
{
serialized_items.push_front(this);
this->s_iter = serialized_items.begin();
}
~Serializable()
{
if (!serialized_items.empty())
serialized_items.erase(this->s_iter);
}
public:
Anope::string serialize_name()
{
return Alloc.serialize_name();
}
void alloc(serialized_data &)
{
throw CoreException();
}
};
template<typename T> typename Serializable<T>::SerializableAllocator Serializable<T>::Alloc;
#endif // SERIALIZE_H
+33 -50
View File
@@ -227,21 +227,6 @@ class ModuleException : public CoreException
virtual ~ModuleException() throw() { }
};
class DatabaseException : public CoreException
{
public:
/** This constructor can be used to specify an error message before throwing.
* @param mmessage The exception
*/
DatabaseException(const Anope::string &message) : CoreException(message, "A database module") { }
/** Destructor
* @throws Nothing
*/
virtual ~DatabaseException() throw() { }
};
/** Debug cast to be used instead of dynamic_cast, this uses dynamic_cast
* for debug builds and static_cast on releass builds to speed up the program
* because dynamic_cast relies on RTTI.
@@ -313,7 +298,29 @@ template<typename T, size_t Size = 32> class Flags
Flag_Values.reset();
}
std::vector<Anope::string> ToString()
Anope::string ToString()
{
std::vector<Anope::string> v = ToVector();
Anope::string flag_buf;
for (unsigned i = 0; i < v.size(); ++i)
flag_buf += v[i] + " ";
flag_buf.trim();
return flag_buf;
}
void FromString(const Anope::string &str)
{
spacesepstream sep(str);
Anope::string buf;
std::vector<Anope::string> v;
while (sep.GetToken(buf))
v.push_back(buf);
FromVector(v);
}
std::vector<Anope::string> ToVector()
{
std::vector<Anope::string> ret;
for (unsigned i = 0; this->Flag_Strings && !this->Flag_Strings[i].empty(); ++i)
@@ -322,7 +329,7 @@ template<typename T, size_t Size = 32> class Flags
return ret;
}
void FromString(const std::vector<Anope::string> &strings)
void FromVector(const std::vector<Anope::string> &strings)
{
for (unsigned i = 0; this->Flag_Strings && !this->Flag_Strings[i].empty(); ++i)
for (unsigned j = 0; j < strings.size(); ++j)
@@ -478,6 +485,7 @@ class Entry;
#include "threadengine.h"
#include "opertype.h"
#include "modes.h"
#include "serialize.h"
/*************************************************************************/
@@ -527,10 +535,14 @@ const Anope::string MemoFlagStrings[] = {
/* Memo info structures. Since both nicknames and channels can have memos,
* we encapsulate memo data in a MemoList to make it easier to handle. */
class CoreExport Memo : public Flags<MemoFlag>
class CoreExport Memo : public Flags<MemoFlag>, public Serializable<Memo>
{
public:
Memo();
Memo();
serialized_data serialize();
static void unserialize(serialized_data &);
Anope::string owner;
time_t time; /* When it was sent */
Anope::string sender;
Anope::string text;
@@ -555,15 +567,7 @@ struct Session
unsigned hits; /* Number of subsequent kills for a host */
};
struct Exception
{
Anope::string mask; /* Hosts to which this exception applies */
unsigned limit; /* Session limit for exception */
Anope::string who; /* Nick of person who added the exception */
Anope::string reason; /* Reason for exception's addition */
time_t time; /* When this exception was added */
time_t expires; /* Time when it expires. 0 == no expiry */
};
struct Exception;
/*************************************************************************/
@@ -611,28 +615,7 @@ class CoreExport HostInfo
/** Retrieve when the vhost was crated
* @return the time it was created
*/
const time_t GetTime() const;
};
/** Flags for badwords
*/
enum BadWordType
{
/* Always kicks if the word is said */
BW_ANY,
/* User must way the entire word */
BW_SINGLE,
/* The word has to start with the badword */
BW_START,
/* The word has to end with the badword */
BW_END
};
/* Structure used to contain bad words. */
struct BadWord
{
Anope::string word;
BadWordType type;
time_t GetTime() const;
};
/* BotServ SET flags */
+76 -47
View File
@@ -577,26 +577,60 @@ class CommandBSKick : public Command
}
};
struct BanData
struct BanData : public ExtensibleItem
{
Anope::string mask;
time_t last_use;
int16 ttb[TTB_SIZE];
BanData()
struct Data
{
this->Clear();
Anope::string mask;
time_t last_use;
int16 ttb[TTB_SIZE];
Data()
{
this->Clear();
}
void Clear()
{
last_use = 0;
for (int i = 0; i < TTB_SIZE; ++i)
this->ttb[i] = 0;
}
};
private:
typedef std::map<Anope::string, Data, std::less<ci::string> > data_type;
data_type data_map;
public:
Data &get(const Anope::string &key)
{
return this->data_map[key];
}
void Clear()
bool empty() const
{
last_use = 0;
for (int i = 0; i < TTB_SIZE; ++i)
this->ttb[i] = 0;
return this->data_map.empty();
}
void purge()
{
for (data_type::iterator it = data_map.begin(), it_end = data_map.end(); it != it_end;)
{
const Anope::string &user = it->first;
Data &bd = it->second;
++it;
if (Anope::CurTime - bd.last_use > Config->BSKeepData)
{
data_map.erase(user);
continue;
}
}
}
};
struct UserData
struct UserData : public ExtensibleItem
{
UserData()
{
@@ -621,6 +655,11 @@ struct UserData
Anope::string lastline;
Anope::string lasttarget;
int16 times;
void OnDelete()
{
delete this;
}
};
@@ -637,23 +676,11 @@ class BanDataPurger : public CallBack
{
Channel *c = it->second;
std::map<Anope::string, BanData> bandata;
if (c->GetExtRegular("bs_main_bandata", bandata))
BanData *bd = c->GetExt<BanData *>("bs_main_bandata");
if (bd != NULL)
{
for (std::map<Anope::string, BanData>::iterator it2 = bandata.begin(), it2_end = bandata.end(); it2 != it2_end;)
{
const Anope::string &user = it2->first;
BanData *bd = &it2->second;
++it2;
if (Anope::CurTime - bd->last_use > Config->BSKeepData)
{
bandata.erase(user);
continue;
}
}
if (bandata.empty())
bd->purge();
if (bd->empty())
c->Shrink("bs_main_bandata");
}
}
@@ -665,30 +692,32 @@ class BSKick : public Module
CommandBSKick commandbskick;
BanDataPurger purger;
BanData *GetBanData(User *u, Channel *c)
BanData::Data &GetBanData(User *u, Channel *c)
{
std::map<Anope::string, BanData> bandatamap;
if (!c->GetExtRegular("bs_main_bandata", bandatamap));
c->Extend("bs_main_bandata", new ExtensibleItemRegular<std::map<Anope::string, BanData> >(bandatamap));
c->GetExtRegular("bs_main_bandata", bandatamap);
BanData *bd = c->GetExt<BanData *>("bs_main_bandata");
if (bd == NULL)
{
bd = new BanData();
c->Extend("bs_main_bandata", bd);
}
BanData *bd = &bandatamap[u->GetMask()];
if (bd->last_use && Anope::CurTime - bd->last_use > Config->BSKeepData)
bd->Clear();
bd->last_use = Anope::CurTime;
return bd;
return bd->get(u->GetMask());
}
UserData *GetUserData(User *u, Channel *c)
{
UserData *ud = NULL;
UserContainer *uc = c->FindUser(u);
if (uc != NULL && !uc->GetExtPointer("bs_main_userdata", ud))
if (uc == NULL)
return NULL;
UserData *ud = uc->GetExt<UserData *>("bs_main_userdata");
if (ud == NULL)
{
ud = new UserData();
uc->Extend("bs_main_userdata", new ExtensibleItemPointer<UserData>(ud));
uc->Extend("bs_main_userdata", ud);
}
return ud;
return ud;
}
void check_ban(ChannelInfo *ci, User *u, int ttbtype)
@@ -697,17 +726,17 @@ class BSKick : public Module
if (u->server->IsULined())
return;
BanData *bd = this->GetBanData(u, ci->c);
BanData::Data &bd = this->GetBanData(u, ci->c);
++bd->ttb[ttbtype];
if (ci->ttb[ttbtype] && bd->ttb[ttbtype] >= ci->ttb[ttbtype])
++bd.ttb[ttbtype];
if (ci->ttb[ttbtype] && bd.ttb[ttbtype] >= ci->ttb[ttbtype])
{
/* Should not use == here because bd->ttb[ttbtype] could possibly be > ci->ttb[ttbtype]
/* Should not use == here because bd.ttb[ttbtype] could possibly be > ci->ttb[ttbtype]
* if the TTB was changed after it was not set (0) before and the user had already been
* kicked a few times. Bug #1056 - Adam */
Anope::string mask;
bd->ttb[ttbtype] = 0;
bd.ttb[ttbtype] = 0;
get_idealban(ci, u, mask);
+39 -3
View File
@@ -28,7 +28,7 @@ static void reset_levels(ChannelInfo *ci)
ci->SetLevel(it->first, it->second);
}
class AccessChanAccess : public ChanAccess
class AccessChanAccess : public ChanAccess, public Serializable<AccessChanAccess>
{
public:
int level;
@@ -86,6 +86,41 @@ class AccessChanAccess : public ChanAccess
return highest;
}
}
Anope::string serialize_name() { return "AccessChanAccess"; }
serialized_data serialize()
{
serialized_data data;
data["provider"] << this->provider->name;
data["ci"] << this->ci->name;
data["mask"] << this->mask;
data["creator"] << this->creator;
data["last_seen"].setType(Serialize::DT_INT) << this->last_seen;
data["created"].setType(Serialize::DT_INT) << this->created;
data["level"].setType(Serialize::DT_INT) << this->level;
return data;
}
static void unserialize(SerializableBase::serialized_data &data)
{
service_reference<AccessProvider> aprovider(data["provider"].astr());
ChannelInfo *ci = cs_findchan(data["ci"].astr());
if (!aprovider || !ci)
return;
AccessChanAccess *access = new AccessChanAccess(aprovider);
access->provider = aprovider;
access->ci = ci;
data["mask"] >> access->mask;
data["creator"] >> access->creator;
data["last_seen"] >> access->last_seen;
data["created"] >> access->created;
data["level"] >> access->level;
ci->AddAccess(access);
}
};
class AccessAccessProvider : public AccessProvider
@@ -459,10 +494,10 @@ class CommandCSAccess : public Command
source.Reply(ACCESS_DENIED);
else
{
ci->ClearAccess();
FOREACH_MOD(I_OnAccessClear, OnAccessClear(ci, u));
ci->ClearAccess();
source.Reply(_("Channel %s access list has been cleared."), ci->name.c_str());
bool override = !IsFounder(u, ci);
@@ -833,6 +868,7 @@ class CSAccess : public Module
{
this->SetAuthor("Anope");
Serializable<AccessChanAccess>::Alloc.Register("AccessChanAccess");
Implementation i[] = { I_OnReload, I_OnCreateChan, I_OnGroupCheckPriv };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
+67 -61
View File
@@ -13,34 +13,70 @@
#include "module.h"
struct EntryMsg
struct EntryMsg : Serializable<EntryMsg>
{
static unsigned MaxEntries;
ChannelInfo *ci;
Anope::string creator;
Anope::string message;
time_t when;
EntryMsg(const Anope::string &cname, const Anope::string &cmessage, time_t ct = Anope::CurTime)
EntryMsg(ChannelInfo *c, const Anope::string &cname, const Anope::string &cmessage, time_t ct = Anope::CurTime)
{
this->ci = c;
this->creator = cname;
this->message = cmessage;
this->when = ct;
}
Anope::string creator;
Anope::string message;
time_t when;
serialized_data serialize()
{
serialized_data data;
data["ci"] << this->ci->name;
data["creator"] << this->creator;
data["message"] << this->message;
data["when"].setType(Serialize::DT_INT) << this->when;
return data;
}
static void unserialize(serialized_data &data);
};
unsigned EntryMsg::MaxEntries = 0;
static unsigned MaxEntries = 0;
struct EntryMessageList : std::vector<EntryMsg>, ExtensibleItem
{
};
void EntryMsg::unserialize(serialized_data &data)
{
ChannelInfo *ci = cs_findchan(data["ci"].astr());
if (!ci)
return;
EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
if (messages == NULL)
{
messages = new EntryMessageList();
ci->Extend("cs_entrymsg", messages);
}
messages->push_back(EntryMsg(ci, data["creator"].astr(), data["message"].astr()));
}
class CommandEntryMessage : public Command
{
private:
void DoList(CommandSource &source, ChannelInfo *ci)
{
std::vector<EntryMsg> messages;
if (ci->GetExtRegular("cs_entrymsg", messages))
EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
if (messages == NULL)
{
source.Reply(_("Entry message list for \2%s\2:"), ci->name.c_str());
for (unsigned i = 0; i < messages.size(); ++i)
source.Reply(CHAN_LIST_ENTRY, i + 1, messages[i].message.c_str(), messages[i].creator.c_str(), do_strftime(messages[i].when).c_str());
for (unsigned i = 0; i < messages->size(); ++i)
source.Reply(CHAN_LIST_ENTRY, i + 1, (*messages)[i].message.c_str(), (*messages)[i].creator.c_str(), do_strftime((*messages)[i].when).c_str());
source.Reply(_("End of entry message list."));
}
else
@@ -49,35 +85,36 @@ class CommandEntryMessage : public Command
void DoAdd(CommandSource &source, ChannelInfo *ci, const Anope::string &message)
{
std::vector<EntryMsg> messages;
ci->GetExtRegular("cs_entrymsg", messages);
EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
if (messages == NULL)
{
messages = new EntryMessageList();
ci->Extend("cs_entrymsg", messages);
}
if (EntryMsg::MaxEntries && messages.size() >= EntryMsg::MaxEntries)
if (MaxEntries && messages->size() >= MaxEntries)
source.Reply(_("The entry message list for \2%s\2 is full."), ci->name.c_str());
else
{
messages.push_back(EntryMsg(source.u->nick, message));
ci->Extend("cs_entrymsg", new ExtensibleItemRegular<std::vector<EntryMsg> >(messages));
messages->push_back(EntryMsg(ci, source.u->nick, message));
source.Reply(_("Entry message added to \2%s\2"), ci->name.c_str());
}
}
void DoDel(CommandSource &source, ChannelInfo *ci, const Anope::string &message)
{
std::vector<EntryMsg> messages;
EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg");
if (!message.is_pos_number_only())
source.Reply(("Entry message \002%s\002 not found on channel \002%s\002."), message.c_str(), ci->name.c_str());
else if (ci->GetExtRegular("cs_entrymsg", messages))
else if (messages != NULL)
{
try
{
unsigned i = convertTo<unsigned>(message);
if (i > 0 && i <= messages.size())
if (i > 0 && i <= messages->size())
{
messages.erase(messages.begin() + i - 1);
if (!messages.empty())
ci->Extend("cs_entrymsg", new ExtensibleItemRegular<std::vector<EntryMsg> >(messages));
else
messages->erase(messages->begin() + i - 1);
if (messages->empty())
ci->Shrink("cs_entrymsg");
source.Reply(_("Entry message \2%i\2 for \2%s\2 deleted."), i, ci->name.c_str());
}
@@ -165,58 +202,27 @@ class CSEntryMessage : public Module
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnJoinChannel, I_OnReload, I_OnDatabaseReadMetadata, I_OnDatabaseWriteMetadata };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
this->OnReload();
Serializable<EntryMsg>::Alloc.Register("EntryMsg");
}
void OnJoinChannel(User *u, Channel *c)
{
if (u && c && c->ci && u->server->IsSynced())
{
std::vector<EntryMsg> messages;
EntryMessageList *messages = c->ci->GetExt<EntryMessageList *>("cs_entrymsg");
if (c->ci->GetExtRegular("cs_entrymsg", messages))
for (unsigned i = 0; i < messages.size(); ++i)
u->SendMessage(c->ci->WhoSends(), "[%s] %s", c->ci->name.c_str(), messages[i].message.c_str());
if (messages != NULL)
for (unsigned i = 0; i < messages->size(); ++i)
u->SendMessage(c->ci->WhoSends(), "[%s] %s", c->ci->name.c_str(), (*messages)[i].message.c_str());
}
}
void OnReload()
{
ConfigReader config;
EntryMsg::MaxEntries = config.ReadInteger("cs_entrymsg", "maxentries", "5", 0, true);
}
EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> &params)
{
if (key.find("CS_ENTRYMSG_") == 0 && params.size() > 2)
{
Anope::string creator = params[0];
time_t t = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime;
Anope::string message = params[2];
for (unsigned j = 3; j < params.size(); ++j)
message += " " + params[j];
std::vector<EntryMsg> messages;
ci->GetExtRegular("cs_entrymsg", messages);
messages.push_back(EntryMsg(creator, message, t));
ci->Extend("cs_entrymsg", new ExtensibleItemRegular<std::vector<EntryMsg> >(messages));
return EVENT_STOP;
}
return EVENT_CONTINUE;
}
void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), ChannelInfo *ci)
{
std::vector<EntryMsg> messages;
if (ci->GetExtRegular("cs_entrymsg", messages))
for (unsigned i = 0; i < messages.size(); ++i)
WriteMetadata("CS_ENTRYMSG_" + stringify(i), messages[i].creator + " " + stringify(messages[i].when) + " " + messages[i].message);
MaxEntries = config.ReadInteger("cs_entrymsg", "maxentries", "5", 0, true);
}
};
+38 -1
View File
@@ -15,7 +15,7 @@
static std::map<Anope::string, char> defaultFlags;
class FlagsChanAccess : public ChanAccess
class FlagsChanAccess : public ChanAccess, public Serializable<FlagsChanAccess>
{
public:
std::set<char> flags;
@@ -65,6 +65,41 @@ class FlagsChanAccess : public ChanAccess
return Anope::string(buffer.begin(), buffer.end());
}
Anope::string serialize_name() { return "FlagsChanAccess"; }
serialized_data serialize()
{
serialized_data data;
data["provider"] << this->provider->name;
data["ci"] << this->ci->name;
data["mask"] << this->mask;
data["creator"] << this->creator;
data["last_seen"].setType(Serialize::DT_INT) << this->last_seen;
data["created"].setType(Serialize::DT_INT) << this->created;
data["flags"] << this->Serialize();
return data;
}
static void unserialize(SerializableBase::serialized_data &data)
{
service_reference<AccessProvider> aprovider(data["provider"].astr());
ChannelInfo *ci = cs_findchan(data["ci"].astr());
if (!aprovider || !ci)
return;
FlagsChanAccess *access = new FlagsChanAccess(aprovider);
access->provider = aprovider;
access->ci = ci;
data["mask"] >> access->mask;
data["creator"] >> access->creator;
data["last_seen"] >> access->last_seen;
data["created"] >> access->created;
access->Unserialize(data["flags"].astr());
ci->AddAccess(access);
}
};
class FlagsAccessProvider : public AccessProvider
@@ -385,6 +420,8 @@ class CSFlags : public Module
ModuleManager::Attach(i, this, 1);
this->OnReload();
Serializable<FlagsChanAccess>::Alloc.Register("FlagsChanAccess");
}
void OnReload()
+3 -4
View File
@@ -100,10 +100,9 @@ class CommandCSInfo : public Command
}
if (ci->HasFlag(CI_SUSPENDED))
{
Anope::string by, reason;
ci->GetExtRegular("suspend_by", by);
ci->GetExtRegular("suspend_reason", reason);
source.Reply(_(" Suspended: [%s] %s"), by.c_str(), !reason.empty() ? reason.c_str() : NO_REASON);
Anope::string *by = ci->GetExt<Anope::string *>("suspend_by"), *reason = ci->GetExt<Anope::string *>("suspend_reason");
if (by != NULL)
source.Reply(_(" Suspended: [%s] %s"), by->c_str(), (reason && !reason->empty() ? reason->c_str() : NO_REASON));
}
FOREACH_MOD(I_OnChanInfo, OnChanInfo(source, ci, show_all));
+57 -96
View File
@@ -19,26 +19,55 @@ enum TypeInfo
NEW, NICK_TO, NICK_FROM, JOIN, PART, QUIT, KICK
};
struct SeenInfo
struct SeenInfo;
typedef Anope::insensitive_map<SeenInfo *> database_map;
database_map database;
struct SeenInfo : Serializable<SeenInfo>
{
Anope::string nick;
Anope::string vhost;
TypeInfo type;
Anope::string nick2; // for nickchanges and kicks
Anope::string channel; // for join/part/kick
Anope::string message; // for part/kick/quit
time_t last; // the time when the user was last seen
serialized_data serialize()
{
serialized_data data;
data["nick"] << nick;
data["vhost"] << vhost;
data["type"] << type;
data["nick2"] << nick2;
data["channel"] << channel;
data["message"] << message;
data["last"].setType(Serialize::DT_INT) << last;
return data;
}
static void unserialize(serialized_data &data)
{
SeenInfo *s = new SeenInfo();
data["nick"] >> s->nick;
data["vhost"] >> s->vhost;
unsigned int n;
data["type"] >> n;
s->type = static_cast<TypeInfo>(n);
data["nick2"] >> s->nick2;
data["channel"] >> s->channel;
data["message"] >> s->message;
data["last"] >> s->last;
database[s->nick] = s;
}
};
class ModuleConfigClass
{
public:
time_t purgetime;
time_t expiretimeout;
};
ModuleConfigClass ModuleConfig;
typedef Anope::insensitive_map<SeenInfo *> database_map;
database_map database;
static time_t purgetime;
static time_t expiretimeout;
static SeenInfo *FindInfo(const Anope::string &nick)
{
@@ -262,7 +291,7 @@ class DataBasePurger : public CallBack
database_map::iterator cur = it;
++it;
if ((Anope::CurTime - cur->second->last) > ModuleConfig.purgetime)
if ((Anope::CurTime - cur->second->last) > purgetime)
{
Log(LOG_DEBUG) << cur->first << " was last seen " << do_strftime(cur->second->last) << ", purging entry";
delete cur->second;
@@ -289,48 +318,55 @@ class CSSeen : public Module
I_OnUserQuit,
I_OnJoinChannel,
I_OnPartChannel,
I_OnUserKicked,
I_OnDatabaseRead,
I_OnDatabaseWrite };
I_OnUserKicked };
ModuleManager::Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
OnReload();
Serializable<SeenInfo>::Alloc.Register("SeenInfo");
}
void OnReload()
{
ConfigReader config;
ModuleConfig.purgetime = dotime(config.ReadValue("cs_seen", "purgetime", "30d", 0));
ModuleConfig.expiretimeout = dotime(config.ReadValue("cs_seen", "expiretimeout", "1d", 0));
purgetime = dotime(config.ReadValue("cs_seen", "purgetime", "30d", 0));
expiretimeout = dotime(config.ReadValue("cs_seen", "expiretimeout", "1d", 0));
if (purger.GetSecs() != ModuleConfig.expiretimeout)
purger.SetSecs(ModuleConfig.expiretimeout);
if (purger.GetSecs() != expiretimeout)
purger.SetSecs(expiretimeout);
}
void OnUserConnect(User *u)
{
UpdateUser(u, NEW, u->nick, "", "", "");
}
void OnUserNickChange(User *u, const Anope::string &oldnick)
{
UpdateUser(u, NICK_TO, oldnick, u->nick, "", "");
UpdateUser(u, NICK_FROM, u->nick, oldnick, "", "");
}
void OnUserQuit(User *u, const Anope::string &msg)
{
UpdateUser(u, QUIT, u->nick, "", "", msg);
}
void OnJoinChannel(User *u, Channel *c)
{
UpdateUser(u, JOIN, u->nick, "", c->name, "");
}
void OnPartChannel(User *u, Channel *c, const Anope::string &channel, const Anope::string &msg)
{
UpdateUser(u, PART, u->nick, "", channel, msg);
}
void OnUserKicked(Channel *c, User *target, const Anope::string &source, const Anope::string &msg)
{
UpdateUser(target, KICK, target->nick, source, c->name, msg);
}
void UpdateUser(const User *u, const TypeInfo Type, const Anope::string &nick, const Anope::string &nick2, const Anope::string &channel, const Anope::string &message)
{
SeenInfo *info = FindInfo(nick);
@@ -339,6 +375,7 @@ class CSSeen : public Module
info = new SeenInfo;
database.insert(std::pair<Anope::string, SeenInfo *>(nick, info));
}
info->nick = nick;
info->vhost = u->GetVIdent() + "@" + u->GetDisplayedHost();
info->type = Type;
info->last = Anope::CurTime;
@@ -346,82 +383,6 @@ class CSSeen : public Module
info->channel = channel;
info->message = message;
}
EventReturn OnDatabaseRead(const std::vector<Anope::string> &params)
{
if (params[0].equals_ci("SEEN") && (params.size() >= 5))
{
SeenInfo *info = new SeenInfo;
database.insert(std::pair<Anope::string, SeenInfo *>(params[1], info));
info->vhost = params[2];
info->last = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0 ;
if (params[4].equals_ci("NEW"))
{
info->type = NEW;
}
else if (params[4].equals_ci("NICK_TO") && params.size() == 6)
{
info->type = NICK_TO;
info->nick2 = params[5];
}
else if (params[4].equals_ci("NICK_FROM") && params.size() == 6)
{
info->type = NICK_FROM;
info->nick2 = params[5];
}
else if (params[4].equals_ci("JOIN") && params.size() == 6)
{
info->type = JOIN;
info->channel = params[5];
}
else if (params[4].equals_ci("PART") && params.size() == 7)
{
info->type = PART;
info->channel = params[5];
info->message = params[6];
}
else if (params[4].equals_ci("QUIT") && params.size() == 6)
{
info->type = QUIT;
info->message = params[5];
}
else if (params[4].equals_ci("KICK") && params.size() == 8)
{
info->type = KICK;
info->nick2 = params[5];
info->channel = params[6];
info->message = params[7];
}
return EVENT_STOP;
}
return EVENT_CONTINUE;
}
void OnDatabaseWrite(void (*Write)(const Anope::string &))
{
for (database_map::iterator it = database.begin(), it_end = database.end(); it != it_end; ++it)
{
std::stringstream buf;
buf << "SEEN " << it->first.c_str() << " " << it->second->vhost << " " << it->second->last << " ";
switch (it->second->type)
{
case NEW:
buf << "NEW"; break;
case NICK_TO:
buf << "NICK_TO " << it->second->nick2; break;
case NICK_FROM:
buf << "NICK_FROM " << it->second->nick2; break;
case JOIN:
buf << "JOIN " << it->second->channel; break;
case PART:
buf << "PART " << it->second->channel << " :" << it->second->message; break;
case QUIT:
buf << "QUIT :" << it->second->message; break;
case KICK:
buf << "KICK " << it->second->nick2 << " " << it->second->channel << " :" << it->second->message; break;
}
Write(buf.str());
}
}
};
MODULE_INIT(CSSeen)
+39 -30
View File
@@ -12,6 +12,37 @@
#include "module.h"
struct MiscData : Anope::string, ExtensibleItem, Serializable<MiscData>
{
ChannelInfo *ci;
Anope::string name;
Anope::string data;
MiscData(ChannelInfo *c, const Anope::string &n, const Anope::string &d) : ci(c), name(n), data(d)
{
}
serialized_data serialize()
{
serialized_data sdata;
sdata["ci"] << this->ci->name;
sdata["name"] << this->name;
sdata["data"] << this->data;
return sdata;
}
static void unserialize(serialized_data &data)
{
ChannelInfo *ci = cs_findchan(data["ci"].astr());
if (ci == NULL)
return;
ci->Extend(data["name"].astr(), new MiscData(ci, data["name"].astr(), data["data"].astr()));
}
};
class CommandCSSetMisc : public Command
{
public:
@@ -34,10 +65,11 @@ class CommandCSSetMisc : public Command
return;
}
ci->Shrink("cs_set_misc:" + source.command.replace_all_cs(" ", "_"));
Anope::string key = "cs_set_misc:" + source.command.replace_all_cs(" ", "_");
ci->Shrink(key);
if (params.size() > 1)
{
ci->Extend("cs_set_misc:" + source.command.replace_all_cs(" ", "_"), new ExtensibleItemRegular<Anope::string>(params[1]));
ci->Extend(key, new MiscData(ci, key, params[1]));
source.Reply(CHAN_SETTING_CHANGED, source.command.c_str(), ci->name.c_str(), params[1].c_str());
}
else
@@ -64,9 +96,10 @@ class CSSetMisc : public Module
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnChanInfo, I_OnDatabaseWriteMetadata, I_OnDatabaseReadMetadata };
Implementation i[] = { I_OnChanInfo };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
Serializable<MiscData>::Alloc.Register("CSMisc");
}
void OnChanInfo(CommandSource &source, ChannelInfo *ci, bool ShowHidden)
@@ -79,35 +112,11 @@ class CSSetMisc : public Module
if (list[i].find("cs_set_misc:") != 0)
continue;
Anope::string value;
if (ci->GetExtRegular(list[i], value))
source.Reply(" %s: %s", list[i].substr(12).replace_all_cs("_", " ").c_str(), value.c_str());
MiscData *data = ci->GetExt<MiscData *>(list[i]);
if (data != NULL)
source.Reply(" %s: %s", list[i].substr(12).replace_all_cs("_", " ").c_str(), data->data.c_str());
}
}
void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), ChannelInfo *ci)
{
std::deque<Anope::string> list;
ci->GetExtList(list);
for (unsigned i = 0; i < list.size(); ++i)
{
if (list[i].find("cs_set_misc:") != 0)
continue;
Anope::string value;
if (ci->GetExtRegular(list[i], value))
WriteMetadata(list[i], ":" + value);
}
}
EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> &params)
{
if (key.find("cs_set_misc:") == 0)
ci->Extend(key, new ExtensibleItemRegular<Anope::string>(params[0]));
return EVENT_CONTINUE;
}
};
MODULE_INIT(CSSetMisc)
+5 -6
View File
@@ -45,9 +45,9 @@ class CommandCSSuspend : public Command
}
ci->SetFlag(CI_SUSPENDED);
ci->Extend("suspend_by", new ExtensibleItemRegular<Anope::string>(u->nick));
ci->Extend("suspend_by", new ExtensibleString(u->nick));
if (!reason.empty())
ci->Extend("suspend_reason", new ExtensibleItemRegular<Anope::string>(reason));
ci->Extend("suspend_reason", new ExtensibleString(reason));
if (ci->c)
{
@@ -113,10 +113,9 @@ class CommandCSUnSuspend : public Command
return;
}
Anope::string by, reason;
ci->GetExtRegular("suspend_by", by);
ci->GetExtRegular("suspend_reason", reason);
Log(LOG_ADMIN, u, this, ci) << " which was suspended by " << by << " for: " << (!reason.empty() ? reason : "No reason");
Anope::string *by = ci->GetExt<Anope::string *>("suspend_by"), *reason = ci->GetExt<Anope::string *>("suspend_reason");
if (by != NULL)
Log(LOG_ADMIN, u, this, ci) << " which was suspended by " << *by << " for: " << (reason && !reason->empty() ? *reason : "No reason");
ci->UnsetFlag(CI_SUSPENDED);
ci->Shrink("suspend_by");
+37 -1
View File
@@ -90,7 +90,7 @@ static struct XOPAccess
}
};
class XOPChanAccess : public ChanAccess
class XOPChanAccess : public ChanAccess, public Serializable<XOPChanAccess>
{
public:
XOPType type;
@@ -188,6 +188,41 @@ class XOPChanAccess : public ChanAccess
return max;
}
}
Anope::string serialize_name() { return "XOPChanAccess"; }
serialized_data serialize()
{
serialized_data data;
data["provider"] << this->provider->name;
data["ci"] << this->ci->name;
data["mask"] << this->mask;
data["creator"] << this->creator;
data["last_seen"] << this->last_seen;
data["created"] << this->created;
data["type"] << this->Serialize();
return data;
}
static void unserialize(SerializableBase::serialized_data &data)
{
service_reference<AccessProvider> aprovider(data["provider"].astr());
ChannelInfo *ci = cs_findchan(data["ci"].astr());
if (!aprovider || !ci)
return;
XOPChanAccess *access = new XOPChanAccess(aprovider);
access->provider = aprovider;
access->ci = ci;
data["mask"] >> access->mask;
data["creator"] >> access->creator;
data["last_seen"] >> access->last_seen;
data["created"] >> access->created;
access->Unserialize(data["type"].astr());
ci->AddAccess(access);
}
};
class XOPAccessProvider : public AccessProvider
@@ -868,6 +903,7 @@ class CSXOP : public Module
{
this->SetAuthor("Anope");
Serializable<XOPChanAccess>::Alloc.Register("XOPChanAccess");
}
};
+66 -99
View File
@@ -21,18 +21,42 @@
static bool HSRequestMemoUser = false;
static bool HSRequestMemoOper = false;
void my_add_host_request(const Anope::string &nick, const Anope::string &vIdent, const Anope::string &vhost, const Anope::string &creator, time_t tmp_time);
void req_send_memos(CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost);
struct HostRequest
struct HostRequest : ExtensibleItem, Serializable<HostRequest>
{
Anope::string nick;
Anope::string ident;
Anope::string host;
time_t time;
};
typedef std::map<Anope::string, HostRequest *, std::less<ci::string> > RequestMap;
RequestMap Requests;
serialized_data serialize()
{
serialized_data data;
data["nick"] << this->nick;
data["ident"] << this->ident;
data["host"] << this->host;
data["time"].setType(Serialize::DT_INT) << this->time;
return data;
}
static void unserialize(serialized_data &data)
{
NickAlias *na = findnick(data["nick"].astr());
if (na == NULL)
return;
HostRequest *req = new HostRequest;
req->nick = na->nick;
data["ident"] >> req->ident;
data["host"] >> req->host;
data["time"] >> req->time;
na->Extend("hs_request", req);
}
};
class CommandHSRequest : public Command
{
@@ -54,6 +78,12 @@ class CommandHSRequest : public Command
{
User *u = source.u;
NickAlias *na = findnick(u->nick);
if (na == NULL)
na = findnick(u->Account()->display);
if (!na)
return;
Anope::string rawhostmask = params[0];
Anope::string user, host;
@@ -111,7 +141,14 @@ class CommandHSRequest : public Command
u->lastmemosend = Anope::CurTime;
return;
}
my_add_host_request(u->nick, user, host, u->nick, Anope::CurTime);
HostRequest *req = new HostRequest;
req->nick = u->nick;
req->ident = user;
req->host = host;
req->time = Anope::CurTime;
na->Extend("hs_request", req);
source.Reply(_("Your vHost has been requested"));
req_send_memos(source, user, host);
@@ -147,29 +184,21 @@ class CommandHSActivate : public Command
const Anope::string &nick = params[0];
NickAlias *na = findnick(nick);
if (na)
HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL;
if (req)
{
RequestMap::iterator it = Requests.find(na->nick);
if (it != Requests.end())
{
na->hostinfo.SetVhost(it->second->ident, it->second->host, u->nick, it->second->time);
FOREACH_MOD(I_OnSetVhost, OnSetVhost(na));
na->hostinfo.SetVhost(req->ident, req->host, u->nick, req->time);
FOREACH_MOD(I_OnSetVhost, OnSetVhost(na));
if (HSRequestMemoUser && memoserv)
memoserv->Send(Config->HostServ, na->nick, _("[auto memo] Your requested vHost has been approved."), true);
if (HSRequestMemoUser && memoserv)
memoserv->Send(Config->HostServ, na->nick, _("[auto memo] Your requested vHost has been approved."), true);
source.Reply(_("vHost for %s has been activated"), na->nick.c_str());
Log(LOG_COMMAND, u, this, NULL) << "for " << na->nick << " for vhost " << (!it->second->ident.empty() ? it->second->ident + "@" : "") << it->second->host;
delete it->second;
Requests.erase(it);
}
else
source.Reply(_("No request for nick %s found."), nick.c_str());
source.Reply(_("vHost for %s has been activated"), na->nick.c_str());
Log(LOG_COMMAND, u, this, NULL) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host;
na->Shrink("hs_request");
}
else
source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
return;
source.Reply(_("No request for nick %s found."), nick.c_str());
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand)
@@ -199,11 +228,11 @@ class CommandHSReject : public Command
const Anope::string &nick = params[0];
const Anope::string &reason = params.size() > 1 ? params[1] : "";
RequestMap::iterator it = Requests.find(nick);
if (it != Requests.end())
NickAlias *na = findnick(nick);
HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL;
if (req)
{
delete it->second;
Requests.erase(it);
na->Shrink("hs_request");
if (HSRequestMemoUser && memoserv)
{
@@ -246,9 +275,13 @@ class HSListBase : public Command
int from = 0, to = 0;
unsigned display_counter = 0;
for (RequestMap::iterator it = Requests.begin(), it_end = Requests.end(); it != it_end; ++it)
for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ++it)
{
HostRequest *hr = it->second;
NickAlias *na = it->second;
HostRequest *hr = na->GetExt<HostRequest *>("hs_request");
if (!hr)
continue;
if (((counter >= from && counter <= to) || (!from && !to)) && display_counter < Config->NSListMax)
{
++display_counter;
@@ -260,8 +293,6 @@ class HSListBase : public Command
++counter;
}
source.Reply(_("Displayed all records (Count: \002%d\002)"), display_counter);
return;
}
public:
HSListBase(Module *creator, const Anope::string &cmd, int min, int max) : Command(creator, cmd, min, max)
@@ -306,8 +337,7 @@ class HSRequest : public Module
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnDelNick, I_OnDatabaseRead, I_OnDatabaseWrite, I_OnReload };
Implementation i[] = { I_OnReload };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
this->OnReload();
@@ -315,47 +345,8 @@ class HSRequest : public Module
~HSRequest()
{
/* Clean up all open host requests */
while (!Requests.empty())
{
delete Requests.begin()->second;
Requests.erase(Requests.begin());
}
}
void OnDelNick(NickAlias *na)
{
RequestMap::iterator it = Requests.find(na->nick);
if (it != Requests.end())
{
delete it->second;
Requests.erase(it);
}
}
EventReturn OnDatabaseRead(const std::vector<Anope::string> &params)
{
if (params[0].equals_ci("HS_REQUEST") && params.size() >= 5)
{
Anope::string vident = params[2].equals_ci("(null)") ? "" : params[2];
my_add_host_request(params[1], vident, params[3], params[1], params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0);
return EVENT_STOP;
}
return EVENT_CONTINUE;
}
void OnDatabaseWrite(void (*Write)(const Anope::string &))
{
for (RequestMap::iterator it = Requests.begin(), it_end = Requests.end(); it != it_end; ++it)
{
HostRequest *hr = it->second;
std::stringstream buf;
buf << "HS_REQUEST " << it->first << " " << (hr->ident.empty() ? "(null)" : hr->ident) << " " << hr->host << " " << hr->time;
Write(buf.str());
}
for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ++it)
it->second->Shrink("hs_request");
}
void OnReload()
@@ -393,28 +384,4 @@ void req_send_memos(CommandSource &source, const Anope::string &vIdent, const An
}
}
void my_add_host_request(const Anope::string &nick, const Anope::string &vIdent, const Anope::string &vhost, const Anope::string &creator, time_t tmp_time)
{
HostRequest *hr = new HostRequest;
hr->ident = vIdent;
hr->host = vhost;
hr->time = tmp_time;
RequestMap::iterator it = Requests.find(nick);
if (it != Requests.end())
{
delete it->second;
Requests.erase(it);
}
Requests.insert(std::make_pair(nick, hr));
}
void my_load_config()
{
ConfigReader config;
HSRequestMemoUser = config.ReadFlag("hs_request", "memouser", "no", 0);
HSRequestMemoOper = config.ReadFlag("hs_request", "memooper", "no", 0);
Log(LOG_DEBUG) << "[hs_request] Set config vars: MemoUser=" << HSRequestMemoUser << " MemoOper=" << HSRequestMemoOper;
}
MODULE_INIT(HSRequest)
+86 -78
View File
@@ -13,66 +13,113 @@
#include "module.h"
struct AJoinList : std::vector<std::pair<Anope::string, Anope::string> >, ExtensibleItem, Serializable<AJoinList>
{
NickCore *nc;
AJoinList(NickCore *n) : nc(n) { }
serialized_data serialize()
{
serialized_data sd;
sd["nc"] << this->nc->display;
Anope::string channels;
for (unsigned i = 0; i < this->size(); ++i)
channels += this->at(i).first + "," + this->at(i).second;
sd["channels"] << channels;
return sd;
}
static void unserialize(serialized_data &sd)
{
NickCore *nc = findcore(sd["nc"].astr());
if (nc == NULL)
return;
AJoinList *aj = new AJoinList(nc);
nc->Extend("ns_ajoin_channels", aj);
Anope::string token;
spacesepstream ssep(sd["channels"].astr());
while (ssep.GetToken(token))
{
size_t c = token.find(',');
Anope::string chan, key;
if (c == Anope::string::npos)
chan = token;
else
{
chan = token.substr(0, c);
key = token.substr(c + 1);
}
aj->push_back(std::make_pair(chan, key));
}
}
};
class CommandNSAJoin : public Command
{
void DoList(CommandSource &source, const std::vector<Anope::string> &params)
{
std::vector<std::pair<Anope::string, Anope::string> > channels;
source.u->Account()->GetExtRegular("ns_ajoin_channels", channels);
AJoinList *channels = source.u->Account()->GetExt<AJoinList *>("ns_ajoin_channels");
if (channels.empty())
if (channels == NULL || channels->empty())
source.Reply(_("Your auto join list is empty."));
else
{
source.Reply(_("Your auto join list:\n"
" Num Channel Key"));
for (unsigned i = 0; i < channels.size(); ++i)
source.Reply(" %3d %-12s %s", i + 1, channels[i].first.c_str(), channels[i].second.c_str());
for (unsigned i = 0; i < channels->size(); ++i)
source.Reply(" %3d %-12s %s", i + 1, channels->at(i).first.c_str(), channels->at(i).second.c_str());
}
}
void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
{
std::vector<std::pair<Anope::string, Anope::string> > channels;
source.u->Account()->GetExtRegular("ns_ajoin_channels", channels);
AJoinList *channels = source.u->Account()->GetExt<AJoinList *>("ns_ajoin_channels");
if (channels == NULL)
{
channels = new AJoinList(source.u->Account());
source.u->Account()->Extend("ns_ajoin_channels", channels);
}
unsigned i;
for (i = 0; i < channels.size(); ++i)
if (channels[i].first.equals_ci(params[1]))
break;
unsigned i = 0;
if (channels != NULL)
for (; i < channels->size(); ++i)
if (channels->at(i).first.equals_ci(params[1]))
break;
if (channels.size() >= Config->AJoinMax)
if (channels->size() >= Config->AJoinMax)
source.Reply(_("Your auto join list is full."));
else if (i != channels.size())
else if (i != channels->size())
source.Reply(_("%s is already on your auto join list."), params[1].c_str());
else if (ircdproto->IsChannelValid(params[1]) == false)
source.Reply(CHAN_X_INVALID, params[1].c_str());
else
{
channels.push_back(std::make_pair(params[1], params.size() > 2 ? params[2] : ""));
channels->push_back(std::make_pair(params[1], params.size() > 2 ? params[2] : ""));
source.Reply(_("Added %s to your auto join list."), params[1].c_str());
source.u->Account()->Extend("ns_ajoin_channels", new ExtensibleItemRegular<std::vector<
std::pair<Anope::string, Anope::string> > >(channels));
}
}
void DoDel(CommandSource &source, const std::vector<Anope::string> &params)
{
std::vector<std::pair<Anope::string, Anope::string> > channels;
source.u->Account()->GetExtRegular("ns_ajoin_channels", channels);
AJoinList *channels = source.u->Account()->GetExt<AJoinList *>("ns_ajoin_channels");
unsigned i;
for (i = 0; i < channels.size(); ++i)
if (channels[i].first.equals_ci(params[1]))
break;
unsigned i = 0;
if (channels != NULL)
for (; i < channels->size(); ++i)
if (channels->at(i).first.equals_ci(params[1]))
break;
if (i == channels.size())
if (channels == NULL || i == channels->size())
source.Reply(_("%s was not found on your auto join list."), params[1].c_str());
else
{
channels.erase(channels.begin() + i);
source.u->Account()->Extend("ns_ajoin_channels", new ExtensibleItemRegular<std::vector<
std::pair<Anope::string, Anope::string> > >(channels));
channels->erase(channels->begin() + i);
source.Reply(_("%s was removed from your auto join list."), params[1].c_str());
}
}
@@ -120,25 +167,28 @@ class NSAJoin : public Module
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnNickIdentify, I_OnDatabaseWriteMetadata, I_OnDatabaseReadMetadata };
Implementation i[] = { I_OnNickIdentify };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
Serializable<AJoinList>::Alloc.Register("AJoinList");
}
void OnNickIdentify(User *u)
{
std::vector<std::pair<Anope::string, Anope::string> > channels;
u->Account()->GetExtRegular("ns_ajoin_channels", channels);
AJoinList *channels = u->Account()->GetExt<AJoinList *>("ns_ajoin_channels");
for (unsigned i = 0; i < channels.size(); ++i)
if (channels == NULL)
return;
for (unsigned i = 0; i < channels->size(); ++i)
{
Channel *c = findchan(channels[i].first);
ChannelInfo *ci = c != NULL ? c->ci : cs_findchan(channels[i].first);
Channel *c = findchan(channels->at(i).first);
ChannelInfo *ci = c != NULL ? c->ci : cs_findchan(channels->at(i).first);
if (c == NULL && ci != NULL)
c = ci->c;
bool need_invite = false;
Anope::string key = channels[i].second;
Anope::string key = channels->at(i).second;
if (ci != NULL)
{
@@ -192,54 +242,12 @@ class NSAJoin : public Module
BotInfo *bi = findbot(Config->NickServ);
if (!bi || !ci->AccessFor(u).HasPriv("INVITE"))
continue;
ircdproto->SendInvite(bi, channels[i].first, u->nick);
ircdproto->SendInvite(bi, channels->at(i).first, u->nick);
}
ircdproto->SendSVSJoin(Config->NickServ, u->nick, channels[i].first, key);
ircdproto->SendSVSJoin(Config->NickServ, u->nick, channels->at(i).first, key);
}
}
void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), NickCore *nc)
{
std::vector<std::pair<Anope::string, Anope::string> > channels;
nc->GetExtRegular("ns_ajoin_channels", channels);
Anope::string chans;
for (unsigned i = 0; i < channels.size(); ++i)
chans += " " + channels[i].first + "," + channels[i].second;
if (!chans.empty())
{
chans.erase(chans.begin());
WriteMetadata("NS_AJOIN", chans);
}
}
EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> &params)
{
if (key == "NS_AJOIN")
{
std::vector<std::pair<Anope::string, Anope::string> > channels;
nc->GetExtRegular("ns_ajoin_channels", channels);
for (unsigned i = 0; i < params.size(); ++i)
{
Anope::string chan, chankey;
commasepstream sep(params[i]);
sep.GetToken(chan);
sep.GetToken(chankey);
channels.push_back(std::make_pair(chan, chankey));
}
nc->Extend("ns_ajoin_channels", new ExtensibleItemRegular<std::vector<
std::pair<Anope::string, Anope::string> > >(channels));
return EVENT_STOP;
}
return EVENT_CONTINUE;
}
};
MODULE_INIT(NSAJoin)
+11 -8
View File
@@ -46,8 +46,8 @@ class CommandNSConfirm : public Command
}
else if (u->Account())
{
Anope::string code;
if (u->Account()->GetExtRegular<Anope::string>("ns_register_passcode", code) && code == passcode)
Anope::string *code = u->Account()->GetExt<Anope::string *>("ns_register_passcode");
if (code != NULL && *code == passcode)
{
u->Account()->Shrink("ns_register_passcode");
Log(LOG_COMMAND, u, this) << "to confirm their email";
@@ -320,8 +320,9 @@ class NSRegister : public Module
static bool SendRegmail(User *u, NickAlias *na, BotInfo *bi)
{
Anope::string code;
if (na->nc->GetExtRegular<Anope::string>("ns_register_passcode", code) == false)
Anope::string *code = na->nc->GetExt<Anope::string *>("ns_register_passcode");
Anope::string codebuf;
if (code == NULL)
{
int chars[] = {
' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
@@ -332,20 +333,22 @@ static bool SendRegmail(User *u, NickAlias *na, BotInfo *bi)
};
int idx, min = 1, max = 62;
for (idx = 0; idx < 9; ++idx)
code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * getrandom16() / 65536.0) + min];
na->nc->Extend("ns_register_passcode", new ExtensibleItemRegular<Anope::string>(code));
codebuf += chars[1 + static_cast<int>((static_cast<float>(max - min)) * getrandom16() / 65536.0) + min];
na->nc->Extend("ns_register_passcode", new ExtensibleString(codebuf));
}
else
codebuf = *code;
Anope::string subject = translate(na->nc, Config->MailRegistrationSubject.c_str());
Anope::string message = translate(na->nc, Config->MailRegistrationMessage.c_str());
subject = subject.replace_all_cs("%n", na->nick);
subject = subject.replace_all_cs("%N", Config->NetworkName);
subject = subject.replace_all_cs("%c", code);
subject = subject.replace_all_cs("%c", codebuf);
message = message.replace_all_cs("%n", na->nick);
message = message.replace_all_cs("%N", Config->NetworkName);
message = message.replace_all_cs("%c", code);
message = message.replace_all_cs("%c", codebuf);
return Mail(u, na->nc, bi, subject, message);
}
+17 -12
View File
@@ -56,6 +56,12 @@ class CommandNSResetPass : public Command
}
};
struct ResetInfo : ExtensibleItem
{
Anope::string code;
time_t time;
};
class NSResetPass : public Module
{
CommandNSResetPass commandnsresetpass;
@@ -80,28 +86,25 @@ class NSResetPass : public Module
User *u = source.u;
NickAlias *na = findnick(params[0]);
time_t t;
Anope::string c;
if (na && na->nc->GetExtRegular("ns_resetpass_code", c) && na->nc->GetExtRegular("ns_resetpass_time", t))
ResetInfo *ri = na ? na->nc->GetExt<ResetInfo *>("ns_resetpass") : NULL;
if (na && ri)
{
const Anope::string &passcode = params[1];
if (t < Anope::CurTime - 3600)
if (ri->time < Anope::CurTime - 3600)
{
na->nc->Shrink("ns_resetpass_code");
na->nc->Shrink("ns_resetpass_time");
na->nc->Shrink("ns_resetpass");
source.Reply(_("Your password reset request has expired."));
}
else if (passcode.equals_cs(c))
else if (passcode.equals_cs(ri->code))
{
na->nc->Shrink("ns_resetpass_code");
na->nc->Shrink("ns_resetpass_time");
na->nc->Shrink("ns_resetpass");
Log(LOG_COMMAND, u, &commandnsresetpass) << "confirmed RESETPASS to forcefully identify to " << na->nick;
na->nc->UnsetFlag(NI_UNCONFIRMED);
u->Identify(na);
source.Reply(_("You are now identified for your nick. Change your passwor now."));
source.Reply(_("You are now identified for your nick. Change your password now."));
}
else
@@ -142,8 +145,10 @@ static bool SendResetEmail(User *u, NickAlias *na, BotInfo *bi)
message = message.replace_all_cs("%N", Config->NetworkName);
message = message.replace_all_cs("%c", passcode);
na->nc->Extend("ns_resetpass_code", new ExtensibleItemRegular<Anope::string>(passcode));
na->nc->Extend("ns_resetpass_time", new ExtensibleItemRegular<time_t>(Anope::CurTime));
ResetInfo *ri = new ResetInfo;
ri->code = passcode;
ri->time = Anope::CurTime;
na->nc->Extend("ns_resetpass", ri);
return Mail(u, na->nc, bi, subject, message);
}
+6 -6
View File
@@ -26,7 +26,7 @@ static bool SendConfirmMail(User *u, BotInfo *bi)
Anope::string code;
for (idx = 0; idx < 9; ++idx)
code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * getrandom16() / 65536.0) + min];
u->Account()->Extend("ns_set_email_passcode", new ExtensibleItemRegular<Anope::string>(code));
u->Account()->Extend("ns_set_email_passcode", new ExtensibleString(code));
Anope::string subject = Config->MailEmailchangeSubject;
Anope::string message = Config->MailEmailchangeMessage;
@@ -80,7 +80,7 @@ class CommandNSSetEmail : public Command
if (!param.empty() && Config->NSConfirmEmailChanges && !u->IsServicesOper())
{
u->Account()->Extend("ns_set_email", new ExtensibleItemRegular<Anope::string>(param));
u->Account()->Extend("ns_set_email", new ExtensibleString(param));
Anope::string old = u->Account()->email;
u->Account()->email = param;
if (SendConfirmMail(u, source.owner))
@@ -163,12 +163,12 @@ class NSSetEmail : public Module
User *u = source.u;
if (command->name == "nickserv/confirm" && !params.empty() && u->IsIdentified())
{
Anope::string new_email, passcode;
if (u->Account()->GetExtRegular("ns_set_email", new_email) && u->Account()->GetExtRegular("ns_set_email_passcode", passcode))
Anope::string *new_email = u->Account()->GetExt<Anope::string *>("ns_set_email"), *passcode = u->Account()->GetExt<Anope::string *>("ns_set_email_passcode");
if (new_email && passcode)
{
if (params[0] == passcode)
if (params[0] == *passcode)
{
u->Account()->email = new_email;
u->Account()->email = *new_email;
Log(LOG_COMMAND, u, command) << "to confirm their email address change to " << u->Account()->email;
source.Reply(_("Your email address has been changed to \002%s\002."), u->Account()->email.c_str());
u->Account()->Shrink("ns_set_email");
+40 -30
View File
@@ -13,6 +13,38 @@
#include "module.h"
struct MiscData : Anope::string, ExtensibleItem, Serializable<MiscData>
{
NickCore *nc;
Anope::string name;
Anope::string data;
MiscData(NickCore *ncore, const Anope::string &n, const Anope::string &d) : nc(ncore), name(n), data(d)
{
}
serialized_data serialize()
{
serialized_data sdata;
sdata["nc"] << this->nc->display;
sdata["name"] << this->name;
sdata["data"] << this->data;
return sdata;
}
static void unserialize(serialized_data &data)
{
NickCore *nc = findcore(data["nc"].astr());
if (nc == NULL)
return;
nc->Extend(data["name"].astr(), new MiscData(nc, data["name"].astr(), data["data"].astr()));
}
};
class CommandNSSetMisc : public Command
{
public:
@@ -31,10 +63,11 @@ class CommandNSSetMisc : public Command
}
NickCore *nc = na->nc;
nc->Shrink("ns_set_misc:" + source.command.replace_all_cs(" ", "_"));
Anope::string key = "ns_set_misc:" + source.command.replace_all_cs(" ", "_");
nc->Shrink(key);
if (!param.empty())
{
nc->Extend("ns_set_misc:" + source.command.replace_all_cs(" ", "_"), new ExtensibleItemRegular<Anope::string>(param));
nc->Extend(key, new MiscData(nc, key, param));
source.Reply(CHAN_SETTING_CHANGED, source.command.c_str(), nc->display.c_str(), param.c_str());
}
else
@@ -75,9 +108,10 @@ class NSSetMisc : public Module
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnNickInfo, I_OnDatabaseWriteMetadata, I_OnDatabaseReadMetadata };
Implementation i[] = { I_OnNickInfo };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
Serializable<MiscData>::Alloc.Register("NSMisc");
}
void OnNickInfo(CommandSource &source, NickAlias *na, bool ShowHidden)
@@ -90,35 +124,11 @@ class NSSetMisc : public Module
if (list[i].find("ns_set_misc:") != 0)
continue;
Anope::string value;
if (na->nc->GetExtRegular(list[i], value))
source.Reply(" %s: %s", list[i].substr(12).replace_all_cs("_", " ").c_str(), value.c_str());
MiscData *data = na->nc->GetExt<MiscData *>(list[i]);
if (data)
source.Reply(" %s: %s", list[i].substr(12).replace_all_cs("_", " ").c_str(), data->data.c_str());
}
}
void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), NickCore *nc)
{
std::deque<Anope::string> list;
nc->GetExtList(list);
for (unsigned i = 0; i < list.size(); ++i)
{
if (list[i].find("ns_set_misc:") != 0)
continue;
Anope::string value;
if (nc->GetExtRegular(list[i], value))
WriteMetadata(list[i], ":" + value);
}
}
EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> &params)
{
if (key.find("ns_set_misc:") == 0)
nc->Extend(key, new ExtensibleItemRegular<Anope::string>(params[0]));
return EVENT_CONTINUE;
}
};
MODULE_INIT(NSSetMisc)
+2 -43
View File
@@ -214,10 +214,11 @@ class OSForbid : public Module
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnUserConnect, I_OnUserNickChange, I_OnJoinChannel, I_OnPreCommand, I_OnDatabaseWrite, I_OnDatabaseRead };
Implementation i[] = { I_OnUserConnect, I_OnUserNickChange, I_OnJoinChannel, I_OnPreCommand };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
Serializable<ForbidData>::Alloc.Register("Forbid");
}
void OnUserConnect(dynamic_reference<User> &u, bool &exempt)
@@ -301,48 +302,6 @@ class OSForbid : public Module
return EVENT_CONTINUE;
}
void OnDatabaseWrite(void (*Write)(const Anope::string &))
{
std::vector<ForbidData *> forbids = this->forbidService.GetForbids();
for (unsigned i = 0; i < forbids.size(); ++i)
{
ForbidData *f = forbids[i];
Anope::string ftype;
if (f->type == FT_NICK)
ftype = "NICK";
else if (f->type == FT_CHAN)
ftype = "CHAN";
else if (f->type == FT_EMAIL)
ftype = "EMAIL";
Write("FORBID " + f->mask + " " + f->creator + " " + stringify(f->created) + " " + stringify(f->expires) + " " + ftype + " " + f->reason);
}
}
EventReturn OnDatabaseRead(const std::vector<Anope::string> &params)
{
if (params.size() > 5 && params[0] == "FORBID")
{
ForbidData *f = new ForbidData();
f->mask = params[1];
f->creator = params[2];
f->created = convertTo<time_t>(params[3]);
f->expires = convertTo<time_t>(params[4]);
if (params[5] == "NICK")
f->type = FT_NICK;
else if (params[5] == "CHAN")
f->type = FT_CHAN;
else if (params[5] == "EMAIL")
f->type = FT_EMAIL;
else
f->type = FT_NONE;
f->reason = params.size() > 6 ? params[6] : "";
this->forbidService.AddForbid(f);
}
return EVENT_CONTINUE;
}
};
MODULE_INIT(OSForbid)
+39 -1
View File
@@ -9,7 +9,7 @@ enum ForbidType
FT_EMAIL
};
struct ForbidData
struct ForbidData : Serializable<ForbidData>
{
Anope::string mask;
Anope::string creator;
@@ -17,6 +17,9 @@ struct ForbidData
time_t created;
time_t expires;
ForbidType type;
serialized_data serialize();
static void unserialize(serialized_data &data);
};
class ForbidService : public Service<Base>
@@ -33,5 +36,40 @@ class ForbidService : public Service<Base>
virtual const std::vector<ForbidData *> &GetForbids() = 0;
};
static service_reference<ForbidService, Base> forbid_service("forbid");
SerializableBase::serialized_data ForbidData::serialize()
{
serialized_data data;
data["mask"] << this->mask;
data["creator"] << this->creator;
data["reason"] << this->reason;
data["created"] << this->created;
data["expires"] << this->expires;
data["type"] << this->type;
return data;
}
void ForbidData::unserialize(SerializableBase::serialized_data &data)
{
if (!forbid_service)
return;
ForbidData *fb = new ForbidData;
data["mask"] >> fb->mask;
data["creator"] >> fb->creator;
data["reason"] >> fb->reason;
data["created"] >> fb->created;
data["expires"] >> fb->expires;
unsigned int t;
data["type"] >> t;
fb->type = static_cast<ForbidType>(t);
forbid_service->AddForbid(fb);
}
#endif
+5 -47
View File
@@ -17,7 +17,7 @@
class OSIgnoreService : public IgnoreService
{
public:
OSIgnoreService(Module *o, const Anope::string &n) : IgnoreService(o, n) { }
OSIgnoreService(Module *o) : IgnoreService(o) { }
void AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime)
{
@@ -124,7 +124,7 @@ class OSIgnoreService : public IgnoreService
}
/* Check whether the entry has timed out */
if (ign != ign_end)// && (*ign)->time && (*ign)->time <= Anope::CurTime)
if (ign != ign_end)
{
IgnoreData &id = *ign;
@@ -146,7 +146,6 @@ class CommandOSIgnore : public Command
private:
void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
{
service_reference<IgnoreService, Base> ignore_service("ignore");
if (!ignore_service)
return;
@@ -181,7 +180,6 @@ class CommandOSIgnore : public Command
void DoList(CommandSource &source)
{
service_reference<IgnoreService, Base> ignore_service("ignore");
if (!ignore_service)
return;
@@ -205,7 +203,6 @@ class CommandOSIgnore : public Command
void DoDel(CommandSource &source, const std::vector<Anope::string> &params)
{
service_reference<IgnoreService, Base> ignore_service("ignore");
if (!ignore_service)
return;
@@ -222,7 +219,6 @@ class CommandOSIgnore : public Command
void DoClear(CommandSource &source)
{
service_reference<IgnoreService, Base> ignore_service("ignore");
if (!ignore_service)
return;
@@ -287,53 +283,15 @@ class OSIgnore : public Module
public:
OSIgnore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
osignoreservice(this, "ignore"), commandosignore(this)
osignoreservice(this), commandosignore(this)
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnDatabaseRead, I_OnDatabaseWrite, I_OnBotPrivmsg };
Implementation i[] = { I_OnBotPrivmsg };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
}
EventReturn OnDatabaseRead(const std::vector<Anope::string> &params)
{
if (params.size() >= 4 && params[0].equals_ci("OS") && params[1].equals_ci("IGNORE"))
{
service_reference<IgnoreService, Base> ignore_service("ignore");
if (ignore_service)
{
const Anope::string &mask = params[2];
time_t time = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0;
const Anope::string &creator = params.size() > 4 ? params[4] : "";
const Anope::string &reason = params.size() > 5 ? params[5] : "";
ignore_service->AddIgnore(mask, creator, reason, time - Anope::CurTime);
return EVENT_STOP;
}
}
return EVENT_CONTINUE;
}
void OnDatabaseWrite(void (*Write)(const Anope::string &))
{
for (std::list<IgnoreData>::iterator ign = this->osignoreservice.GetIgnores().begin(), ign_end = this->osignoreservice.GetIgnores().end(); ign != ign_end; )
{
if (ign->time && ign->time <= Anope::CurTime)
{
Log(LOG_DEBUG) << "[os_ignore] Expiring ignore entry " << ign->mask;
ign = this->osignoreservice.GetIgnores().erase(ign);
}
else
{
std::stringstream buf;
buf << "OS IGNORE " << ign->mask << " " << ign->time << " " << ign->creator << " :" << ign->reason;
Write(buf.str());
++ign;
}
}
Serializable<IgnoreData>::Alloc.Register("Ignore");
}
EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message)
+30 -2
View File
@@ -10,12 +10,15 @@
*/
struct IgnoreData
struct IgnoreData : Serializable<IgnoreData>
{
Anope::string mask;
Anope::string creator;
Anope::string reason;
time_t time; /* When do we stop ignoring them? */
serialized_data serialize();
static void unserialize(serialized_data &data);
};
class IgnoreService : public Service<Base>
@@ -23,7 +26,7 @@ class IgnoreService : public Service<Base>
protected:
std::list<IgnoreData> ignores;
IgnoreService(Module *c, const Anope::string &n) : Service<Base>(c, n) { }
IgnoreService(Module *c) : Service<Base>(c, "ignore") { }
public:
virtual void AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime) = 0;
@@ -37,3 +40,28 @@ class IgnoreService : public Service<Base>
inline std::list<IgnoreData> &GetIgnores() { return this->ignores; }
};
static service_reference<IgnoreService, Base> ignore_service("ignore");
SerializableBase::serialized_data IgnoreData::serialize()
{
serialized_data data;
data["mask"] << this->mask;
data["creator"] << this->creator;
data["reason"] << this->reason;
data["time"] << this->time;
return data;
}
void IgnoreData::unserialize(SerializableBase::serialized_data &data)
{
if (!ignore_service)
return;
time_t t;
data["time"] >> t;
ignore_service->AddIgnore(data["mask"].astr(), data["creator"].astr(), data["reason"].astr(), t);
}
+3 -3
View File
@@ -32,7 +32,7 @@ class CommandOSLogin : public Command
source.Reply(_("No oper block for your nick."));
else if (o->password.empty())
source.Reply(_("Your oper block doesn't require logging in."));
else if (source.u->GetExt("os_login_password_correct"))
else if (source.u->HasExt("os_login_password_correct"))
source.Reply(_("You are already identified."));
else if (o->password != password)
{
@@ -42,7 +42,7 @@ class CommandOSLogin : public Command
else
{
Log(LOG_ADMIN, source.u, this) << "and successfully identified to " << source.owner->nick;
source.u->Extend("os_login_password_correct");
source.u->Extend("os_login_password_correct", NULL);
source.Reply(_("Password accepted."));
}
@@ -84,7 +84,7 @@ class OSLogin : public Module
{
if (!u->Account()->o->password.empty())
{
if (u->GetExt("os_login_password_correct"))
if (u->HasExt("os_login_password_correct"))
return EVENT_ALLOW;
return EVENT_STOP;
}
-14
View File
@@ -32,13 +32,6 @@ class CommandOSModLoad : public Command
{
ircdproto->SendGlobops(source.owner, "%s loaded module %s", u->nick.c_str(), mname.c_str());
source.Reply(_("Module \002%s\002 loaded"), mname.c_str());
/* If a user is loading this module, then the core databases have already been loaded
* so trigger the event manually
*/
Module *m = ModuleManager::FindModule(mname);
if (m)
m->OnPostLoadDatabases();
}
else if (status == MOD_ERR_EXISTS)
source.Reply(_("Module \002%s\002 is already loaded."), mname.c_str());
@@ -100,13 +93,6 @@ class CommandOSModReLoad : public Command
{
ircdproto->SendGlobops(source.owner, "%s reloaded module %s", u->nick.c_str(), mname.c_str());
source.Reply(_("Module \002%s\002 reloaded"), mname.c_str());
/* If a user is loading this module, then the core databases have already been loaded
* so trigger the event manually
*/
m = ModuleManager::FindModule(mname);
if (m)
m->OnPostLoadDatabases();
}
else
{
+2 -46
View File
@@ -377,9 +377,10 @@ class OSNews : public Module
this->SetAuthor("Anope");
Implementation i[] = { I_OnUserModeSet, I_OnUserConnect, I_OnDatabaseRead, I_OnDatabaseWrite };
Implementation i[] = { I_OnUserModeSet, I_OnUserConnect };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
Serializable<NewsItem>::Alloc.Register("NewsItem");
}
void OnUserModeSet(User *u, UserModeName Name)
@@ -396,51 +397,6 @@ class OSNews : public Module
DisplayNews(user, NEWS_LOGON);
DisplayNews(user, NEWS_RANDOM);
}
EventReturn OnDatabaseRead(const std::vector<Anope::string> &params)
{
if (params[0].equals_ci("OS") && params.size() >= 7 && params[1].equals_ci("NEWS"))
{
NewsItem *n = new NewsItem();
// params[2] was news number
n->time = params[3].is_number_only() ? convertTo<time_t>(params[3]) : 0;
n->who = params[4];
if (params[5].equals_ci("LOGON"))
n->type = NEWS_LOGON;
else if (params[5].equals_ci("RANDOM"))
n->type = NEWS_RANDOM;
else if (params[5].equals_ci("OPER"))
n->type = NEWS_OPER;
n->text = params[6];
this->newsservice.AddNewsItem(n);
return EVENT_STOP;
}
return EVENT_CONTINUE;
}
void OnDatabaseWrite(void (*Write)(const Anope::string &))
{
for (unsigned i = 0; i < 3; ++i)
{
std::vector<NewsItem *> &list = this->newsservice.GetNewsList(static_cast<NewsType>(i));
for (std::vector<NewsItem *>::iterator it = list.begin(); it != list.end(); ++it)
{
NewsItem *n = *it;
Anope::string ntype;
if (n->type == NEWS_LOGON)
ntype = "LOGON";
else if (n->type == NEWS_RANDOM)
ntype = "RANDOM";
else if (n->type == NEWS_OPER)
ntype = "OPER";
Anope::string buf = "OS NEWS 0 " + stringify(n->time) + " " + n->who + " " + ntype + " :" + n->text;
Write(buf);
}
}
}
};
MODULE_INIT(OSNews)
+35 -1
View File
@@ -15,12 +15,15 @@ struct NewsMessages
const char *msgs[10];
};
struct NewsItem
struct NewsItem : Serializable<NewsItem>
{
NewsType type;
Anope::string text;
Anope::string who;
time_t time;
serialized_data serialize();
static void unserialize(serialized_data &data);
};
class NewsService : public Service<Base>
@@ -35,5 +38,36 @@ class NewsService : public Service<Base>
virtual std::vector<NewsItem *> &GetNewsList(NewsType t) = 0;
};
static service_reference<NewsService, Base> news_service("news");
SerializableBase::serialized_data NewsItem::serialize()
{
serialized_data data;
data["type"] << this->type;
data["text"] << this->text;
data["who"] << this->who;
data["time"] << this->time;
return data;
}
void NewsItem::unserialize(SerializableBase::serialized_data &data)
{
if (!news_service)
return;
NewsItem *ni = new NewsItem();
unsigned int t;
data["type"] >> t;
ni->type = static_cast<NewsType>(t);
data["text"] >> ni->text;
data["who"] >> ni->who;
data["time"] >> ni->time;
news_service->AddNewsItem(ni);
}
#endif // OS_NEWS
+33 -31
View File
@@ -13,6 +13,34 @@
#include "module.h"
struct MyOper : Oper, Serializable<MyOper>
{
MyOper(const Anope::string &n, OperType *o) : Oper(n, o) { }
serialized_data serialize()
{
serialized_data data;
data["name"] << this->name;
data["type"] << this->ot->GetName();
return data;
}
static void unserialize(serialized_data &data)
{
OperType *ot = OperType::Find(data["type"].astr());
if (ot == NULL)
return;
NickCore *nc = findcore(data["name"].astr());
if (nc == NULL)
return;
nc->o = new MyOper(nc->display, ot);
Log(LOG_NORMAL, "operserv/oper") << "Tied oper " << nc->display << " to type " << ot->GetName();
}
};
class CommandOSOper : public Command
{
public:
@@ -46,8 +74,7 @@ class CommandOSOper : public Command
source.Reply(_("Oper type \2%s\2 has not been configured."), type.c_str());
else
{
delete na->nc->o;
na->nc->o = new Oper(na->nc->display, ot);
na->nc->o = new MyOper(na->nc->display, ot);
Log(LOG_ADMIN, source.u, this) << "ADD " << na->nick << " as type " << ot->GetName();
source.Reply("%s (%s) added to the \2%s\2 list.", na->nick.c_str(), na->nc->display.c_str(), ot->GetName().c_str());
@@ -177,43 +204,18 @@ class OSOper : public Module
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnDatabaseWrite, I_OnDatabaseRead };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
Serializable<MyOper>::Alloc.Register("Oper");
}
void OnDatabaseWrite(void (*Write)(const Anope::string &))
~OSOper()
{
for (nickcore_map::const_iterator it = NickCoreList.begin(), it_end = NickCoreList.end(); it != it_end; ++it)
{
NickCore *nc = it->second;
if (!nc->o)
continue;
bool found = false;
for (std::list<NickAlias *>::const_iterator it2 = nc->aliases.begin(), it2_end = nc->aliases.end(); it2 != it2_end; ++it2)
if (Oper::Find((*it2)->nick) != NULL)
found = true;
if (found == false)
{
Write("OPER " + nc->display + " :" + nc->o->ot->GetName());
}
}
}
EventReturn OnDatabaseRead(const std::vector<Anope::string> &params)
{
if (params[0] == "OPER" && params.size() > 2)
{
NickCore *nc = findcore(params[1]);
if (!nc || nc->o)
return EVENT_CONTINUE;
OperType *ot = OperType::Find(params[2]);
if (ot == NULL)
return EVENT_CONTINUE;
nc->o = new Oper(nc->display, ot);
Log(LOG_NORMAL, "operserv/oper") << "Tied oper " << nc->display << " to type " << ot->GetName();
if (nc->o && !nc->o->config)
delete nc->o;
}
return EVENT_CONTINUE;
}
};
+34 -36
View File
@@ -14,8 +14,6 @@
#include "module.h"
#include "os_session.h"
static service_reference<SessionService, Base> sessionservice("session");
class MySessionService : public SessionService
{
SessionMap Sessions;
@@ -94,18 +92,18 @@ class ExpireTimer : public Timer
void Tick(time_t)
{
if (!sessionservice)
if (!session_service)
return;
for (unsigned i = sessionservice->GetExceptions().size(); i > 0; --i)
for (unsigned i = session_service->GetExceptions().size(); i > 0; --i)
{
Exception *e = sessionservice->GetExceptions()[i - 1];
Exception *e = session_service->GetExceptions()[i - 1];
if (!e->expires || e->expires > Anope::CurTime)
continue;
BotInfo *bi = findbot(Config->OperServ);
if (Config->WallExceptionExpire && bi)
ircdproto->SendGlobops(bi, "Session exception for %s has expired.", e->mask.c_str());
sessionservice->DelException(e);
session_service->DelException(e);
delete e;
}
}
@@ -133,7 +131,7 @@ class ExceptionDelCallback : public NumberList
virtual void HandleNumber(unsigned Number)
{
if (!Number || Number > sessionservice->GetExceptions().size())
if (!Number || Number > session_service->GetExceptions().size())
return;
++Deleted;
@@ -143,10 +141,10 @@ class ExceptionDelCallback : public NumberList
static void DoDel(CommandSource &source, unsigned index)
{
Exception *e = sessionservice->GetExceptions()[index];
Exception *e = session_service->GetExceptions()[index];
FOREACH_MOD(I_OnExceptionDel, OnExceptionDel(source.u, e));
sessionservice->DelException(e);
session_service->DelException(e);
delete e;
}
};
@@ -163,7 +161,7 @@ class ExceptionListCallback : public NumberList
virtual void HandleNumber(unsigned Number)
{
if (!Number || Number > sessionservice->GetExceptions().size())
if (!Number || Number > session_service->GetExceptions().size())
return;
if (!SentHeader)
@@ -178,10 +176,10 @@ class ExceptionListCallback : public NumberList
static void DoList(CommandSource &source, unsigned index)
{
if (index >= sessionservice->GetExceptions().size())
if (index >= session_service->GetExceptions().size())
return;
source.Reply(_("%3d %4d %s"), index + 1, sessionservice->GetExceptions()[index]->limit, sessionservice->GetExceptions()[index]->mask.c_str());
source.Reply(_("%3d %4d %s"), index + 1, session_service->GetExceptions()[index]->limit, session_service->GetExceptions()[index]->mask.c_str());
}
};
@@ -194,7 +192,7 @@ class ExceptionViewCallback : public ExceptionListCallback
void HandleNumber(unsigned Number)
{
if (!Number || Number > sessionservice->GetExceptions().size())
if (!Number || Number > session_service->GetExceptions().size())
return;
if (!SentHeader)
@@ -208,12 +206,12 @@ class ExceptionViewCallback : public ExceptionListCallback
static void DoList(CommandSource &source, unsigned index)
{
if (index >= sessionservice->GetExceptions().size())
if (index >= session_service->GetExceptions().size())
return;
Anope::string expirebuf = expire_left(source.u->Account(), sessionservice->GetExceptions()[index]->expires);
Anope::string expirebuf = expire_left(source.u->Account(), session_service->GetExceptions()[index]->expires);
source.Reply(_("%3d. %s (by %s on %s; %s)\n " " Limit: %-4d - %s"), index + 1, sessionservice->GetExceptions()[index]->mask.c_str(), !sessionservice->GetExceptions()[index]->who.empty() ? sessionservice->GetExceptions()[index]->who.c_str() : "<unknown>", do_strftime((sessionservice->GetExceptions()[index]->time ? sessionservice->GetExceptions()[index]->time : Anope::CurTime)).c_str(), expirebuf.c_str(), sessionservice->GetExceptions()[index]->limit, sessionservice->GetExceptions()[index]->reason.c_str());
source.Reply(_("%3d. %s (by %s on %s; %s)\n " " Limit: %-4d - %s"), index + 1, session_service->GetExceptions()[index]->mask.c_str(), !session_service->GetExceptions()[index]->who.empty() ? session_service->GetExceptions()[index]->who.c_str() : "<unknown>", do_strftime((session_service->GetExceptions()[index]->time ? session_service->GetExceptions()[index]->time : Anope::CurTime)).c_str(), expirebuf.c_str(), session_service->GetExceptions()[index]->limit, session_service->GetExceptions()[index]->reason.c_str());
}
};
@@ -238,7 +236,7 @@ class CommandOSSession : public Command
source.Reply(_("Hosts with at least \002%d\002 sessions:"), mincount);
source.Reply(_("Sessions Host"));
for (SessionService::SessionMap::iterator it = sessionservice->GetSessions().begin(), it_end = sessionservice->GetSessions().end(); it != it_end; ++it)
for (SessionService::SessionMap::iterator it = session_service->GetSessions().begin(), it_end = session_service->GetSessions().end(); it != it_end; ++it)
{
Session *session = it->second;
@@ -253,13 +251,13 @@ class CommandOSSession : public Command
void DoView(CommandSource &source, const std::vector<Anope::string> &params)
{
Anope::string param = params[1];
Session *session = sessionservice->FindSession(param);
Session *session = session_service->FindSession(param);
if (!session)
source.Reply(_("\002%s\002 not found on session list."), param.c_str());
else
{
Exception *exception = sessionservice->FindException(param);
Exception *exception = session_service->FindException(param);
source.Reply(_("The host \002%s\002 currently has \002%d\002 sessions with a limit of \002%d\002."), param.c_str(), session->count, exception ? exception-> limit : Config->DefSessionLimit);
}
@@ -375,7 +373,7 @@ class CommandOSException : public Command
return;
}
for (std::vector<Exception *>::iterator it = sessionservice->GetExceptions().begin(), it_end = sessionservice->GetExceptions().end(); it != it_end; ++it)
for (std::vector<Exception *>::iterator it = session_service->GetExceptions().begin(), it_end = session_service->GetExceptions().end(); it != it_end; ++it)
{
Exception *e = *it;
if (e->mask.equals_ci(mask))
@@ -405,7 +403,7 @@ class CommandOSException : public Command
delete exception;
else
{
sessionservice->AddException(exception);
session_service->AddException(exception);
source.Reply(_("Session limit for \002%s\002 set to \002%d\002."), mask.c_str(), limit);
if (readonly)
source.Reply(READ_ONLY_MODE);
@@ -432,9 +430,9 @@ class CommandOSException : public Command
}
else
{
unsigned i = 0, end = sessionservice->GetExceptions().size();
unsigned i = 0, end = session_service->GetExceptions().size();
for (; i < end; ++i)
if (mask.equals_ci(sessionservice->GetExceptions()[i]->mask))
if (mask.equals_ci(session_service->GetExceptions()[i]->mask))
{
ExceptionDelCallback::DoDel(source, i);
source.Reply(_("\002%s\002 deleted from session-limit exception list."), mask.c_str());
@@ -470,13 +468,13 @@ class CommandOSException : public Command
}
catch (const ConvertException &) { }
if (n1 >= 0 && n1 < sessionservice->GetExceptions().size() && n2 >= 0 && n2 < sessionservice->GetExceptions().size() && n1 != n2)
if (n1 >= 0 && n1 < session_service->GetExceptions().size() && n2 >= 0 && n2 < session_service->GetExceptions().size() && n1 != n2)
{
Exception *temp = sessionservice->GetExceptions()[n1];
sessionservice->GetExceptions()[n1] = sessionservice->GetExceptions()[n2];
sessionservice->GetExceptions()[n2] = temp;
Exception *temp = session_service->GetExceptions()[n1];
session_service->GetExceptions()[n1] = session_service->GetExceptions()[n2];
session_service->GetExceptions()[n2] = temp;
source.Reply(_("Exception for \002%s\002 (#%d) moved to position \002%d\002."), sessionservice->GetExceptions()[n1]->mask.c_str(), n1 + 1, n2 + 1);
source.Reply(_("Exception for \002%s\002 (#%d) moved to position \002%d\002."), session_service->GetExceptions()[n1]->mask.c_str(), n1 + 1, n2 + 1);
if (readonly)
source.Reply(READ_ONLY_MODE);
@@ -500,8 +498,8 @@ class CommandOSException : public Command
{
bool SentHeader = false;
for (unsigned i = 0, end = sessionservice->GetExceptions().size(); i < end; ++i)
if (mask.empty() || Anope::Match(sessionservice->GetExceptions()[i]->mask, mask))
for (unsigned i = 0, end = session_service->GetExceptions().size(); i < end; ++i)
if (mask.empty() || Anope::Match(session_service->GetExceptions()[i]->mask, mask))
{
if (!SentHeader)
{
@@ -533,8 +531,8 @@ class CommandOSException : public Command
{
bool SentHeader = false;
for (unsigned i = 0, end = sessionservice->GetExceptions().size(); i < end; ++i)
if (mask.empty() || Anope::Match(sessionservice->GetExceptions()[i]->mask, mask))
for (unsigned i = 0, end = session_service->GetExceptions().size(); i < end; ++i)
if (mask.empty() || Anope::Match(session_service->GetExceptions()[i]->mask, mask))
{
if (!SentHeader)
{
@@ -614,10 +612,10 @@ class CommandOSException : public Command
"the format of the optional \037expiry\037 parameter.\n"
"\002EXCEPTION DEL\002 removes the given mask from the exception list.\n"
"\002EXCEPTION MOVE\002 moves exception \037num\037 to \037position\037. The\n"
"sessionservice->GetExceptions() inbetween will be shifted up or down to fill the gap.\n"
"sessions inbetween will be shifted up or down to fill the gap.\n"
"\002EXCEPTION LIST\002 and \002EXCEPTION VIEW\002 show all current\n"
"sessionservice->GetExceptions(); if the optional mask is given, the list is limited\n"
"to those sessionservice->GetExceptions() matching the mask. The difference is that\n"
"sessions if the optional mask is given, the list is limited\n"
"to those sessions matching the mask. The difference is that\n"
"\002EXCEPTION VIEW\002 is more verbose, displaying the name of the\n"
"person who added the exception, its session limit, reason, \n"
"host mask and the expiry date and time.\n"
@@ -728,7 +726,7 @@ class OSSession : public Module
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
ModuleManager::SetPriority(this, PRIORITY_FIRST);
Serializable<Exception>::Alloc.Register("Exception");
}
void OnUserConnect(dynamic_reference<User> &user, bool &exempt)
+46
View File
@@ -1,6 +1,20 @@
#ifndef OS_SESSION_H
#define OS_SESSION_H
struct Exception : Serializable<Exception>
{
Anope::string mask; /* Hosts to which this exception applies */
unsigned limit; /* Session limit for exception */
Anope::string who; /* Nick of person who added the exception */
Anope::string reason; /* Reason for exception's addition */
time_t time; /* When this exception was added */
time_t expires; /* Time when it expires. 0 == no expiry */
serialized_data serialize();
static void unserialize(serialized_data &data);
};
class SessionService : public Service<Base>
{
public:
@@ -28,5 +42,37 @@ class SessionService : public Service<Base>
virtual SessionMap &GetSessions() = 0;
};
static service_reference<SessionService, Base> session_service("session");
SerializableBase::serialized_data Exception::serialize()
{
serialized_data data;
data["mask"] << this->mask;
data["limit"] << this->limit;
data["who"] << this->who;
data["reason"] << this->reason;
data["time"] << this->time;
data["expires"] << this->expires;
return data;
}
void Exception::unserialize(SerializableBase::serialized_data &data)
{
if (!session_service)
return;
Exception *ex = new Exception;
data["mask"] >> ex->mask;
data["limit"] >> ex->limit;
data["who"] >> ex->who;
data["reason"] >> ex->reason;
data["time"] >> ex->time;
data["expires"] >> ex->expires;
session_service->AddException(ex);
}
#endif
+2 -2
View File
@@ -55,8 +55,8 @@ class CommandOSRestart : public Command
{
User *u = source.u;
quitmsg = "RESTART command received from " + u->nick;
save_databases();
quitting = restarting = true;
save_databases();
return;
}
@@ -82,8 +82,8 @@ class CommandOSShutdown : public Command
{
User *u = source.u;
quitmsg = source.command + " command received from " + u->nick;
save_databases();
quitting = true;
save_databases();
return;
}
+191
View File
@@ -0,0 +1,191 @@
/*
* (C) 2003-2011 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*/
/*************************************************************************/
#include "module.h"
Anope::string DatabaseFile;
class DBFlatFile : public Module
{
/* Day the last backup was on */
int LastDay;
/* Backup file names */
std::list<Anope::string> Backups;
SerializableBase *find(const Anope::string &sname)
{
for (unsigned i = 0; i < serialized_types.size(); ++i)
if (serialized_types[i]->serialize_name() == sname)
return serialized_types[i];
return NULL;
}
public:
DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE)
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnReload, I_OnLoadDatabase, I_OnSaveDatabase };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
OnReload();
LastDay = 0;
}
void BackupDatabase()
{
/* Do not backup a database that doesn't exist */
if (!IsFile(DatabaseFile))
return;
time_t now = Anope::CurTime;
tm *tm = localtime(&now);
if (tm->tm_mday != LastDay)
{
LastDay = tm->tm_mday;
Anope::string newname = "backups/" + DatabaseFile + "." + stringify(tm->tm_year) + stringify(tm->tm_mon) + stringify(tm->tm_mday);
/* Backup already exists */
if (IsFile(newname))
return;
Log(LOG_DEBUG) << "db_flatfile: Attemping to rename " << DatabaseFile << " to " << newname;
if (rename(DatabaseFile.c_str(), newname.c_str()))
{
Log() << "Unable to back up database!";
if (!Config->NoBackupOkay)
quitting = true;
return;
}
Backups.push_back(newname);
if (Config->KeepBackups > 0 && Backups.size() > static_cast<unsigned>(Config->KeepBackups))
{
DeleteFile(Backups.front().c_str());
Backups.pop_front();
}
}
}
void OnReload()
{
ConfigReader config;
DatabaseFile = config.ReadValue("flatfile", "database", "anope.db", 0);
}
EventReturn OnLoadDatabase()
{
std::fstream db;
db.open(DatabaseFile.c_str(), std::ios_base::in);
if (!db.is_open())
{
Log() << "Unable to open " << DatabaseFile << " for reading!";
return EVENT_CONTINUE;
}
SerializableBase *sb = NULL;
SerializableBase::serialized_data data;
std::multimap<SerializableBase *, SerializableBase::serialized_data> objects;
for (Anope::string buf, token; std::getline(db, buf.str());)
{
spacesepstream sep(buf);
if (!sep.GetToken(token))
continue;
if (token == "OBJECT" && sep.GetToken(token))
{
sb = this->find(token);
data.clear();
}
else if (token == "DATA" && sb != NULL && sep.GetToken(token))
data[token] << sep.GetRemaining();
else if (token == "END" && sb != NULL)
{
objects.insert(std::make_pair(sb, data));
sb = NULL;
data.clear();
}
}
for (unsigned i = 0; i < serialized_types.size(); ++i)
{
SerializableBase *stype = serialized_types[i];
std::multimap<SerializableBase *, SerializableBase::serialized_data>::iterator it = objects.find(stype), it_end = objects.upper_bound(stype);
if (it == objects.end())
continue;
for (; it != it_end; ++it)
it->first->alloc(it->second);
}
db.close();
return EVENT_STOP;
}
EventReturn OnSaveDatabase()
{
BackupDatabase();
Anope::string tmp_db = DatabaseFile + ".tmp";
if (IsFile(DatabaseFile))
rename(DatabaseFile.c_str(), tmp_db.c_str());
std::fstream db(DatabaseFile.c_str(), std::ios_base::out | std::ios_base::trunc);
if (!db.is_open())
{
Log() << "Unable to open " << DatabaseFile << " for writing";
if (IsFile(tmp_db))
rename(tmp_db.c_str(), DatabaseFile.c_str());
return EVENT_CONTINUE;
}
for (std::list<SerializableBase *>::iterator it = serialized_items.begin(), it_end = serialized_items.end(); it != it_end; ++it)
{
SerializableBase *base = *it;
SerializableBase::serialized_data data = base->serialize();
db << "OBJECT " << base->serialize_name() << "\n";
for (SerializableBase::serialized_data::iterator dit = data.begin(), dit_end = data.end(); dit != dit_end; ++dit)
db << "DATA " << dit->first << " " << dit->second.astr() << "\n";
db << "END\n";
}
db.close();
if (db.good() == false)
{
Log() << "Unable to write database";
if (!Config->NoBackupOkay)
quitting = true;
if (IsFile(tmp_db))
rename(tmp_db.c_str(), DatabaseFile.c_str());
}
else
DeleteFile(tmp_db.c_str());
return EVENT_CONTINUE;
}
};
MODULE_INIT(DBFlatFile)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+333 -373
View File
@@ -15,7 +15,14 @@
Anope::string DatabaseFile;
std::stringstream db_buffer;
service_reference<SessionService, Base> SessionInterface("session");
class DatabaseException : public CoreException
{
public:
DatabaseException(const Anope::string &reason = "") : CoreException(reason) { }
virtual ~DatabaseException() throw() { }
};
/** Enum used for what METADATA type we are reading
*/
@@ -28,6 +35,300 @@ enum MDType
MD_CH
};
static void LoadNickCore(const std::vector<Anope::string> &params);
static void LoadNickAlias(const std::vector<Anope::string> &params);
static void LoadBotInfo(const std::vector<Anope::string> &params);
static void LoadChanInfo(const std::vector<Anope::string> &params);
static void LoadOperInfo(const std::vector<Anope::string> &params);
EventReturn OnDatabaseRead(const std::vector<Anope::string> &params)
{
Anope::string key = params[0];
std::vector<Anope::string> otherparams = params;
otherparams.erase(otherparams.begin());
if (key.equals_ci("NC"))
LoadNickCore(otherparams);
else if (key.equals_ci("NA"))
LoadNickAlias(otherparams);
else if (key.equals_ci("BI"))
LoadBotInfo(otherparams);
else if (key.equals_ci("CH"))
LoadChanInfo(otherparams);
else if (key.equals_ci("OS"))
LoadOperInfo(otherparams);
return EVENT_CONTINUE;
}
EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> &params)
{
try
{
if (key.equals_ci("LANGUAGE"))
nc->language = params[0];
else if (key.equals_ci("MEMOMAX"))
nc->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : -1;
else if (key.equals_ci("EMAIL"))
nc->email = params[0];
else if (key.equals_ci("GREET"))
nc->greet = params[0];
else if (key.equals_ci("ACCESS"))
nc->AddAccess(params[0]);
else if (key.equals_ci("CERT"))
nc->AddCert(params[0]);
else if (key.equals_ci("FLAGS"))
nc->FromVector(params);
else if (key.equals_ci("MI"))
{
Memo *m = new Memo;
m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0;
m->sender = params[1];
for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j)
{
if (params[j].equals_ci("UNREAD"))
m->SetFlag(MF_UNREAD);
else if (params[j].equals_ci("RECEIPT"))
m->SetFlag(MF_RECEIPT);
}
m->text = params[params.size() - 1];
nc->memos.memos.push_back(m);
}
else if (key.equals_ci("MIG"))
nc->memos.ignores.push_back(params[0].ci_str());
}
catch (const ConvertException &ex)
{
throw DatabaseException(ex.GetReason());
}
return EVENT_CONTINUE;
}
EventReturn OnDatabaseReadMetadata(NickAlias *na, const Anope::string &key, const std::vector<Anope::string> &params)
{
if (key.equals_ci("LAST_USERMASK"))
na->last_usermask = params[0];
else if (key.equals_ci("LAST_REALHOST"))
na->last_realhost = params[0];
else if (key.equals_ci("LAST_REALNAME"))
na->last_realname = params[0];
else if (key.equals_ci("LAST_QUIT"))
na->last_quit = params[0];
else if (key.equals_ci("FLAGS"))
na->FromVector(params);
else if (key.equals_ci("VHOST"))
na->hostinfo.SetVhost(params.size() > 3 ? params[3] : "", params[2], params[0], params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0);
return EVENT_CONTINUE;
}
EventReturn OnDatabaseReadMetadata(BotInfo *bi, const Anope::string &key, const std::vector<Anope::string> &params)
{
if (key.equals_ci("FLAGS"))
bi->FromVector(params);
return EVENT_CONTINUE;
}
EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> &params)
{
try
{
if (key.equals_ci("BANTYPE"))
ci->bantype = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : Config->CSDefBantype;
else if (key.equals_ci("MEMOMAX"))
ci->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : -1;
else if (key.equals_ci("FOUNDER"))
ci->SetFounder(findcore(params[0]));
else if (key.equals_ci("SUCCESSOR"))
ci->successor = findcore(params[0]);
else if (key.equals_ci("LEVELS"))
{
for (unsigned j = 0, end = params.size(); j < end; j += 2)
{
Privilege *p = PrivilegeManager::FindPrivilege(params[j]);
if (p == NULL)
continue;
ci->SetLevel(p->name, params[j + 1].is_number_only() ? convertTo<int16>(params[j + 1]) : 0);
}
}
else if (key.equals_ci("FLAGS"))
ci->FromVector(params);
else if (key.equals_ci("DESC"))
ci->desc = params[0];
else if (key.equals_ci("TOPIC"))
{
ci->last_topic_setter = params[0];
ci->last_topic_time = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0;
ci->last_topic = params[2];
}
else if (key.equals_ci("SUSPEND"))
{
ci->Extend("suspend_by", new ExtensibleString(params[0]));
ci->Extend("suspend_reason", new ExtensibleString(params[1]));
}
else if (key.equals_ci("ACCESS")) // Older access system, from Anope 1.9.4.
{
service_reference<AccessProvider> provider("access/access");
if (!provider)
throw DatabaseException("Old access entry for nonexistant provider");
ChanAccess *access = provider->Create();
access->ci = ci;
access->mask = params[0];
access->Unserialize(params[1]);
access->last_seen = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0;
access->creator = params[3];
access->created = Anope::CurTime;
ci->AddAccess(access);
}
else if (key.equals_ci("ACCESS2"))
{
service_reference<AccessProvider> provider(params[0]);
if (!provider)
throw DatabaseException("Access entry for nonexistant provider " + params[0]);
ChanAccess *access = provider->Create();
access->ci = ci;
access->mask = params[1];
access->Unserialize(params[2]);
access->last_seen = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0;
access->creator = params[4];
access->created = params.size() > 5 && params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime;
ci->AddAccess(access);
}
else if (key.equals_ci("AKICK"))
{
// 0 is the old stuck
bool Nick = params[1].equals_ci("NICK");
NickCore *nc = NULL;
if (Nick)
{
nc = findcore(params[2]);
if (!nc)
throw DatabaseException("Akick for nonexistant core " + params[2] + " on " + ci->name);
}
AutoKick *ak;
if (Nick)
ak = ci->AddAkick(params[3], nc, params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0);
else
ak = ci->AddAkick(params[3], params[2], params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0);
if (Nick)
ak->SetFlag(AK_ISNICK);
}
else if (key.equals_ci("LOG"))
{
LogSetting l;
l.service_name = params[0];
l.command_service = params[1];
l.command_name = params[2];
l.method = params[3];
l.creator = params[4];
l.created = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime;
l.extra = params.size() > 6 ? params[6] : "";
ci->log_settings.push_back(l);
}
else if (key.equals_ci("MLOCK"))
{
bool set = params[0] == "1" ? true : false;
Anope::string mode_name = params[1];
Anope::string setter = params[2];
time_t mcreated = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : Anope::CurTime;
Anope::string param = params.size() > 4 ? params[4] : "";
for (size_t i = CMODE_BEGIN + 1; i < CMODE_END; ++i)
if (ChannelModeNameStrings[i] == mode_name)
{
ChannelModeName n = static_cast<ChannelModeName>(i);
ci->mode_locks.insert(std::make_pair(n, ModeLock(ci, set, n, param, setter, mcreated)));
break;
}
}
else if (key.equals_ci("MI"))
{
Memo *m = new Memo;
m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0;
m->sender = params[1];
for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j)
{
if (params[j].equals_ci("UNREAD"))
m->SetFlag(MF_UNREAD);
else if (params[j].equals_ci("RECEIPT"))
m->SetFlag(MF_RECEIPT);
}
m->text = params[params.size() - 1];
ci->memos.memos.push_back(m);
}
else if (key.equals_ci("MIG"))
ci->memos.ignores.push_back(params[0].ci_str());
else if (key.equals_ci("BI"))
{
if (params[0].equals_ci("NAME"))
ci->bi = findbot(params[1]);
else if (params[0].equals_ci("FLAGS"))
ci->botflags.FromVector(params);
else if (params[0].equals_ci("TTB"))
{
for (unsigned j = 1, end = params.size(); j < end; j += 2)
{
if (params[j].equals_ci("BOLDS"))
ci->ttb[0] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("COLORS"))
ci->ttb[1] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("REVERSES"))
ci->ttb[2] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("UNDERLINES"))
ci->ttb[3] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("BADWORDS"))
ci->ttb[4] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("CAPS"))
ci->ttb[5] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("FLOOD"))
ci->ttb[6] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("REPEAT"))
ci->ttb[7] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("ITALICS"))
ci->ttb[8] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("AMSGS"))
ci->ttb[9] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
}
}
else if (params[0].equals_ci("CAPSMIN"))
ci->capsmin = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("CAPSPERCENT"))
ci->capspercent = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("FLOODLINES"))
ci->floodlines = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("FLOODSECS"))
ci->floodsecs = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("REPEATTIMES"))
ci->repeattimes = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("BADWORD"))
{
BadWordType Type;
if (params[1].equals_ci("SINGLE"))
Type = BW_SINGLE;
else if (params[1].equals_ci("START"))
Type = BW_START;
else if (params[1].equals_ci("END"))
Type = BW_END;
else
Type = BW_ANY;
ci->AddBadWord(params[2], Type);
}
}
}
catch (const ConvertException &ex)
{
throw DatabaseException(ex.GetReason());
}
return EVENT_CONTINUE;
}
/* Character for newlines, in my research I have concluded it is significantly faster
* to use \n instead of std::endl because std::endl also flushes the buffer, which
* is not necessary here
@@ -39,7 +340,7 @@ static const char endl = '\n';
*/
static void ReadDatabase(Module *m = NULL)
{
EventReturn MOD_RESULT;
//EventReturn MOD_RESULT;
MDType Type = MD_NONE;
std::fstream db;
@@ -81,12 +382,13 @@ static void ReadDatabase(Module *m = NULL)
params.push_back(buf);
}
if (m)
/*if (m)
MOD_RESULT = m->OnDatabaseRead(params);
else
FOREACH_RESULT(I_OnDatabaseRead, OnDatabaseRead(params));
if (MOD_RESULT == EVENT_STOP)
continue;
continue;*/
OnDatabaseRead(params);
if (!params.empty())
{
@@ -120,10 +422,7 @@ static void ReadDatabase(Module *m = NULL)
{
try
{
if (m)
m->OnDatabaseReadMetadata(nc, key, params);
else
FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(nc, key, params));
OnDatabaseReadMetadata(nc, key, params);
}
catch (const DatabaseException &ex)
{
@@ -134,10 +433,7 @@ static void ReadDatabase(Module *m = NULL)
{
try
{
if (m)
m->OnDatabaseReadMetadata(na, key, params);
else
FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(na, key, params));
OnDatabaseReadMetadata(na, key, params);
}
catch (const DatabaseException &ex)
{
@@ -148,10 +444,7 @@ static void ReadDatabase(Module *m = NULL)
{
try
{
if (m)
m->OnDatabaseReadMetadata(bi, key, params);
else
FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(bi, key, params));
OnDatabaseReadMetadata(bi, key, params);
}
catch (const DatabaseException &ex)
{
@@ -162,10 +455,7 @@ static void ReadDatabase(Module *m = NULL)
{
try
{
if (m)
m->OnDatabaseReadMetadata(ci, key, params);
else
FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(ci, key, params));
OnDatabaseReadMetadata(ci, key, params);
}
catch (const DatabaseException &ex)
{
@@ -179,19 +469,6 @@ static void ReadDatabase(Module *m = NULL)
db.close();
}
static Anope::string ToString(const std::vector<Anope::string> &strings)
{
Anope::string ret;
for (unsigned i = 0; i < strings.size(); ++i)
ret += " " + strings[i];
if (!ret.empty())
ret.erase(ret.begin());
return ret;
}
static void LoadNickCore(const std::vector<Anope::string> &params)
{
NickCore *nc = new NickCore(params[0]);
@@ -278,7 +555,7 @@ static void LoadOperInfo(const std::vector<Anope::string> &params)
}
}
}
else if (params[0].equals_ci("EXCEPTION") && SessionInterface)
else if (params[0].equals_ci("EXCEPTION") && session_service)
{
Exception *exception = new Exception();
exception->mask = params[1];
@@ -287,7 +564,7 @@ static void LoadOperInfo(const std::vector<Anope::string> &params)
exception->time = params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0;
exception->expires = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0;
exception->reason = params[6];
SessionInterface->AddException(exception);
session_service->AddException(exception);
}
}
@@ -312,7 +589,7 @@ class DBPlain : public Module
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnReload, I_OnDatabaseRead, I_OnLoadDatabase, I_OnDatabaseReadMetadata, I_OnSaveDatabase, I_OnModuleLoad };
Implementation i[] = { I_OnReload, I_OnLoadDatabase, I_OnSaveDatabase };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
OnReload();
@@ -370,308 +647,17 @@ class DBPlain : public Module
DatabaseFile = config.ReadValue("db_plain", "database", "anope.db", 0);
}
EventReturn OnDatabaseRead(const std::vector<Anope::string> &params)
{
Anope::string key = params[0];
std::vector<Anope::string> otherparams = params;
otherparams.erase(otherparams.begin());
if (key.equals_ci("NC"))
LoadNickCore(otherparams);
else if (key.equals_ci("NA"))
LoadNickAlias(otherparams);
else if (key.equals_ci("BI"))
LoadBotInfo(otherparams);
else if (key.equals_ci("CH"))
LoadChanInfo(otherparams);
else if (key.equals_ci("OS"))
LoadOperInfo(otherparams);
return EVENT_CONTINUE;
}
EventReturn OnLoadDatabase()
{
ReadDatabase();
/* No need to ever reload this again, although this should never be trigged again */
ModuleManager::Detach(I_OnLoadDatabase, this);
ModuleManager::Detach(I_OnDatabaseReadMetadata, this);
//ModuleManager::Detach(I_OnDatabaseReadMetadata, this);
return EVENT_STOP;
}
EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> &params)
{
try
{
if (key.equals_ci("LANGUAGE"))
nc->language = params[0];
else if (key.equals_ci("MEMOMAX"))
nc->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : -1;
else if (key.equals_ci("EMAIL"))
nc->email = params[0];
else if (key.equals_ci("GREET"))
nc->greet = params[0];
else if (key.equals_ci("ACCESS"))
nc->AddAccess(params[0]);
else if (key.equals_ci("CERT"))
nc->AddCert(params[0]);
else if (key.equals_ci("FLAGS"))
nc->FromString(params);
else if (key.equals_ci("MI"))
{
Memo *m = new Memo;
m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0;
m->sender = params[1];
for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j)
{
if (params[j].equals_ci("UNREAD"))
m->SetFlag(MF_UNREAD);
else if (params[j].equals_ci("RECEIPT"))
m->SetFlag(MF_RECEIPT);
}
m->text = params[params.size() - 1];
nc->memos.memos.push_back(m);
}
else if (key.equals_ci("MIG"))
nc->memos.ignores.push_back(params[0].ci_str());
}
catch (const ConvertException &ex)
{
throw DatabaseException(ex.GetReason());
}
return EVENT_CONTINUE;
}
EventReturn OnDatabaseReadMetadata(NickAlias *na, const Anope::string &key, const std::vector<Anope::string> &params)
{
if (key.equals_ci("LAST_USERMASK"))
na->last_usermask = params[0];
else if (key.equals_ci("LAST_REALHOST"))
na->last_realhost = params[0];
else if (key.equals_ci("LAST_REALNAME"))
na->last_realname = params[0];
else if (key.equals_ci("LAST_QUIT"))
na->last_quit = params[0];
else if (key.equals_ci("FLAGS"))
na->FromString(params);
else if (key.equals_ci("VHOST"))
na->hostinfo.SetVhost(params.size() > 3 ? params[3] : "", params[2], params[0], params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0);
return EVENT_CONTINUE;
}
EventReturn OnDatabaseReadMetadata(BotInfo *bi, const Anope::string &key, const std::vector<Anope::string> &params)
{
if (key.equals_ci("FLAGS"))
bi->FromString(params);
return EVENT_CONTINUE;
}
EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> &params)
{
try
{
if (key.equals_ci("BANTYPE"))
ci->bantype = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : Config->CSDefBantype;
else if (key.equals_ci("MEMOMAX"))
ci->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : -1;
else if (key.equals_ci("FOUNDER"))
ci->SetFounder(findcore(params[0]));
else if (key.equals_ci("SUCCESSOR"))
ci->successor = findcore(params[0]);
else if (key.equals_ci("LEVELS"))
{
for (unsigned j = 0, end = params.size(); j < end; j += 2)
{
Privilege *p = PrivilegeManager::FindPrivilege(params[j]);
if (p == NULL)
continue;
ci->SetLevel(p->name, params[j + 1].is_number_only() ? convertTo<int16>(params[j + 1]) : 0);
}
}
else if (key.equals_ci("FLAGS"))
ci->FromString(params);
else if (key.equals_ci("DESC"))
ci->desc = params[0];
else if (key.equals_ci("TOPIC"))
{
ci->last_topic_setter = params[0];
ci->last_topic_time = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0;
ci->last_topic = params[2];
}
else if (key.equals_ci("SUSPEND"))
{
ci->Extend("suspend_by", new ExtensibleItemRegular<Anope::string>(params[0]));
ci->Extend("suspend_reason", new ExtensibleItemRegular<Anope::string>(params[1]));
}
else if (key.equals_ci("ACCESS")) // Older access system, from Anope 1.9.4.
{
service_reference<AccessProvider> provider("access/access");
if (!provider)
throw DatabaseException("Old access entry for nonexistant provider");
ChanAccess *access = provider->Create();
access->ci = ci;
access->mask = params[0];
access->Unserialize(params[1]);
access->last_seen = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0;
access->creator = params[3];
access->created = Anope::CurTime;
ci->AddAccess(access);
}
else if (key.equals_ci("ACCESS2"))
{
service_reference<AccessProvider> provider(params[0]);
if (!provider)
throw DatabaseException("Access entry for nonexistant provider " + params[0]);
ChanAccess *access = provider->Create();
access->ci = ci;
access->mask = params[1];
access->Unserialize(params[2]);
access->last_seen = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0;
access->creator = params[4];
access->created = params.size() > 5 && params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime;
ci->AddAccess(access);
}
else if (key.equals_ci("AKICK"))
{
// 0 is the old stuck
bool Nick = params[1].equals_ci("NICK");
NickCore *nc = NULL;
if (Nick)
{
nc = findcore(params[2]);
if (!nc)
throw DatabaseException("Akick for nonexistant core " + params[2] + " on " + ci->name);
}
AutoKick *ak;
if (Nick)
ak = ci->AddAkick(params[3], nc, params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0);
else
ak = ci->AddAkick(params[3], params[2], params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0);
if (Nick)
ak->SetFlag(AK_ISNICK);
}
else if (key.equals_ci("LOG"))
{
LogSetting l;
l.service_name = params[0];
l.command_service = params[1];
l.command_name = params[2];
l.method = params[3];
l.creator = params[4];
l.created = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime;
l.extra = params.size() > 6 ? params[6] : "";
ci->log_settings.push_back(l);
}
else if (key.equals_ci("MLOCK"))
{
bool set = params[0] == "1" ? true : false;
Anope::string mode_name = params[1];
Anope::string setter = params[2];
time_t mcreated = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : Anope::CurTime;
Anope::string param = params.size() > 4 ? params[4] : "";
for (size_t i = CMODE_BEGIN + 1; i < CMODE_END; ++i)
if (ChannelModeNameStrings[i] == mode_name)
{
ChannelModeName n = static_cast<ChannelModeName>(i);
ci->mode_locks.insert(std::make_pair(n, ModeLock(set, n, param, setter, mcreated)));
break;
}
}
else if (key.equals_ci("MI"))
{
Memo *m = new Memo;
m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0;
m->sender = params[1];
for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j)
{
if (params[j].equals_ci("UNREAD"))
m->SetFlag(MF_UNREAD);
else if (params[j].equals_ci("RECEIPT"))
m->SetFlag(MF_RECEIPT);
}
m->text = params[params.size() - 1];
ci->memos.memos.push_back(m);
}
else if (key.equals_ci("MIG"))
ci->memos.ignores.push_back(params[0].ci_str());
else if (key.equals_ci("BI"))
{
if (params[0].equals_ci("NAME"))
ci->bi = findbot(params[1]);
else if (params[0].equals_ci("FLAGS"))
ci->botflags.FromString(params);
else if (params[0].equals_ci("TTB"))
{
for (unsigned j = 1, end = params.size(); j < end; j += 2)
{
if (params[j].equals_ci("BOLDS"))
ci->ttb[0] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("COLORS"))
ci->ttb[1] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("REVERSES"))
ci->ttb[2] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("UNDERLINES"))
ci->ttb[3] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("BADWORDS"))
ci->ttb[4] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("CAPS"))
ci->ttb[5] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("FLOOD"))
ci->ttb[6] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("REPEAT"))
ci->ttb[7] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("ITALICS"))
ci->ttb[8] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
else if (params[j].equals_ci("AMSGS"))
ci->ttb[9] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0;
}
}
else if (params[0].equals_ci("CAPSMIN"))
ci->capsmin = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("CAPSPERCENT"))
ci->capspercent = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("FLOODLINES"))
ci->floodlines = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("FLOODSECS"))
ci->floodsecs = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("REPEATTIMES"))
ci->repeattimes = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0;
else if (params[0].equals_ci("BADWORD"))
{
BadWordType Type;
if (params[1].equals_ci("SINGLE"))
Type = BW_SINGLE;
else if (params[1].equals_ci("START"))
Type = BW_START;
else if (params[1].equals_ci("END"))
Type = BW_END;
else
Type = BW_ANY;
ci->AddBadWord(params[2], Type);
}
}
}
catch (const ConvertException &ex)
{
throw DatabaseException(ex.GetReason());
}
return EVENT_CONTINUE;
}
EventReturn OnSaveDatabase()
{
@@ -705,7 +691,7 @@ class DBPlain : public Module
db_buffer << "MD CERT " << *it << endl;
}
if (nc->FlagCount())
db_buffer << "MD FLAGS " << ToString(nc->ToString()) << endl;
db_buffer << "MD FLAGS " << nc->ToString() << endl;
MemoInfo *mi = &nc->memos;
for (unsigned k = 0, end = mi->memos.size(); k < end; ++k)
{
@@ -718,7 +704,7 @@ class DBPlain : public Module
}
for (unsigned k = 0, end = mi->ignores.size(); k < end; ++k)
db_buffer << "MD MIG " << Anope::string(mi->ignores[k]) << endl;
FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, nc));
//FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, nc));
}
for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ++it)
@@ -735,11 +721,11 @@ class DBPlain : public Module
if (!na->last_quit.empty())
db_buffer << "MD LAST_QUIT :" << na->last_quit << endl;
if (na->FlagCount())
db_buffer << "MD FLAGS " << ToString(na->ToString()) << endl;
db_buffer << "MD FLAGS " << na->ToString() << endl;
if (na->hostinfo.HasVhost())
db_buffer << "MD VHOST " << na->hostinfo.GetCreator() << " " << na->hostinfo.GetTime() << " " << na->hostinfo.GetHost() << " :" << na->hostinfo.GetIdent() << endl;
FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, na));
//FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, na));
}
for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it)
@@ -751,7 +737,7 @@ class DBPlain : public Module
db_buffer << "BI " << bi->nick << " " << bi->GetIdent() << " " << bi->host << " " << bi->created << " " << bi->chancount << " :" << bi->realname << endl;
if (bi->FlagCount())
db_buffer << "MD FLAGS " << ToString(bi->ToString()) << endl;
db_buffer << "MD FLAGS " << bi->ToString() << endl;
}
for (registered_channel_map::const_iterator cit = RegisteredChannelList.begin(), cit_end = RegisteredChannelList.end(); cit != cit_end; ++cit)
@@ -778,13 +764,12 @@ class DBPlain : public Module
}
db_buffer << endl;
if (ci->FlagCount())
db_buffer << "MD FLAGS " << ToString(ci->ToString()) << endl;
db_buffer << "MD FLAGS " << ci->ToString() << endl;
if (ci->HasFlag(CI_SUSPENDED))
{
Anope::string by, reason;
ci->GetExtRegular("suspend_by", by);
ci->GetExtRegular("suspend_reason", reason);
db_buffer << "MD SUSPEND " << by << " :" << reason << endl;
Anope::string *by = ci->GetExt<Anope::string *>("suspend_by"), *reason = ci->GetExt<Anope::string *>("suspend_reason");
if (by && reason)
db_buffer << "MD SUSPEND " << *by << " :" << *reason << endl;
}
for (unsigned k = 0, end = ci->GetAccessCount(); k < end; ++k)
{
@@ -805,21 +790,12 @@ class DBPlain : public Module
db_buffer << "MD LOG " << l.service_name << " " << l.command_service << " " << l.command_name << " " << l.method << " " << l.creator << " " << l.created << " " << l.extra << endl;
}
for (std::multimap<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it)
{
std::vector<Anope::string> mlocks;
if (ci->GetExtRegular("db_mlock", mlocks))
for (unsigned i = 0; i < mlocks.size(); ++i)
db_buffer << mlocks[i] << endl;
else
{
for (std::multimap<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it)
{
const ModeLock &ml = it->second;
ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name);
if (cm != NULL)
db_buffer << "MD MLOCK " << (ml.set ? 1 : 0) << " " << cm->NameAsString() << " " << ml.setter << " " << ml.created << " " << ml.param << endl;
}
}
const ModeLock &ml = it->second;
ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name);
if (cm != NULL)
db_buffer << "MD MLOCK " << (ml.set ? 1 : 0) << " " << cm->NameAsString() << " " << ml.setter << " " << ml.created << " " << ml.param << endl;
}
MemoInfo *memos = &ci->memos;
for (unsigned k = 0, end = memos->memos.size(); k < end; ++k)
@@ -836,7 +812,7 @@ class DBPlain : public Module
if (ci->bi)
db_buffer << "MD BI NAME " << ci->bi->nick << endl;
if (ci->botflags.FlagCount())
db_buffer << "MD BI FLAGS " << ToString(ci->botflags.ToString()) << endl;
db_buffer << "MD BI FLAGS " << ci->botflags.ToString() << endl;
db_buffer << "MD BI TTB BOLDS " << ci->ttb[0] << " COLORS " << ci->ttb[1] << " REVERSES " << ci->ttb[2] << " UNDERLINES " << ci->ttb[3] << " BADWORDS " << ci->ttb[4] << " CAPS " << ci->ttb[5] << " FLOOD " << ci->ttb[6] << " REPEAT " << ci->ttb[7] << " ITALICS " << ci->ttb[8] << " AMSGS " << ci->ttb[9] << endl;
if (ci->capsmin)
db_buffer << "MD BI CAPSMIN " << ci->capsmin << endl;
@@ -852,7 +828,7 @@ class DBPlain : public Module
db_buffer << "MD BI BADWORD " << (ci->GetBadWord(k)->type == BW_ANY ? "ANY " : "") << (ci->GetBadWord(k)->type == BW_SINGLE ? "SINGLE " : "") << (ci->GetBadWord(k)->type == BW_START ? "START " : "") <<
(ci->GetBadWord(k)->type == BW_END ? "END " : "") << ":" << ci->GetBadWord(k)->word << endl;
FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, ci));
//FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, ci));
}
db_buffer << "OS STATS " << maxusercnt << " " << maxusertime << endl;
@@ -867,14 +843,14 @@ class DBPlain : public Module
}
}
if (SessionInterface)
for (SessionService::ExceptionVector::iterator it = SessionInterface->GetExceptions().begin(); it != SessionInterface->GetExceptions().end(); ++it)
if (session_service)
for (SessionService::ExceptionVector::iterator it = session_service->GetExceptions().begin(); it != session_service->GetExceptions().end(); ++it)
{
Exception *e = *it;
db_buffer << "OS EXCEPTION " << e->mask << " " << e->limit << " " << e->who << " " << e->time << " " << e->expires << " " << e->reason << endl;
}
FOREACH_MOD(I_OnDatabaseWrite, OnDatabaseWrite(Write));
//FOREACH_MOD(I_OnDatabaseWrite, OnDatabaseWrite(Write));
std::fstream db;
db.open(DatabaseFile.c_str(), std::ios_base::out | std::ios_base::trunc);
@@ -892,22 +868,6 @@ class DBPlain : public Module
return EVENT_CONTINUE;
}
void OnModuleLoad(User *u, Module *m)
{
if (!u)
return;
Implementation events[] = {I_OnDatabaseRead, I_OnDatabaseReadMetadata};
for (int i = 0; i < 2; ++i)
{
std::vector<Module *>::iterator it = std::find(ModuleManager::EventHandlers[events[i]].begin(), ModuleManager::EventHandlers[events[i]].end(), m);
/* This module wants to read from the database */
if (it != ModuleManager::EventHandlers[events[i]].end())
/* Loop over the database and call the events it would on a normal startup */
ReadDatabase(m);
}
}
};
MODULE_INIT(DBPlain)
+169
View File
@@ -0,0 +1,169 @@
/*
* (C) 2003-2011 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*/
#include "module.h"
#include "../extra/sql.h"
class SQLSQLInterface : public SQLInterface
{
public:
SQLSQLInterface(Module *o) : SQLInterface(o) { }
void OnResult(const SQLResult &r)
{
Log(LOG_DEBUG) << "SQL successfully executed query: " << r.finished_query;
}
void OnError(const SQLResult &r)
{
if (!r.GetQuery().query.empty())
Log(LOG_DEBUG) << "Error executing query " << r.finished_query << ": " << r.GetError();
else
Log(LOG_DEBUG) << "Error executing query: " << r.GetError();
}
};
class DBSQL : public Module
{
service_reference<SQLProvider, Base> sql;
SQLSQLInterface sqlinterface;
void RunBackground(const SQLQuery &q)
{
if (!quitting)
this->sql->Run(&sqlinterface, q);
else
this->sql->RunQuery(q);
}
void DropTable(const Anope::string &table)
{
SQLQuery query("DROP TABLE `" + table + "`");
this->RunBackground(query);
}
void AlterTable(const Anope::string &table, const SerializableBase::serialized_data &oldd, const SerializableBase::serialized_data &newd)
{
for (SerializableBase::serialized_data::const_iterator it = newd.begin(), it_end = newd.end(); it != it_end; ++it)
{
if (oldd.count(it->first) > 0)
continue;
Anope::string query_text = "ALTER TABLE `" + table + "` ADD `" + it->first + "` ";
if (it->second.getType() == Serialize::DT_INT)
query_text += "int(11)";
else if (it->second.getMax() > 0)
query_text += "varchar(" + stringify(it->second.getMax()) + ")";
else
query_text += "text";
this->RunBackground(SQLQuery(query_text));
}
}
void Insert(const Anope::string &table, const SerializableBase::serialized_data &data)
{
Anope::string query_text = "INSERT INTO `" + table + "` (";
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query_text += "`" + it->first + "`,";
query_text.erase(query_text.end() - 1);
query_text += ") VALUES (";
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query_text += "@" + it->first + "@,";
query_text.erase(query_text.end() - 1);
query_text += ")";
SQLQuery query(query_text);
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query.setValue(it->first, it->second.astr());
this->RunBackground(query);
}
public:
DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), sql(""), sqlinterface(this)
{
this->SetAuthor("Anope");
Implementation i[] = { I_OnReload, I_OnSaveDatabase, I_OnLoadDatabase };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
this->OnReload();
}
void OnReload()
{
ConfigReader config;
Anope::string engine = config.ReadValue("db_sql", "engine", "", 0);
this->sql = engine;
}
EventReturn OnSaveDatabase()
{
if (!this->sql)
{
Log() << "db_sql: Unable to save databases, is SQL configured correctly?";
return EVENT_CONTINUE;
}
std::map<Anope::string, SerializableBase::serialized_data> table_layout;
for (std::list<SerializableBase *>::iterator it = serialized_items.begin(), it_end = serialized_items.end(); it != it_end; ++it)
{
SerializableBase *base = *it;
SerializableBase::serialized_data data = base->serialize();
if (data.empty())
continue;
if (table_layout.count(base->serialize_name()) == 0)
{
this->DropTable(base->serialize_name());
this->RunBackground(this->sql->CreateTable(base->serialize_name(), data));
}
else
this->AlterTable(base->serialize_name(), table_layout[base->serialize_name()], data);
table_layout[base->serialize_name()] = data;
this->Insert(base->serialize_name(), data);
}
return EVENT_CONTINUE;
}
EventReturn OnLoadDatabase()
{
if (!this->sql)
{
Log() << "db_sql: Unable to load databases, is SQL configured correctly?";
return EVENT_CONTINUE;
}
for (std::vector<SerializableBase *>::iterator it = serialized_types.begin(), it_end = serialized_types.end(); it != it_end; ++it)
{
SerializableBase *sb = *it;
SQLQuery query("SELECT * FROM `" + sb->serialize_name() + "`");
SQLResult res = this->sql->RunQuery(query);
for (int i = 0; i < res.Rows(); ++i)
{
SerializableBase::serialized_data data;
const std::map<Anope::string, Anope::string> &row = res.Row(i);
for (std::map<Anope::string, Anope::string>::const_iterator rit = row.begin(), rit_end = row.end(); rit != rit_end; ++rit)
data[rit->first] << rit->second;
sb->alloc(data);
}
}
return EVENT_CONTINUE;
}
};
MODULE_INIT(DBSQL)
+434
View File
@@ -0,0 +1,434 @@
#include "module.h"
#include "../extra/sql.h"
#include "../commands/os_session.h"
class MySQLInterface : public SQLInterface
{
public:
MySQLInterface(Module *o) : SQLInterface(o) { }
void OnResult(const SQLResult &r)
{
Log(LOG_DEBUG) << "SQL successfully executed query: " << r.finished_query;
}
void OnError(const SQLResult &r)
{
if (!r.GetQuery().query.empty())
Log(LOG_DEBUG) << "Error executing query " << r.finished_query << ": " << r.GetError();
else
Log(LOG_DEBUG) << "Error executing query: " << r.GetError();
}
};
class DBMySQL : public Module
{
private:
MySQLInterface sqlinterface;
service_reference<SQLProvider, Base> SQL;
std::set<Anope::string> tables;
void RunQuery(const SQLQuery &query)
{
if (SQL)
{
if (readonly && this->ro)
{
readonly = this->ro = false;
BotInfo *bi = findbot(Config->OperServ);
if (bi)
ircdproto->SendGlobops(bi, "Found SQL again, going out of readonly mode...");
}
SQL->Run(&sqlinterface, query);
}
else
{
if (Anope::CurTime - Config->UpdateTimeout > lastwarn)
{
BotInfo *bi = findbot(Config->OperServ);
if (bi)
ircdproto->SendGlobops(bi, "Unable to locate SQL reference, going to readonly...");
readonly = this->ro = true;
this->lastwarn = Anope::CurTime;
}
}
}
void Insert(const Anope::string &table, const SerializableBase::serialized_data &data)
{
if (tables.count(table) == 0 && SQL)
{
this->RunQuery(this->SQL->CreateTable(table, data));
tables.insert(table);
}
Anope::string query_text = "INSERT INTO `" + table + "` (";
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query_text += "`" + it->first + "`,";
query_text.erase(query_text.end() - 1);
query_text += ") VALUES (";
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query_text += "@" + it->first + "@,";
query_text.erase(query_text.end() - 1);
query_text += ") ON DUPLICATE KEY UPDATE ";
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query_text += it->first + "=VALUES(" + it->first + "),";
query_text.erase(query_text.end() - 1);
SQLQuery query(query_text);
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query.setValue(it->first, it->second.astr());
this->RunQuery(query);
}
void Delete(const Anope::string &table, const SerializableBase::serialized_data &data)
{
Anope::string query_text = "DELETE FROM `" + table + "` WHERE ";
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query_text += "`" + it->first + "` = @" + it->first + "@";
SQLQuery query(query_text);
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
query.setValue(it->first, it->second.astr());
this->RunQuery(query);
}
public:
time_t lastwarn;
bool ro;
DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), sqlinterface(this), SQL("")
{
this->lastwarn = 0;
this->ro = false;
Implementation i[] = { I_OnReload, I_OnServerConnect };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
OnReload();
if (CurrentUplink)
OnServerConnect();
}
void OnReload()
{
ConfigReader config;
Anope::string engine = config.ReadValue("db_sql", "engine", "", 0);
this->SQL = engine;
}
void OnServerConnect()
{
Implementation i[] = {
/* Misc */
I_OnPostCommand,
/* NickServ */
I_OnNickAddAccess, I_OnNickEraseAccess, I_OnNickClearAccess,
I_OnDelCore, I_OnNickForbidden, I_OnNickGroup,
I_OnNickRegister, I_OnChangeCoreDisplay,
I_OnNickSuspended, I_OnDelNick,
/* ChanServ */
I_OnAccessAdd, I_OnAccessDel, I_OnAccessClear, I_OnLevelChange,
I_OnDelChan, I_OnChanRegistered, I_OnChanSuspend,
I_OnAkickAdd, I_OnAkickDel, I_OnMLock, I_OnUnMLock,
/* BotServ */
I_OnBotCreate, I_OnBotChange, I_OnBotDelete,
I_OnBotAssign, I_OnBotUnAssign,
I_OnBadWordAdd, I_OnBadWordDel,
/* MemoServ */
I_OnMemoSend, I_OnMemoDel,
/* OperServ */
I_OnExceptionAdd, I_OnExceptionDel,
I_OnAddXLine, I_OnDelXLine,
/* HostServ */
I_OnSetVhost, I_OnDeleteVhost
};
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
}
void OnPostCommand(CommandSource &source, Command *command, const std::vector<Anope::string> &params)
{
User *u = source.u;
if (command->name.find("nickserv/set/") == 0)
{
NickAlias *na = findnick(source.u->nick);
if (!na)
this->Insert(na->nc->serialize_name(), na->nc->serialize());
}
else if (command->name.find("nickserv/saset/") == 0)
{
NickAlias *na = findnick(params[1]);
if (!na)
this->Insert(na->nc->serialize_name(), na->nc->serialize());
}
else if (command->name.find("chanserv/set") == 0 || command->name.find("chanserv/saset") == 0)
{
ChannelInfo *ci = params.size() > 0 ? cs_findchan(params[0]) : NULL;
if (!ci)
this->Insert(ci->serialize_name(), ci->serialize());
}
else if (command->name == "botserv/kick" && params.size() > 2)
{
ChannelInfo *ci = cs_findchan(params[0]);
if (!ci)
return;
if (!ci->AccessFor(u).HasPriv("SET") && !u->HasPriv("botserv/administration"))
return;
this->Insert(ci->serialize_name(), ci->serialize());
}
else if (command->name == "botserv/set" && params.size() > 1)
{
ChannelInfo *ci = cs_findchan(params[0]);
BotInfo *bi = NULL;
if (!ci)
bi = findbot(params[0]);
if (bi && params[1].equals_ci("PRIVATE") && u->HasPriv("botserv/set/private"))
this->Insert(bi->serialize_name(), bi->serialize());
else if (ci && !ci->AccessFor(u).HasPriv("SET") && !u->HasPriv("botserv/administration"))
this->Insert(ci->serialize_name(), ci->serialize());
}
else if (command->name == "memoserv/ignore" && params.size() > 0)
{
Anope::string target = params[0];
if (target[0] != '#')
{
NickCore *nc = u->Account();
if (nc)
this->Insert(nc->serialize_name(), nc->serialize());
}
else
{
ChannelInfo *ci = cs_findchan(target);
if (ci && ci->AccessFor(u).HasPriv("MEMO"))
this->Insert(ci->serialize_name(), ci->serialize());
}
}
}
void OnNickAddAccess(NickCore *nc, const Anope::string &entry)
{
this->Insert(nc->serialize_name(), nc->serialize());
}
void OnNickEraseAccess(NickCore *nc, const Anope::string &entry)
{
this->Insert(nc->serialize_name(), nc->serialize());
}
void OnNickClearAccess(NickCore *nc)
{
this->Insert(nc->serialize_name(), nc->serialize());
}
void OnDelCore(NickCore *nc)
{
this->Delete(nc->serialize_name(), nc->serialize());
}
void OnNickForbidden(NickAlias *na)
{
this->Insert(na->serialize_name(), na->serialize());
}
void OnNickGroup(User *u, NickAlias *)
{
OnNickRegister(findnick(u->nick));
}
void InsertAlias(NickAlias *na)
{
this->Insert(na->serialize_name(), na->serialize());
}
void InsertCore(NickCore *nc)
{
this->Insert(nc->serialize_name(), nc->serialize());
}
void OnNickRegister(NickAlias *na)
{
this->InsertCore(na->nc);
this->InsertAlias(na);
}
void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay)
{
SerializableBase::serialized_data data = nc->serialize();
this->Delete(nc->serialize_name(), data);
data.erase("display");
data["display"] << newdisplay;
this->Insert(nc->serialize_name(), data);
for (std::list<NickAlias *>::iterator it = nc->aliases.begin(), it_end = nc->aliases.end(); it != it_end; ++it)
{
NickAlias *na = *it;
data = na->serialize();
this->Delete(na->serialize_name(), data);
data.erase("nc");
data["nc"] << newdisplay;
this->Insert(na->serialize_name(), data);
}
}
void OnNickSuspend(NickAlias *na)
{
this->Insert(na->serialize_name(), na->serialize());
}
void OnDelNick(NickAlias *na)
{
this->Delete(na->serialize_name(), na->serialize());
}
void OnAccessAdd(ChannelInfo *ci, User *, ChanAccess *access)
{
this->Insert(access->serialize_name(), access->serialize());
}
void OnAccessDel(ChannelInfo *ci, User *u, ChanAccess *access)
{
this->Delete(access->serialize_name(), access->serialize());
}
void OnAccessClear(ChannelInfo *ci, User *u)
{
for (unsigned i = 0; i < ci->GetAccessCount(); ++i)
this->OnAccessDel(ci, NULL, ci->GetAccess(i));
}
void OnLevelChange(User *u, ChannelInfo *ci, const Anope::string &priv, int16 what)
{
this->Insert(ci->serialize_name(), ci->serialize());
}
void OnDelChan(ChannelInfo *ci)
{
this->Delete(ci->serialize_name(), ci->serialize());
}
void OnChanRegistered(ChannelInfo *ci)
{
this->Insert(ci->serialize_name(), ci->serialize());
}
void OnChanSuspend(ChannelInfo *ci)
{
this->Insert(ci->serialize_name(), ci->serialize());
}
void OnAkickAdd(ChannelInfo *ci, AutoKick *ak)
{
this->Insert(ak->serialize_name(), ak->serialize());
}
void OnAkickDel(ChannelInfo *ci, AutoKick *ak)
{
this->Delete(ak->serialize_name(), ak->serialize());
}
EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock)
{
this->Insert(lock->serialize_name(), lock->serialize());
return EVENT_CONTINUE;
}
EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock)
{
this->Delete(lock->serialize_name(), lock->serialize());
return EVENT_CONTINUE;
}
void OnBotCreate(BotInfo *bi)
{
this->Insert(bi->serialize_name(), bi->serialize());
}
void OnBotChange(BotInfo *bi)
{
OnBotCreate(bi);
}
void OnBotDelete(BotInfo *bi)
{
this->Delete(bi->serialize_name(), bi->serialize());
}
EventReturn OnBotAssign(User *sender, ChannelInfo *ci, BotInfo *bi)
{
this->Insert(ci->serialize_name(), ci->serialize());
return EVENT_CONTINUE;
}
EventReturn OnBotUnAssign(User *sender, ChannelInfo *ci)
{
this->Insert(ci->serialize_name(), ci->serialize());
return EVENT_CONTINUE;
}
void OnBadWordAdd(ChannelInfo *ci, BadWord *bw)
{
this->Insert(bw->serialize_name(), bw->serialize());
}
void OnBadWordDel(ChannelInfo *ci, BadWord *bw)
{
this->Delete(bw->serialize_name(), bw->serialize());
}
void OnMemoSend(const Anope::string &source, const Anope::string &target, MemoInfo *mi, Memo *m)
{
this->Insert(m->serialize_name(), m->serialize());
}
void OnMemoDel(const NickCore *nc, MemoInfo *mi, Memo *m)
{
this->Delete(m->serialize_name(), m->serialize());
}
void OnMemoDel(ChannelInfo *ci, MemoInfo *mi, Memo *m)
{
this->Delete(m->serialize_name(), m->serialize());
}
EventReturn OnExceptionAdd(Exception *ex)
{
this->Insert(ex->serialize_name(), ex->serialize());
return EVENT_CONTINUE;
}
void OnExceptionDel(User *, Exception *ex)
{
this->Delete(ex->serialize_name(), ex->serialize());
}
EventReturn OnAddXLine(XLine *x, XLineManager *xlm)
{
this->Insert(x->serialize_name(), x->serialize());
return EVENT_CONTINUE;
}
void OnDelXLine(User *, XLine *x, XLineManager *xlm)
{
this->Delete(x->serialize_name(), x->serialize());
}
void OnDeleteVhost(NickAlias *na)
{
this->Insert(na->serialize_name(), na->serialize());
}
void OnSetVhost(NickAlias *na)
{
this->Insert(na->serialize_name(), na->serialize());
}
};
MODULE_INIT(DBMySQL)
@@ -32,19 +32,25 @@ class SQLCache : public Timer
}
};
static void ChanInfoUpdate(const SQLResult &res)
static void ChanInfoUpdate(const Anope::string &name, const SQLResult &res)
{
ChannelInfo *ci = cs_findchan(name);
if (res.Rows() == 0)
{
delete ci;
return;
}
try
{
ChannelInfo *ci = cs_findchan(res.Get(0, "name"));
if (!ci)
ci = new ChannelInfo(res.Get(0, "name"));
ci = new ChannelInfo(name);
ci->SetFounder(findcore(res.Get(0, "founder")));
ci->successor = findcore(res.Get(0, "successor"));
ci->desc = res.Get(0, "descr");
ci->time_registered = convertTo<time_t>(res.Get(0, "time_registered"));
ci->ClearFlags();
ci->FromString(BuildStringVector(res.Get(0, "flags")));
ci->FromString(res.Get(0, "flags"));
ci->bantype = convertTo<int>(res.Get(0, "bantype"));
ci->memos.memomax = convertTo<unsigned>(res.Get(0, "memomax"));
@@ -68,21 +74,27 @@ static void ChanInfoUpdate(const SQLResult &res)
}
catch (const SQLException &ex)
{
Log(LOG_DEBUG) << ex.GetReason();
Log() << ex.GetReason();
}
catch (const ConvertException &) { }
}
static void NickInfoUpdate(const SQLResult &res)
static void NickInfoUpdate(const Anope::string &name, const SQLResult &res)
{
NickAlias *na = findnick(name);
if (res.Rows() == 0)
{
delete na;
return;
}
try
{
NickCore *nc = findcore(res.Get(0, "display"));
if (!nc)
return;
NickAlias *na = findnick(res.Get(0, "nick"));
if (!na)
na = new NickAlias(res.Get(0, "nick"), nc);
na = new NickAlias(name, nc);
na->last_quit = res.Get(0, "last_quit");
na->last_realname = res.Get(0, "last_realname");
@@ -91,7 +103,7 @@ static void NickInfoUpdate(const SQLResult &res)
na->time_registered = convertTo<time_t>(res.Get(0, "time_registered"));
na->last_seen = convertTo<time_t>(res.Get(0, "last_seen"));
na->ClearFlags();
na->FromString(BuildStringVector(res.Get(0, "flags")));
na->FromString(res.Get(0, "flags"));
if (na->nc != nc)
{
@@ -105,29 +117,35 @@ static void NickInfoUpdate(const SQLResult &res)
}
catch (const SQLException &ex)
{
Log(LOG_DEBUG) << ex.GetReason();
Log() << ex.GetReason();
}
catch (const ConvertException &) { }
}
static void NickCoreUpdate(const SQLResult &res)
static void NickCoreUpdate(const Anope::string &name, const SQLResult &res)
{
NickCore *nc = findcore(name);
if (res.Rows() == 0)
{
delete nc;
return;
}
try
{
NickCore *nc = findcore(res.Get(0, "display"));
if (!nc)
nc = new NickCore(res.Get(0, "display"));
nc = new NickCore(name);
nc->pass = res.Get(0, "pass");
nc->email = res.Get(0, "email");
nc->greet = res.Get(0, "greet");
nc->ClearFlags();
nc->FromString(BuildStringVector(res.Get(0, "flags")));
nc->FromString(res.Get(0, "flags"));
nc->language = res.Get(0, "language");
}
catch (const SQLException &ex)
{
Log(LOG_DEBUG) << ex.GetReason();
Log() << ex.GetReason();
}
catch (const ConvertException &) { }
}
@@ -141,7 +159,7 @@ class MySQLLiveModule : public Module
SQLResult RunQuery(const SQLQuery &query)
{
if (!this->SQL)
throw SQLException("Unable to locate SQL reference, is m_mysql loaded and configured correctly?");
throw SQLException("Unable to locate SQL reference, is db_sql loaded and configured correctly?");
SQLResult res = SQL->RunQuery(query);
if (!res.GetError().empty())
@@ -151,12 +169,19 @@ class MySQLLiveModule : public Module
public:
MySQLLiveModule(const Anope::string &modname, const Anope::string &creator) :
Module(modname, creator, DATABASE), SQL("mysql/main")
Module(modname, creator, DATABASE), SQL("")
{
Implementation i[] = { I_OnFindChan, I_OnFindNick, I_OnFindCore, I_OnShutdown };
Implementation i[] = { I_OnReload, I_OnFindChan, I_OnFindNick, I_OnFindCore, I_OnShutdown };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
}
void OnReload()
{
ConfigReader config;
Anope::string engine = config.ReadValue("db_sql", "engine", "", 0);
this->SQL = engine;
}
void OnShutdown()
{
Implementation i[] = { I_OnFindChan, I_OnFindNick, I_OnFindCore };
@@ -171,10 +196,10 @@ class MySQLLiveModule : public Module
try
{
SQLQuery query("SELECT * FROM `anope_cs_info` WHERE `name` = @name");
SQLQuery query("SELECT * FROM `ChannelInfo` WHERE `name` = @name@");
query.setValue("name", chname);
SQLResult res = this->RunQuery(query);
ChanInfoUpdate(res);
ChanInfoUpdate(chname, res);
}
catch (const SQLException &ex)
{
@@ -189,10 +214,10 @@ class MySQLLiveModule : public Module
try
{
SQLQuery query("SELECT * FROM `anope_ns_alias` WHERE `nick` = @nick");
SQLQuery query("SELECT * FROM `NickAlias` WHERE `nick` = @nick@");
query.setValue("nick", nick);
SQLResult res = this->RunQuery(query);
NickInfoUpdate(res);
NickInfoUpdate(nick, res);
}
catch (const SQLException &ex)
{
@@ -207,10 +232,10 @@ class MySQLLiveModule : public Module
try
{
SQLQuery query("SELECT * FROM `anope_ns_core` WHERE `display` = @display");
SQLQuery query("SELECT * FROM `NickCore` WHERE `display` = @display@");
query.setValue("display", nick);
SQLResult res = this->RunQuery(query);
NickCoreUpdate(res);
NickCoreUpdate(nick, res);
}
catch (const SQLException &ex)
{
+2 -2
View File
@@ -30,7 +30,7 @@ class DNSBLResolver : public DNSRequest
void OnLookupComplete(const DNSQuery *record)
{
if (!user || user->GetExt("m_dnsbl_akilled"))
if (!user || user->HasExt("m_dnsbl_akilled"))
return;
const ResourceRecord &ans_record = record->answers[0];
@@ -50,7 +50,7 @@ class DNSBLResolver : public DNSRequest
record_reason = this->blacklist.replies[result];
}
user->Extend("m_dnsbl_akilled");
user->Extend("m_dnsbl_akilled", NULL);
Anope::string reason = this->blacklist.reason;
reason = reason.replace_all_cs("%n", user->nick);
+4 -4
View File
@@ -49,7 +49,7 @@ class IdentifyInterface : public LDAPInterface
User *u = ii->user;
Command *c = ii->command;
u->Extend("m_ldap_authentication_authenticated");
u->Extend("m_ldap_authentication_authenticated", NULL);
NickAlias *na = findnick(ii->account);
if (na == NULL)
@@ -87,7 +87,7 @@ class IdentifyInterface : public LDAPInterface
User *u = ii->user;
Command *c = ii->command;
u->Extend("m_ldap_authentication_error");
u->Extend("m_ldap_authentication_error", NULL);
c->Execute(ii->source, ii->params);
@@ -218,12 +218,12 @@ class NSIdentifyLDAP : public Module
return EVENT_CONTINUE;
User *u = source->u;
if (u->GetExt("m_ldap_authentication_authenticated"))
if (u->HasExt("m_ldap_authentication_authenticated"))
{
u->Shrink("m_ldap_authentication_authenticated");
return EVENT_ALLOW;
}
else if (u->GetExt("m_ldap_authentication_error"))
else if (u->HasExt("m_ldap_authentication_error"))
{
u->Shrink("m_ldap_authentication_error");
return EVENT_CONTINUE;
+40 -15
View File
@@ -82,8 +82,6 @@ class MySQLResult : public SQLResult
MySQLResult(const SQLQuery &q, const Anope::string &fq, const Anope::string &err) : SQLResult(q, fq, err), res(NULL)
{
if (this->finished_query.empty())
this->finished_query = q.query;
}
~MySQLResult()
@@ -125,6 +123,8 @@ class MySQLService : public SQLProvider
SQLResult RunQuery(const SQLQuery &query);
SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data);
void Connect();
bool CheckConnection();
@@ -211,7 +211,7 @@ class ModuleSQL : public Module, public Pipe
for (i = 0, num = config.Enumerate("mysql"); i < num; ++i)
{
Anope::string connname = config.ReadValue("mysql", "name", "main", i);
Anope::string connname = config.ReadValue("mysql", "name", "mysql/main", i);
if (this->MySQLServices.find(connname) == this->MySQLServices.end())
{
@@ -284,7 +284,7 @@ class ModuleSQL : public Module, public Pipe
};
MySQLService::MySQLService(Module *o, const Anope::string &n, const Anope::string &d, const Anope::string &s, const Anope::string &u, const Anope::string &p, int po)
: SQLProvider(o, "mysql/" + n), database(d), server(s), user(u), password(p), port(po), sql(NULL)
: SQLProvider(o, n), database(d), server(s), user(u), password(p), port(po), sql(NULL)
{
Connect();
}
@@ -323,16 +323,7 @@ SQLResult MySQLService::RunQuery(const SQLQuery &query)
{
this->Lock.Lock();
Anope::string real_query;
try
{
real_query = this->BuildQuery(query);
}
catch (const SQLException &ex)
{
this->Lock.Unlock();
return MySQLResult(query, real_query, ex.GetReason());
}
Anope::string real_query = this->BuildQuery(query);
if (this->CheckConnection() && !mysql_real_query(this->sql, real_query.c_str(), real_query.length()))
{
@@ -349,6 +340,40 @@ SQLResult MySQLService::RunQuery(const SQLQuery &query)
}
}
SQLQuery MySQLService::CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data)
{
Anope::string query_text = "CREATE TABLE `" + table + "` (", key_buf;
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
{
query_text += "`" + it->first + "` ";
if (it->second.getType() == Serialize::DT_INT)
query_text += "int(11)";
else if (it->second.getMax() > 0)
query_text += "varchar(" + stringify(it->second.getMax()) + ")";
else
query_text += "text";
query_text += ",";
if (it->second.getKey())
{
if (key_buf.empty())
key_buf = "UNIQUE KEY `ukey` (";
key_buf += "`" + it->first + "`,";
}
}
if (!key_buf.empty())
{
key_buf.erase(key_buf.end() - 1);
key_buf += ")";
query_text += " " + key_buf;
}
else
query_text.erase(query_text.end() - 1);
query_text += ")";
return SQLQuery(query_text);
}
void MySQLService::Connect()
{
this->sql = mysql_init(this->sql);
@@ -392,7 +417,7 @@ Anope::string MySQLService::BuildQuery(const SQLQuery &q)
Anope::string real_query = q.query;
for (std::map<Anope::string, Anope::string>::const_iterator it = q.parameters.begin(), it_end = q.parameters.end(); it != it_end; ++it)
real_query = real_query.replace_all_cs("@" + it->first, "'" + this->Escape(it->second) + "'");
real_query = real_query.replace_all_cs("@" + it->first + "@", "'" + this->Escape(it->second) + "'");
return real_query;
}
+235
View File
@@ -0,0 +1,235 @@
/* RequiredLibraries: sqlite3 */
#include "module.h"
#include <sqlite3.h>
#include "sql.h"
/* SQLite3 API, based from InspiRCd */
/** A SQLite result
*/
class SQLiteResult : public SQLResult
{
public:
SQLiteResult(const SQLQuery &q, const Anope::string &fq) : SQLResult(q, fq)
{
}
SQLiteResult(const SQLQuery &q, const Anope::string &fq, const Anope::string &err) : SQLResult(q, fq, err)
{
}
void addRow(const std::map<Anope::string, Anope::string> &data)
{
this->entries.push_back(data);
}
};
/** A SQLite database, there can be multiple
*/
class SQLiteService : public SQLProvider
{
Anope::string database;
sqlite3 *sql;
Anope::string Escape(const Anope::string &query);
public:
SQLiteService(Module *o, const Anope::string &n, const Anope::string &d);
~SQLiteService();
void Run(SQLInterface *i, const SQLQuery &query);
SQLResult RunQuery(const SQLQuery &query);
SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data);
Anope::string BuildQuery(const SQLQuery &q);
};
class ModuleSQLite : public Module
{
/* SQL connections */
std::map<Anope::string, SQLiteService *> SQLiteServices;
public:
ModuleSQLite(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED)
{
Implementation i[] = { I_OnReload };
ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
OnReload();
}
~ModuleSQLite()
{
for (std::map<Anope::string, SQLiteService *>::iterator it = this->SQLiteServices.begin(); it != this->SQLiteServices.end(); ++it)
delete it->second;
SQLiteServices.clear();
}
void OnReload()
{
ConfigReader config;
int i, num;
for (std::map<Anope::string, SQLiteService *>::iterator it = this->SQLiteServices.begin(); it != this->SQLiteServices.end();)
{
const Anope::string &cname = it->first;
SQLiteService *s = it->second;
++it;
for (i = 0, num = config.Enumerate("sqlite"); i < num; ++i)
if (config.ReadValue("sqlite", "name", "sqlite/main", i) == cname)
break;
if (i == num)
{
Log(LOG_NORMAL, "sqlite") << "SQLite: Removing server connection " << cname;
delete s;
this->SQLiteServices.erase(cname);
}
}
for (i = 0, num = config.Enumerate("sqlite"); i < num; ++i)
{
Anope::string connname = config.ReadValue("sqlite", "name", "sqlite/main", i);
if (this->SQLiteServices.find(connname) == this->SQLiteServices.end())
{
Anope::string database = config.ReadValue("sqlite", "database", "anope", i);
try
{
SQLiteService *ss = new SQLiteService(this, connname, database);
this->SQLiteServices[connname] = ss;
Log(LOG_NORMAL, "sqlite") << "SQLite: Successfully added database " << database;
}
catch (const SQLException &ex)
{
Log(LOG_NORMAL, "sqlite") << "SQLite: " << ex.GetReason();
}
}
}
}
};
SQLiteService::SQLiteService(Module *o, const Anope::string &n, const Anope::string &d)
: SQLProvider(o, n), database(d), sql(NULL)
{
int db = sqlite3_open_v2(database.c_str(), &this->sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
if (db != SQLITE_OK)
throw SQLException("Unable to open SQLite database " + database + ": " + sqlite3_errmsg(this->sql));
}
SQLiteService::~SQLiteService()
{
sqlite3_interrupt(this->sql);
sqlite3_close(this->sql);
}
void SQLiteService::Run(SQLInterface *i, const SQLQuery &query)
{
SQLResult res = this->RunQuery(query);
if (!res.GetError().empty())
i->OnError(res);
else
i->OnResult(res);
}
SQLResult SQLiteService::RunQuery(const SQLQuery &query)
{
Anope::string real_query = this->BuildQuery(query);
sqlite3_stmt *stmt;
int err = sqlite3_prepare_v2(this->sql, real_query.c_str(), real_query.length(), &stmt, NULL);
if (err != SQLITE_OK)
return SQLiteResult(query, real_query, sqlite3_errmsg(this->sql));
std::vector<Anope::string> columns;
int cols = sqlite3_column_count(stmt);
columns.resize(cols);
for (int i = 0; i < cols; ++i)
columns[i] = sqlite3_column_name(stmt, i);
SQLiteResult result(query, real_query);
do
{
err = sqlite3_step(stmt);
if (err == SQLITE_ROW)
{
std::map<Anope::string, Anope::string> items;
for (int i = 0; i < cols; ++i)
{
const char *data = reinterpret_cast<const char *>(sqlite3_column_text(stmt, i));
if (data && *data)
items[columns[i]] = data;
}
result.addRow(items);
}
}
while (err == SQLITE_ROW);
if (err != SQLITE_DONE)
return SQLiteResult(query, real_query, sqlite3_errmsg(this->sql));
return result;
}
SQLQuery SQLiteService::CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data)
{
Anope::string query_text = "CREATE TABLE `" + table + "` (", key_buf;
for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it)
{
query_text += "`" + it->first + "` ";
if (it->second.getType() == Serialize::DT_INT)
query_text += "int(11)";
else if (it->second.getMax() > 0)
query_text += "varchar(" + stringify(it->second.getMax()) + ")";
else
query_text += "text";
query_text += ",";
if (it->second.getKey())
{
if (key_buf.empty())
key_buf = "UNIQUE (";
key_buf += "`" + it->first + "`,";
}
}
if (!key_buf.empty())
{
key_buf.erase(key_buf.end() - 1);
key_buf += ")";
query_text += " " + key_buf;
}
else
query_text.erase(query_text.end() - 1);
query_text += ")";
return SQLQuery(query_text);
}
Anope::string SQLiteService::Escape(const Anope::string &query)
{
char *e = sqlite3_mprintf("%q", query.c_str());
Anope::string buffer = e;
sqlite3_free(e);
return buffer;
}
Anope::string SQLiteService::BuildQuery(const SQLQuery &q)
{
Anope::string real_query = q.query;
for (std::map<Anope::string, Anope::string>::const_iterator it = q.parameters.begin(), it_end = q.parameters.end(); it != it_end; ++it)
real_query = real_query.replace_all_cs("@" + it->first + "@", "'" + this->Escape(it->second) + "'");
return real_query;
}
MODULE_INIT(ModuleSQLite)
+2
View File
@@ -116,5 +116,7 @@ class SQLProvider : public Service<Base>
virtual void Run(SQLInterface *i, const SQLQuery &query) = 0;
virtual SQLResult RunQuery(const SQLQuery &query) = 0;
virtual SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data) = 0;
};
+3 -4
View File
@@ -268,8 +268,7 @@ class InspIRCdProto : public IRCDProto
Anope::string svidbuf = stringify(u->timestamp);
u->Account()->Shrink("authenticationtoken");
u->Account()->Extend("authenticationtoken", new ExtensibleItemRegular<Anope::string>(svidbuf));
u->Account()->Extend("authenticationtoken", new ExtensibleString(svidbuf));
}
};
@@ -321,8 +320,8 @@ class InspircdIRCdMessage : public IRCdMessage
user->SetCloakedHost(params[3]);
NickAlias *na = findnick(user->nick);
Anope::string svidbuf;
if (na && na->nc->GetExtRegular("authenticationtoken", svidbuf) && svidbuf == params[0])
Anope::string *svidbuf = na ? na->nc->GetExt<Anope::string *>("authenticationtoken") : NULL;
if (na && svidbuf && *svidbuf == params[0])
{
user->Login(na->nc);
if (na->nc->HasFlag(NI_UNCONFIRMED))
+1
View File
@@ -85,6 +85,7 @@ class MyMemoServService : public MemoServService
Memo *m = new Memo();
mi->memos.push_back(m);
m->owner = target;
m->sender = source;
m->time = Anope::CurTime;
m->text = message;
+13
View File
@@ -273,6 +273,19 @@ class OperServCore : public Module
XLineManager::RegisterXLineManager(&sglines);
XLineManager::RegisterXLineManager(&sqlines);
XLineManager::RegisterXLineManager(&snlines);
Serializable<XLine>::Alloc.Register("XLine");
}
~OperServCore()
{
this->sglines.Clear();
this->sqlines.Clear();
this->snlines.Clear();
XLineManager::UnregisterXLineManager(&sglines);
XLineManager::UnregisterXLineManager(&sqlines);
XLineManager::UnregisterXLineManager(&snlines);
}
EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message)
-1
View File
@@ -11,7 +11,6 @@
#include "services.h"
#include "modules.h"
#include "access.h"
enum
{
+16
View File
@@ -1,6 +1,22 @@
#include "services.h"
#include "modules.h"
std::vector<SerializableBase *> serialized_types;
std::list<SerializableBase *> serialized_items;
void RegisterTypes()
{
Serializable<NickCore>::Alloc.Register("NickCore");
Serializable<NickAlias>::Alloc.Register("NickAlias");
Serializable<BotInfo>::Alloc.Register("BotInfo");
Serializable<ChannelInfo>::Alloc.Register("ChannelInfo");
Serializable<LogSetting>::Alloc.Register("LogSetting");
Serializable<ModeLock>::Alloc.Register("ModeLock");
Serializable<AutoKick>::Alloc.Register("AutoKick");
Serializable<BadWord>::Alloc.Register("BadWord");
Serializable<Memo>::Alloc.Register("Memo");
}
Base::Base()
{
}
+1 -1
View File
@@ -1,7 +1,7 @@
# If not on Windows, generate anoperc and install it along with mydbgen
if(NOT WIN32)
configure_file(${Anope_SOURCE_DIR}/src/bin/anoperc.in ${Anope_BINARY_DIR}/src/bin/anoperc)
install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/anoperc ${CMAKE_CURRENT_SOURCE_DIR}/mydbgen
install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/anoperc
DESTINATION bin
)
-21
View File
@@ -1,21 +0,0 @@
#!/bin/sh
if [ $1 = "-t" ] ; then
shift
fi
if [ ! "$2" ] ; then
echo >&2 Usage: $0 '<sourcedir> <targetdir>'
exit 1
fi
if [ -d "$1" ] ; then
dir="$1"
else
dir="`echo $1 | sed 's#\(.*\)/.*#\1#'`"
fi
while [ "$2" ] ; do
shift
done
if [ ! -d $1 ] ; then
mkdir -p $1 || exit 1
fi
/bin/tar -Ccf $dir - . | /bin/tar -Cxf $1 -
-239
View File
@@ -1,239 +0,0 @@
#!/usr/bin/perl
#
# Ribosome's all in one language tool
# 1) Compares to check for missing lines
# 2) Compares to check for equal lines
# 3) Fixes (on request) missing lines
# 4) Checks for errors in lines
# 5) Checks for long lines (>60 characters)
#
# Check to see if we have received arguments
if (!$ARGV[0]) {
print "Usage: $0 [language file]\n";
exit;
}
# If yes, set $sourcefile to the language filename
$testagainst = $ARGV[0];
# Set $sourcefile to en_us language file
$sourcefile = "en_us.l";
# Number of Keys in File, Number of Equal Lines, Number of Missing Lines
# Fixed Lines (optional) and Number of Format Error Lines, Number of Long Lines
my $numberlines = 0;
my $equallines = 0;
my $missinglines = 0;
my $fixedlines = 0;
my $errorline = 0;
my $longlines = 0;
# Array to hold the lines from the source file and explosion array for long line check
my @sourcearray;
my @explosion;
# Create associative arrays which will contain keys and definitions
# One for the control source and one for what is being tested against
my %sourcehash= ();
my %testhash= ();
# Check if Files Exist
if (! -f $sourcefile) {
print "Critical Error: The source file does not exist or is unreadable.\nNote: This tool must be run from the language directory.\n";
exit;
}
if (! -f $testagainst) {
print "Critical Error: The language file does not exist or is unreadable\n";
exit;
}
###########################################
# Function to load sourcefile into memory #
###########################################
sub load_sourcefile {
my $_key; # This variable will hold the key
my $_def; # This variable will hold the definition
my $line; # This variable will hold the current line
open (SOURCEFILE, "< $sourcefile"); # Open the source file
while (<SOURCEFILE>) { # For each line the source file
$line = $_; # $line is set to the line in the source file
# Skip comments
if (/^#/) { # This checks for # which indicates comment
next; # If detected, the next line is skipped to
}
# Start of a key
if (/^[A-Z]/) { # Checks to see if the line is a key
chomp($line); # Removes things that shouldn't be at the end
push (@sourcearray, $line); # Puts the line into the source array
# If a key is defined, load definition into the hash
if ($_key ne undef) { # If the key is defined
$sourcehash{$_key} = $_def; # Add the definition to the associative array
}
$_key=$line; # Set the key to the line
$_def=""; # Reset the definition
next; # Move onto the next line
}
if ($_key ne undef) { # If the key is set already
$_def.=$line; # The definition is the current line
}
$sourcehash{$_key} = $_def; # Load the definition into the associative array
} # End of while which reads lines
close (SOURCEFILE); # Close the source file
} # End of load_sourcefile function
#################################################
# Function to load testagainst file into memory #
#################################################
sub load_testagainst {
my $_key; # This variable will hold the key
my $_def; # This variable will hold the definition
my $line; # This variable will hold the current line
open (TESTAGAINSTFILE, "< $testagainst"); # Open the file containing the control lines
while (<TESTAGAINSTFILE>) { # For each line in the file
$line = $_; # $line is set to the lines value
# Skip comments
if (/^#/) { # This checks for # which indicates comment
next; # If detected, the next line is skipped to
}
# Start of a key
if (/^[A-Z]/) { # Checks to see if the line is a key
chomp($line); # Removes things that shouldn't be at the end
if ($_key ne undef) { # If the key is defined
$testhash{$_key} = $_def; # Add the definition to the associative array
}
$_key=$line; # Set the key to the line
$_def=""; # Reset the definition
next; # Move onto the next line
}
if ($_key ne undef) { # If the key is set already
$_def.=$line; # The definition is the current line
}
$testhash{$_key} = $_def; # Load the definition into the associative array
} # End of while which reads lines
close (TESTAGAINSTFILE); # Close the source file
}
sub get_format { # Function to get the formatting from a string
my $fmt="";
my $str=shift; # Get the input
while ($str =~ m/%\w/g) {
$fmt .= $&;
}
return $fmt; # Return the formatting
}
load_sourcefile; # Call function to load the source file
load_testagainst; # Call function to load the test file
if (!grep(/^LANG_NAME/,%testhash)) {
print "Critical Error: $ARGV[0] is not a valid language file!\n";
exit;
}
open (LOG,"> langcheck.log"); # Open logfile for writing
foreach $sourcearray (@sourcearray) { # For each key stored in the source array
my $_key=$_; # Store key from source array in $_key
if ((get_format($sourcehash{$sourcearray})) ne (get_format($testhash{$sourcearray}))) {
if ($sourcearray !~ STRFTIME ) {
$errorline++;
print LOG "FORMAT: $sourcearray - (expecting '".get_format($sourcehash{$sourcearray})."' and got '".get_format($testhash{$sourcearray})."')\n";
} }
if ($testhash{$sourcearray} eq $sourcehash{$sourcearray} ) {
# If the definitions between the source and the test are equal
$equallines++; # Number of equal lines increases
print LOG "EQUAL: $sourcearray\n"; # Line is written to logfile
}
if (!grep(/^$sourcearray/,%testhash)) { # If the key is found in the testhash associative array
$missinglines++; # Increase missing lines
print LOG "MISSING: $sourcearray\n"; # Line is written to logfile
}
@explosion = split(/\n/, $testhash{$sourcearray});
foreach $explosion (@explosion) {
$explosion =~ s/\002//g;
$explosion =~ s/\037//g;
if (length($explosion) > 61) {
print LOG "LONGLINE: $sourcearray (".substr($explosion,1,30)."...)\n";
$longlines++;
}
}
$numberlines++; # Increase the number of lines tested by 1
}
close (LOG); # Close the logfile
#########################
# Show the test results #
#########################
print "Calculation Results:\n";
print "----------------------------------\n";
print "[$numberlines] line(s) were compared\n";
print "[$equallines] line(s) were found to equal their $sourcefile counterpart(s)\n";
print "[$missinglines] line(s) were found to be missing\n";
print "[$longlines] line(s) were found to be long (>60 chars)\n";
print "[$errorline] line(s) were found to have formatting errors\n";
print "The specific details of the test have been saved in langcheck.log\n";
if ($missinglines) { # If missing lines exist
print "----------------------------------\n";
print "Missing line(s) have been detected in this test, would you like to fix the file?\n";
print "This automatically inserts values from the control file ($sourcefile) for the missing values\n";
print "y/N? (Default: No) ";
my $input = <STDIN>; # Ask if the file should be fixed
if ((substr($input,0,1) eq "y") || (substr($input,0,1) eq "Y")) { # If Yes...
open (FIX, ">> $testagainst"); # Open the file and append changes
foreach $sourcearray (@sourcearray) { # For each key stored in the source array
my $_key=$_; # Store key from source array in $_key
if (!grep(/^$sourcearray/,%testhash)) { # If the key is not found in the testhash associative array
print FIX "$sourcearray\n$sourcehash{$sourcearray}"; # Add the line(s) to the language file
$fixedlines++; # Increase the fixed line count
}
}
close (FIX); # Close file after fixing
print "Fixing Compete. [$fixedlines] line(s) fixed.\n";
exit; # And Exit!
}
# Otherwise, quit without fixing
print "Exiting. The language file has NOT been fixed.\n";
}
-148
View File
@@ -1,148 +0,0 @@
#!/bin/sh
#
# Location of the .sql file with the schema
DBSQL="tables.sql"
# Schema Version
SVER="2"
# Local Version, defaults to 0
LVER="0"
TFILE="/tmp/.anopedb.$$"
if [ "`eval echo -n 'a'`" = "-n a" ] ; then
c="\c"
else
n="-n"
fi
DBFILE=../data/$DBSQL
if [ ! -f "./$DBFILE" ] ; then
echo "Error: Required file $DBSQL was not found!";
exit
fi
echo ""
echo "This script will guide you through the process of configuring your Anope"
echo "installation to make use of MySQL support. This script must be used for both"
echo "new installs as well as for upgrading for users who have a previous version"
echo "of Anope installed"
while [ -z "$SQLHOST" ] ; do
echo ""
echo "What is the hostname of your MySQL server?"
echo $n "-> $c"
read cc
if [ ! -z "$cc" ] ; then
SQLHOST=$cc
fi
done
while [ -z "$SQLUSER" ] ; do
echo ""
echo "What is your MySQL username?"
echo $n "-> $c"
read cc
if [ ! -z "$cc" ] ; then
SQLUSER=$cc
fi
done
OLD_TTY=`stty -g`
echo ""
echo "What is your MySQL password?"
echo $n "-> $c"
stty -echo echonl
read cc
SQLPASS_PREFIX=""
if [ ! -z "$cc" ] ; then
SQLPASS_PREFIX="-p"
SQLPASS=$cc
fi
stty $OLD_TTY
mysqlshow -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS >/dev/null 2>&1
if test "$?" = "1" ; then
echo "Error: Unable to login, verify your login/password and hostname"
exit
fi
while [ -z "$SQLDB" ] ; do
echo ""
echo "What is the name of the Anope SQL database?"
echo $n "-> $c"
read cc
if [ ! -z "$cc" ] ; then
SQLDB=$cc
fi
done
MYSQLDUMP="mysqldump -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB"
MYSQLSHOW="mysqlshow -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB"
MYSQL="mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS $SQLDB"
echo ""
$MYSQLSHOW | grep -q $SQLDB
if test "$?" = "1" ; then
echo -n "Unable to find databse, creating... "
mysql -h$SQLHOST -u$SQLUSER $SQLPASS_PREFIX$SQLPASS -Bs -e "create database $SQLDB" >/dev/null 2>&1
if test "$?" = "0" ; then
echo "done!"
else
echo "failed!"
FAILED="$FAILED 'database creation'"
fi
fi
$MYSQL -Bs -e "show tables like 'anope_os_core'" | grep -q anope_os_core
if test "$?" = "1" ; then
echo -n "Unable to find Anope schema, creating... "
$MYSQL < $DBFILE
if test "$?" = "0" ; then
echo "done!"
else
echo "failed!"
FAILED="$FAILED 'schema creation'"
fi
else
echo "done!"
fi
echo ""
if [ $LVER -ne $SVER ]; then
echo -n "Inserting initial version number... "
$MYSQL -Bs -e "delete from anope_info"
echo "INSERT INTO anope_info (version, date) VALUES ($SVER, now())" > $TFILE
$MYSQL < $TFILE >/dev/null 2>&1
if test "$?" = "0" ; then
echo "done!"
else
echo "failed!"
FAILED="$FAILED 'version insert'"
fi
fi
rm -f $TFILE
if test "x$FAILED" = "x" ; then
# Try to find out more about this installation
SQLPORT="$(mysql_config --port 2> /dev/null)"
if test "$SQLPORT" = "0" ; then
SQLPORT=3306
fi
echo ""
echo "Your MySQL setup is complete and your Anope schema is up to date. Make"
echo "sure you configure MySQL on your services.conf file prior to launching"
echo "Anope with MySQL support."
echo ""
else
echo "The following operations failed:"
echo "$FAILED"
fi
exit
+23
View File
@@ -64,6 +64,29 @@ BotInfo::~BotInfo()
BotListByUID.erase(this->uid);
}
SerializableBase::serialized_data BotInfo::serialize()
{
SerializableBase::serialized_data data;
data["nick"] << this->nick;
data["user"] << this->ident;
data["host"] << this->host;
data["realname"] << this->realname;
data["created"] << this->created;
data["chancount"] << this->chancount;
return data;
}
void BotInfo::unserialize(SerializableBase::serialized_data &data)
{
BotInfo *bi = findbot(data["nick"].astr());
if (bi == NULL)
bi = new BotInfo(data["nick"].astr(), data["user"].astr(), data["host"].astr(), data["realname"].astr());
data["created"] >> bi->created;
data["chancount"] >> bi->chancount;
}
void BotInfo::GenerateUID()
{
if (!this->uid.empty())
+1 -1
View File
@@ -72,7 +72,7 @@ const Anope::string &HostInfo::GetCreator() const
/** Retrieve when the vhost was crated
* @return the time it was created
*/
const time_t HostInfo::GetTime() const
time_t HostInfo::GetTime() const
{
return Time;
}
+2 -2
View File
@@ -241,6 +241,8 @@ void Init(int ac, char **av)
#endif
if (set_group() < 0)
throw FatalException("set_group() fail");
RegisterTypes();
/* Parse command line arguments */
ParseCommandLineArguments(ac, av);
@@ -442,8 +444,6 @@ void Init(int ac, char **av)
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnLoadDatabase, OnLoadDatabase());
Log() << "Databases loaded";
FOREACH_MOD(I_OnPostLoadDatabases, OnPostLoadDatabases());
}
/*************************************************************************/
+1
View File
@@ -375,6 +375,7 @@ int main(int ac, char **av, char **envp)
ModuleManager::UnloadModule(m, NULL);
ModuleManager::CleanupRuntimeDirectory();
serialized_items.clear();
#ifdef _WIN32
OnShutdown();
+32
View File
@@ -11,9 +11,41 @@
#include "services.h"
#include "modules.h"
#include "memoserv.h"
Memo::Memo() : Flags<MemoFlag>(MemoFlagStrings) { }
SerializableBase::serialized_data Memo::serialize()
{
serialized_data data;
data["owner"] << this->owner;
data["time"] << this->time;
data["sender"] << this->sender;
data["text"] << this->text;
return data;
}
void Memo::unserialize(SerializableBase::serialized_data &data)
{
if (!memoserv)
return;
bool ischan;
MemoInfo *mi = memoserv->GetMemoInfo(data["owner"].astr(), ischan);
if (!mi)
return;
Memo *m = new Memo();
data["owner"] >> m->owner;
data["time"] >> m->time;
data["sender"] >> m->sender;
data["text"] >> m->text;
mi->memos.push_back(m);
}
unsigned MemoInfo::GetIndex(Memo *m) const
{
for (unsigned i = 0; i < this->memos.size(); ++i)
+13
View File
@@ -14,6 +14,19 @@
#include "version.h"
#include "modules.h"
ExtensibleItem::ExtensibleItem()
{
}
ExtensibleItem::~ExtensibleItem()
{
}
void ExtensibleItem::OnDelete()
{
delete this;
}
struct arc4_stream
{
uint8 i;
+1 -1
View File
@@ -54,7 +54,7 @@ void SetDefaultMLock(ServerConfig *config)
if (cm->Type != MODE_LIST) // Only MODE_LIST can have duplicates
def_mode_locks.erase(cm->Name);
def_mode_locks.insert(std::make_pair(cm->Name, ModeLock(adding == 1, cm->Name, param)));
def_mode_locks.insert(std::make_pair(cm->Name, ModeLock(NULL, adding == 1, cm->Name, param)));
}
}
}
+44
View File
@@ -102,3 +102,47 @@ void NickAlias::OnCancel(User *)
new NickServRelease(this, Config->NSReleaseTimeout);
}
}
SerializableBase::serialized_data NickAlias::serialize()
{
serialized_data data;
data["nick"].setKey().setMax(Config->NickLen) << this->nick;
data["last_quit"] << this->last_quit;
data["last_realname"] << this->last_realname;
data["last_usermask"] << this->last_usermask;
data["last_realhost"] << this->last_realhost;
data["time_registered"].setType(Serialize::DT_INT) << this->time_registered;
data["last_seen"].setType(Serialize::DT_INT) << this->last_seen;
data["nc"] << this->nc->display;
if (this->hostinfo.HasVhost())
{
data["vhost_ident"] << this->hostinfo.GetIdent();
data["vhost_host"] << this->hostinfo.GetHost();
data["vhost_creator"] << this->hostinfo.GetCreator();
data["vhost_time"] << this->hostinfo.GetTime();
}
return data;
}
void NickAlias::unserialize(SerializableBase::serialized_data &data)
{
NickCore *core = findcore(data["nc"].astr());
if (core == NULL)
return;
NickAlias *na = new NickAlias(data["nick"].astr(), core);
data["last_quit"] >> na->last_quit;
data["last_realname"] >> na->last_realname;
data["last_usermask"] >> na->last_usermask;
data["last_realhost"] >> na->last_realhost;
data["time_registered"] >> na->time_registered;
data["last_seen"] >> na->last_seen;
time_t vhost_time;
data["vhost_time"] >> vhost_time;
na->hostinfo.SetVhost(data["vhost_ident"].astr(), data["vhost_host"].astr(), data["vhost_creator"].astr(), vhost_time);
}
+51
View File
@@ -45,6 +45,57 @@ NickCore::~NickCore()
}
}
SerializableBase::serialized_data NickCore::serialize()
{
serialized_data data;
data["display"].setKey().setMax(Config->NickLen) << this->display;
data["pass"] << this->pass;
data["email"] << this->email;
data["greet"] << this->greet;
data["language"] << this->language;
for (unsigned i = 0; i < this->access.size(); ++i)
data["access"] << this->access[i] << " ";
for (unsigned i = 0; i < this->cert.size(); ++i)
data["cert"] << this->cert[i] << " ";
data["memomax"] << this->memos.memomax;
for (unsigned i = 0; i < this->memos.ignores.size(); ++i)
data["memoignores"] << this->memos.ignores[i] << " ";
return data;
}
void NickCore::unserialize(serialized_data &data)
{
NickCore *nc = new NickCore(data["display"].astr());
data["pass"] >> nc->pass;
data["email"] >> nc->email;
data["greet"] >> nc->greet;
data["language"] >> nc->language;
{
Anope::string buf;
data["access"] >> buf;
spacesepstream sep(buf);
while (sep.GetToken(buf))
nc->access.push_back(buf);
}
{
Anope::string buf;
data["cert"] >> buf;
spacesepstream sep(buf);
while (sep.GetToken(buf))
nc->access.push_back(buf);
}
data["memomax"] >> nc->memos.memomax;
{
Anope::string buf;
data["memoignores"] >> buf;
spacesepstream sep(buf);
while (sep.GetToken(buf))
nc->memos.ignores.push_back(buf);
}
}
bool NickCore::IsServicesOper() const
{
return this->o != NULL;
+39 -2
View File
@@ -16,6 +16,10 @@
/* List of XLine managers we check users against in XLineManager::CheckAll */
std::list<XLineManager *> XLineManager::XLineManagers;
XLine::XLine()
{
}
XLine::XLine(const Anope::string &mask, const Anope::string &reason) : Mask(mask), Created(0), Expires(0), Reason(reason)
{
}
@@ -66,6 +70,37 @@ sockaddrs XLine::GetIP() const
return addr;
}
SerializableBase::serialized_data XLine::serialize()
{
serialized_data data;
data["mask"] << this->Mask;
data["by"] << this->By;
data["created"] << this->Created;
data["expires"] << this->Expires;
data["reason"] << this->Reason;
data["manager"] << this->Manager;
return data;
}
void XLine::unserialize(SerializableBase::serialized_data &data)
{
service_reference<XLineManager> xlm(data["manager"].astr());
if (!xlm)
return;
XLine *xl = new XLine();
data["mask"] >> xl->Mask;
data["by"] >> xl->By;
data["created"] >> xl->Created;
data["expires"] >> xl->Expires;
data["reason"] >> xl->Reason;
xlm->AddXLine(xl);
}
/** Constructor
*/
XLineManager::XLineManager(Module *creator, const Anope::string &xname, char t) : Service<XLineManager>(creator, xname), type(t)
@@ -159,6 +194,7 @@ const std::vector<XLine *> &XLineManager::GetList() const
*/
void XLineManager::AddXLine(XLine *x)
{
x->Manager = this->name;
this->XLines.push_back(x);
}
@@ -199,8 +235,9 @@ XLine *XLineManager::GetEntry(unsigned index)
*/
void XLineManager::Clear()
{
while (!this->XLines.empty())
this->DelXLine(this->XLines.front());
for (unsigned i = 0; i < this->XLines.size(); ++i)
delete this->XLines[i];
this->XLines.clear();
}
/** Add an entry to this XLine Manager
+214 -7
View File
@@ -12,6 +12,124 @@
#include "services.h"
#include "modules.h"
SerializableBase::serialized_data BadWord::serialize()
{
serialized_data data;
data["word"] << this->word;
data["type"].setType(Serialize::DT_INT) << this->type;
return data;
}
void BadWord::unserialize(SerializableBase::serialized_data &data)
{
BadWord *bw = new BadWord();
data["word"] >> bw->word;
unsigned int n;
data["type"] >> n;
bw->type = static_cast<BadWordType>(n);
}
SerializableBase::serialized_data AutoKick::serialize()
{
serialized_data data;
if (this->HasFlag(AK_ISNICK) && this->nc)
data["nc"] << this->nc->display;
else
data["mask"] << this->mask;
data["reason"] << this->reason;
data["creator"] << this->creator;
data["addtime"].setType(Serialize::DT_INT) << this->addtime;
data["last_used"].setType(Serialize::DT_INT) << this->last_used;
return data;
}
void AutoKick::unserialize(SerializableBase::serialized_data &data)
{
AutoKick *ak = new AutoKick();
data["mask"] >> ak->mask;
ak->nc = findcore(data["nc"].astr());
data["reason"] >> ak->reason;
data["creator"] >> ak->creator;
data["addtime"] >> ak->addtime;
data["last_used"] >> ak->last_used;
}
SerializableBase::serialized_data ModeLock::serialize()
{
serialized_data data;
if (this->ci == NULL)
return data;
data["ci"] << this->ci->name;
data["set"] << this->set;
data["name"] << ChannelModeNameStrings[this->name];
data["param"] << this->param;
data["setter"] << this->setter;
data["created"].setType(Serialize::DT_INT) << this->created;
return data;
}
void ModeLock::unserialize(SerializableBase::serialized_data &data)
{
ChannelInfo *ci = cs_findchan(data["ci"].astr());
if (ci == NULL)
return;
ModeLock ml;
ml.ci = ci;
data["set"] >> ml.set;
Anope::string n;
data["name"] >> n;
for (unsigned i = 0; !ChannelModeNameStrings[i].empty(); ++i)
if (n == ChannelModeNameStrings[i])
{
ml.name = static_cast<ChannelModeName>(i);
break;
}
data["param"] >> ml.param;
data["setter"] >> ml.setter;
data["created"] >> ml.created;
ci->mode_locks.insert(std::make_pair(ml.name, ml));
}
SerializableBase::serialized_data LogSetting::serialize()
{
serialized_data data;
data["service_name"] << service_name;
data["command_service"] << command_service;
data["command_name"] << command_name;
data["method"] << method;
data["extra"] << extra;
data["creator"] << creator;
data["created"].setType(Serialize::DT_INT) << created;
return data;
}
void LogSetting::unserialize(serialized_data &data)
{
LogSetting ls;
data["service_name"] >> ls.service_name;
data["command_service"] >> ls.command_service;
data["command_name"] >> ls.command_name;
data["method"] >> ls.method;
data["extra"] >> ls.extra;
data["creator"] >> ls.creator;
data["created"] >> ls.created;
}
/** Default constructor
* @param chname The channel name
*/
@@ -142,6 +260,83 @@ ChannelInfo::~ChannelInfo()
--this->founder->channelcount;
}
SerializableBase::serialized_data ChannelInfo::serialize()
{
serialized_data data;
data["name"].setKey().setMax(255) << this->name;
if (this->founder)
data["founder"] << this->founder->display;
if (this->successor)
data["successor"] << this->successor->display;
data["description"] << this->desc;
data["time_registered"].setType(Serialize::DT_INT) << this->time_registered;
data["last_used"].setType(Serialize::DT_INT) << this->last_used;
data["last_topic"] << this->last_topic;
data["last_topic_setter"] << this->last_topic_setter;
data["last_topic_time"].setType(Serialize::DT_INT) << this->last_topic_time;
data["bantype"].setType(Serialize::DT_INT) << this->bantype;
data["botflags"] << this->botflags.ToString();
{
Anope::string levels_buffer;
for (std::map<Anope::string, int16>::iterator it = this->levels.begin(), it_end = this->levels.end(); it != it_end; ++it)
levels_buffer += it->first + " " + stringify(it->second) + " ";
data["levels"] << levels_buffer;
}
if (this->bi)
data["bi"] << this->bi->nick;
for (int i = 0; i < TTB_SIZE; ++i)
data["ttb"] << this->ttb[i] << " ";
data["capsmin"].setType(Serialize::DT_INT) << this->capsmin;
data["capspercent"].setType(Serialize::DT_INT) << this->capspercent;
data["floodlines"].setType(Serialize::DT_INT) << this->floodlines;
data["floodsecs"].setType(Serialize::DT_INT) << this->floodsecs;
data["repeattimes"].setType(Serialize::DT_INT) << this->repeattimes;
data["memomax"] << this->memos.memomax;
for (unsigned i = 0; i < this->memos.ignores.size(); ++i)
data["memoignores"] << this->memos.ignores[i] << " ";
return data;
}
void ChannelInfo::unserialize(SerializableBase::serialized_data &data)
{
ChannelInfo *ci = new ChannelInfo(data["name"].astr());
if (data.count("founder") > 0)
ci->founder = findcore(data["founder"].astr());
if (data.count("successor") > 0)
ci->successor = findcore(data["successor"].astr());
data["description"] >> ci->desc;
data["time_registered"] >> ci->time_registered;
data["last_used"] >> ci->last_used;
data["last_topic"] >> ci->last_topic;
data["last_topic_setter"] >> ci->last_topic_setter;
data["last_topic_time"] >> ci->last_topic_time;
data["bantype"] >> ci->bantype;
ci->botflags.FromString(data["botflags"].astr());
{
std::vector<Anope::string> v = BuildStringVector(data["levels"].astr());
for (unsigned i = 0; i + 1 < v.size(); i += 2)
ci->levels[v[i]] = convertTo<int16>(v[i + 1]);
}
if (data.count("bi") > 0)
ci->bi = findbot(data["bi"].astr());
data["capsmin"] >> ci->capsmin;
data["capspercent"] >> ci->capspercent;
data["floodlines"] >> ci->floodlines;
data["floodsecs"] >> ci->floodsecs;
data["repeattimes"] >> ci->repeattimes;
data["memomax"] >> ci->memos.memomax;
{
Anope::string buf;
data["memoignores"] >> buf;
spacesepstream sep(buf);
while (sep.GetToken(buf))
ci->memos.ignores.push_back(buf);
}
}
/** Change the founder of the channek
* @params nc The new founder
*/
@@ -338,6 +533,7 @@ AutoKick *ChannelInfo::AddAkick(const Anope::string &user, const Anope::string &
{
AutoKick *autokick = new AutoKick();
autokick->mask = mask;
autokick->nc = NULL;
autokick->reason = reason;
autokick->creator = user;
autokick->addtime = t;
@@ -484,7 +680,7 @@ bool ChannelInfo::SetMLock(ChannelMode *mode, bool status, const Anope::string &
{
if (setter.empty())
setter = this->founder ? this->founder->display : "Unknown";
std::pair<ChannelModeName, ModeLock> ml = std::make_pair(mode->Name, ModeLock(status, mode->Name, param, setter, created));
std::pair<ChannelModeName, ModeLock> ml = std::make_pair(mode->Name, ModeLock(this, status, mode->Name, param, setter, created));
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnMLock, OnMLock(this, &ml.second));
@@ -525,13 +721,20 @@ bool ChannelInfo::SetMLock(ChannelMode *mode, bool status, const Anope::string &
*/
bool ChannelInfo::RemoveMLock(ChannelMode *mode, const Anope::string &param)
{
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnUnMLock, OnUnMLock(this, mode, param));
if (MOD_RESULT == EVENT_STOP)
return false;
if (mode->Type == MODE_REGULAR || mode->Type == MODE_PARAM)
return this->mode_locks.erase(mode->Name) > 0;
{
std::multimap<ChannelModeName, ModeLock>::iterator it = this->mode_locks.find(mode->Name), it_end = this->mode_locks.upper_bound(mode->Name), it_next = it;
if (it != this->mode_locks.end())
for (; it != it_end; it = it_next)
{
++it_next;
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnUnMLock, OnUnMLock(this, &it->second));
if (MOD_RESULT != EVENT_STOP)
this->mode_locks.erase(it);
}
return true;
}
else
{
// For list or status modes, we must check the parameter
@@ -544,6 +747,10 @@ bool ChannelInfo::RemoveMLock(ChannelMode *mode, const Anope::string &param)
const ModeLock &ml = it->second;
if (ml.param == param)
{
EventReturn MOD_RESULT;
FOREACH_RESULT(I_OnUnMLock, OnUnMLock(this, &it->second));
if (MOD_RESULT == EVENT_STOP)
return false;
this->mode_locks.erase(it);
return true;
}
File diff suppressed because it is too large Load Diff
-975
View File
@@ -1,975 +0,0 @@
/*
* Copyright (C) 2003-2011 Anope Team <team@anope.org>
* Copyright (C) 2005-2006 Florian Schulze <certus@anope.org>
* Copyright (C) 2008-2011 Robin Burchell <w00t@inspircd.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (see it online
* at http://www.gnu.org/copyleft/gpl.html) as published by the Free
* Software Foundation;
*
* 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.
*/
#ifndef DB_CONVERT_H
#define DB_CONVERT_H
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <ctime>
#include <fcntl.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <windows.h>
#include <io.h>
#endif
#include "sysconf.h"
#ifndef _WIN32
#define C_LBLUE "\033[1;34m"
#define C_NONE "\033[m"
#else
#define C_LBLUE ""
#define C_NONE ""
#endif
#define getc_db(f) (fgetc((f)->fp))
#define HASH(nick) ((tolower((nick)[0]) & 31)<<5 | (tolower((nick)[1]) & 31))
#define HASH2(chan) ((chan)[1] ? ((chan)[1] & 31)<<5 | ((chan)[2] & 31) : 0)
#define read_buffer(buf, f) (read_db((f), (buf), sizeof(buf)) == sizeof(buf))
#define write_buffer(buf, f) (write_db((f), (buf), sizeof(buf)) == sizeof(buf))
#define read_db(f, buf, len) (fread((buf), 1, (len), (f)->fp))
#define write_db(f, buf, len) (fwrite((buf), 1, (len), (f)->fp))
#define read_int8(ret, f) ((*(ret) = fgetc((f)->fp)) == EOF ? -1 : 0)
#define write_int8(val, f) (fputc((val), (f)->fp) == EOF ? -1 : 0)
#define SAFE(x) \
if (true) \
{ \
if ((x) < 0) \
printf("Error, the database is broken, trying to continue... no guarantee.\n"); \
} \
else \
static_cast<void>(0)
#define READ(x) \
if (true) \
{ \
if ((x) < 0) \
{ \
printf("Error, the database is broken, trying to continue... no guarantee.\n"); \
exit(0); \
} \
} \
else \
static_cast<void>(0)
struct Memo
{
uint32 number; /* Index number -- not necessarily array position! */
uint16 flags; /* Flags */
time_t time; /* When was it sent? */
char sender[32]; /* Name of the sender */
char *text;
};
struct dbFILE
{
int mode; /* 'r' for reading, 'w' for writing */
FILE *fp; /* The normal file descriptor */
char filename[1024]; /* Name of the database file */
};
struct MemoInfo
{
int16 memocount; /* Current # of memos */
int16 memomax; /* Max # of memos one can hold*/
Memo *memos; /* Pointer to original memos */
};
struct NickCore
{
NickCore *next, *prev;
char *display; /* How the nick is displayed */
char pass[32]; /* Password of the nicks */
char *email; /* E-mail associated to the nick */
char *greet; /* Greet associated to the nick */
uint32 icq; /* ICQ # associated to the nick */
char *url; /* URL associated to the nick */
uint32 flags; /* See NI_* below */
uint16 language; /* Language selected by nickname owner (LANG_*) */
uint16 accesscount; /* # of entries */
char **access; /* Array of strings */
MemoInfo memos; /* Memo information */
uint16 channelcount; /* Number of channels currently registered */
int unused; /* Used for nick collisions */
int aliascount; /* How many aliases link to us? Remove the core if 0 */
};
struct NickAlias
{
NickAlias *next, *prev;
char *nick; /* Nickname */
time_t time_registered; /* When the nick was registered */
time_t last_seen; /* When it was seen online for the last time */
uint16 status; /* See NS_* below */
NickCore *nc; /* I'm an alias of this */
char *last_usermask;
char *last_realname;
char *last_quit;
};
struct ChanAccess
{
uint16 in_use; /* 1 if this entry is in use, else 0 */
int16 level;
NickCore *nc; /* Guaranteed to be non-NULL if in use, NULL if not */
time_t last_seen;
};
struct AutoKick
{
int16 in_use; /* Always 0 if not in use */
int16 is_nick; /* 1 if a regged nickname, 0 if a nick!user@host mask */
uint16 flags;
union
{
char *mask; /* Guaranteed to be non-NULL if in use, NULL if not */
NickCore *nc; /* Same */
} u;
char *reason;
char *creator;
time_t addtime;
};
struct BadWord
{
uint16 in_use;
char *word;
uint16 type;
};
struct ChannelInfo
{
ChannelInfo *next, *prev;
char name[64]; /* Channel name */
char *founder; /* Who registered the channel */
char *successor; /* Who gets the channel if the founder nick is dropped or expires */
char founderpass[32]; /* Channel password */
char *desc; /* Description */
char *url; /* URL */
char *email; /* Email address */
time_t time_registered; /* When was it registered */
time_t last_used; /* When was it used hte last time */
char *last_topic; /* Last topic on the channel */
char last_topic_setter[32]; /* Who set the last topic */
time_t last_topic_time; /* When the last topic was set */
uint32 flags; /* Flags */
char *forbidby; /* if forbidden: who did it */
char *forbidreason; /* if forbidden: why */
int16 bantype; /* Bantype */
int16 *levels; /* Access levels for commands */
uint16 accesscount; /* # of pple with access */
ChanAccess *access; /* List of authorized users */
uint16 akickcount; /* # of akicked pple */
AutoKick *akick; /* List of users to kickban */
uint32 mlock_on, mlock_off; /* See channel modes below */
uint32 mlock_limit; /* 0 if no limit */
char *mlock_key; /* NULL if no key */
char *mlock_flood; /* NULL if no +f */
char *mlock_redirect; /* NULL if no +L */
char *entry_message; /* Notice sent on entering channel */
MemoInfo memos; /* Memos */
char *bi; /* Bot used on this channel */
uint32 botflags; /* BS_* below */
int16 *ttb; /* Times to ban for each kicker */
uint16 bwcount; /* Badword count */
BadWord *badwords; /* For BADWORDS kicker */
int16 capsmin, capspercent; /* For CAPS kicker */
int16 floodlines, floodsecs; /* For FLOOD kicker */
int16 repeattimes; /* For REPEAT kicker */
};
struct HostCore
{
HostCore *next;
char *nick;
char *vIdent;
char *vHost;
char *creator;
int32 time;
};
dbFILE *open_db_read(const char *service, const char *filename, int version);
NickCore *findcore(const char *nick, int version);
NickAlias *findnick(const char *nick);
ChannelInfo *cs_findchan(const char *chan);
char *strscpy(char *d, const char *s, size_t len);
int write_file_version(dbFILE * f, uint32 version);
int mystricmp(const char *s1, const char *s2);
int delnick(NickAlias *na, int donttouchthelist);
int write_string(const char *s, dbFILE * f);
int write_ptr(const void *ptr, dbFILE * f);
int read_int16(int16 * ret, dbFILE * f);
int read_int32(int32 * ret, dbFILE * f);
int read_uint16(uint16 * ret, dbFILE * f);
int read_uint32(uint32 * ret, dbFILE * f);
int read_string(char **ret, dbFILE * f);
int write_int16(uint16 val, dbFILE * f);
int write_int32(uint32 val, dbFILE * f);
int read_ptr(void **ret, dbFILE * f);
int delcore(NickCore *nc);
void alpha_insert_chan(ChannelInfo * ci);
void close_db(dbFILE * f);
ChannelInfo *chanlists[256];
NickAlias *nalists[1024];
NickCore *nclists[1024];
HostCore *head = NULL;
void b64_encode(const std::string &src, std::string &target);
/* Memo Flags */
#define MF_UNREAD 0x0001 /* Memo has not yet been read */
#define MF_RECEIPT 0x0002 /* Sender requested receipt */
#define MF_NOTIFYS 0x0004 /* Memo is a notification of receitp */
/* Nickname status flags: */
#define NS_FORBIDDEN 0x0002 /* Nick may not be registered or used */
#define NS_NO_EXPIRE 0x0004 /* Nick never expires */
/* Nickname setting flags: */
#define NI_KILLPROTECT 0x00000001 /* Kill others who take this nick */
#define NI_SECURE 0x00000002 /* Don't recognize unless IDENTIFY'd */
#define NI_MSG 0x00000004 /* Use PRIVMSGs instead of NOTICEs */
#define NI_MEMO_HARDMAX 0x00000008 /* Don't allow user to change memo limit */
#define NI_MEMO_SIGNON 0x00000010 /* Notify of memos at signon and un-away */
#define NI_MEMO_RECEIVE 0x00000020 /* Notify of new memos when sent */
#define NI_PRIVATE 0x00000040 /* Don't show in LIST to non-servadmins */
#define NI_HIDE_EMAIL 0x00000080 /* Don't show E-mail in INFO */
#define NI_HIDE_MASK 0x00000100 /* Don't show last seen address in INFO */
#define NI_HIDE_QUIT 0x00000200 /* Don't show last quit message in INFO */
#define NI_KILL_QUICK 0x00000400 /* Kill in 20 seconds instead of 60 */
#define NI_KILL_IMMED 0x00000800 /* Kill immediately instead of in 60 sec */
#define NI_ENCRYPTEDPW 0x00004000 /* Nickname password is encrypted */
#define NI_MEMO_MAIL 0x00010000 /* User gets email on memo */
#define NI_HIDE_STATUS 0x00020000 /* Don't show services access status */
#define NI_SUSPENDED 0x00040000 /* Nickname is suspended */
#define NI_AUTOOP 0x00080000 /* Autoop nickname in channels */
#define NI_NOEXPIRE 0x00100000 /* nicks in this group won't expire */
// Old NS_FORBIDDEN, very fucking temporary.
#define NI_FORBIDDEN 0x80000000
/* Retain topic even after last person leaves channel */
#define CI_KEEPTOPIC 0x00000001
/* Don't allow non-authorized users to be opped */
#define CI_SECUREOPS 0x00000002
/* Hide channel from ChanServ LIST command */
#define CI_PRIVATE 0x00000004
/* Topic can only be changed by SET TOPIC */
#define CI_TOPICLOCK 0x00000008
/* Those not allowed ops are kickbanned */
#define CI_RESTRICTED 0x00000010
/* Don't allow ChanServ and BotServ commands to do bad things to bigger levels */
#define CI_PEACE 0x00000020
/* Don't allow any privileges unless a user is IDENTIFY'd with NickServ */
#define CI_SECURE 0x00000040
/* Don't allow the channel to be registered or used */
#define CI_FORBIDDEN 0x00000080
/* Channel password is encrypted */
#define CI_ENCRYPTEDPW 0x00000100
/* Channel does not expire */
#define CI_NO_EXPIRE 0x00000200
/* Channel memo limit may not be changed */
#define CI_MEMO_HARDMAX 0x00000400
/* Send notice to channel on use of OP/DEOP */
#define CI_OPNOTICE 0x00000800
/* Stricter control of channel founder status */
#define CI_SECUREFOUNDER 0x00001000
/* Always sign kicks */
#define CI_SIGNKICK 0x00002000
/* Sign kicks if level is < than the one defined by the SIGNKICK level */
#define CI_SIGNKICK_LEVEL 0x00004000
/* Use the xOP lists */
#define CI_XOP 0x00008000
/* Channel is suspended */
#define CI_SUSPENDED 0x00010000
/* akick */
#define AK_USED 0x0001
#define AK_ISNICK 0x0002
#define AK_STUCK 0x0004
/* botflags */
#define BI_PRIVATE 0x0001
#define BI_CHANSERV 0x0002
#define BI_BOTSERV 0x0004
#define BI_HOSTSERV 0x0008
#define BI_OPERSERV 0x0010
#define BI_MEMOSERV 0x0020
#define BI_NICKSERV 0x0040
#define BI_GLOBAL 0x0080
/* BotServ SET flags */
#define BS_DONTKICKOPS 0x00000001
#define BS_DONTKICKVOICES 0x00000002
#define BS_FANTASY 0x00000004
#define BS_SYMBIOSIS 0x00000008
#define BS_GREET 0x00000010
#define BS_NOBOT 0x00000020
/* BotServ Kickers flags */
#define BS_KICK_BOLDS 0x80000000
#define BS_KICK_COLORS 0x40000000
#define BS_KICK_REVERSES 0x20000000
#define BS_KICK_UNDERLINES 0x10000000
#define BS_KICK_BADWORDS 0x08000000
#define BS_KICK_CAPS 0x04000000
#define BS_KICK_FLOOD 0x02000000
#define BS_KICK_REPEAT 0x01000000
/* Indices for TTB (Times To Ban) */
enum
{
TTB_BOLDS,
TTB_COLORS,
TTB_REVERSES,
TTB_UNDERLINES,
TTB_BADWORDS,
TTB_CAPS,
TTB_FLOOD,
TTB_REPEAT,
TTB_SIZE
};
enum
{
LANG_EN_US, /* United States English */
LANG_JA_JIS, /* Japanese (JIS encoding) */
LANG_JA_EUC, /* Japanese (EUC encoding) */
LANG_JA_SJIS, /* Japanese (SJIS encoding) */
LANG_ES, /* Spanish */
LANG_PT, /* Portugese */
LANG_FR, /* French */
LANG_TR, /* Turkish */
LANG_IT, /* Italian */
LANG_DE, /* German */
LANG_CAT, /* Catalan */
LANG_GR, /* Greek */
LANG_NL, /* Dutch */
LANG_RU, /* Russian */
LANG_HUN, /* Hungarian */
LANG_PL /* Polish */
};
const std::string GetLanguageID(int id)
{
switch (id)
{
case LANG_EN_US:
return "en_US";
break;
case LANG_JA_JIS:
case LANG_JA_EUC:
case LANG_JA_SJIS: // these seem to be unused
return "en_US";
break;
case LANG_ES:
return "es_ES";
break;
case LANG_PT:
return "pt_PT";
break;
case LANG_FR:
return "fr_FR";
break;
case LANG_TR:
return "tr_TR";
break;
case LANG_IT:
return "it_IT";
break;
case LANG_DE:
return "de_DE";
break;
case LANG_CAT:
return "ca_ES"; // yes, iso639 defines catalan as CA
break;
case LANG_GR:
return "el_GR";
break;
case LANG_NL:
return "nl_NL";
break;
case LANG_RU:
return "ru_RU";
break;
case LANG_HUN:
return "hu_HU";
break;
case LANG_PL:
return "pl_PL";
break;
default:
abort();
}
}
/* Open a database file for reading and check for the version */
dbFILE *open_db_read(const char *service, const char *filename, int version)
{
dbFILE *f;
FILE *fp;
int myversion;
f = new dbFILE;
if (!f)
{
printf("Can't allocate memory for %s database %s.\n", service, filename);
exit(0);
}
strscpy(f->filename, filename, sizeof(f->filename));
f->mode = 'r';
fp = fopen(f->filename, "rb");
if (!fp)
{
printf("Can't read %s database %s.\n", service, f->filename);
//free(f);
delete f;
return NULL;
}
f->fp = fp;
myversion = fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp);
if (feof(fp))
{
printf("Error reading version number on %s: End of file detected.\n", f->filename);
exit(0);
}
else if (myversion < version)
{
printf("Unsuported database version (%d) on %s.\n", myversion, f->filename);
exit(0);
}
return f;
}
/* Close it */
void close_db(dbFILE *f)
{
fclose(f->fp);
delete f;
}
int read_int16(int16 *ret, dbFILE *f)
{
int c1, c2;
c1 = fgetc(f->fp);
c2 = fgetc(f->fp);
if (c1 == EOF || c2 == EOF)
return -1;
*ret = c1 << 8 | c2;
return 0;
}
int read_uint16(uint16 *ret, dbFILE *f)
{
int c1, c2;
c1 = fgetc(f->fp);
c2 = fgetc(f->fp);
if (c1 == EOF || c2 == EOF)
return -1;
*ret = c1 << 8 | c2;
return 0;
}
int write_int16(uint16 val, dbFILE *f)
{
if (fputc((val >> 8) & 0xFF, f->fp) == EOF || fputc(val & 0xFF, f->fp) == EOF)
return -1;
return 0;
}
int read_int32(int32 *ret, dbFILE *f)
{
int c1, c2, c3, c4;
c1 = fgetc(f->fp);
c2 = fgetc(f->fp);
c3 = fgetc(f->fp);
c4 = fgetc(f->fp);
if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
return -1;
*ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
return 0;
}
int read_uint32(uint32 *ret, dbFILE *f)
{
int c1, c2, c3, c4;
c1 = fgetc(f->fp);
c2 = fgetc(f->fp);
c3 = fgetc(f->fp);
c4 = fgetc(f->fp);
if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
return -1;
*ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
return 0;
}
int write_int32(uint32 val, dbFILE *f)
{
if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
return -1;
if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
return -1;
if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
return -1;
if (fputc((val) & 0xFF, f->fp) == EOF)
return -1;
return 0;
}
int read_ptr(void **ret, dbFILE *f)
{
int c;
c = fgetc(f->fp);
if (c == EOF)
return -1;
*ret = c ? reinterpret_cast<void *>(1) : reinterpret_cast<void *>(0);
return 0;
}
int write_ptr(const void *ptr, dbFILE * f)
{
if (fputc(ptr ? 1 : 0, f->fp) == EOF)
return -1;
return 0;
}
int read_string(char **ret, dbFILE *f)
{
char *s;
uint16 len;
if (read_uint16(&len, f) < 0)
return -1;
if (len == 0)
{
*ret = NULL;
return 0;
}
s = new char[len];
if (len != fread(s, 1, len, f->fp))
{
delete [] s;
return -1;
}
*ret = s;
return 0;
}
int write_string(const char *s, dbFILE *f)
{
uint32 len;
if (!s)
return write_int16(0, f);
len = strlen(s);
if (len > 65534)
len = 65534;
if (write_int16(static_cast<uint16>(len + 1), f) < 0)
return -1;
if (len > 0 && fwrite(s, 1, len, f->fp) != len)
return -1;
if (fputc(0, f->fp) == EOF)
return -1;
return 0;
}
NickCore *findcore(const char *nick, int unused)
{
NickCore *nc;
for (nc = nclists[HASH(nick)]; nc; nc = nc->next)
if (!mystricmp(nc->display, nick) && ((nc->unused && unused) || (!nc->unused && !unused)))
return nc;
return NULL;
}
NickAlias *findnick(const char *nick)
{
NickAlias *na;
for (na = nalists[HASH(nick)]; na; na = na->next)
if (!mystricmp(na->nick, nick))
return na;
return NULL;
}
int write_file_version(dbFILE *f, uint32 version)
{
FILE *fp = f->fp;
if (fputc(version >> 24 & 0xFF, fp) < 0 || fputc(version >> 16 & 0xFF, fp) < 0 || fputc(version >> 8 & 0xFF, fp) < 0 || fputc(version & 0xFF, fp) < 0)
{
printf("Error writing version number on %s.\n", f->filename);
exit(0);
}
return 1;
}
/* strscpy: Copy at most len-1 characters from a string to a buffer, and
* add a null terminator after the last character copied.
*/
char *strscpy(char *d, const char *s, size_t len)
{
char *d_orig = d;
if (!len)
return d;
while (--len && (*d++ = *s++));
*d = '\0';
return d_orig;
}
int mystricmp(const char *s1, const char *s2)
{
register int c;
while ((c = tolower(*s1)) == tolower(*s2))
{
if (!c)
return 0;
++s1;
++s2;
}
if (c < tolower(*s2))
return -1;
return 1;
}
int delnick(NickAlias *na, int donttouchthelist)
{
if (!donttouchthelist)
{
/* Remove us from the aliases list */
if (na->next)
na->next->prev = na->prev;
if (na->prev)
na->prev->next = na->next;
else
nalists[HASH(na->nick)] = na->next;
}
if (na->last_usermask)
delete [] na->last_usermask;
if (na->last_realname)
delete [] na->last_realname;
if (na->last_quit)
delete [] na->last_quit;
/* free() us */
delete [] na->nick;
delete na;
return 1;
}
int delcore(NickCore *nc)
{
int i;
/* Remove the core from the list */
if (nc->next)
nc->next->prev = nc->prev;
if (nc->prev)
nc->prev->next = nc->next;
else
nclists[HASH(nc->display)] = nc->next;
delete [] nc->display;
if (nc->email)
delete [] nc->email;
if (nc->greet)
delete [] nc->greet;
if (nc->url)
delete [] nc->url;
if (nc->access)
{
for (i = 0; i < nc->accesscount; ++i)
if (nc->access[i])
delete [] nc->access[i];
delete [] nc->access;
}
if (nc->memos.memos)
{
for (i = 0; i < nc->memos.memocount; ++i)
if (nc->memos.memos[i].text)
delete [] nc->memos.memos[i].text;
delete [] nc->memos.memos;
}
delete nc;
return 1;
}
ChannelInfo *cs_findchan(const char *chan)
{
ChannelInfo *ci;
for (ci = chanlists[tolower(chan[1])]; ci; ci = ci->next)
if (!mystricmp(ci->name, chan))
return ci;
return NULL;
}
void alpha_insert_chan(ChannelInfo *ci)
{
ChannelInfo *ptr, *prev;
char *chan = ci->name;
for (prev = NULL, ptr = chanlists[tolower(chan[1])]; ptr && mystricmp(ptr->name, chan) < 0; prev = ptr, ptr = ptr->next);
ci->prev = prev;
ci->next = ptr;
if (!prev)
chanlists[tolower(chan[1])] = ci;
else
prev->next = ci;
if (ptr)
ptr->prev = ci;
}
HostCore *findHostCore(char *nick)
{
for (HostCore *hc = head; hc; hc = hc->next)
if (nick && hc->nick && !mystricmp(hc->nick, nick))
return hc;
return NULL;
}
static char *int_to_base64(long);
static long base64_to_int(char *);
const char *base64enc(long i)
{
if (i < 0)
return "0";
return int_to_base64(i);
}
long base64dec(char *b64)
{
if (b64)
return base64_to_int(b64);
else
return 0;
}
std::string Hex(const std::string &data)
{
const char hextable[] = "0123456789abcdef";
size_t l = data.length();
std::string rv;
for (size_t i = 0; i < l; ++i)
{
unsigned char c = data[i];
rv += hextable[c >> 4];
rv += hextable[c & 0xF];
}
return rv;
}
static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
The following encoding technique is taken from RFC 1521 by Borenstein
and Freed. It is reproduced here in a slightly edited form for
convenience.
A 65-character subset of US-ASCII is used, enabling 6 bits to be
represented per printable character. (The extra 65th character, "=",
is used to signify a special processing function.)
The encoding process represents 24-bit groups of input bits as output
strings of 4 encoded characters. Proceeding from left to right, a
24-bit input group is formed by concatenating 3 8-bit input groups.
These 24 bits are then treated as 4 concatenated 6-bit groups, each
of which is translated into a single digit in the base64 alphabet.
Each 6-bit group is used as an index into an array of 64 printable
characters. The character referenced by the index is placed in the
output string.
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
Special processing is performed if fewer than 24 bits are available
at the end of the data being encoded. A full encoding quantum is
always completed at the end of a quantity. When fewer than 24 input
bits are available in an input group, zero bits are added (on the
right) to form an integral number of 6-bit groups. Padding at the
end of the data is performed using the '=' character.
Since all base64 input is an integral number of octets, only the
-------------------------------------------------
following cases can arise:
(1) the final quantum of encoding input is an integral
multiple of 24 bits; here, the final unit of encoded
output will be an integral multiple of 4 characters
with no "=" padding,
(2) the final quantum of encoding input is exactly 8 bits;
here, the final unit of encoded output will be two
characters followed by two "=" padding characters, or
(3) the final quantum of encoding input is exactly 16 bits;
here, the final unit of encoded output will be three
characters followed by one "=" padding character.
*/
void b64_encode(const std::string &src, std::string &target)
{
size_t src_pos = 0, src_len = src.length();
unsigned char input[3];
target.clear();
while (src_len - src_pos > 2)
{
input[0] = src[src_pos++];
input[1] = src[src_pos++];
input[2] = src[src_pos++];
target += Base64[input[0] >> 2];
target += Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
target += Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
target += Base64[input[2] & 0x3f];
}
/* Now we worry about padding */
if (src_pos != src_len)
{
input[0] = input[1] = input[2] = 0;
for (size_t i = 0; i < src_len - src_pos; ++i)
input[i] = src[src_pos + i];
target += Base64[input[0] >> 2];
target += Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
if (src_pos == src_len - 1)
target += Pad64;
else
target += Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
target += Pad64;
}
}
/* ':' and '#' and '&' and '+' and '@' must never be in this table. */
/* these tables must NEVER CHANGE! >) */
char int6_to_base64_map[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'{', '}'
};
char base64_to_int6_map[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
-1, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, 63, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
static char *int_to_base64(long val)
{
/* 32/6 == max 6 bytes for representation,
* +1 for the null, +1 for byte boundaries
*/
static char base64buf[8];
long i = 7;
base64buf[i] = '\0';
/* Temporary debugging code.. remove before 2038 ;p.
* This might happen in case of 64bit longs (opteron/ia64),
* if the value is then too large it can easily lead to
* a buffer underflow and thus to a crash. -- Syzop
*/
if (val > 2147483647L)
abort();
do
{
base64buf[--i] = int6_to_base64_map[val & 63];
}
while (val >>= 6);
return base64buf + i;
}
static long base64_to_int(char *b64)
{
int v = base64_to_int6_map[static_cast<unsigned char>(*b64++)];
if (!b64)
return 0;
while (*b64)
{
v <<= 6;
v += base64_to_int6_map[static_cast<unsigned char>(*b64++)];
}
return v;
}
#endif // DB_CONVERT_H