diff options
75 files changed, 4132 insertions, 5869 deletions
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index a9f27a5f8..94aa3d8ca 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -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 ) diff --git a/data/example.conf b/data/example.conf index b9a37a275..b29e56280 100644 --- a/data/example.conf +++ b/data/example.conf @@ -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_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" } +#module { name = "db_plain" } db_plain { /* @@ -1046,25 +1064,52 @@ db_plain } /* - * db_mysql and db_mysql_live + * db_flatfile + * + * This is the default flatfile database format. + */ +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) MySQL support. + * Enables (live) SQL 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. + * The db_sql_live modules are an extension to db_sql, and should only be used if + * db_sql is being used. * - * This effectively allows you to edit your database and have it be immediately - * reflected back in Anope. + * 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. * - * 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. + * The db_sql_live_write module writes data to SQL in real time as it is modified by + * the core. * - * db_mysql provides the command operserv/sqlsync, which is used for importing other database - * methods into MySQL. */ -#module { name = "db_mysql" } -#module { name = "db_mysql_live" } +#module { name = "db_sql_live_read" } +#module { name = "db_sql_live_write" } /* * [REQUIRED] Encryption modules. diff --git a/data/modules.example.conf b/data/modules.example.conf index 74c8bff5d..e03761fb2 100644 --- a/data/modules.example.conf +++ b/data/modules.example.conf @@ -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" @@ -297,6 +297,20 @@ proxyscan } /* + * 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 * * This module uses SSL to connect to the uplink server(s) diff --git a/data/tables.sql b/data/tables.sql deleted file mode 100644 index ec99b7479..000000000 --- a/data/tables.sql +++ /dev/null @@ -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; - diff --git a/include/access.h b/include/access.h index 229a16f4b..d86539d8f 100644 --- a/include/access.h +++ b/include/access.h @@ -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; diff --git a/include/account.h b/include/account.h index 6c6295f5c..3cfb803f8 100644 --- a/include/account.h +++ b/include/account.h @@ -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. */ diff --git a/include/bots.h b/include/bots.h index 20daeddcf..c23a354fc 100644 --- a/include/bots.h +++ b/include/bots.h @@ -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. diff --git a/include/extensible.h b/include/extensible.h index 2d7fb5509..c5de2dae4 100644 --- a/include/extensible.h +++ b/include/extensible.h @@ -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() { } -}; - -/** Class used to represent an extensible item that doesn't hold a pointer - */ -template<typename T> class ExtensibleItemRegular : public ExtensibleItemBase -{ - protected: - T Item; - - public: - ExtensibleItemRegular(T item) : Item(item) { } - virtual ~ExtensibleItemRegular() { } - T &GetItem() { return Item; } + ExtensibleItem(); + virtual ~ExtensibleItem(); + virtual void OnDelete(); }; -/** Class used to represent an extensible item that holds a pointer - */ -template<typename T> class ExtensibleItemPointer : public ExtensibleItemBase +class ExtensibleString : public Anope::string, public ExtensibleItem { - 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 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 this->extension_items.erase(key) > 0; } 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 + /** Get an extension item. * * @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. + * @return The item found */ - template<typename T> bool GetExtArray(const Anope::string &key, T *&p) + template<typename T> T GetExt(const Anope::string &key) { - extensible_map::iterator it = this->Extension_Items.find(key); + extensible_map::iterator it = this->extension_items.find(key); + if (it != this->extension_items.end()) + return debug_cast<T>(it->second); - if (it != this->Extension_Items.end()) - { - p = debug_cast<ExtensibleItemPointerArray<T> *>(it->second)->GetItem(); - return true; - } - - p = NULL; - return false; + return NULL; } - /** Get an extension item. + /** Check if an extension item exists. * * @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 True if the item was found. */ - bool GetExt(const Anope::string &key) + bool HasExt(const Anope::string &key) { - return this->Extension_Items.find(key) != this->Extension_Items.end(); + 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); } }; diff --git a/include/hashcomp.h b/include/hashcomp.h index 9c1f0d2dc..c36211cde 100644 --- a/include/hashcomp.h +++ b/include/hashcomp.h @@ -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 * diff --git a/include/modules.h b/include/modules.h index d35c1f2ba..00e48250b 100644 --- a/include/modules.h +++ b/include/modules.h @@ -342,11 +342,6 @@ class CoreExport Module : public Extensible */ virtual void OnPostCommand(CommandSource &source, Command *command, const std::vector<Anope::string> ¶ms) { } - /** 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> ¶ms) { 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> ¶ms) { 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> ¶ms) { 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> ¶ms) { 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> ¶ms) { 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 ¶m) { 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) diff --git a/include/oper.h b/include/oper.h index 8c587794b..fb046bdbe 100644 --- a/include/oper.h +++ b/include/oper.h @@ -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> diff --git a/include/regchannel.h b/include/regchannel.h index 017b93afe..680be5b44 100644 --- a/include/regchannel.h +++ b/include/regchannel.h @@ -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 */ diff --git a/include/serialize.h b/include/serialize.h new file mode 100644 index 000000000..e4c6bce1f --- /dev/null +++ b/include/serialize.h @@ -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 diff --git a/include/services.h b/include/services.h index 77b9e9cd1..e863ab8d1 100644 --- a/include/services.h +++ b/include/services.h @@ -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 */ diff --git a/modules/commands/bs_kick.cpp b/modules/commands/bs_kick.cpp index 74ccaf05c..2c41b4b90 100644 --- a/modules/commands/bs_kick.cpp +++ b/modules/commands/bs_kick.cpp @@ -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]; + struct Data + { + 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; - BanData() + public: + Data &get(const Anope::string &key) { - this->Clear(); + return this->data_map[key]; } - void Clear() + bool empty() const + { + return this->data_map.empty(); + } + + void purge() { - last_use = 0; - for (int i = 0; i < TTB_SIZE; ++i) - this->ttb[i] = 0; + 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 = &bandatamap[u->GetMask()]; - if (bd->last_use && Anope::CurTime - bd->last_use > Config->BSKeepData) - bd->Clear(); - bd->last_use = Anope::CurTime; - return bd; + BanData *bd = c->GetExt<BanData *>("bs_main_bandata"); + if (bd == NULL) + { + bd = new BanData(); + c->Extend("bs_main_bandata", 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); diff --git a/modules/commands/cs_access.cpp b/modules/commands/cs_access.cpp index 2821ba5c3..3e737b709 100644 --- a/modules/commands/cs_access.cpp +++ b/modules/commands/cs_access.cpp @@ -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)); diff --git a/modules/commands/cs_entrymsg.cpp b/modules/commands/cs_entrymsg.cpp index 05b97e027..6fa8d5dd3 100644 --- a/modules/commands/cs_entrymsg.cpp +++ b/modules/commands/cs_entrymsg.cpp @@ -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> ¶ms) - { - 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); } }; diff --git a/modules/commands/cs_flags.cpp b/modules/commands/cs_flags.cpp index 5ead6f2d9..1b790b5f1 100644 --- a/modules/commands/cs_flags.cpp +++ b/modules/commands/cs_flags.cpp @@ -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() diff --git a/modules/commands/cs_info.cpp b/modules/commands/cs_info.cpp index 5fc85666a..e7c8e039e 100644 --- a/modules/commands/cs_info.cpp +++ b/modules/commands/cs_info.cpp @@ -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)); diff --git a/modules/commands/cs_seen.cpp b/modules/commands/cs_seen.cpp index d466acca4..f828e181d 100644 --- a/modules/commands/cs_seen.cpp +++ b/modules/commands/cs_seen.cpp @@ -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 -}; -class ModuleConfigClass -{ - public: - time_t purgetime; - time_t expiretimeout; + 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; + } }; -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> ¶ms) - { - 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) diff --git a/modules/commands/cs_set_misc.cpp b/modules/commands/cs_set_misc.cpp index 61c8c163b..0757e965b 100644 --- a/modules/commands/cs_set_misc.cpp +++ b/modules/commands/cs_set_misc.cpp @@ -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> ¶ms) - { - if (key.find("cs_set_misc:") == 0) - ci->Extend(key, new ExtensibleItemRegular<Anope::string>(params[0])); - - return EVENT_CONTINUE; - } }; MODULE_INIT(CSSetMisc) diff --git a/modules/commands/cs_suspend.cpp b/modules/commands/cs_suspend.cpp index d9f846d71..d59931b45 100644 --- a/modules/commands/cs_suspend.cpp +++ b/modules/commands/cs_suspend.cpp @@ -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"); diff --git a/modules/commands/cs_xop.cpp b/modules/commands/cs_xop.cpp index b2aaffde6..e132f19f5 100644 --- a/modules/commands/cs_xop.cpp +++ b/modules/commands/cs_xop.cpp @@ -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"); } }; diff --git a/modules/commands/hs_request.cpp b/modules/commands/hs_request.cpp index 3d330bc2a..82bba1bbc 100644 --- a/modules/commands/hs_request.cpp +++ b/modules/commands/hs_request.cpp @@ -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> ¶ms) - { - 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) diff --git a/modules/commands/ns_ajoin.cpp b/modules/commands/ns_ajoin.cpp index bed0442d7..d7bde685e 100644 --- a/modules/commands/ns_ajoin.cpp +++ b/modules/commands/ns_ajoin.cpp @@ -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> ¶ms) { - 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> ¶ms) { - 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> ¶ms) { - 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"); + + if (channels == NULL) + return; - for (unsigned i = 0; i < channels.size(); ++i) + 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> ¶ms) - { - 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) diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp index aced3046e..acfcd2acd 100644 --- a/modules/commands/ns_register.cpp +++ b/modules/commands/ns_register.cpp @@ -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); } diff --git a/modules/commands/ns_resetpass.cpp b/modules/commands/ns_resetpass.cpp index 153691cdf..3cced2de2 100644 --- a/modules/commands/ns_resetpass.cpp +++ b/modules/commands/ns_resetpass.cpp @@ -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); } diff --git a/modules/commands/ns_set_email.cpp b/modules/commands/ns_set_email.cpp index 175ed5b9e..e86338075 100644 --- a/modules/commands/ns_set_email.cpp +++ b/modules/commands/ns_set_email.cpp @@ -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"); diff --git a/modules/commands/ns_set_misc.cpp b/modules/commands/ns_set_misc.cpp index c511159d2..a9b93083d 100644 --- a/modules/commands/ns_set_misc.cpp +++ b/modules/commands/ns_set_misc.cpp @@ -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()); - } - } - - 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); + 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()); } } - - EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - if (key.find("ns_set_misc:") == 0) - nc->Extend(key, new ExtensibleItemRegular<Anope::string>(params[0])); - - return EVENT_CONTINUE; - } }; MODULE_INIT(NSSetMisc) diff --git a/modules/commands/os_forbid.cpp b/modules/commands/os_forbid.cpp index ef591923c..00731f703 100644 --- a/modules/commands/os_forbid.cpp +++ b/modules/commands/os_forbid.cpp @@ -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> ¶ms) - { - 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) diff --git a/modules/commands/os_forbid.h b/modules/commands/os_forbid.h index 06a936645..1aac412a3 100644 --- a/modules/commands/os_forbid.h +++ b/modules/commands/os_forbid.h @@ -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 diff --git a/modules/commands/os_ignore.cpp b/modules/commands/os_ignore.cpp index 5f2cbb195..6462284f5 100644 --- a/modules/commands/os_ignore.cpp +++ b/modules/commands/os_ignore.cpp @@ -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> ¶ms) { - 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> ¶ms) { - 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> ¶ms) - { - 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) diff --git a/modules/commands/os_ignore.h b/modules/commands/os_ignore.h index b00f427dd..753a4cfaf 100644 --- a/modules/commands/os_ignore.h +++ b/modules/commands/os_ignore.h @@ -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); +} + diff --git a/modules/commands/os_login.cpp b/modules/commands/os_login.cpp index 57c172f7f..d08310424 100644 --- a/modules/commands/os_login.cpp +++ b/modules/commands/os_login.cpp @@ -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; } diff --git a/modules/commands/os_module.cpp b/modules/commands/os_module.cpp index 7f9f1d990..36fe570cd 100644 --- a/modules/commands/os_module.cpp +++ b/modules/commands/os_module.cpp @@ -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 { diff --git a/modules/commands/os_news.cpp b/modules/commands/os_news.cpp index 6a959ee47..b2537bbc9 100644 --- a/modules/commands/os_news.cpp +++ b/modules/commands/os_news.cpp @@ -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> ¶ms) - { - 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) diff --git a/modules/commands/os_news.h b/modules/commands/os_news.h index 436cadcb4..9e41173d7 100644 --- a/modules/commands/os_news.h +++ b/modules/commands/os_news.h @@ -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 diff --git a/modules/commands/os_oper.cpp b/modules/commands/os_oper.cpp index db300f1ce..1d38a0279 100644 --- a/modules/commands/os_oper.cpp +++ b/modules/commands/os_oper.cpp @@ -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> ¶ms) - { - 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; } }; diff --git a/modules/commands/os_session.cpp b/modules/commands/os_session.cpp index 8b174f333..a6a2d2396 100644 --- a/modules/commands/os_session.cpp +++ b/modules/commands/os_session.cpp @@ -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> ¶ms) { 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) diff --git a/modules/commands/os_session.h b/modules/commands/os_session.h index d406a7154..8a839318d 100644 --- a/modules/commands/os_session.h +++ b/modules/commands/os_session.h @@ -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 diff --git a/modules/commands/os_shutdown.cpp b/modules/commands/os_shutdown.cpp index efc55c0be..c43be2d51 100644 --- a/modules/commands/os_shutdown.cpp +++ b/modules/commands/os_shutdown.cpp @@ -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; } diff --git a/modules/database/db_flatfile.cpp b/modules/database/db_flatfile.cpp new file mode 100644 index 000000000..f17ed6fd1 --- /dev/null +++ b/modules/database/db_flatfile.cpp @@ -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) + + diff --git a/modules/database/db_mysql.cpp b/modules/database/db_mysql.cpp deleted file mode 100644 index e03c89d16..000000000 --- a/modules/database/db_mysql.cpp +++ /dev/null @@ -1,1568 +0,0 @@ -#include "module.h" -#include "../extra/sql.h" -#include "../commands/os_session.h" - -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 std::vector<Anope::string> MakeVector(const Anope::string &buf) -{ - Anope::string s; - spacesepstream sep(buf); - std::vector<Anope::string> params; - - while (sep.GetToken(s)) - { - if (s[0] == ':') - { - s.erase(s.begin()); - if (!s.empty() && !sep.StreamEnd()) - params.push_back(s + " " + sep.GetRemaining()); - else if (!s.empty()) - params.push_back(s); - } - else - params.push_back(s); - } - - return params; -} - -static NickAlias *CurNick = NULL; -static NickCore *CurCore = NULL; -static ChannelInfo *CurChannel = NULL; -static BotInfo *CurBot = NULL; - -static void Write(const Anope::string &data); -static void WriteNickMetadata(const Anope::string &key, const Anope::string &data); -static void WriteCoreMetadata(const Anope::string &key, const Anope::string &data); -static void WriteChannelMetadata(const Anope::string &key, const Anope::string &data); -static void WriteBotMetadata(const Anope::string &key, const Anope::string &data); - -class CommandSQLSync : public Command -{ - public: - CommandSQLSync(Module *creator) : Command(creator, "operserv/sqlsync", 0, 0) - { - this->SetDesc(_("Import your databases to SQL")); - this->SetSyntax(""); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms); - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("This command syncs your databases with SQL. You should\n" - "only have to execute this command once, when you initially\n" - "import your databases into SQL.")); - return true; - } -}; - -class MySQLInterface : public SQLInterface -{ - public: - MySQLInterface(Module *o) : SQLInterface(o) { } - - void OnResult(const SQLResult &r); - - void OnError(const SQLResult &r); -}; - -class DBMySQL; -static DBMySQL *me; -class DBMySQL : public Module -{ - private: - CommandSQLSync commandsqlsync; - MySQLInterface sqlinterface; - service_reference<SQLProvider, Base> SQL; - - public: - service_reference<SessionService, Base> SessionInterface; - time_t lastwarn; - bool ro; - - 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, is m_mysql loaded? Going to readonly..."); - readonly = this->ro = true; - this->lastwarn = Anope::CurTime; - } - } - } - - DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), commandsqlsync(this), sqlinterface(this), SQL("mysql/main"), SessionInterface("session") - { - me = this; - - this->lastwarn = 0; - this->ro = false; - - Implementation i[] = { - I_OnLoadDatabase, I_OnServerConnect - }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - - if (CurrentUplink) - OnServerConnect(); - } - - void OnServerConnect() - { - Implementation i[] = { - /* Misc */ - I_OnSaveDatabase, 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_OnChanForbidden, 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)); - } - - EventReturn OnLoadDatabase() - { - if (!SQL) - { - Log() << "Error, unable to find service reference for SQL, is m_mysql loaded and configured properly?"; - return EVENT_CONTINUE; - } - - SQLQuery query; - - query = "SELECT * FROM `anope_ns_core`"; - SQLResult r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = new NickCore(r.Get(i, "display")); - nc->pass = r.Get(i, "pass"); - nc->email = r.Get(i, "email"); - nc->greet = r.Get(i, "greet"); - - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - nc->FromString(flags); - - nc->language = r.Get(i, "language"); - nc->memos.memomax = r.Get(i, "memomax").is_number_only() ? convertTo<int16>(r.Get(i, "memomax")) : 20; - } - - query = "SELECT * FROM `anope_ns_access`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = findcore(r.Get(i, "display")); - if (!nc) - { - Log() << "MySQL: Got NickCore access entry for nonexistant core " << r.Get(i, "display"); - continue; - } - - nc->AddAccess(r.Get(i, "access")); - } - - query = "SELECT * FROM `anope_ns_core_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = findcore(r.Get(i, "display")); - if (!nc) - { - Log() << "MySQL: Got NickCore access entry for nonexistant core " << r.Get(i, "display"); - continue; - } - - EventReturn MOD_RESULT;; - std::vector<Anope::string> Params = MakeVector(r.Get(i, "value")); - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(nc, r.Get(i, "name"), Params)); - } - - query = "SELECT * FROM `anope_ns_alias`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = findcore(r.Get(i, "display")); - if (!nc) - { - Log() << "MySQL: Got NickAlias for nick " << r.Get(i, "nick") << " with nonexistant core " << r.Get(i, "display"); - continue; - } - - NickAlias *na = new NickAlias(r.Get(i, "nick"), nc); - na->last_quit = r.Get(i, "last_quit"); - na->last_realname = r.Get(i, "last_realname"); - na->last_usermask = r.Get(i, "last_usermask"); - na->last_realhost = r.Get(i, "last_realhost"); - na->time_registered = r.Get(i, "time_registered").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "time_registered")) : Anope::CurTime; - na->last_seen = r.Get(i, "last_seen").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "last_seen")) : Anope::CurTime; - - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - na->FromString(flags); - } - - query = "SELECT * FROM `anope_ns_alias_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickAlias *na = findnick(r.Get(i, "nick")); - if (!na) - { - Log() << "MySQL: Got metadata for nonexistant nick " << r.Get(i, "nick"); - continue; - } - - EventReturn MOD_RESULT; - std::vector<Anope::string> Params = MakeVector(r.Get(i, "value")); - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(na, r.Get(i, "name"), Params)); - } - - query = "SELECT * FROM `anope_hs_core`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickAlias *na = findnick(r.Get(i, "nick")); - if (!na) - { - Log() << "MySQL: Got vhost entry for nonexistant nick " << r.Get(i, "nick"); - continue; - } - - time_t creation = r.Get(i, "time").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "time")) : Anope::CurTime; - na->hostinfo.SetVhost(r.Get(i, "vident"), r.Get(i, "vhost"), r.Get(i, "creator"), creation); - } - - query = "SELECT * FROM `anope_bs_core`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - BotInfo *bi = findbot(r.Get(i, "nick")); - if (!bi) - bi = new BotInfo(r.Get(i, "nick"), r.Get(i, "user"), r.Get(i, "host")); - bi->realname = r.Get(i, "rname"); - bi->created = r.Get(i, "created").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "created")) : Anope::CurTime; - - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - bi->FromString(flags); - } - - query = "SELECT * FROM `anope_bs_info_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - BotInfo *bi = findbot(r.Get(i, "botname")); - if (!bi) - { - Log() << "MySQL: BotInfo metadata for nonexistant bot " << r.Get(i, "botname"); - continue; - } - - EventReturn MOD_RESULT; - std::vector<Anope::string> Params = MakeVector(r.Get(i, "value")); - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(bi, r.Get(i, "name"), Params)); - } - - query = "SELECT * FROM `anope_cs_info`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = NULL; - - if (!r.Get(i, "founder").empty()) - { - nc = findcore(r.Get(i, "founder")); - if (!nc) - { - Log() << "MySQL: Channel " << r.Get(i, "name") << " with nonexistant founder " << r.Get(i, "founder"); - continue; - } - - ChannelInfo *ci = new ChannelInfo(r.Get(i, "name")); - ci->SetFounder(nc); - if (!r.Get(i, "successor").empty()) - ci->successor = findcore(r.Get(i, "successor")); - ci->desc = r.Get(i, "descr"); - ci->time_registered = r.Get(i, "time_registered").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "time_registered")) : Anope::CurTime; - ci->last_used = r.Get(i, "last_used").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "last_used")) : Anope::CurTime; - ci->last_topic = r.Get(i, "last_topic"); - ci->last_topic_setter = r.Get(i, "last_topic_setter"); - ci->last_topic_time = r.Get(i, "last_topic_time").is_number_only() ? convertTo<int>(r.Get(i, "last_topic_time")) : Anope::CurTime; - ci->bantype = r.Get(i, "bantype").is_number_only() ? convertTo<int>(r.Get(i, "bantype")) : 2; - ci->memos.memomax = r.Get(i, "memomax").is_number_only() ? convertTo<int16>(r.Get(i, "memomax")) : 20; - ci->capsmin = r.Get(i, "capsmin").is_number_only() ? convertTo<int>(r.Get(i, "capsmin")) : 0; - ci->capspercent = r.Get(i, "capspercent").is_number_only() ? convertTo<int>(r.Get(i, "capspercent")) : 0; - ci->floodlines = r.Get(i, "floodlines").is_number_only() ? convertTo<int>(r.Get(i, "floodlines")) : 0; - ci->floodsecs = r.Get(i, "floodsecs").is_number_only() ? convertTo<int>(r.Get(i, "floodsecs")) : 0; - ci->repeattimes = r.Get(i, "repeattimes").is_number_only() ? convertTo<int>(r.Get(i, "repeattimes")) : 0; - ci->bi = findbot(r.Get(i, "botnick")); - if (ci->bi && !r.Get(i, "botflags").empty()) - { - spacesepstream sep(r.Get(i, "botflags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - ci->botflags.FromString(flags); - } - - if (!r.Get(i, "flags").empty()) - { - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - ci->FromString(flags); - } - } - } - - query = "SELECT * FROM `anope_cs_ttb`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel ttb for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - ci->ttb[atoi(r.Get(i, "ttb_id").c_str())] = atoi(r.Get(i, "value").c_str()); - } - - query = "SELECT * FROM `anope_bs_badwords`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel badwords entry for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - BadWordType BWTYPE = BW_ANY; - if (r.Get(i, "type").equals_cs("SINGLE")) - BWTYPE = BW_SINGLE; - else if (r.Get(i, "type").equals_cs("START")) - BWTYPE = BW_START; - else if (r.Get(i, "type").equals_cs("END")) - BWTYPE = BW_END; - ci->AddBadWord(r.Get(i, "word"), BWTYPE); - } - - query = "SELECT * FROM `anope_cs_access`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel access entry for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - const Anope::string &provider = r.Get(i, "provider"), &data = r.Get(i, "data"); - service_reference<AccessProvider> ap(provider); - if (!ap) - { - Log() << "MySQL: Access entry for " << ci->name << " using nonexistant provider " << provider; - continue; - } - - ChanAccess *access = ap->Create(); - access->ci = ci; - access->mask = r.Get(i, "mask"); - access->creator = r.Get(i, "creator"); - access->last_seen = r.Get(i, "last_seen").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "last_seen")) : Anope::CurTime; - access->created = r.Get(i, "created").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "created")) : Anope::CurTime; - access->Unserialize(data); - ci->AddAccess(access); - } - - query = "SELECT * FROM `anope_cs_akick`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel access entry for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - NickCore *nc = NULL; - spacesepstream sep(r.Get(i, "flags")); - Anope::string flag, mask; - while (sep.GetToken(flag)) - { - if (flag.equals_cs("ISNICK")) - nc = findcore(r.Get(i, "mask")); - - AutoKick *ak; - if (nc) - ak = ci->AddAkick(r.Get(i, "creator"), nc, r.Get(i, "reason"), atol(r.Get(i, "created").c_str()), atol(r.Get(i, "last_used").c_str())); - else - ak = ci->AddAkick(r.Get(i, "creator"), r.Get(i, "mask"), r.Get(i, "reason"), atol(r.Get(i, "created").c_str()), atol(r.Get(i, "last_used").c_str())); - if (nc) - ak->SetFlag(AK_ISNICK); - } - } - - query = "SELECT * FROM `anope_cs_levels`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel level entry for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - ci->SetLevel(r.Get(i, "name"), atoi(r.Get(i, "level").c_str())); - } - - query = "SELECT * FROM `anope_cs_info_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel metadata for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - EventReturn MOD_RESULT; - std::vector<Anope::string> Params = MakeVector(r.Get(i, "value")); - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(ci, r.Get(i, "name"), Params)); - } - - query = "SELECT * FROM `anope_cs_mlock`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel mlock for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - Anope::string mode_name = r.Get(i, "mode"); - bool set = r.Get(i, "status") == "1" ? true : false; - Anope::string setter = r.Get(i, "setter"); - time_t mcreated = r.Get(i, "created").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "created")) : Anope::CurTime; - Anope::string param = r.Get(i, "param"); - - for (size_t j = CMODE_BEGIN + 1; j < CMODE_END; ++j) - if (ChannelModeNameStrings[j] == mode_name) - { - ChannelModeName n = static_cast<ChannelModeName>(j); - ci->mode_locks.insert(std::make_pair(n, ModeLock(set, n, param, setter, mcreated))); - break; - } - } - - query = "SELECT * FROM `anope_ms_info`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - MemoInfo *mi = NULL; - if (r.Get(i, "serv").equals_cs("NICK")) - { - NickCore *nc = findcore(r.Get(i, "receiver")); - if (nc) - mi = &nc->memos; - } - else if (r.Get(i, "serv").equals_cs("CHAN")) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "receiver")); - if (ci) - mi = &ci->memos; - } - if (mi) - { - Memo *m = new Memo(); - mi->memos.push_back(m); - m->sender = r.Get(i, "sender"); - m->time = r.Get(i, "time").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "time")) : Anope::CurTime; - m->text = r.Get(i, "text"); - - if (!r.Get(i, "flags").empty()) - { - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - m->FromString(flags); - } - } - } - - for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it) - { - XLineManager *xm = *it; - - query = "SELECT * FROM `anope_os_xlines` WHERE `type` = @type"; - query.setValue("type", Anope::string(xm->Type())); - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - Anope::string user = r.Get(i, "user"); - Anope::string host = r.Get(i, "host"); - Anope::string by = r.Get(i, "xby"); - Anope::string reason = r.Get(i, "reason"); - time_t seton = r.Get(i, "seton").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "seton")) : Anope::CurTime; - time_t expires = r.Get(i, "expires").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "expires")) : Anope::CurTime; - - XLine *x = xm->Add(user + "@" + host, by, expires, reason); - if (x) - x->Created = seton; - } - } - - query = "SELECT * FROM `anope_os_exceptions`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - Anope::string mask = r.Get(i, "mask"); - unsigned limit = convertTo<unsigned>(r.Get(i, "slimit")); - Anope::string creator = r.Get(i, "who"); - Anope::string reason = r.Get(i, "reason"); - time_t expires = convertTo<time_t>(r.Get(i, "expires")); - - if (SessionInterface) - { - Exception *e = new Exception(); - e->mask = mask; - e->limit = limit; - e->who = creator; - e->reason = reason; - e->time = expires; - SessionInterface->AddException(e); - } - } - - query = "SELECT * FROM `anope_extra`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - std::vector<Anope::string> params = MakeVector(r.Get(i, "data")); - EventReturn MOD_RESULT; - FOREACH_RESULT(I_OnDatabaseRead, OnDatabaseRead(params)); - } - - query = "SELECT * FROM `anope_ns_core_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = findcore(r.Get(i, "nick")); - if (!nc) - continue; - if (r.Get(i, "name") == "MEMO_IGNORE") - nc->memos.ignores.push_back(r.Get(i, "value").ci_str()); - } - - query = "SELECT * FROM `anope_cs_info_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - continue; - if (r.Get(i, "name") == "MEMO_IGNORE") - ci->memos.ignores.push_back(r.Get(i, "value").ci_str()); - } - - return EVENT_STOP; - } - - EventReturn OnSaveDatabase() - { - SQLQuery query; - - query = "TRUNCATE TABLE `anope_os_core`"; - this->RunQuery(query); - - query = "INSERT INTO `anope_os_core` (maxusercnt, maxusertime) VALUES(@maxusercnt, @maxusertime)"; - query.setValue("maxusercnt", maxusercnt); - query.setValue("maxusertime", maxusertime); - this->RunQuery(query); - - for (nickcore_map::const_iterator it = NickCoreList.begin(), it_end = NickCoreList.end(); it != it_end; ++it) - { - CurCore = it->second; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteCoreMetadata, CurCore)); - } - - for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ++it) - { - CurNick = it->second; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteNickMetadata, CurNick)); - } - - for (registered_channel_map::const_iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end; ++it) - { - CurChannel = it->second; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteChannelMetadata, CurChannel)); - } - - for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it) - { - if (it->second->HasFlag(BI_CONF)) - continue; - - CurBot = it->second; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteBotMetadata, CurBot)); - - query = "INSERT INTO `anope_bs_core` (nick, user, host, rname, flags, created, chancount) VALUES(@nick, @user, @host, @rname, @flags, @created, @chancount) ON DUPLICATE KEY UPDATE nick=VALUES(nick), user=VALUES(user), host=VALUES(host), rname=VALUES(rname), flags=VALUES(flags), created=VALUES(created), chancount=VALUES(chancount)"; - query.setValue("nick", CurBot->nick); - query.setValue("user", CurBot->GetIdent()); - query.setValue("host", CurBot->host); - query.setValue("rname", CurBot->realname); - query.setValue("flags", ToString(CurBot->ToString())); - query.setValue("created", CurBot->created); - query.setValue("chancount", CurBot->chancount); - this->RunQuery(query); - } - - query = "TRUNCATE TABLE `anope_extra`"; - this->RunQuery(query); - FOREACH_MOD(I_OnDatabaseWrite, OnDatabaseWrite(Write)); - - return EVENT_CONTINUE; - } - - void OnPostCommand(CommandSource &source, Command *command, const std::vector<Anope::string> ¶ms) - { - User *u = source.u; - - if (command->name.find("nickserv/set/") == 0 || command->name.find("nickserv/saset/") == 0) - { - NickAlias *na = findnick(command->name.find("nickserv/set/") == 0 ? source.u->nick : params[1]); - if (!na) - return; - - if (command->name == "nickserv/set/password" || command->name == "nickserv/saset/password") - { - SQLQuery query("UPDATE `anope_ns_core` SET `pass` = @pass WHERE `display` = @display"); - query.setValue("pass", na->nc->pass); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - else if (command->name == "nickserv/set/language" || command->name == "nickserv/saset/language") - { - SQLQuery query("UPDATE `anope_ns_core` SET `language` = @language WHERE `display` = @display"); - query.setValue("language", na->nc->language); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - else if (command->name == "nickserv/set/email" || command->name == "nickserv/saset/email") - { - SQLQuery query("UPDATE `anope_ns_core` SET `email` = @email WHERE `display` = @display"); - query.setValue("email", na->nc->email); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - else if (command->name == "nickserv/set/greet" || command->name == "nickserv/saset/greet") - { - SQLQuery query("UPDATE `anope_ns_core` SET `greet` = @greet WHERE `display` = @display"); - query.setValue("greet", na->nc->greet); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - else - { - SQLQuery query("UPDATE `anope_ns_core` SET `flags` = @flags WHERE `display` = @display"); - query.setValue("flags", ToString(na->nc->ToString())); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - } - 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) - return; - - if (command->name == "chanserv/set/founder" || command->name == "chanserv/saset/founder") - { - SQLQuery query("UPDATE `anope_cs_info` SET `founder` = @founder WHERE `name` = @name"); - query.setValue("founder", ci->GetFounder() ? ci->GetFounder()->display : ""); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (command->name == "chanserv/set/successor" || command->name == "chanserv/saset/successor") - { - SQLQuery query("UPDATE `anope_cs_info` SET `successor` = @successor WHERE `name` = @name"); - query.setValue("successor", ci->successor ? ci->successor->display : ""); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (command->name == "chanserv/set/desc" || command->name == "chanserv/saset/desc") - { - SQLQuery query("UPDATE `anope_cs_info` SET `descr` = @descr WHERE `name` = @name"); - query.setValue("descr", ci->desc); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (command->name == "chanserv/set/bantype" || command->name == "chanserv/saset/bantype") - { - SQLQuery query("UPDATE `anope_cs_info` SET `bantype` = @bantype WHERE `name` = @name"); - query.setValue("bantype", ci->bantype); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else - { - SQLQuery query("UPDATE `anope_cs_info` SET `flags` = @flags WHERE `name` = @name"); - query.setValue("flags", ToString(ci->ToString())); - query.setValue("name", ci->name); - this->RunQuery(query); - } - } - 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; - if (params[1].equals_ci("BADWORDS") || params[1].equals_ci("BOLDS") || params[1].equals_ci("CAPS") || params[1].equals_ci("COLORS") || params[1].equals_ci("FLOOD") || params[1].equals_ci("REPEAT") || params[1].equals_ci("REVERSES") || params[1].equals_ci("UNDERLINES")) - { - if (params[2].equals_ci("ON") || params[2].equals_ci("OFF")) - { - for (int i = 0; i < TTB_SIZE; ++i) - { - SQLQuery query("INSERT INTO `anope_cs_ttb` (channel, ttb_id, value) VALUES(@channel, @ttb_id, @value) ON DUPLICATE KEY UPDATE channel=VALUES(channel), ttb_id=VALUES(ttb_id), value=VALUES(value)"); - query.setValue("channel", ci->name); - query.setValue("ttb_id", i); - query.setValue("value", ci->ttb[i]); - this->RunQuery(query); - } - - { - SQLQuery query("UPDATE `anope_cs_info` SET `botflags` = @botflags WHERE `name` = @name"); - query.setValue("botflags", ToString(ci->botflags.ToString())); - query.setValue("name", ci->name); - this->RunQuery(query); - } - - if (params[1].equals_ci("CAPS")) - { - SQLQuery query("UPDATE `anope_cs_info` SET `capsmin` = @capsmin, `capspercent` = @capspercent WHERE `name` = @name"); - query.setValue("capsmin", ci->capsmin); - query.setValue("capspercent", ci->capspercent); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (params[1].equals_ci("FLOOD")) - { - SQLQuery query("UPDATE `anope_cs_info` SET `floodlines` = @floodlines, `floodsecs` = @floodsecs WHERE `name` = @name"); - query.setValue("floodlines", ci->floodlines); - query.setValue("floodsecs", ci->floodsecs); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (params[1].equals_ci("REPEAT")) - { - SQLQuery query("UPDATE `anope_cs_info` SET `repeattimes` = @ WHERE `name` = @"); - query.setValue("repeattimes", ci->repeattimes); - query.setValue("name", ci->name); - this->RunQuery(query); - } - } - } - } - else if (command->name == "botserv/set" && params.size() > 1) - { - ChannelInfo *ci = cs_findchan(params[0]); - if (ci && !ci->AccessFor(u).HasPriv("SET") && !u->HasPriv("botserv/administration")) - return; - BotInfo *bi = NULL; - if (!ci) - bi = findbot(params[0]); - if (bi && params[1].equals_ci("PRIVATE") && u->HasPriv("botserv/set/private")) - { - SQLQuery query("UPDATE `anope_bs_core` SET `flags` = @ WHERE `nick` = @"); - query.setValue("flags", ToString(bi->ToString())); - query.setValue("nick", bi->nick); - this->RunQuery(query); - } - else if (!ci) - return; - else if (params[1].equals_ci("DONTKICKOPS") || params[1].equals_ci("DONTKICKVOICES") || params[1].equals_ci("FANTASY") || params[1].equals_ci("GREET") || params[1].equals_ci("SYMBIOSIS") || params[1].equals_ci("NOBOT")) - { - SQLQuery query("UPDATE `anope_cs_info` SET `botflags` = @ WHERE `name` = @"); - query.setValue("botflags", ToString(ci->botflags.ToString())); - query.setValue("name", ci->name); - this->RunQuery(query); - } - } - else if (command->name == "memoserv/ignore" && params.size() > 0) - { - Anope::string target = params[0]; - NickCore *nc = NULL; - ChannelInfo *ci = NULL; - if (target[0] != '#') - { - target = u->nick; - nc = u->Account(); - if (!nc) - return; - } - else - { - ci = cs_findchan(target); - if (!ci || !ci->AccessFor(u).HasPriv("MEMO")) - return; - } - - MemoInfo *mi = ci ? &ci->memos : &nc->memos; - Anope::string table = ci ? "anope_cs_info_metadata" : "anope_ns_core_metadata"; - Anope::string ename = ci ? "channel" : "nick"; - - SQLQuery query("DELETE FROM `" + table + "` WHERE `" + ename + "` = @target AND `name` = 'MEMO_IGNORE'"); - query.setValue("target", target); - this->RunQuery(query); - - query = "INSERT INTO `" + table + "` VALUES(" + ename + ", name, value) (@target, 'MEMO_IGNORE, @ignore)"; - query.setValue("target", target); - for (unsigned j = 0; j < mi->ignores.size(); ++j) - { - query.setValue("ignore", mi->ignores[j]); - this->RunQuery(query); - } - } - } - - void OnNickAddAccess(NickCore *nc, const Anope::string &entry) - { - SQLQuery query("INSERT INTO `anope_ns_access` (display, access) VALUES(@display, @access)"); - query.setValue("display", nc->display); - query.setValue("access", entry); - this->RunQuery(query); - } - - void OnNickEraseAccess(NickCore *nc, const Anope::string &entry) - { - SQLQuery query("DELETE FROM `anope_ns_access` WHERE `display` = @display AND `access` = @access"); - query.setValue("display", nc->display); - query.setValue("access", entry); - this->RunQuery(query); - } - - void OnNickClearAccess(NickCore *nc) - { - SQLQuery query("DELETE FROM `anope_ns_access` WHERE `display` = @display"); - query.setValue("display", nc->display); - this->RunQuery(query); - } - - void OnDelCore(NickCore *nc) - { - SQLQuery query("DELETE FROM `anope_ns_core` WHERE `display` = @display"); - query.setValue("display", nc->display); - this->RunQuery(query); - } - - void OnNickForbidden(NickAlias *na) - { - SQLQuery query("UPDATE `anope_ns_alias` SET `flags` = @flags WHERE `nick` = @nick"); - query.setValue("flags", ToString(na->ToString())); - query.setValue("nick", na->nick); - this->RunQuery(query); - } - - void OnNickGroup(User *u, NickAlias *) - { - OnNickRegister(findnick(u->nick)); - } - - void InsertAlias(NickAlias *na) - { - SQLQuery query("INSERT INTO `anope_ns_alias` (nick, last_quit, last_realname, last_usermask, last_realhost, time_registered, last_seen, flags, display) VALUES(@nick, @last_quit, @last_realname, @last_usermask, @last_realhost, @time_registered, @last_seen, @flags, @display) ON DUPLICATE KEY UPDATE last_quit=VALUES(last_quit), last_realname=VALUES(last_realname), last_usermask=VALUES(last_usermask), last_realhost=VALUES(last_realhost), time_registered=VALUES(time_registered), last_seen=VALUES(last_seen), flags=VALUES(flags), display=VALUES(display)"); - query.setValue("nick", na->nick); - query.setValue("last_quit", na->last_quit); - query.setValue("last_realname", na->last_realname); - query.setValue("last_usermask", na->last_usermask); - query.setValue("last_realhost", na->last_realhost); - query.setValue("time_registered", na->time_registered); - query.setValue("last_seen", na->last_seen); - query.setValue("flags", ToString(na->ToString())); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - - void InsertCore(NickCore *nc) - { - SQLQuery query("INSERT INTO `anope_ns_core` (display, pass, email, greet, flags, language, memomax) VALUES(@display, @pass, @email, @greet, @flags, @language, @memomax) ON DUPLICATE KEY UPDATE pass=VALUES(pass), email=VALUES(email), greet=VALUES(greet), flags=VALUES(flags), language=VALUES(language), memomax=VALUES(memomax)"); - query.setValue("display", nc->display); - query.setValue("pass", nc->pass); - query.setValue("email", nc->email); - query.setValue("greet", nc->greet); - query.setValue("flags", ToString(nc->ToString())); - query.setValue("language", nc->language); - query.setValue("memomax", nc->memos.memomax); - this->RunQuery(query); - } - - void OnNickRegister(NickAlias *na) - { - this->InsertCore(na->nc); - this->InsertAlias(na); - } - - void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay) - { - SQLQuery query("UPDATE `anope_ns_core` SET `display` = @newdisplay WHERE `display` = @olddisplay"); - query.setValue("newdisplay", newdisplay); - query.setValue("olddisplay", nc->display); - this->RunQuery(query); - } - - void OnNickSuspend(NickAlias *na) - { - SQLQuery query("UPDATE `anope_ns_core` SET `flags` = @flags WHERE `display` = @display"); - query.setValue("flags", ToString(na->nc->ToString())); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - - void OnDelNick(NickAlias *na) - { - SQLQuery query("DELETE FROM `anope_ns_alias` WHERE `nick` = @nick"); - query.setValue("nick", na->nick); - this->RunQuery(query); - } - - void OnAccessAdd(ChannelInfo *ci, User *, ChanAccess *access) - { - SQLQuery query("INSERT INTO `anope_cs_access` (provider, data, mask, channel, last_seen, creator) VALUES (@provider, @data, @mask, @channel, @last_seen, @creator) ON DUPLICATE KEY UPDATE level=VALUES(level), display=VALUES(display), channel=VALUES(channel), last_seen=VALUES(last_seen), creator=VALUES(creator)"); - query.setValue("provider", access->provider->name); - query.setValue("data", access->Serialize()); - query.setValue("mask", access->mask); - query.setValue("channel", ci->name); - query.setValue("last_seen", access->last_seen); - query.setValue("creator", access->creator); - this->RunQuery(query); - } - - void OnAccessDel(ChannelInfo *ci, User *u, ChanAccess *access) - { - SQLQuery query("DELETE FROM `anope_cs_access` WHERE `mask` = @mask AND `channel` = @channel"); - query.setValue("mask", access->mask); - query.setValue("channel", ci->name); - this->RunQuery(query); - } - - void OnAccessClear(ChannelInfo *ci, User *u) - { - SQLQuery query("DELETE FROM `anope_cs_access` WHERE `channel` = @channel"); - query.setValue("channel", ci->name); - this->RunQuery(query); - } - - void OnLevelChange(User *u, ChannelInfo *ci, const Anope::string &priv, int16 what) - { - SQLQuery query("UPDATE `anope_cs_levels` SET `level` = @level WHERE `channel` = @channel AND `name` = @name ON DUPLICATE KEY UPDATE level=VALUES(level), name=VALUES(name)"); - query.setValue("channel", ci->name); - if (priv == "ALL") - { - const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges(); - for (unsigned i = 0; i < privs.size(); ++i) - { - const Privilege &p = privs[i]; - query.setValue("level", ci->GetLevel(p.name)); - query.setValue("name", p.name); - this->RunQuery(query); - } - } - else - { - query.setValue("level", what); - query.setValue("name", name); - this->RunQuery(query); - } - } - - void OnChanForbidden(ChannelInfo *ci) - { - SQLQuery query("INSERT INTO `anope_cs_info` (name, time_registered, last_used, flags) VALUES (@name, @time_registered, @last_used, @flags)"); - query.setValue("name", ci->name); - query.setValue("time_registered", ci->time_registered); - query.setValue("last_used", ci->last_used); - query.setValue("flags", ToString(ci->ToString())); - this->RunQuery(query); - } - - void OnDelChan(ChannelInfo *ci) - { - SQLQuery query("DELETE FROM `anope_cs_info` WHERE `name` = @name"); - query.setValue("name", ci->name); - this->RunQuery(query); - } - - void OnChanRegistered(ChannelInfo *ci) - { - SQLQuery query("INSERT INTO `anope_cs_info` (name, founder, successor, descr, time_registered, last_used, last_topic, last_topic_setter, last_topic_time, flags, bantype, memomax, botnick, botflags, capsmin, capspercent, floodlines, floodsecs, repeattimes) VALUES(@name, @founder, @successor, @descr, @time_registered, @last_used, @last_topic_text, @last_topic_setter, @last_topic_time, @flags, @bantype, @memomax, @botnick, @botflags, @capsmin, @capspercent, @floodlines, @floodsecs, @repeattimes) ON DUPLICATE KEY UPDATE founder=VALUES(founder), successor=VALUES(successor), descr=VALUES(descr), time_registered=VALUES(time_registered), last_used=VALUES(last_used), last_topic=VALUES(last_topic), last_topic_setter=VALUES(last_topic_setter), last_topic_time=VALUES(last_topic_time), flags=VALUES(flags), bantype=VALUES(bantype), memomax=VALUES(memomax), botnick=VALUES(botnick), botflags=VALUES(botflags), capsmin=VALUES(capsmin), capspercent=VALUES(capspercent), floodlines=VALUES(floodlines), floodsecs=VALUES(floodsecs), repeattimes=VALUES(repeattimes)"); - query.setValue("name", ci->name); - query.setValue("founder", ci->GetFounder() ? ci->GetFounder()->display : ""); - query.setValue("successor", ci->successor ? ci->successor->display : ""); - query.setValue("descr", ci->desc); - query.setValue("time_registered", ci->time_registered); - query.setValue("last_used", ci->last_used); - query.setValue("last_topic_text", ci->last_topic); - query.setValue("last_topic_setter", ci->last_topic_setter); - query.setValue("last_topic_time", ci->last_topic_time); - query.setValue("flags", ToString(ci->ToString())); - query.setValue("bantype", ci->bantype); - query.setValue("memomax", ci->memos.memomax); - query.setValue("botnick", ci->bi ? ci->bi->nick : ""); - query.setValue("botflags", ToString(ci->botflags.ToString())); - query.setValue("capsmin", ci->capsmin); - query.setValue("capspercent", ci->capspercent); - query.setValue("floodlines", ci->floodlines); - query.setValue("floodsecs", ci->floodsecs); - query.setValue("repeattimes", ci->repeattimes); - this->RunQuery(query); - - 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) - { - query = "INSERT INTO `anope_cs_mlock` (channel, mode, status, setter, created, param) VALUES(@channel, @mode, @status, @setter, @created, @param) ON DUPLICATE KEY UPDATE channel=VALUES(channel), mode=VALUES(mode), status=VALUES(status), setter=VALUES(setter), created=VALUES(created), param=VALUES(param)"; - query.setValue("channel", ci->name); - query.setValue("mode", cm->NameAsString()); - query.setValue("status", ml.set ? 1 : 0); - query.setValue("setter", ml.setter); - query.setValue("created", ml.created); - query.setValue("param", ml.param); - this->RunQuery(query); - } - } - } - - void OnChanSuspend(ChannelInfo *ci) - { - SQLQuery query("UPDATE `anope_cs_info` SET `flags` = @flags WHERE `name` = @name"); - query.setValue("flags", ToString(ci->ToString())); - query.setValue("name", ci->name); - this->RunQuery(query); - } - - void OnAkickAdd(ChannelInfo *ci, AutoKick *ak) - { - SQLQuery query("INSERT INTO `anope_cs_akick` (channel, flags, mask, reason, creator, created, last_used) VALUES(@channel, @flags, @mask, @reason, @creator, @created, @last_used)"); - query.setValue("channel", ci->name); - query.setValue("flags", ak->HasFlag(AK_ISNICK) ? "ISNICK" : ""); - query.setValue("mask", ak->HasFlag(AK_ISNICK) ? ak->nc->display : ak->mask); - query.setValue("reason", ak->reason); - query.setValue("creator", ak->creator); - query.setValue("created", ak->addtime); - query.setValue("last_used", ak->last_used); - this->RunQuery(query); - } - - void OnAkickDel(ChannelInfo *ci, AutoKick *ak) - { - SQLQuery query("DELETE FROM `anope_cs_akick` WHERE `channel`= @mask AND `mask` = @mask"); - query.setValue("channel", ci->name); - query.setValue("mask", ak->HasFlag(AK_ISNICK) ? ak->nc->display : ak->mask); - this->RunQuery(query); - } - - EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) - { - ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); - if (cm != NULL) - { - SQLQuery query("INSERT INTO `anope_cs_mlock` (channel, mode, status, setter, created, param) VALUES(@channel, @mode, @status, @setter, @created, @param) ON DUPLICATE KEY UPDATE channel=VALUES(channel), mode=VALUES(mode), status=VALUES(status), setter=VALUES(setter), created=VALUES(created), param=VALUES(param)"); - query.setValue("channel", ci->name); - query.setValue("mode", cm->NameAsString()); - query.setValue("status", lock->set ? 1 : 0); - query.setValue("setter", lock->setter); - query.setValue("created", lock->created); - query.setValue("param", lock->param); - this->RunQuery(query); - } - return EVENT_CONTINUE; - } - - EventReturn OnUnMLock(ChannelInfo *ci, ChannelMode *mode, const Anope::string ¶m) - { - ChannelMode *cm = ModeManager::FindChannelModeByName(mode->Name); - if (cm != NULL) - { - SQLQuery query("DELETE FROM `anope_cs_mlock` WHERE `channel` = @channel AND `mode` = @mode AND `param` = @param"); - query.setValue("channel", ci->name); - query.setValue("mode", mode->NameAsString()); - query.setValue("param", param); - this->RunQuery(query); - } - return EVENT_CONTINUE; - } - - void OnBotCreate(BotInfo *bi) - { - SQLQuery query("INSERT INTO `anope_bs_core` (nick, user, host, rname, flags, created, chancount) VALUES(@nick, @user, @host, @rname, @flags, @created, @chancount) ON DUPLICATE KEY UPDATE nick=VALUES(nick), user=VALUES(user), host=VALUES(host), rname=VALUES(rname), flags=VALUES(flags), created=VALUES(created), chancount=VALUES(chancount)"); - query.setValue("nick", bi->nick); - query.setValue("user", bi->GetIdent()); - query.setValue("host", bi->host); - query.setValue("rname", bi->realname); - query.setValue("flags", ToString(bi->ToString())); - query.setValue("created", bi->created); - query.setValue("chancount", bi->chancount); - this->RunQuery(query); - } - - void OnBotChange(BotInfo *bi) - { - OnBotCreate(bi); - } - - void OnBotDelete(BotInfo *bi) - { - SQLQuery query("UPDATE `anope_cs_info` SET `botnick` = '' WHERE `botnick` = @botnick"); - query.setValue("botnick", bi->nick); - this->RunQuery(query); - } - - EventReturn OnBotAssign(User *sender, ChannelInfo *ci, BotInfo *bi) - { - SQLQuery query("UPDATE `anope_cs_info` SET `botnick` = @botnick WHERE `name` = @channel"); - query.setValue("botnick", bi->nick); - query.setValue("channel", ci->name); - this->RunQuery(query); - return EVENT_CONTINUE; - } - - EventReturn OnBotUnAssign(User *sender, ChannelInfo *ci) - { - SQLQuery query("UPDATE `anope_cs_info` SET `botnick` = '' WHERE `name` = @channel"); - query.setValue("channel", ci->name); - this->RunQuery(query); - return EVENT_CONTINUE; - } - - void OnBadWordAdd(ChannelInfo *ci, BadWord *bw) - { - SQLQuery query("INSERT INTO `anope_bs_badwords` (channel, word, type) VALUES(@channel, @word, @type) ON DUPLICATE KEY UPDATE channel=VALUES(channel), word=VALUES(word), type=VALUES(type)"); - query.setValue("channel", ci->name); - query.setValue("word", bw->word); - switch (bw->type) - { - case BW_SINGLE: - query.setValue("type", "SINGLE"); - break; - case BW_START: - query.setValue("type", "START"); - break; - case BW_END: - query.setValue("type", "END"); - break; - default: - query.setValue("type", "ANY"); - } - this->RunQuery(query); - } - - void OnBadWordDel(ChannelInfo *ci, BadWord *bw) - { - SQLQuery query("DELETE FROM `anope_bs_badwords` WHERE `channel` = @channel AND `word` = @word AND `type` = @type"); - query.setValue("channel", ci->name); - query.setValue("word", bw->word); - switch (bw->type) - { - case BW_SINGLE: - query.setValue("type", "SINGLE"); - break; - case BW_START: - query.setValue("type", "START"); - break; - case BW_END: - query.setValue("type", "END"); - break; - default: - query.setValue("type", "ANY"); - } - this->RunQuery(query); - } - - void OnMemoSend(const Anope::string &source, const Anope::string &target, MemoInfo *mi, Memo *m) - { - const Anope::string &mtype = (!target.empty() && target[0] == '#' ? "CHAN" : "NICK"); - SQLQuery query("INSERT INTO `anope_ms_info` (receiver, flags, time, sender, text, serv) VALUES(@receiver, @flags, @time, @sender, @text, @serv)"); - query.setValue("receiver", target); - query.setValue("flags", ToString(m->ToString())); - query.setValue("time", m->time); - query.setValue("sender", source); - query.setValue("text", m->text); - query.setValue("serv", mtype); - this->RunQuery(query); - } - - void OnMemoDel(const NickCore *nc, MemoInfo *mi, Memo *m) - { - SQLQuery query; - - if (m) - { - query = "DELETE FROM `anope_ms_info` WHERE `receiver` = @receiver AND `time` = @time"; - query.setValue("receiver", nc->display); - query.setValue("time", m->time); - } - else - { - query = "DELETE FROM `anope_ms_info` WHERE `receiver` = @receiver"; - query.setValue("receiver", nc->display); - } - - this->RunQuery(query); - } - - void OnMemoDel(ChannelInfo *ci, MemoInfo *mi, Memo *m) - { - SQLQuery query; - - if (m) - { - query = "DELETE FROM `anope_ms_info` WHERE `receiver` = @receiver AND `time` = @time"; - query.setValue("receiver", ci->name); - query.setValue("time", m->time); - } - else - { - query = "DELETE FROM `anope_ms_info` WHERE `receiver` = @receiver"; - query.setValue("receiver", ci->name); - } - - this->RunQuery(query); - } - - EventReturn OnExceptionAdd(Exception *ex) - { - SQLQuery query("INSERT INTO `anope_os_exceptions` (mask, slimit, who, reason, time, expires) VALUES(@mask, @slimit, @who, @reason, @time, @expires)"); - query.setValue("mask", ex->mask); - query.setValue("slimit", ex->limit); - query.setValue("who", ex->who); - query.setValue("reason", ex->reason); - query.setValue("time", ex->time); - query.setValue("expires", ex->expires); - return EVENT_CONTINUE; - } - - void OnExceptionDel(User *, Exception *ex) - { - SQLQuery query("DELETE FROM `anope_os_exceptions` WHERE `mask` = @mask"); - query.setValue("mask", ex->mask); - this->RunQuery(query); - } - - EventReturn OnAddXLine(XLine *x, XLineManager *xlm) - { - SQLQuery query("INSERT INTO `anope_os_xlines` (type, mask, xby, reason, seton, expire) VALUES(@type, @mask, @xby, @reason, @seton, @expire)"); - query.setValue("type", Anope::string(xlm->Type())); - query.setValue("mask", x->Mask); - query.setValue("xby", x->By); - query.setValue("reason", x->Reason); - query.setValue("seton", x->Created); - query.setValue("expire", x->Expires); - this->RunQuery(query); - return EVENT_CONTINUE; - } - - void OnDelXLine(User *, XLine *x, XLineManager *xlm) - { - SQLQuery query; - - if (x) - { - query = "DELETE FROM `anope_os_xlines` WHERE `mask` = @mask AND `type` = @type"; - query.setValue("mask", x->Mask); - query.setValue("type", Anope::string(xlm->Type())); - } - else - { - query = "DELETE FROM `anope_os_xlines` WHERE `type` = @type"; - query.setValue("type", Anope::string(xlm->Type())); - } - - this->RunQuery(query); - } - - void OnDeleteVhost(NickAlias *na) - { - SQLQuery query("DELETE FROM `anope_hs_core` WHERE `nick` = @nick"); - query.setValue("nick", na->nick); - this->RunQuery(query); - } - - void OnSetVhost(NickAlias *na) - { - SQLQuery query("INSERT INTO `anope_hs_core` (nick, vident, vhost, creator, time) VALUES(@nick, @vident, @vhost, @creator, @time)"); - query.setValue("nick", na->nick); - query.setValue("vident", na->hostinfo.GetIdent()); - query.setValue("vhost", na->hostinfo.GetHost()); - query.setValue("creator", na->hostinfo.GetCreator()); - query.setValue("time", na->hostinfo.GetTime()); - this->RunQuery(query); - } -}; - -void MySQLInterface::OnResult(const SQLResult &r) -{ - Log(LOG_DEBUG) << "MySQL successfully executed query: " << r.finished_query; -} - -void MySQLInterface::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(); -} - - -static void Write(const Anope::string &data) -{ - SQLQuery query("INSERT INTO `anope_extra` (data) VALUES(@data)"); - query.setValue("data", data); - me->RunQuery(query); -} - -static void WriteNickMetadata(const Anope::string &key, const Anope::string &data) -{ - if (!CurNick) - throw CoreException("WriteNickMetadata without a nick to write"); - - SQLQuery query("INSERT INTO `anope_ns_alias_metadata` (nick, name, value) VALUES(@nick, @name, @value)"); - query.setValue("nick", CurNick->nick); - query.setValue("name", key); - query.setValue("value", data); - me->RunQuery(query); -} - -static void WriteCoreMetadata(const Anope::string &key, const Anope::string &data) -{ - if (!CurCore) - throw CoreException("WritCoreMetadata without a core to write"); - - SQLQuery query("INSERT INTO `anope_ns_core_metadata` (nick, name, value) VALUES(@nick, @name, @value)"); - query.setValue("nick", CurCore->display); - query.setValue("name", key); - query.setValue("value", data); - me->RunQuery(query); -} - -static void WriteChannelMetadata(const Anope::string &key, const Anope::string &data) -{ - if (!CurChannel) - throw CoreException("WriteChannelMetadata without a channel to write"); - - SQLQuery query("INSERT INTO `anope_cs_info_metadata` (channel, name, value) VALUES(@channel, @name, @value)"); - query.setValue("channel", CurChannel->name); - query.setValue("name", key); - query.setValue("value", data); - me->RunQuery(query); -} - -static void WriteBotMetadata(const Anope::string &key, const Anope::string &data) -{ - if (!CurBot) - throw CoreException("WriteBotMetadata without a bot to write"); - - SQLQuery query("INSERT INTO `anope_bs_info_metadata` (botname, name, value) VALUES(@botname, @name, @value)"); - query.setValue("botname", CurBot->nick); - query.setValue("name", key); - query.setValue("value", data); - me->RunQuery(query); -} - -static void SaveDatabases() -{ - SQLQuery query; - - query = "TRUNCATE TABLE `anope_ns_core`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_ms_info`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_ns_alias`"; - me->RunQuery(query); - - for (nickcore_map::const_iterator nit = NickCoreList.begin(), nit_end = NickCoreList.end(); nit != nit_end; ++nit) - { - NickCore *nc = nit->second; - - me->InsertCore(nc); - - for (std::list<NickAlias *>::iterator it = nc->aliases.begin(), it_end = nc->aliases.end(); it != it_end; ++it) - { - me->InsertAlias(*it); - if ((*it)->hostinfo.HasVhost()) - me->OnSetVhost(*it); - } - - for (std::vector<Anope::string>::iterator it = nc->access.begin(), it_end = nc->access.end(); it != it_end; ++it) - { - query = "INSERT INTO `anope_ns_access` (display, access) VALUES(@display, @access)"; - query.setValue("display", nc->display); - query.setValue("access", *it); - me->RunQuery(query); - } - - for (unsigned j = 0, end = nc->memos.memos.size(); j < end; ++j) - { - Memo *m = nc->memos.memos[j]; - - me->OnMemoSend(m->sender, nc->display, &nc->memos, m); - } - } - - query = "TRUNCATE TABLE `anope_bs_core`"; - me->RunQuery(query); - - for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it) - me->OnBotCreate(it->second); - - query = "TRUNCATE TABLE `anope_cs_info`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_bs_badwords`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_cs_access`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_cs_akick`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_cs_levels`"; - me->RunQuery(query); - - for (registered_channel_map::const_iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end; ++it) - { - ChannelInfo *ci = it->second; - - me->OnChanRegistered(ci); - - for (unsigned j = 0, end = ci->GetBadWordCount(); j < end; ++j) - { - BadWord *bw = ci->GetBadWord(j); - - me->OnBadWordAdd(ci, bw); - } - - for (unsigned j = 0, end = ci->GetAccessCount(); j < end; ++j) - { - ChanAccess *access = ci->GetAccess(j); - - me->OnAccessAdd(ci, NULL, access); - } - - for (unsigned j = 0, end = ci->GetAkickCount(); j < end; ++j) - { - AutoKick *ak = ci->GetAkick(j); - - me->OnAkickAdd(ci, ak); - } - - me->OnLevelChange(NULL, ci, "ALL", -1); - - for (unsigned j = 0, end = ci->memos.memos.size(); j < end; ++j) - { - Memo *m = ci->memos.memos[j]; - - me->OnMemoSend(m->sender, ci->name, &ci->memos, m); - } - } - - for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it) - for (unsigned i = 0, end = (*it)->GetCount(); i < end; ++i) - me->OnAddXLine((*it)->GetEntry(i), *it); - - if (me->SessionInterface) - for (SessionService::ExceptionVector::iterator it = me->SessionInterface->GetExceptions().begin(); it != me->SessionInterface->GetExceptions().end(); ++it) - me->OnExceptionAdd(*it); -} - -void CommandSQLSync::Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) -{ - SaveDatabases(); - source.Reply(_("Updating MySQL.")); - return; -} - -MODULE_INIT(DBMySQL) - diff --git a/modules/database/db_old.cpp b/modules/database/db_old.cpp new file mode 100644 index 000000000..55956da78 --- /dev/null +++ b/modules/database/db_old.cpp @@ -0,0 +1,1021 @@ +/* + * (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" + +#define READ(x) \ +if (true) \ +{ \ + if ((x) < 0) \ + printf("Error, the database is broken, line %d, trying to continue... no guarantee.\n", __LINE__); \ +} \ +else \ + static_cast<void>(0) + +#define getc_db(f) (fgetc((f)->fp)) +#define read_db(f, buf, len) (fread((buf), 1, (len), (f)->fp)) +#define read_buffer(buf, f) (read_db((f), (buf), sizeof(buf)) == sizeof(buf)) + +#define OLD_BI_PRIVATE 0x0001 + +#define OLD_NI_KILLPROTECT 0x00000001 /* Kill others who take this nick */ +#define OLD_NI_SECURE 0x00000002 /* Don't recognize unless IDENTIFY'd */ +#define OLD_NI_MSG 0x00000004 /* Use PRIVMSGs instead of NOTICEs */ +#define OLD_NI_MEMO_HARDMAX 0x00000008 /* Don't allow user to change memo limit */ +#define OLD_NI_MEMO_SIGNON 0x00000010 /* Notify of memos at signon and un-away */ +#define OLD_NI_MEMO_RECEIVE 0x00000020 /* Notify of new memos when sent */ +#define OLD_NI_PRIVATE 0x00000040 /* Don't show in LIST to non-servadmins */ +#define OLD_NI_HIDE_EMAIL 0x00000080 /* Don't show E-mail in INFO */ +#define OLD_NI_HIDE_MASK 0x00000100 /* Don't show last seen address in INFO */ +#define OLD_NI_HIDE_QUIT 0x00000200 /* Don't show last quit message in INFO */ +#define OLD_NI_KILL_QUICK 0x00000400 /* Kill in 20 seconds instead of 60 */ +#define OLD_NI_KILL_IMMED 0x00000800 /* Kill immediately instead of in 60 sec */ +#define OLD_NI_MEMO_MAIL 0x00010000 /* User gets email on memo */ +#define OLD_NI_HIDE_STATUS 0x00020000 /* Don't show services access status */ +#define OLD_NI_SUSPENDED 0x00040000 /* Nickname is suspended */ +#define OLD_NI_AUTOOP 0x00080000 /* Autoop nickname in channels */ +#define OLD_NI_NOEXPIRE 0x00100000 /* nicks in this group won't expire */ + +#define OLD_CI_KEEPTOPIC 0x00000001 +#define OLD_CI_SECUREOPS 0x00000002 +#define OLD_CI_PRIVATE 0x00000004 +#define OLD_CI_TOPICLOCK 0x00000008 +#define OLD_CI_RESTRICTED 0x00000010 +#define OLD_CI_PEACE 0x00000020 +#define OLD_CI_SECURE 0x00000040 +#define OLD_CI_FORBIDDEN 0x00000080 +#define OLD_CI_ENCRYPTEDPW 0x00000100 +#define OLD_CI_NO_EXPIRE 0x00000200 +#define OLD_CI_MEMO_HARDMAX 0x00000400 +#define OLD_CI_OPNOTICE 0x00000800 +#define OLD_CI_SECUREFOUNDER 0x00001000 +#define OLD_CI_SIGNKICK 0x00002000 +#define OLD_CI_SIGNKICK_LEVEL 0x00004000 +#define OLD_CI_XOP 0x00008000 +#define OLD_CI_SUSPENDED 0x00010000 + +/* BotServ SET flags */ +#define OLD_BS_DONTKICKOPS 0x00000001 +#define OLD_BS_DONTKICKVOICES 0x00000002 +#define OLD_BS_FANTASY 0x00000004 +#define OLD_BS_SYMBIOSIS 0x00000008 +#define OLD_BS_GREET 0x00000010 +#define OLD_BS_NOBOT 0x00000020 + +/* BotServ Kickers flags */ +#define OLD_BS_KICK_BOLDS 0x80000000 +#define OLD_BS_KICK_COLORS 0x40000000 +#define OLD_BS_KICK_REVERSES 0x20000000 +#define OLD_BS_KICK_UNDERLINES 0x10000000 +#define OLD_BS_KICK_BADWORDS 0x08000000 +#define OLD_BS_KICK_CAPS 0x04000000 +#define OLD_BS_KICK_FLOOD 0x02000000 +#define OLD_BS_KICK_REPEAT 0x01000000 + +static Anope::string hashm; + +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 */ +}; + +static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +static void my_b64_encode(const Anope::string &src, Anope::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; + } +} + +static Anope::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 Anope::string GetLevelName(int level) +{ + switch (level) + { + case 0: + return "INVITE"; + case 1: + return "AKICK"; + case 2: + return "SET"; + case 3: + return "UNBAN"; + case 4: + return "AUTOOP"; + case 5: + return "AUTODEOP"; + case 6: + return "AUTOVOICE"; + case 7: + return "OPDEOP"; + case 8: + return "LIST"; + case 9: + return "CLEAR"; + case 10: + return "NOJOIN"; + case 11: + return "CHANGE"; + case 12: + return "MEMO"; + case 13: + return "ASSIGN"; + case 14: + return "BADWORDS"; + case 15: + return "NOKICK"; + case 16: + return "FANTASIA"; + case 17: + return "SAY"; + case 18: + return "GREET"; + case 19: + return "VOICEME"; + case 20: + return "VOICE"; + case 21: + return "GETKEY"; + case 22: + return "AUTOHALFOP"; + case 23: + return "AUTOPROTECT"; + case 24: + return "OPDEOPME"; + case 25: + return "HALFOPME"; + case 26: + return "HALFOP"; + case 27: + return "PROTECTME"; + case 28: + return "PROTECT"; + case 29: + return "KICKME"; + case 30: + return "KICK"; + case 31: + return "SIGNKICK"; + case 32: + return "BANME"; + case 33: + return "BAN"; + case 34: + return "TOPIC"; + case 35: + return "INFO"; + default: + return "INVALID"; + } +} + +static 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; +} + +struct dbFILE +{ + int mode; /* 'r' for reading, 'w' for writing */ + FILE *fp; /* The normal file descriptor */ + char filename[1024]; /* Name of the database file */ +}; + +static dbFILE *open_db_read(const char *service, const char *filename, int version) +{ + dbFILE *f; + FILE *fp; + int myversion; + + f = new dbFILE; + strscpy(f->filename, filename, sizeof(f->filename)); + f->mode = 'r'; + fp = fopen(f->filename, "rb"); + if (!fp) + { + Log() << "Can't read " << service << " database " << f->filename; + delete f; + return NULL; + } + f->fp = fp; + myversion = fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp); + if (feof(fp)) + { + Log() << "Error reading version number on " << f->filename << ": End of file detected."; + delete f; + return NULL; + } + else if (myversion < version) + { + Log() << "Unsuported database version (" << myversion << ") on " << f->filename << "."; + delete f; + return NULL; + } + return f; +} + +void close_db(dbFILE *f) +{ + fclose(f->fp); + delete f; +} + +static int read_int16(int16 *ret, dbFILE *f) +{ + int c1, c2; + + *ret = 0; + + c1 = fgetc(f->fp); + c2 = fgetc(f->fp); + if (c1 == EOF || c2 == EOF) + return -1; + *ret = c1 << 8 | c2; + return 0; +} + +static int read_uint16(uint16 *ret, dbFILE *f) +{ + int c1, c2; + + *ret = 0; + + c1 = fgetc(f->fp); + c2 = fgetc(f->fp); + if (c1 == EOF || c2 == EOF) + return -1; + *ret = c1 << 8 | c2; + return 0; +} + +static int read_string(Anope::string &str, dbFILE *f) +{ + str.clear(); + uint16 len; + + if (read_uint16(&len, f) < 0) + return -1; + if (len == 0) + return 0; + char *s = new char[len]; + if (len != fread(s, 1, len, f->fp)) + { + delete [] s; + return -1; + } + str = s; + delete [] s; + return 0; +} + +static int read_uint32(uint32 *ret, dbFILE *f) +{ + int c1, c2, c3, c4; + + *ret = 0; + + 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_int32(int32 *ret, dbFILE *f) +{ + int c1, c2, c3, c4; + + *ret = 0; + + 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; +} + +static void LoadNicks() +{ + dbFILE *f = open_db_read("NickServ", "nick.db", 14); + if (f == NULL) + return; + for (int i = 0; i < 1024; ++i) + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string buffer; + + READ(read_string(buffer, f)); + NickCore *nc = new NickCore(buffer); + + char pwbuf[32]; + READ(read_buffer(pwbuf, f)); + if (hashm == "plain") + my_b64_encode(pwbuf, nc->pass); + else + nc->pass = Hex(pwbuf); + nc->pass = hashm + ":" + nc->pass; + + READ(read_string(buffer, f)); + nc->email = buffer; + + READ(read_string(buffer, f)); + nc->greet = buffer; + + uint32 uint; + READ(read_uint32(&uint, f)); + //nc->icq = uint; + + READ(read_string(buffer, f)); + //nc->url = buffer; + + READ(read_uint32(&uint, f)); + if (uint & OLD_NI_KILLPROTECT) + nc->SetFlag(NI_KILLPROTECT); + if (uint & OLD_NI_SECURE) + nc->SetFlag(NI_SECURE); + if (uint & OLD_NI_MSG) + nc->SetFlag(NI_MSG); + if (uint & OLD_NI_MEMO_HARDMAX) + nc->SetFlag(NI_MEMO_HARDMAX); + if (uint & OLD_NI_MEMO_SIGNON) + nc->SetFlag(NI_MEMO_SIGNON); + if (uint & OLD_NI_MEMO_RECEIVE) + nc->SetFlag(NI_MEMO_RECEIVE); + if (uint & OLD_NI_PRIVATE) + nc->SetFlag(NI_PRIVATE); + if (uint & OLD_NI_HIDE_EMAIL) + nc->SetFlag(NI_HIDE_EMAIL); + if (uint & OLD_NI_HIDE_MASK) + nc->SetFlag(NI_HIDE_MASK); + if (uint & OLD_NI_HIDE_QUIT) + nc->SetFlag(NI_HIDE_QUIT); + if (uint & OLD_NI_KILL_QUICK) + nc->SetFlag(NI_KILL_QUICK); + if (uint & OLD_NI_KILL_IMMED) + nc->SetFlag(NI_KILL_IMMED); + if (uint & OLD_NI_MEMO_MAIL) + nc->SetFlag(NI_MEMO_MAIL); + if (uint & OLD_NI_HIDE_STATUS) + nc->SetFlag(NI_HIDE_STATUS); + if (uint & OLD_NI_SUSPENDED) + nc->SetFlag(NI_SUSPENDED); + if (!(uint & OLD_NI_AUTOOP)) + nc->SetFlag(NI_AUTOOP); + if (uint & OLD_NI_NOEXPIRE) + nc->Extend("noexpire", NULL); + + uint16 u16; + READ(read_uint16(&u16, f)); + switch (u16) + { + case LANG_ES: + nc->language = "es_ES"; + break; + case LANG_PT: + nc->language = "pt_PT"; + break; + case LANG_FR: + nc->language = "fr_FR"; + break; + case LANG_TR: + nc->language = "tr_TR"; + break; + case LANG_IT: + nc->language = "it_IT"; + break; + case LANG_DE: + nc->language = "de_DE"; + break; + case LANG_CAT: + nc->language = "ca_ES"; // yes, iso639 defines catalan as CA + break; + case LANG_GR: + nc->language = "el_GR"; + break; + case LANG_NL: + nc->language = "nl_NL"; + break; + case LANG_RU: + nc->language = "ru_RU"; + break; + case LANG_HUN: + nc->language = "hu_HU"; + break; + case LANG_PL: + nc->language = "pl_PL"; + break; + case LANG_EN_US: + case LANG_JA_JIS: + case LANG_JA_EUC: + case LANG_JA_SJIS: // these seem to be unused + default: + nc->language = "en_US"; + } + + READ(read_uint16(&u16, f)); + for (uint16 j = 0; j < u16; ++j) + { + READ(read_string(buffer, f)); + nc->access.push_back(buffer); + } + + int16 i16; + READ(read_int16(&i16, f)); + READ(read_int16(&nc->memos.memomax, f)); + for (int16 j = 0; j < i16; ++j) + { + Memo *m = new Memo; + READ(read_uint32(&uint, f)); + uint16 flags; + READ(read_uint16(&flags, f)); + int32 tmp32; + READ(read_int32(&tmp32, f)); + m->time = tmp32; + char sbuf[32]; + READ(read_buffer(sbuf, f)); + m->sender = sbuf; + READ(read_string(m->text, f)); + nc->memos.memos.push_back(m); + } + READ(read_uint16(&u16, f)); + READ(read_int16(&i16, f)); + + Log(LOG_DEBUG) << "Loaded NickCore " << nc->display; + } + + for (int i = 0; i < 1024; ++i) + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string nick, last_usermask, last_realname, last_quit; + time_t time_registered, last_seen; + + READ(read_string(nick, f)); + READ(read_string(last_usermask, f)); + READ(read_string(last_realname, f)); + READ(read_string(last_quit, f)); + + int32 tmp32; + READ(read_int32(&tmp32, f)); + time_registered = tmp32; + READ(read_int32(&tmp32, f)); + last_seen = tmp32; + + uint16 tmpu16; + READ(read_uint16(&tmpu16, f)); + Anope::string core; + READ(read_string(core, f)); + NickCore *nc = findcore(core); + if (nc == NULL) + { + Log() << "Skipping coreless nick " << nick << " with core " << core; + continue; + } + NickAlias *na = new NickAlias(nick, nc); + na->last_usermask = last_usermask; + na->last_realname = last_realname; + na->last_quit = last_quit; + na->time_registered = time_registered; + na->last_seen = last_seen; + + if (na->nc->HasExt("noexpire")) + na->SetFlag(NS_NO_EXPIRE); + + Log(LOG_DEBUG) << "Loaded NickAlias " << na->nick; + } + + close_db(f); /* End of section Ia */ +} + +static void LoadVHosts() +{ + dbFILE *f = open_db_read("HostServ", "hosts.db", 3); + if (f == NULL) + return; + + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string nick, ident, host, creator; + int32 vtime; + + READ(read_string(nick, f)); + READ(read_string(ident, f)); + READ(read_string(host, f)); + READ(read_string(creator, f)); + READ(read_int32(&vtime, f)); + + NickAlias *na = findnick(nick); + if (na == NULL) + { + Log() << "Removing vhost for nonexistant nick " << nick; + continue; + } + + na->hostinfo.SetVhost(ident, host, creator, vtime); + + Log() << "Loaded vhost for " << na->nick; + } + + close_db(f); +} + +static void LoadBots() +{ + dbFILE *f = open_db_read("Botserv", "bot.db", 10); + if (f == NULL) + return; + + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string nick, user, host, real; + int16 flags, chancount; + int32 created; + + READ(read_string(nick, f)); + READ(read_string(user, f)); + READ(read_string(host, f)); + READ(read_string(real, f)); + READ(read_int16(&flags, f)); + READ(read_int32(&created, f)); + READ(read_int16(&chancount, f)); + + BotInfo *bi = new BotInfo(nick, user, host, real); + bi->created = created; + bi->chancount = chancount; + + if (flags & OLD_BI_PRIVATE) + bi->SetFlag(BI_PRIVATE); + + Log(LOG_DEBUG) << "Loaded bot " << bi->nick; + } + + close_db(f); +} + +static void LoadChannels() +{ + dbFILE *f = open_db_read("ChanServ", "chan.db", 16); + if (f == NULL) + return; + + for (int i = 0; i < 256; ++i) + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string buffer; + char namebuf[64]; + READ(read_buffer(namebuf, f)); + ChannelInfo *ci = new ChannelInfo(namebuf); + + READ(read_string(buffer, f)); + ci->SetFounder(findcore(buffer)); + + READ(read_string(buffer, f)); + ci->successor = findcore(buffer); + + char pwbuf[32]; + READ(read_buffer(pwbuf, f)); + + READ(read_string(ci->desc, f)); + READ(read_string(buffer, f)); + READ(read_string(buffer, f)); + + int32 tmp32; + READ(read_int32(&tmp32, f)); + ci->time_registered = tmp32; + + READ(read_int32(&tmp32, f)); + ci->last_used = tmp32; + + READ(read_string(ci->last_topic, f)); + + READ(read_buffer(pwbuf, f)); + ci->last_topic_setter = pwbuf; + + READ(read_int32(&tmp32, f)); + ci->last_topic_time = tmp32; + + uint32 tmpu32; + READ(read_uint32(&tmpu32, f)); + // Temporary flags cleanup + tmpu32 &= ~0x80000000; + if (tmpu32 & OLD_CI_KEEPTOPIC) + ci->SetFlag(CI_KEEPTOPIC); + if (tmpu32 & OLD_CI_SECUREOPS) + ci->SetFlag(CI_SECUREOPS); + if (tmpu32 & OLD_CI_PRIVATE) + ci->SetFlag(CI_PRIVATE); + if (tmpu32 & OLD_CI_TOPICLOCK) + ci->SetFlag(CI_TOPICLOCK); + if (tmpu32 & OLD_CI_RESTRICTED) + ci->SetFlag(CI_RESTRICTED); + if (tmpu32 & OLD_CI_PEACE) + ci->SetFlag(CI_PEACE); + if (tmpu32 & OLD_CI_SECURE) + ci->SetFlag(CI_SECURE); + if (tmpu32 & OLD_CI_NO_EXPIRE) + ci->SetFlag(CI_NO_EXPIRE); + if (tmpu32 & OLD_CI_MEMO_HARDMAX) + ci->SetFlag(CI_MEMO_HARDMAX); + if (tmpu32 & OLD_CI_SECUREFOUNDER) + ci->SetFlag(CI_SECUREFOUNDER); + if (tmpu32 & OLD_CI_SIGNKICK) + ci->SetFlag(CI_SIGNKICK); + if (tmpu32 & OLD_CI_SIGNKICK_LEVEL) + ci->SetFlag(CI_SIGNKICK_LEVEL); + if (tmpu32 & OLD_CI_SUSPENDED) + ci->SetFlag(CI_SUSPENDED); + + READ(read_string(buffer, f)); + READ(read_string(buffer, f)); + + int16 tmp16; + READ(read_int16(&tmp16, f)); + ci->bantype = tmp16; + + READ(read_int16(&tmp16, f)); + if (tmp16 > 36) + tmp16 = 36; + for (int16 j = 0; j < tmp16; ++j) + { + int16 level; + READ(read_int16(&level, f)); + + ci->SetLevel(GetLevelName(j), level); + } + + uint16 tmpu16; + READ(read_uint16(&tmpu16, f)); + for (uint16 j = 0; j < tmpu16; ++j) + { + uint16 in_use; + READ(read_uint16(&in_use, f)); + if (in_use) + { + service_reference<AccessProvider> provider("access/access"); + if (!provider) + break; + + ChanAccess *access = provider->Create(); + access->ci = ci; + + int16 level; + READ(read_int16(&level, f)); + access->Unserialize(stringify(level)); + + Anope::string mask; + READ(read_string(mask, f)); + access->mask = mask; + + READ(read_int32(&tmp32, f)); + access->last_seen = tmp32; + access->creator = "Unknown"; + access->created = Anope::CurTime; + + ci->AddAccess(access); + } + } + + READ(read_uint16(&tmpu16, f)); + for (uint16 j = 0; j < tmpu16; ++j) + { + uint16 flags; + READ(read_uint16(&flags, f)); + if (flags & 0x0001) + { + Anope::string mask, reason, creator; + READ(read_string(mask, f)); + READ(read_string(reason, f)); + READ(read_string(creator, f)); + READ(read_int32(&tmp32, f)); + + ci->AddAkick(creator, mask, reason, tmp32); + } + } + + READ(read_uint32(&tmpu32, f)); // mlock on + READ(read_uint32(&tmpu32, f)); // mlock off + READ(read_uint32(&tmpu32, f)); // mlock limit + READ(read_string(buffer, f)); + READ(read_string(buffer, f)); + READ(read_string(buffer, f)); + + READ(read_int16(&tmp16, f)); + READ(read_int16(&ci->memos.memomax, f)); + for (int16 j = 0; j < tmp16; ++j) + { + READ(read_uint32(&tmpu32, f)); + READ(read_uint16(&tmpu16, f)); + Memo *m = new Memo; + READ(read_int32(&tmp32, f)); + m->time = tmp32; + char sbuf[32]; + READ(read_buffer(sbuf, f)); + m->sender = sbuf; + READ(read_string(m->text, f)); + ci->memos.memos.push_back(m); + } + + READ(read_string(buffer, f)); + + READ(read_string(buffer, f)); + ci->bi = findbot(buffer); + + READ(read_int32(&tmp32, f)); + if (tmp32 & OLD_BS_DONTKICKOPS) + ci->botflags.SetFlag(BS_DONTKICKOPS); + if (tmp32 & OLD_BS_DONTKICKVOICES) + ci->botflags.SetFlag(BS_DONTKICKVOICES); + if (tmp32 & OLD_BS_FANTASY) + ci->botflags.SetFlag(BS_FANTASY); + if (tmp32 & OLD_BS_GREET) + ci->botflags.SetFlag(BS_GREET); + if (tmp32 & OLD_BS_NOBOT) + ci->botflags.SetFlag(BS_NOBOT); + if (tmp32 & OLD_BS_KICK_BOLDS) + ci->botflags.SetFlag(BS_KICK_BOLDS); + if (tmp32 & OLD_BS_KICK_COLORS) + ci->botflags.SetFlag(BS_KICK_COLORS); + if (tmp32 & OLD_BS_KICK_REVERSES) + ci->botflags.SetFlag(BS_KICK_REVERSES); + if (tmp32 & OLD_BS_KICK_UNDERLINES) + ci->botflags.SetFlag(BS_KICK_UNDERLINES); + if (tmp32 & OLD_BS_KICK_BADWORDS) + ci->botflags.SetFlag(BS_KICK_BADWORDS); + if (tmp32 & OLD_BS_KICK_CAPS) + ci->botflags.SetFlag(BS_KICK_CAPS); + if (tmp32 & OLD_BS_KICK_FLOOD) + ci->botflags.SetFlag(BS_KICK_FLOOD); + if (tmp32 & OLD_BS_KICK_REPEAT) + ci->botflags.SetFlag(BS_KICK_REPEAT); + + READ(read_int16(&tmp16, f)); + for (int16 j = 0; j < tmp16; ++j) + { + int16 ttb; + READ(read_int16(&ttb, f)); + if (j < TTB_SIZE) + ci->ttb[j] = ttb; + } + + READ(read_int16(&tmp16, f)); + ci->capsmin = tmp16; + READ(read_int16(&tmp16, f)); + ci->capspercent = tmp16; + READ(read_int16(&tmp16, f)); + ci->floodlines = tmp16; + READ(read_int16(&tmp16, f)); + ci->floodsecs = tmp16; + READ(read_int16(&tmp16, f)); + ci->repeattimes = tmp16; + + READ(read_uint16(&tmpu16, f)); + for (uint16 j = 0; j < tmpu16; ++j) + { + uint16 in_use; + READ(read_uint16(&in_use, f)); + if (in_use) + { + READ(read_string(buffer, f)); + uint16 type; + READ(read_uint16(&type, f)); + + BadWordType bwtype = BW_ANY; + if (type == 1) + bwtype = BW_SINGLE; + else if (type == 2) + bwtype = BW_START; + else if (type == 3) + bwtype = BW_END; + + ci->AddBadWord(buffer, bwtype); + } + } + + Log(LOG_DEBUG) << "Loaded channel " << ci->name; + } + + close_db(f); +} + +static void LoadOper() +{ + dbFILE *f = open_db_read("OperServ", "oper.db", 13); + if (f == NULL) + return; + + XLineManager *akill, *sqline, *snline, *szline; + akill = sqline = snline = szline = NULL; + + for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it) + { + XLineManager *xl = *it; + if (xl->Type() == 'G') + akill = xl; + else if (xl->Type() == 'Q') + sqline = xl; + else if (xl->Type() == 'N') + snline = xl; + else if (xl->Type() == 'Z') + szline = xl; + } + + int32 tmp32; + READ(read_int32(&tmp32, f)); + READ(read_int32(&tmp32, f)); + + int16 capacity; + read_int16(&capacity, f); // AKill count + for (int16 i = 0; i < capacity; ++i) + { + Anope::string user, host, by, reason; + int32 seton, expires; + + READ(read_string(user, f)); + READ(read_string(host, f)); + READ(read_string(by, f)); + READ(read_string(reason, f)); + READ(read_int32(&seton, f)); + READ(read_int32(&expires, f)); + + if (!akill) + continue; + + XLine *x = akill->Add(user + "@" + host, by, expires, reason); + if (x) + x->Created = seton; + } + + read_int16(&capacity, f); // SNLines + for (int16 i = 0; i < capacity; ++i) + { + Anope::string mask, by, reason; + int32 seton, expires; + + READ(read_string(mask, f)); + READ(read_string(by, f)); + READ(read_string(reason, f)); + READ(read_int32(&seton, f)); + READ(read_int32(&expires, f)); + + if (!snline) + continue; + + XLine *x = snline->Add(mask, by, expires, reason); + if (x) + x->Created = seton; + } + + read_int16(&capacity, f); // SQLines + for (int16 i = 0; i < capacity; ++i) + { + Anope::string mask, by, reason; + int32 seton, expires; + + READ(read_string(mask, f)); + READ(read_string(by, f)); + READ(read_string(reason, f)); + READ(read_int32(&seton, f)); + READ(read_int32(&expires, f)); + + if (!sqline) + continue; + + XLine *x = sqline->Add(mask, by, expires, reason); + if (x) + x->Created = seton; + } + + read_int16(&capacity, f); // SZLines + for (int16 i = 0; i < capacity; ++i) + { + Anope::string mask, by, reason; + int32 seton, expires; + + READ(read_string(mask, f)); + READ(read_string(by, f)); + READ(read_string(reason, f)); + READ(read_int32(&seton, f)); + READ(read_int32(&expires, f)); + + if (!szline) + continue; + + XLine *x = szline->Add(mask, by, expires, reason); + if (x) + x->Created = seton; + } + + close_db(f); +} + +class DBOld : public Module +{ + public: + DBOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE) + { + this->SetAuthor("Anope"); + + Implementation i[] = { I_OnLoadDatabase }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + ConfigReader conf; + hashm = conf.ReadValue("db_old", "hash", "", 0); + + if (hashm != "md5" && hashm != "oldmd5" && hashm == "sha1" && hashm == "plain") + throw ModuleException("Invalid hash method"); + } + + EventReturn OnLoadDatabase() + { + LoadNicks(); + LoadVHosts(); + LoadBots(); + LoadChannels(); + LoadOper(); + + return EVENT_STOP; + } +}; + +MODULE_INIT(DBOld) + diff --git a/modules/database/db_plain.cpp b/modules/database/db_plain.cpp index bf0b05e3d..711434336 100644 --- a/modules/database/db_plain.cpp +++ b/modules/database/db_plain.cpp @@ -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> ¶ms); +static void LoadNickAlias(const std::vector<Anope::string> ¶ms); +static void LoadBotInfo(const std::vector<Anope::string> ¶ms); +static void LoadChanInfo(const std::vector<Anope::string> ¶ms); +static void LoadOperInfo(const std::vector<Anope::string> ¶ms); + +EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) +{ + 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> ¶ms) +{ + 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> ¶ms) +{ + 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> ¶ms) +{ + if (key.equals_ci("FLAGS")) + bi->FromVector(params); + + return EVENT_CONTINUE; +} + +EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> ¶ms) +{ + 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> ¶ms) { NickCore *nc = new NickCore(params[0]); @@ -278,7 +555,7 @@ static void LoadOperInfo(const std::vector<Anope::string> ¶ms) } } } - 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> ¶ms) 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> ¶ms) - { - 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> ¶ms) - { - 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> ¶ms) - { - 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> ¶ms) - { - if (key.equals_ci("FLAGS")) - bi->FromString(params); - - return EVENT_CONTINUE; - } - - EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - 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) diff --git a/modules/database/db_sql.cpp b/modules/database/db_sql.cpp new file mode 100644 index 000000000..43e7cfe6d --- /dev/null +++ b/modules/database/db_sql.cpp @@ -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) + diff --git a/modules/database/db_sql_live_read.cpp b/modules/database/db_sql_live_read.cpp new file mode 100644 index 000000000..1159e41fc --- /dev/null +++ b/modules/database/db_sql_live_read.cpp @@ -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> ¶ms) + { + 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) + diff --git a/modules/database/db_mysql_live.cpp b/modules/database/db_sql_live_write.cpp index d583c394c..769c53b66 100644 --- a/modules/database/db_mysql_live.cpp +++ b/modules/database/db_sql_live_write.cpp @@ -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) { diff --git a/modules/extra/m_dnsbl.cpp b/modules/extra/m_dnsbl.cpp index c8f18a34c..894eebb8a 100644 --- a/modules/extra/m_dnsbl.cpp +++ b/modules/extra/m_dnsbl.cpp @@ -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); diff --git a/modules/extra/m_ldap_authentication.cpp b/modules/extra/m_ldap_authentication.cpp index 8a4ef2702..148ee8250 100644 --- a/modules/extra/m_ldap_authentication.cpp +++ b/modules/extra/m_ldap_authentication.cpp @@ -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; diff --git a/modules/extra/m_mysql.cpp b/modules/extra/m_mysql.cpp index 05a85b93c..876d2ae4e 100644 --- a/modules/extra/m_mysql.cpp +++ b/modules/extra/m_mysql.cpp @@ -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; } diff --git a/modules/extra/m_sqlite.cpp b/modules/extra/m_sqlite.cpp new file mode 100644 index 000000000..adf244bbd --- /dev/null +++ b/modules/extra/m_sqlite.cpp @@ -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) + diff --git a/modules/extra/sql.h b/modules/extra/sql.h index 2487b2305..85b3c291a 100644 --- a/modules/extra/sql.h +++ b/modules/extra/sql.h @@ -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; }; diff --git a/modules/protocol/inspircd11.cpp b/modules/protocol/inspircd11.cpp index 6d72c5d61..062ad92f0 100644 --- a/modules/protocol/inspircd11.cpp +++ b/modules/protocol/inspircd11.cpp @@ -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)) diff --git a/modules/pseudoclients/memoserv.cpp b/modules/pseudoclients/memoserv.cpp index c1f99bc41..a713b7409 100644 --- a/modules/pseudoclients/memoserv.cpp +++ b/modules/pseudoclients/memoserv.cpp @@ -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; diff --git a/modules/pseudoclients/operserv.cpp b/modules/pseudoclients/operserv.cpp index c30809e49..6dfacd19f 100644 --- a/modules/pseudoclients/operserv.cpp +++ b/modules/pseudoclients/operserv.cpp @@ -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) diff --git a/src/access.cpp b/src/access.cpp index 8a293a42d..d519abf39 100644 --- a/src/access.cpp +++ b/src/access.cpp @@ -11,7 +11,6 @@ #include "services.h" #include "modules.h" -#include "access.h" enum { diff --git a/src/base.cpp b/src/base.cpp index 0aec072a1..18450ef90 100644 --- a/src/base.cpp +++ b/src/base.cpp @@ -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() { } diff --git a/src/bin/CMakeLists.txt b/src/bin/CMakeLists.txt index 7c6fe514b..cb110edb5 100644 --- a/src/bin/CMakeLists.txt +++ b/src/bin/CMakeLists.txt @@ -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 ) diff --git a/src/bin/cp-recursive b/src/bin/cp-recursive deleted file mode 100755 index e51230db7..000000000 --- a/src/bin/cp-recursive +++ /dev/null @@ -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 - diff --git a/src/bin/langtool b/src/bin/langtool deleted file mode 100755 index c1072760c..000000000 --- a/src/bin/langtool +++ /dev/null @@ -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"; - -} diff --git a/src/bin/mydbgen b/src/bin/mydbgen deleted file mode 100755 index 12bee8063..000000000 --- a/src/bin/mydbgen +++ /dev/null @@ -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 diff --git a/src/bots.cpp b/src/bots.cpp index 390fc6a69..928dcb2c1 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -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()) diff --git a/src/hostserv.cpp b/src/hostserv.cpp index d3000d552..55cbaff29 100644 --- a/src/hostserv.cpp +++ b/src/hostserv.cpp @@ -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; } diff --git a/src/init.cpp b/src/init.cpp index beb34aafb..c4cd62b07 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -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()); } /*************************************************************************/ diff --git a/src/main.cpp b/src/main.cpp index aab9edce5..5d3b5e3de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -375,6 +375,7 @@ int main(int ac, char **av, char **envp) ModuleManager::UnloadModule(m, NULL); ModuleManager::CleanupRuntimeDirectory(); + serialized_items.clear(); #ifdef _WIN32 OnShutdown(); diff --git a/src/memoserv.cpp b/src/memoserv.cpp index 21940aca1..faaca180b 100644 --- a/src/memoserv.cpp +++ b/src/memoserv.cpp @@ -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) diff --git a/src/misc.cpp b/src/misc.cpp index 5e41d42b7..0090dfa3b 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -14,6 +14,19 @@ #include "version.h" #include "modules.h" +ExtensibleItem::ExtensibleItem() +{ +} + +ExtensibleItem::~ExtensibleItem() +{ +} + +void ExtensibleItem::OnDelete() +{ + delete this; +} + struct arc4_stream { uint8 i; diff --git a/src/modes.cpp b/src/modes.cpp index 4fc5d6483..e6f3a27a1 100644 --- a/src/modes.cpp +++ b/src/modes.cpp @@ -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))); } } } diff --git a/src/nickalias.cpp b/src/nickalias.cpp index f5269cc9f..7b07a4af3 100644 --- a/src/nickalias.cpp +++ b/src/nickalias.cpp @@ -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); +} + diff --git a/src/nickcore.cpp b/src/nickcore.cpp index a33382f06..968e4d0e9 100644 --- a/src/nickcore.cpp +++ b/src/nickcore.cpp @@ -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; diff --git a/src/operserv.cpp b/src/operserv.cpp index b17f9e0ad..b0db3aee1 100644 --- a/src/operserv.cpp +++ b/src/operserv.cpp @@ -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 diff --git a/src/regchannel.cpp b/src/regchannel.cpp index 7eceb5942..4c90fa458 100644 --- a/src/regchannel.cpp +++ b/src/regchannel.cpp @@ -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 ¶m) { - 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 ¶m) 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; } diff --git a/src/tools/db-convert.cpp b/src/tools/db-convert.cpp deleted file mode 100644 index 16dc3516a..000000000 --- a/src/tools/db-convert.cpp +++ /dev/null @@ -1,1032 +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. - */ - -#include "db-convert.h" - -static std::string GetLevelName(int level) -{ - switch (level) - { - case 0: - return "INVITE"; - case 1: - return "AKICK"; - case 2: - return "SET"; - case 3: - return "UNBAN"; - case 4: - return "AUTOOP"; - case 5: - return "AUTODEOP"; - case 6: - return "AUTOVOICE"; - case 7: - return "OPDEOP"; - case 8: - return "LIST"; - case 9: - return "CLEAR"; - case 10: - return "NOJOIN"; - case 11: - return "CHANGE"; - case 12: - return "MEMO"; - case 13: - return "ASSIGN"; - case 14: - return "BADWORDS"; - case 15: - return "NOKICK"; - case 16: - return "FANTASIA"; - case 17: - return "SAY"; - case 18: - return "GREET"; - case 19: - return "VOICEME"; - case 20: - return "VOICE"; - case 21: - return "GETKEY"; - case 22: - return "AUTOHALFOP"; - case 23: - return "AUTOPROTECT"; - case 24: - return "OPDEOPME"; - case 25: - return "HALFOPME"; - case 26: - return "HALFOP"; - case 27: - return "PROTECTME"; - case 28: - return "PROTECT"; - case 29: - return "KICKME"; - case 30: - return "KICK"; - case 31: - return "SIGNKICK"; - case 32: - return "BANME"; - case 33: - return "BAN"; - case 34: - return "TOPIC"; - case 35: - return "INFO"; - default: - return "INVALID"; - } -} - -void process_mlock_modes(std::ofstream &fs, size_t m, const std::string &ircd) -{ - /* this is the same in all protocol modules */ - if (m & 0x1) fs << " CMODE_INVITE"; // CMODE_i - if (m & 0x2) fs << " CMODE_MODERATED"; // CMODE_m - if (m & 0x4) fs << " CMODE_NOEXTERNAL"; // CMODE_n - if (m & 0x8) fs << " CMODE_PRIVATE"; // CMODE_p - if (m & 0x10) fs << " CMODE_SECRET"; // CMODE_s - if (m & 0x20) fs << " CMODE_TOPIC"; // CMODE_t - if (m & 0x40) fs << " CMODE_KEY"; // CMODE_k - if (m & 0x80) fs << " CMODE_LIMIT"; // CMODE_l - if (m & 0x200) fs << " CMODE_REGISTERED"; // CMODE_r - - if (ircd == "unreal" || ircd == "inspircd") - { - if (m & 0x100) fs << " CMODE_REGISTEREDONLY"; // CMODE_R - if (m & 0x400) fs << " CMODE_BLOCKCOLOR"; // CMODE_c - if (m & 0x2000) fs << " CMODE_NOKNOCK"; // CMODE_K - if (m & 0x4000) fs << " CMODE_REDIRECT"; // CMODE_L - if (m & 0x8000) fs << " CMODE_OPERONLY"; // CMODE_O - if (m & 0x10000) fs << " CMODE_NOKICK"; // CMODE_Q - if (m & 0x20000) fs << " CMODE_STRIPCOLOR"; // CMODE_S - if (m & 0x80000) fs << " CMODE_FLOOD"; // CMODE_f - if (m & 0x100000) fs << " CMODE_FILTER"; // CMODE_G - if (m & 0x200000) fs << " CMODE_NOCTCP"; // CMODE_C - if (m & 0x400000) fs << " CMODE_AUDITORIUM"; // CMODE_u - if (m & 0x800000) fs << " CMODE_SSL"; // CMODE_z - if (m & 0x1000000) fs << " CMODE_NONICK"; // CMODE_N - if (m & 0x4000000) fs << " CMODE_REGMODERATED"; // CMODE_M - } - - if (ircd == "unreal") - { - if (m & 0x800) fs << " CMODE_ADMINONLY"; // CMODE_A - if (m & 0x40000) fs << " CMODE_NOINVITE"; // CMODE_f - if (m & 0x2000000) fs << " CMODE_NONOTICE"; // CMODE_T - if (m & 0x8000000) fs << " CMODE_JOINFLOOD"; // CMODE_j - } - if (ircd == "inspircd" ) - { - if (m & 0x800) fs << " CMODE_ALLINVITE"; // CMODE_A - if (m & 0x1000) fs << " CMODE_NONOTICE"; // CMODE_T - /* for some reason, there is no CMODE_P in 1.8.x and no CMODE_V in the 1.9.1 protocol module - we are ignoring this flag until we find a solution for this problem, - so the +V/+P mlock mode is lost on convert - anope 1.8: if (m & 0x40000) fs << " NOINVITE"; // CMODE_V - anope 1.9: if (m & 0x40000) fs << " PERM"; // CMODE_P - */ - if (m & 0x2000000) fs << " CMODE_JOINFLOOD"; // CMODE_j - if (m & 0x8000000) fs << " CMODE_BLOCKCAPS"; // CMODE_B - if (m & 0x10000000) fs << " CMODE_NICKFLOOD"; // CMODE_F - //if (m & 0x20000000) fs << ""; // CMODE_g (mode +g <badword>) ... can't be mlocked in older version - //if (m & 0x40000000) fs << ""; // CMODE_J (mode +J [seconds] ... can't be mlocked in older versions - } -} - -int main(int argc, char *argv[]) -{ - dbFILE *f; - std::ofstream fs; - std::string hashm, ircd; - - printf("\n"C_LBLUE"Anope 1.8.x -> 1.9.3+ database converter"C_NONE"\n\n"); - - while (hashm != "md5" && hashm != "sha1" && hashm != "oldmd5" && hashm != "plain") - { - if (!hashm.empty()) - std::cout << "Select a valid option, thanks!" << std::endl; - std::cout << "Which hash method did you use? (md5, sha1, oldmd5, plain)" << std::endl << "? "; - std::cin >> hashm; - } - - while (ircd != "bahamut" && ircd != "charybdis" && ircd != "dreamforge" && ircd != "hybrid" && ircd != "inspircd" && ircd != "plexus2" && ircd != "plexus3" && ircd != "ptlink" && ircd != "rageircd" && ircd != "ratbox" && ircd != "shadowircd" && ircd != "solidircd" && ircd != "ultimate2" && ircd != "ultimate3" && ircd != "unreal" && ircd != "viagra") - { - if (!ircd.empty()) - std::cout << "Select a valid option!" << std::endl; - std::cout << "Which IRCd did you use? (required for converting the mlock modes)" << std::endl; - std::cout << "(bahamut, charybdis, dreamforge, hybrid, inspircd, plexus2, plexus3, ptlink," << std::endl; - std::cout << "rageircd, ratbox, shadowircd, solidircd, ultimate2, ultimate3, unreal, viagra)" << std::endl; - std::cout << "Your IRCd: "; std::cin >> ircd; - } - - std::cout << "You selected " << hashm << std::endl; - - fs.clear(); - fs.open("anope.db"); - if (!fs.is_open()) - { - printf("\n"C_LBLUE"Could not open anope.db for write"C_NONE"\n\n"); - exit(1); - } - - fs << "VER 2" << std::endl; - - /* Section I: Nicks */ - /* Ia: First database */ - if ((f = open_db_read("NickServ", "nick.db", 14))) - { - NickAlias *na, **nalast, *naprev; - NickCore *nc, **nclast, *ncprev; - int16 tmp16; - int32 tmp32; - int i, j, c; - - printf("Trying to merge nicks...\n"); - - /* Nick cores */ - for (i = 0; i < 1024; ++i) - { - nclast = &nclists[i]; - ncprev = NULL; - - while ((c = getc_db(f)) == 1) - { - if (c != 1) - { - printf("Invalid format in nickserv db.\n"); - exit(0); - } - - nc = new NickCore; - nc->aliascount = 0; - nc->unused = 0; - - *nclast = nc; - nclast = &nc->next; - nc->prev = ncprev; - ncprev = nc; - - READ(read_string(&nc->display, f)); - READ(read_buffer(nc->pass, f)); - READ(read_string(&nc->email, f)); - READ(read_string(&nc->greet, f)); - READ(read_uint32(&nc->icq, f)); - READ(read_string(&nc->url, f)); - READ(read_uint32(&nc->flags, f)); - READ(read_uint16(&nc->language, f)); - READ(read_uint16(&nc->accesscount, f)); - if (nc->accesscount) - { - char **access = new char *[nc->accesscount + 1]; - nc->access = access; - for (j = 0; j < nc->accesscount; ++j, ++access) - READ(read_string(access, f)); - } - READ(read_int16(&nc->memos.memocount, f)); - READ(read_int16(&nc->memos.memomax, f)); - if (nc->memos.memocount) - { - Memo *memos = new Memo[nc->memos.memocount]; - nc->memos.memos = memos; - for (j = 0; j < nc->memos.memocount; ++j, ++memos) - { - READ(read_uint32(&memos->number, f)); - READ(read_uint16(&memos->flags, f)); - READ(read_int32(&tmp32, f)); - memos->time = tmp32; - READ(read_buffer(memos->sender, f)); - READ(read_string(&memos->text, f)); - } - } - READ(read_uint16(&nc->channelcount, f)); - READ(read_int16(&tmp16, f)); - } /* getc_db() */ - *nclast = NULL; - } /* for() loop */ - - /* Nick aliases */ - for (i = 0; i < 1024; ++i) - { - char *s = NULL; - - nalast = &nalists[i]; - naprev = NULL; - - while ((c = getc_db(f)) == 1) - { - if (c != 1) - { - printf("Invalid format in nick db.\n"); - exit(0); - } - - na = new NickAlias; - - READ(read_string(&na->nick, f)); - READ(read_string(&na->last_usermask, f)); - READ(read_string(&na->last_realname, f)); - READ(read_string(&na->last_quit, f)); - - READ(read_int32(&tmp32, f)); - na->time_registered = tmp32; - READ(read_int32(&tmp32, f)); - na->last_seen = tmp32; - READ(read_uint16(&na->status, f)); - READ(read_string(&s, f)); - na->nc = findcore(s, 0); - ++na->nc->aliascount; - //free(s); - delete [] s; - - *nalast = na; - nalast = &na->next; - na->prev = naprev; - naprev = na; - } /* getc_db() */ - *nalast = NULL; - } /* for() loop */ - close_db(f); /* End of section Ia */ - } - - /* CLEAN THE CORES */ - int i; - for (i = 0; i < 1024; ++i) - { - NickCore *ncnext; - for (NickCore *nc = nclists[i]; nc; nc = ncnext) - { - ncnext = nc->next; - if (nc->aliascount < 1) - { - printf("Deleting core %s (%s).\n", nc->display, nc->email); - delcore(nc); - } - } - } - - head = NULL; - if ((f = open_db_read("HostServ", "hosts.db", 3))) - { - int c; - HostCore *hc; - - while ((c = getc_db(f)) == 1) - { - hc = new HostCore; - READ(read_string(&hc->nick, f)); - READ(read_string(&hc->vIdent, f)); - READ(read_string(&hc->vHost, f)); - READ(read_string(&hc->creator, f)); - READ(read_int32(&hc->time, f)); - - hc->next = head; - head = hc; - } - - close_db(f); - } - - /* Nick cores */ - for (i = 0; i < 1024; ++i) - { - NickAlias *na; - NickCore *nc; - char **access; - Memo *memos; - int j, len; - std::string cpass; - for (nc = nclists[i]; nc; nc = nc->next) - { - if (!nc->display) - { - std::cout << "Skipping core with no display" << std::endl; - continue; - } - - if (nc->aliascount < 1) - { - std::cout << "Skipping core with 0 or less aliases (wtf?)" << std::endl; - continue; - } - - if (nc->flags & 0x80000000) - { - std::cout << "Skipping forbidden nick " << nc->display << std::endl; - continue; - } - - // Enc pass - if (hashm == "plain") - len = strlen(nc->pass); - else if (hashm == "md5") - len = 16; - else if (hashm == "sha1") - len = 20; - else if (hashm == "oldmd5") - len = 16; - else - len = 32; - - if (hashm == "plain") - b64_encode(nc->pass, cpass); - else - cpass = Hex(nc->pass); - - fs << "NC " << nc->display << " " << hashm << ":" << cpass << std::endl; - fs << "MD LANGUAGE " << GetLanguageID(nc->language) << std::endl; - fs << "MD MEMOMAX " << nc->memos.memomax << std::endl; - fs << "MD CHANCOUNT " << nc->channelcount << std::endl; - - std::cout << "Wrote account for " << nc->display << " passlen " << cpass.length() << std::endl; - if (nc->email) - fs << "MD EMAIL " << nc->email << std::endl; - if (nc->greet) - fs << "MD GREET :" << nc->greet << std::endl; - if (nc->icq) - fs << "MD ICQ :" << nc->icq << std::endl; - if (nc->url) - fs << "MD URL :" << nc->url << std::endl; - - if (nc->accesscount) - for (j = 0, access = nc->access; j < nc->accesscount && *access; ++j, ++access) - fs << "MD ACCESS " << *access << std::endl; - - fs << "MD FLAGS " - << (nc->flags & NI_KILLPROTECT ? "KILLPROTECT " : "") - << (nc->flags & NI_SECURE ? "SECURE " : "") - << (nc->flags & NI_MSG ? "MSG " : "") - << (nc->flags & NI_MEMO_HARDMAX ? "MEMO_HARDMAX " : "") - << (nc->flags & NI_MEMO_SIGNON ? "MEMO_SIGNON " : "") - << (nc->flags & NI_MEMO_RECEIVE ? "MEMO_RECEIVE " : "") - << (nc->flags & NI_PRIVATE ? "PRIVATE " : "") - << (nc->flags & NI_HIDE_EMAIL ? "HIDE_EMAIL " : "") - << (nc->flags & NI_HIDE_MASK ? "HIDE_MASK " : "") - << (nc->flags & NI_HIDE_QUIT ? "HIDE_QUIT " : "") - << (nc->flags & NI_KILL_QUICK ? "KILL_QUICK " : "") - << (nc->flags & NI_KILL_IMMED ? "KILL_IMMED " : "") - << (nc->flags & NI_MEMO_MAIL ? "MEMO_MAIL " : "") - << (nc->flags & NI_HIDE_STATUS ? "HIDE_STATUS " : "") - << (nc->flags & NI_SUSPENDED ? "SUSPENDED " : "") - // in 1.8, the AUTOOP flag was set to disable AUTOOP. Now we enable it. --DP - << (!(nc->flags & NI_AUTOOP) ? "AUTOOP " : "") - << (nc->flags & NI_FORBIDDEN ? "FORBIDDEN " : "") << std::endl; - if (nc->memos.memocount) - { - memos = nc->memos.memos; - for (j = 0; j < nc->memos.memocount; ++j, ++memos) - { - if (!memos->text || !memos->sender) - continue; - fs << "MD MI " << memos->time << " " << memos->sender; - if (memos->flags & MF_UNREAD) - fs << " UNREAD"; - if (memos->flags & MF_RECEIPT) - fs << " RECEIPT"; - if (memos->flags & MF_NOTIFYS) - fs << " NOTIFYS"; - fs << " :" << memos->text << std::endl; - } - } - - /* we could do this in a seperate loop, I'm doing it here for tidiness. */ - for (int tmp = 0; tmp < 1024; ++tmp) - { - for (na = nalists[tmp]; na; na = na->next) - { - if (!na->nc) - { - std::cout << "Skipping alias with no core (wtf?)" << std::endl; - continue; - } - - if (na->nc != nc) - continue; - - std::cout << "Writing: " << na->nc->display << "'s nick: " << na->nick << std::endl; - - fs << "NA " << na->nc->display << " " << na->nick << " " << na->time_registered << " " << na->last_seen << std::endl; - if (na->last_usermask) - fs << "MD LAST_USERMASK " << na->last_usermask << std::endl; - if (na->last_realname) - fs << "MD LAST_REALNAME :" << na->last_realname << std::endl; - if (na->last_quit) - fs << "MD LAST_QUIT :" << na->last_quit << std::endl; - if ((na->status & NS_FORBIDDEN) || (na->status & NS_NO_EXPIRE)) - fs << "MD FLAGS" << (na->status & NS_FORBIDDEN ? " FORBIDDEN" : "") << (na->status & NS_NO_EXPIRE ? " NOEXPIRE" : "") << std::endl; - - HostCore *hc = findHostCore(na->nick); - if (hc && hc->creator && hc->vHost) - fs << "MD VHOST " << hc->creator << " " << hc->time << " " << hc->vHost << " :" << (hc->vIdent ? hc->vIdent : "") << std::endl; - } - } - } - } - - /* Section II: Bots */ - /* IIa: First database */ - if ((f = open_db_read("Botserv", "bot.db", 10))) - { - std::string input; - int c, broken = 0; - int32 created; - int16 flags, chancount; - char *nick, *user, *host, *real; - - std::cout << "Trying to convert bots..." << std::endl; - - while (input != "y" && input != "n") - { - std::cout << std::endl << "Are you converting a 1.9.0 database? (y/n) " << std::endl << "? "; - std::cin >> input; - } - if (input == "y") - broken = 1; - input = ""; - while (input != "y" && input != "n") - { - std::cout << std::endl << "Are you converting a 1.8.x database? (y/n) " << std::endl << "? "; - std::cin >> input; - } - /* 1.8 doesn't have nickserv etc in bot.db, create them */ - if (input == "y") - { - time_t now = time(NULL); - fs << "BI NickServ NickServ services.anope.org " << now << " 0 :NickServ" << std::endl; - fs << "MD FLAGS NICKSERV" << std::endl; - - fs << "BI ChanServ ChanServ services.anope.org " << now << " 0 :ChanServ" << std::endl; - fs << "MD FLAGS CHANSERV" << std::endl; - - fs << "BI BotServ BotServ services.anope.org " << now << " 0 :BotServ" << std::endl; - fs << "MD FLAGS BOTSERV" << std::endl; - - fs << "BI HostServ HostServ services.anope.org " << now << " 0 :HostServ" << std::endl; - fs << "MD FLAGS HOSTSERV" << std::endl; - - fs << "BI OperServ OperServ services.anope.org " << now << " 0 :OperServ" << std::endl; - fs << "MD FLAGS OPERSERV" << std::endl; - - fs << "BI MemoServ MemoServ services.anope.org " << now << " 0 :MemoServ" << std::endl; - fs << "MD FLAGS MEMOSERV" << std::endl; - - fs << "BI Global Global services.anope.org " << now << " 0: Global" << std::endl; - fs << "MD FLAGS GLOBAL" << std::endl; - } - - while ((c = getc_db(f)) == 1) - { - READ(read_string(&nick, f)); - READ(read_string(&user, f)); - READ(read_string(&host, f)); - READ(read_string(&real, f)); - SAFE(read_int16(&flags, f)); - READ(read_int32(&created, f)); - READ(read_int16(&chancount, f)); - - if (!created) - created = time(NULL); // Unfortunatley, we forgot to store the created bot time in 1.9.1+ - - /* fix for the 1.9.0 broken bot.db */ - if (broken) - { - flags = 0; - if (!mystricmp(nick, "ChanServ")) - flags |= BI_CHANSERV; - if (!mystricmp(nick, "BotServ")) - flags |= BI_BOTSERV; - if (!mystricmp(nick, "HostServ")) - flags |= BI_HOSTSERV; - if (!mystricmp(nick, "OperServ")) - flags |= BI_OPERSERV; - if (!mystricmp(nick, "MemoServ")) - flags |= BI_MEMOSERV; - if (!mystricmp(nick, "NickServ")) - flags |= BI_NICKSERV; - if (!mystricmp(nick, "Global")) - flags |= BI_GLOBAL; - } /* end of 1.9.0 broken database fix */ - std::cout << "Writing Bot " << nick << "!" << user << "@" << host << std::endl; - fs << "BI " << nick << " " << user << " " << host << " " << created << " " << chancount << " :" << real << std::endl; - fs << "MD FLAGS" - << (flags & BI_PRIVATE ? " PRIVATE" : "") - << (flags & BI_CHANSERV ? " CHANSERV" : "") - << (flags & BI_BOTSERV ? " BOTSERV" : "") - << (flags & BI_HOSTSERV ? " HOSTSERV" : "") - << (flags & BI_OPERSERV ? " OPERSERV" : "") - << (flags & BI_MEMOSERV ? " MEMOSERV" : "") - << (flags & BI_NICKSERV ? " NICKSERV" : "") - << (flags & BI_GLOBAL ? " GLOBAL" : "") << std::endl; - } - close_db(f); - } - - /* Section III: Chans */ - // IIIa: First database - if ((f = open_db_read("ChanServ", "chan.db", 16))) - { - ChannelInfo *ci, **last, *prev; - int c; - - printf("Trying to merge channels...\n"); - - for (i = 0; i < 256; ++i) - { - int16 tmp16; - int32 tmp32; - int n_levels; - char *s; - int n_ttb; - - last = &chanlists[i]; - prev = NULL; - - while ((c = getc_db(f)) == 1) - { - int j; - - if (c != 1) - { - printf("Invalid format in chans.db.\n"); - exit(0); - } - - ci = new ChannelInfo; - *last = ci; - last = &ci->next; - ci->prev = prev; - prev = ci; - READ(read_buffer(ci->name, f)); - READ(read_string(&ci->founder, f)); - READ(read_string(&ci->successor, f)); - READ(read_buffer(ci->founderpass, f)); - READ(read_string(&ci->desc, f)); - if (!ci->desc) - ci->desc = strdup(""); - std::cout << "Read " << ci->name << " founder " << (ci->founder ? ci->founder : "N/A") << std::endl; - READ(read_string(&ci->url, f)); - READ(read_string(&ci->email, f)); - READ(read_int32(&tmp32, f)); - ci->time_registered = tmp32; - READ(read_int32(&tmp32, f)); - ci->last_used = tmp32; - READ(read_string(&ci->last_topic, f)); - READ(read_buffer(ci->last_topic_setter, f)); - READ(read_int32(&tmp32, f)); - ci->last_topic_time = tmp32; - READ(read_uint32(&ci->flags, f)); - // Temporary flags cleanup - ci->flags &= ~0x80000000; - READ(read_string(&ci->forbidby, f)); - READ(read_string(&ci->forbidreason, f)); - READ(read_int16(&tmp16, f)); - ci->bantype = tmp16; - READ(read_int16(&tmp16, f)); - n_levels = tmp16; - ci->levels = new int16[36]; - for (j = 0; j < n_levels; ++j) - { - if (j < 36) - READ(read_int16(&ci->levels[j], f)); - else - READ(read_int16(&tmp16, f)); - } - READ(read_uint16(&ci->accesscount, f)); - if (ci->accesscount) - { - ci->access = new ChanAccess[ci->accesscount]; - for (j = 0; j < ci->accesscount; ++j) - { - READ(read_uint16(&ci->access[j].in_use, f)); - if (ci->access[j].in_use) - { - READ(read_int16(&ci->access[j].level, f)); - READ(read_string(&s, f)); - if (s) - { - ci->access[j].nc = findcore(s, 0); - delete [] s; - } - if (ci->access[j].nc == NULL) - ci->access[j].in_use = 0; - READ(read_int32(&tmp32, f)); - ci->access[j].last_seen = tmp32; - } - } - } - else - ci->access = NULL; - READ(read_uint16(&ci->akickcount, f)); - if (ci->akickcount) - { - ci->akick = new AutoKick[ci->akickcount]; - for (j = 0; j < ci->akickcount; ++j) - { - SAFE(read_uint16(&ci->akick[j].flags, f)); - if (ci->akick[j].flags & 0x0001) - { - SAFE(read_string(&s, f)); - if (ci->akick[j].flags & 0x0002) - { - ci->akick[j].u.nc = findcore(s, 0); - if (!ci->akick[j].u.nc) - ci->akick[j].flags &= ~0x0001; - delete [] s; - } - else - ci->akick[j].u.mask = s; - SAFE(read_string(&s, f)); - if (ci->akick[j].flags & 0x0001) - ci->akick[j].reason = s; - else if (s) - delete [] s; - SAFE(read_string(&s, f)); - if (ci->akick[j].flags & 0x0001) - ci->akick[j].creator = s; - else if (s) - delete [] s; - SAFE(read_int32(&tmp32, f)); - if (ci->akick[j].flags & 0x0001) - ci->akick[j].addtime = tmp32; - } - } - } - else - ci->akick = NULL; - READ(read_uint32(&ci->mlock_on, f)); - READ(read_uint32(&ci->mlock_off, f)); - READ(read_uint32(&ci->mlock_limit, f)); - READ(read_string(&ci->mlock_key, f)); - READ(read_string(&ci->mlock_flood, f)); - READ(read_string(&ci->mlock_redirect, f)); - READ(read_int16(&ci->memos.memocount, f)); - READ(read_int16(&ci->memos.memomax, f)); - if (ci->memos.memocount) - { - Memo *memos = new Memo[ci->memos.memocount]; - ci->memos.memos = memos; - for (j = 0; j < ci->memos.memocount; ++j, ++memos) - { - READ(read_uint32(&memos->number, f)); - READ(read_uint16(&memos->flags, f)); - READ(read_int32(&tmp32, f)); - memos->time = tmp32; - READ(read_buffer(memos->sender, f)); - READ(read_string(&memos->text, f)); - } - } - READ(read_string(&ci->entry_message, f)); - - // BotServ options - READ(read_string(&ci->bi, f)); - READ(read_int32(&tmp32, f)); - ci->botflags = tmp32; - READ(read_int16(&tmp16, f)); - n_ttb = tmp16; - ci->ttb = new int16[16]; - for (j = 0; j < n_ttb; ++j) - { - if (j < 8) - READ(read_int16(&ci->ttb[j], f)); - else - READ(read_int16(&tmp16, f)); - } - for (j = n_ttb; j < 8; ++j) - ci->ttb[j] = 0; - READ(read_int16(&tmp16, f)); - ci->capsmin = tmp16; - READ(read_int16(&tmp16, f)); - ci->capspercent = tmp16; - READ(read_int16(&tmp16, f)); - ci->floodlines = tmp16; - READ(read_int16(&tmp16, f)); - ci->floodsecs = tmp16; - READ(read_int16(&tmp16, f)); - ci->repeattimes = tmp16; - - READ(read_uint16(&ci->bwcount, f)); - if (ci->bwcount) - { - ci->badwords = new BadWord[ci->bwcount]; - for (j = 0; j < ci->bwcount; ++j) - { - SAFE(read_uint16(&ci->badwords[j].in_use, f)); - if (ci->badwords[j].in_use) - { - SAFE(read_string(&ci->badwords[j].word, f)); - SAFE(read_uint16(&ci->badwords[j].type, f)); - } - } - } - else - ci->badwords = NULL; - } - *last = NULL; - } - - close_db(f); - } - - ChannelInfo *ci; - - for (i = 0; i < 256; ++i) - { - for (ci = chanlists[i]; ci; ci = ci->next) - { - int j; - - fs << "CH " << ci->name << " " << ci->time_registered << " " << ci->last_used << std::endl; - if (ci->founder) - fs << "MD FOUNDER " << ci->founder << std::endl; - if (ci->successor) - fs << "MD SUCCESSOR " << ci->successor << std::endl; - fs << "MD BANTYPE " << ci->bantype << std::endl; - fs << "MD MEMOMAX " << ci->memos.memomax << std::endl; - fs << "MD LEVELS"; - for (j = 0; j < 36; ++j) - { - /* In 1.8 disabled meant founder only. In 1.9.2 disabled literally means its disabled so, we will set these to ACCESS_QOP */ - if (ci->levels[j] == -10000) - fs << " " << GetLevelName(j) << " " << 10000; - else - fs << " " << GetLevelName(j) << " " << ci->levels[j]; - } - fs << std::endl; - fs << "MD FLAGS" - << (ci->flags & CI_KEEPTOPIC ? " KEEPTOPIC" : "") - << (ci->flags & CI_SECUREOPS ? " SECUREOPS" : "") - << (ci->flags & CI_PRIVATE ? " PRIVATE" : "") - << (ci->flags & CI_TOPICLOCK ? " TOPICLOCK" : "") - << (ci->flags & CI_RESTRICTED ? " RESTRICTED" : "") - << (ci->flags & CI_PEACE ? " PEACE" : "") - << (ci->flags & CI_SECURE ? " SECURE" : "") - << (ci->flags & CI_FORBIDDEN ? " FORBIDDEN" : "") - << (ci->flags & CI_NO_EXPIRE ? " NO_EXPIRE" : "") - << (ci->flags & CI_MEMO_HARDMAX ? " MEMO_HARDMAX" : "") - << (ci->flags & CI_OPNOTICE ? " OPNOTICE" : "") - << (ci->flags & CI_SECUREFOUNDER ? " SECUREFOUNDER" : "") - << (ci->flags & CI_SIGNKICK ? " SIGNKICK" : "") - << (ci->flags & CI_SIGNKICK_LEVEL ? " SIGNKICKLEVEL" : "") - << (ci->flags & CI_XOP ? " XOP" : "") - << (ci->flags & CI_SUSPENDED ? " SUSPENDED" : "") << std::endl; - if (ci->desc && *ci->desc) - fs << "MD DESC :" << ci->desc << std::endl; - if (ci->url) - fs << "MD URL :" << ci->url << std::endl; - if (ci->email) - fs << "MD EMAIL :" << ci->email << std::endl; - if (ci->last_topic && ci->last_topic_setter) // MD CH topic <setter> <time> :topic - fs << "MD TOPIC " << ci->last_topic_setter << " " << ci->last_topic_time << " :" << ci->last_topic << std::endl; - if (ci->flags & CI_FORBIDDEN) - fs << "MD FORBID " << (ci->forbidby ? ci->forbidby : "db-convert") << " :" << (ci->forbidreason ? ci->forbidreason : "no reason given") << std::endl; - - for (j = 0; j < ci->accesscount; ++j) - // MD ACCESS <display> <level> <last_seen> <creator> - creator isn't in 1.9.0-1, but is in 1.9.2 - if (ci->access[j].in_use) - fs << "MD ACCESS " << ci->access[j].nc->display << " " << ci->access[j].level << " " << ci->access[j].last_seen << " Unknown" << std::endl; - - for (j = 0; j < ci->akickcount; ++j) - // MD AKICK <STUCK/UNSTUCK> <NICK/MASK> <akick> <creator> <addtime> :<reason> - if (ci->akick[j].flags & 0x0001) - { - fs << "MD AKICK " - << (ci->akick[j].flags & AK_STUCK ? "STUCK " : "UNSTUCK ") - << (ci->akick[j].flags & AK_ISNICK ? "NICK " : "MASK ") - << (ci->akick[j].flags & AK_ISNICK ? ci->akick[j].u.nc->display : ci->akick[j].u.mask) - << " " << ci->akick[j].creator << " " << ci->akick[j].addtime << " 0 :"; // 0 is for last used, added in 1.9.2 - if (ci->akick[j].reason) - fs << ci->akick[j].reason; - fs << std::endl; - } - - if (ci->mlock_on) - { - fs << "MD MLOCK_ON"; - process_mlock_modes(fs, ci->mlock_on, ircd); - fs << std::endl; - } - if (ci->mlock_off) - { - fs << "MD MLOCK_OFF"; - process_mlock_modes(fs, ci->mlock_off, ircd); - fs << std::endl; - } - if (ci->mlock_limit) - fs << "MD MLP CMODE_LIMIT " << ci->mlock_limit << std::endl; - if (ci->mlock_key && *ci->mlock_key) - fs << "MD MLP CMODE_KEY " << ci->mlock_key << std::endl; - if (ci->mlock_flood && *ci->mlock_flood) - fs << "MD MLP CMODE_FLOOD " << ci->mlock_flood << std::endl; - if (ci->mlock_redirect && *ci->mlock_redirect) - fs << "MD MLP CMODE_REDIRECT " << ci->mlock_redirect << std::endl; - if (ci->memos.memocount) - { - Memo *memos = ci->memos.memos; - for (j = 0; j < ci->memos.memocount; ++j, ++memos) - { - fs << "MD MI " << memos->number << " " << memos->time << " " << memos->sender; - if (memos->flags & MF_UNREAD) - fs << " UNREAD"; - if (memos->flags & MF_RECEIPT) - fs << " RECEIPT"; - if (memos->flags & MF_NOTIFYS) - fs << " NOTIFYS"; - fs << " :" << memos->text << std::endl; - } - } - - if (ci->entry_message) - fs << "MD ENTRYMSG :" << ci->entry_message << std::endl; - if (ci->bi) // here is "bi" a *Char, not a pointer to BotInfo ! - fs << "MD BI NAME " << ci->bi << std::endl; - if (ci->botflags) - fs << "MD BI FLAGS" - << (ci->botflags & BS_DONTKICKOPS ? " DONTKICKOPS" : "" ) - << (ci->botflags & BS_DONTKICKVOICES ? " DONTKICKVOICES" : "") - << (ci->botflags & BS_FANTASY ? " FANTASY" : "") - << (ci->botflags & BS_SYMBIOSIS ? " SYMBIOSIS" : "") - << (ci->botflags & BS_GREET ? " GREET" : "") - << (ci->botflags & BS_NOBOT ? " NOBOT" : "") - << (ci->botflags & BS_KICK_BOLDS ? " KICK_BOLDS" : "") - << (ci->botflags & BS_KICK_COLORS ? " KICK_COLORS" : "") - << (ci->botflags & BS_KICK_REVERSES ? " KICK_REVERSES" : "") - << (ci->botflags & BS_KICK_UNDERLINES ? " KICK_UNDERLINES" : "") - << (ci->botflags & BS_KICK_BADWORDS ? " KICK_BADWORDS" : "") - << (ci->botflags & BS_KICK_CAPS ? " KICK_CAPS" : "") - << (ci->botflags & BS_KICK_FLOOD ? " KICK_FLOOD" : "") - << (ci->botflags & BS_KICK_REPEAT ? " KICK_REPEAT" : "") << std::endl; - fs << "MD BI TTB"; - fs << " BOLDS " << ci->ttb[0]; - fs << " COLORS " << ci->ttb[1]; - fs << " REVERSES " << ci->ttb[2]; - fs << " UNDERLINES " << ci->ttb[3]; - fs << " BADWORDS " << ci->ttb[4]; - fs << " CAPS " << ci->ttb[5]; - fs << " FLOOD " << ci->ttb[6]; - fs << " REPEAT " << ci->ttb[7]; - fs << std::endl; - if (ci->capsmin) - fs << "MD BI CAPSMINS " << ci->capsmin << std::endl; - if (ci->capspercent) - fs << "MD BI CAPSPERCENT " << ci->capspercent << std::endl; - if (ci->floodlines) - fs << "MD BI FLOODLINES " << ci->floodlines << std::endl; - if (ci->floodsecs) - fs << "MD BI FLOODSECS " << ci->floodsecs << std::endl; - if (ci->repeattimes) - fs << "MD BI REPEATTIMES " << ci->repeattimes << std::endl; - for (j = 0; j < ci->bwcount; ++j) - if (ci->badwords[j].in_use) - { - fs << "MD BI BADWORD " - << (!ci->badwords[j].type ? "ANY " : "") - << (ci->badwords[j].type == 1 ? "SINGLE " : "") - << (ci->badwords[j].type == 2 ? "START " : "") - << (ci->badwords[j].type == 3 ? "END " : "") - << ":" << ci->badwords[j].word << std::endl; - } - - } /* for (chanlists[i]) */ - } /* for (i) */ - - /*********************************/ - /* OPERSERV Section */ - /*********************************/ - - if ((f = open_db_read("OperServ", "oper.db", 13))) - { - int32 maxusercnt = 0, maxusertime = 0, seton = 0, expires = 0; - int16 capacity = 0; - char *user, *host, *by, *reason, *mask; - - std::cout << "Writing operserv data (stats, akills, sglines, szlines)" << std::endl; - - SAFE(read_int32(&maxusercnt, f)); - SAFE(read_int32(&maxusertime, f)); - fs << "OS STATS " << maxusercnt << " " << maxusertime << std::endl; - - /* AKILLS */ - read_int16(&capacity, f); - for (i = 0; i < capacity; ++i) - { - SAFE(read_string(&user, f)); - SAFE(read_string(&host, f)); - SAFE(read_string(&by, f)); - SAFE(read_string(&reason, f)); - SAFE(read_int32(&seton, f)); - SAFE(read_int32(&expires, f)); - fs << "OS AKILL " << user << " " << host << " " << by << " " << seton << " " << expires << " :" << reason << std::endl; - delete [] user; - delete [] host; - delete [] by; - delete [] reason; - } - /* SNLINES */ - read_int16(&capacity, f); - for (i = 0; i < capacity; ++i) - { - SAFE(read_string(&mask, f)); - SAFE(read_string(&by, f)); - SAFE(read_string(&reason, f)); - SAFE(read_int32(&seton, f)); - SAFE(read_int32(&expires, f)); - fs << "OS SNLINE " << mask << " " << by << " " << seton << " " << expires << " :" << reason << std::endl; - delete [] mask; - delete [] by; - delete [] reason; - } - /* SQLINES */ - read_int16(&capacity, f); - for (i = 0; i < capacity; ++i) - { - SAFE(read_string(&mask, f)); - SAFE(read_string(&by, f)); - SAFE(read_string(&reason, f)); - SAFE(read_int32(&seton, f)); - SAFE(read_int32(&expires, f)); - fs << "OS SQLINE " << mask << " " << by << " " << seton << " " << expires << " :" << reason << std::endl; - delete [] mask; - delete [] by; - delete [] reason; - } - /* SZLINES */ - read_int16(&capacity, f); - for (i = 0; i < capacity; ++i) - { - SAFE(read_string(&mask, f)); - SAFE(read_string(&by, f)); - SAFE(read_string(&reason, f)); - SAFE(read_int32(&seton, f)); - SAFE(read_int32(&expires, f)); - fs << "OS SZLINE " << mask << " " << by << " " << seton << " " << expires << " :" << reason << std::endl; - delete [] mask; - delete [] by; - delete [] reason; - } - close_db(f); - } // operserv database - - /* CONVERTING DONE \o/ HURRAY! */ - fs.flush(); - fs.close(); - return 0; -} /* End of main() */ diff --git a/src/tools/db-convert.h b/src/tools/db-convert.h deleted file mode 100644 index 9ec4a882a..000000000 --- a/src/tools/db-convert.h +++ /dev/null @@ -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 |