From ac41137ce2741df8faf539e0655a10cd4a8f7e32 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 7 Nov 2010 20:51:41 -0500 Subject: [PATCH] Added /ms ignore --- data/example.conf | 2 +- docs/Changes.conf | 1 + docs/TODO | 2 +- include/language.h | 9 +++ include/services.h | 2 + modules/core/db_plain.cpp | 55 ++++++++--------- modules/core/ms_ignore.cpp | 117 +++++++++++++++++++++++++++++++++++++ modules/extra/db_mysql.cpp | 50 ++++++++++++++++ src/language.cpp | 21 +++++++ src/memoserv.cpp | 15 ++++- 10 files changed, 243 insertions(+), 31 deletions(-) create mode 100644 modules/core/ms_ignore.cpp diff --git a/data/example.conf b/data/example.conf index e573cbaac..106dba189 100644 --- a/data/example.conf +++ b/data/example.conf @@ -1160,7 +1160,7 @@ memoserv * The core modules to load for MemoServ. This is a space separated list that corresponds * to the base names of the modules for MemoServ. This directive is optional, but highly recommended. */ - modules = "ms_send ms_cancel ms_list ms_read ms_del ms_set ms_info ms_rsend ms_check ms_staff ms_sendall ms_help" + modules = "ms_send ms_cancel ms_list ms_read ms_del ms_set ms_info ms_rsend ms_check ms_staff ms_sendall ms_ignore ms_help" /* * The maximum number of memos a user is allowed to keep by default. Normal users may set the diff --git a/docs/Changes.conf b/docs/Changes.conf index a57a96455..b453fec76 100644 --- a/docs/Changes.conf +++ b/docs/Changes.conf @@ -1,5 +1,6 @@ Anope Version 1.9.4 ------------------- +memoserv:modules added ms_ignore Anope Version 1.9.3 ------------------ diff --git a/docs/TODO b/docs/TODO index 99aca91e9..2b66a1fa8 100644 --- a/docs/TODO +++ b/docs/TODO @@ -5,6 +5,7 @@ Legend: 1.9.4 ----- +[x] MS IGNORE. Make it take nick (accounts) or n!u@h masks. Fake success of memo send still, but send to opers? Future ------ @@ -16,7 +17,6 @@ Future [?] Last successful login time/ip? perhaps both of these should be a new nick setting [ ] NS INFO: seperate field for last seen realhost, shown to SRA only [ ] NS SUSPEND: show suspender and reason, probably to sopers only (see CS SUSPEND) -[ ] MS IGNORE. Make it take nick (accounts) or n!u@h masks. Fake success of memo send still, but send to opers? [ ] Allow channel founders to change the fantasy trigger for their channel. [ ] CIDR Akills, session exceptions, etc [ ] Language charset stuff, including collation (1.9.1? phoenix?) diff --git a/include/language.h b/include/language.h index 4366d93c9..51f3e1cfc 100644 --- a/include/language.h +++ b/include/language.h @@ -705,6 +705,13 @@ enum LanguageString MEMO_CHECK_READ, MEMO_CHECK_NO_MEMO, MEMO_NO_RSEND_SELF, + MEMO_IGNORE_SYNTAX, + MEMO_IGNORE_ADD, + MEMO_IGNORE_ALREADY_IGNORED, + MEMO_IGNORE_DEL, + MEMO_IGNORE_NOT_IGNORED, + MEMO_IGNORE_LIST_EMPTY, + MEMO_IGNORE_LIST_HEADER, BOT_DOES_NOT_EXIST, BOT_NOT_ASSIGNED, BOT_NOT_ON_CHANNEL, @@ -1373,6 +1380,7 @@ enum LanguageString MEMO_HELP_CMD_CHECK, MEMO_HELP_CMD_SENDALL, MEMO_HELP_CMD_STAFF, + MEMO_HELP_CMD_IGNORE, MEMO_HELP_HEADER, MEMO_HELP_FOOTER, MEMO_HELP_SEND, @@ -1390,6 +1398,7 @@ enum LanguageString MEMO_HELP_SENDALL, MEMO_HELP_RSEND, MEMO_HELP_CHECK, + MEMO_HELP_IGNORE, OPER_HELP_CMD_GLOBAL, OPER_HELP_CMD_STATS, OPER_HELP_CMD_STAFF, diff --git a/include/services.h b/include/services.h index d1dca8724..1b14f5e88 100644 --- a/include/services.h +++ b/include/services.h @@ -487,10 +487,12 @@ struct CoreExport MemoInfo { unsigned memomax; std::vector memos; + std::vector ignores; unsigned GetIndex(Memo *m) const; void Del(unsigned index); void Del(Memo *m); + bool HasIgnore(User *u); }; /*************************************************************************/ diff --git a/modules/core/db_plain.cpp b/modules/core/db_plain.cpp index 041ea752e..1c8de7fee 100644 --- a/modules/core/db_plain.cpp +++ b/modules/core/db_plain.cpp @@ -609,6 +609,8 @@ class DBPlain : public Module 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()); return EVENT_CONTINUE; } @@ -766,6 +768,8 @@ class DBPlain : public Module 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("ENTRYMSG")) ci->entry_message = params[0]; else if (key.equals_ci("BI")) @@ -884,21 +888,20 @@ class DBPlain : public Module db << " " << NickCoreFlags[j].Name; db << endl; } - if (!nc->memos.memos.empty()) + MemoInfo *mi = &nc->memos; + for (unsigned k = 0, end = mi->memos.size(); k < end; ++k) { - MemoInfo *mi = &nc->memos; - for (unsigned k = 0, end = mi->memos.size(); k < end; ++k) - { - db << "MD MI " << mi->memos[k]->time << " " << mi->memos[k]->sender; - if (mi->memos[k]->HasFlag(MF_UNREAD)) - db << " UNREAD"; - if (mi->memos[k]->HasFlag(MF_RECEIPT)) - db << " RECEIPT"; - if (mi->memos[k]->HasFlag(MF_NOTIFYS)) - db << " NOTIFYS"; - db << " :" << mi->memos[k]->text << endl; - } + db << "MD MI " << mi->memos[k]->time << " " << mi->memos[k]->sender; + if (mi->memos[k]->HasFlag(MF_UNREAD)) + db << " UNREAD"; + if (mi->memos[k]->HasFlag(MF_RECEIPT)) + db << " RECEIPT"; + if (mi->memos[k]->HasFlag(MF_NOTIFYS)) + db << " NOTIFYS"; + db << " :" << mi->memos[k]->text << endl; } + for (unsigned k = 0, end = mi->ignores.size(); k < end; ++k) + db << "MD MIG " << Anope::string(mi->ignores[k]) << endl; FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, nc)); } @@ -1030,22 +1033,20 @@ class DBPlain : public Module db << "MD MLP " << cm->NameAsString << " " << Param << endl; } } - if (!ci->memos.memos.empty()) + MemoInfo *memos = &ci->memos; + for (unsigned k = 0, end = memos->memos.size(); k < end; ++k) { - MemoInfo *memos = &ci->memos; - - for (unsigned k = 0, end = memos->memos.size(); k < end; ++k) - { - db << "MD MI " << memos->memos[k]->time << " " << memos->memos[k]->sender; - if (memos->memos[k]->HasFlag(MF_UNREAD)) - db << " UNREAD"; - if (memos->memos[k]->HasFlag(MF_RECEIPT)) - db << " RECEIPT"; - if (memos->memos[k]->HasFlag(MF_NOTIFYS)) - db << " NOTIFYS"; - db << " :" << memos->memos[k]->text << endl; - } + db << "MD MI " << memos->memos[k]->time << " " << memos->memos[k]->sender; + if (memos->memos[k]->HasFlag(MF_UNREAD)) + db << " UNREAD"; + if (memos->memos[k]->HasFlag(MF_RECEIPT)) + db << " RECEIPT"; + if (memos->memos[k]->HasFlag(MF_NOTIFYS)) + db << " NOTIFYS"; + db << " :" << memos->memos[k]->text << endl; } + for (unsigned k = 0, end = memos->ignores.size(); k < end; ++k) + db << "MD MIG " << Anope::string(memos->ignores[k]) << endl; if (!ci->entry_message.empty()) db << "MD ENTRYMSG :" << ci->entry_message << endl; if (ci->bi) diff --git a/modules/core/ms_ignore.cpp b/modules/core/ms_ignore.cpp new file mode 100644 index 000000000..347657437 --- /dev/null +++ b/modules/core/ms_ignore.cpp @@ -0,0 +1,117 @@ +/* MemoServ core functions + * + * (C) 2003-2010 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" + +class CommandMSIgnore : public Command +{ + public: + CommandMSIgnore() : Command("IGNORE", 1, 3) + { + } + + CommandReturn Execute(User *u, const std::vector ¶ms) + { + Anope::string channel = params[0]; + Anope::string command = (params.size() > 1 ? params[1] : ""); + Anope::string param = (params.size() > 2 ? params[2] : ""); + + if (channel[0] != '#') + { + param = command; + command = channel; + channel = u->nick; + } + + bool ischan, isforbid; + MemoInfo *mi = getmemoinfo(channel, ischan, isforbid); + if (!mi) + { + if (isforbid) + u->SendMessage(MemoServ, ischan ? CHAN_X_FORBIDDEN : NICK_X_FORBIDDEN, channel.c_str()); + else + u->SendMessage(MemoServ, ischan ? CHAN_X_NOT_REGISTERED : NICK_X_NOT_REGISTERED, channel.c_str()); + } + else if (ischan && !check_access(u, cs_findchan(channel), CA_MEMO)) + u->SendMessage(MemoServ, ACCESS_DENIED); + else if (command.equals_ci("ADD") && !param.empty()) + { + if (std::find(mi->ignores.begin(), mi->ignores.end(), param.ci_str()) == mi->ignores.end()) + { + mi->ignores.push_back(param.ci_str()); + u->SendMessage(MemoServ, MEMO_IGNORE_ADD, param.c_str()); + } + else + u->SendMessage(MemoServ, MEMO_IGNORE_ALREADY_IGNORED, param.c_str()); + } + else if (command.equals_ci("DEL") && !param.empty()) + { + std::vector::iterator it = std::find(mi->ignores.begin(), mi->ignores.end(), param.ci_str()); + + if (it != mi->ignores.end()) + { + mi->ignores.erase(it); + u->SendMessage(MemoServ, MEMO_IGNORE_DEL, param.c_str()); + } + else + u->SendMessage(MemoServ, MEMO_IGNORE_NOT_IGNORED, param.c_str()); + } + else if (command.equals_ci("LIST")) + { + if (mi->ignores.empty()) + u->SendMessage(MemoServ, MEMO_IGNORE_LIST_EMPTY); + else + { + u->SendMessage(MemoServ, MEMO_IGNORE_LIST_HEADER); + for (unsigned i = 0; i < mi->ignores.size(); ++i) + u->SendMessage(Config->s_MemoServ, " %s", mi->ignores[i].c_str()); + } + } + else + this->OnSyntaxError(u, ""); + + return MOD_CONT; + } + + bool OnHelp(User *u, const Anope::string &subcommand) + { + u->SendMessage(MemoServ, MEMO_HELP_IGNORE); + return true; + } + + void OnSyntaxError(User *u, const Anope::string &subcommand) + { + SyntaxError(MemoServ, u, "IGNORE", MEMO_IGNORE_SYNTAX); + } + + void OnServHelp(User *u) + { + u->SendMessage(MemoServ, MEMO_HELP_CMD_IGNORE); + } +}; + +class MSIgnore : public Module +{ + CommandMSIgnore commandmsignore; + + public: + MSIgnore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator) + { + this->SetAuthor("Anope"); + this->SetType(CORE); + + this->AddCommand(MemoServ, &commandmsignore); + } +}; + +MODULE_INIT(MSIgnore) diff --git a/modules/extra/db_mysql.cpp b/modules/extra/db_mysql.cpp index f6e0f8f12..fc9f47df9 100644 --- a/modules/extra/db_mysql.cpp +++ b/modules/extra/db_mysql.cpp @@ -905,6 +905,26 @@ class DBMySQL : public Module FOREACH_RESULT(I_OnDatabaseRead, OnDatabaseRead(params)); } + r = SQL->RunQuery("SELECT * FROM `anope_ns_core_metadata`"); + 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()); + } + + r = SQL->RunQuery("SELECT * FROM `anope_cs_info_metadata`"); + 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; } @@ -1073,6 +1093,36 @@ class DBMySQL : public Module } } } + else if (service == MemoServ) + { + if (command.equals_ci("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 || !check_access(u, ci, CA_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"; + + this->RunQuery("DELETE FROM `" + table + "` WHERE `" + ename + "` = '" + this->Escape(target) + "' AND `name` = 'MEMO_IGNORE'"); + for (unsigned j = 0; j < mi->ignores.size(); ++j) + this->RunQuery("INSERT INTO `" + table + "` VALUES(" + ename + ", name, value) ('" + this->Escape(target) + "', 'MEMO_IGNORE', '" + this->Escape(mi->ignores[j]) + "')"); + } + } } void OnNickAddAccess(NickCore *nc, const Anope::string &entry) diff --git a/src/language.cpp b/src/language.cpp index 3fb2beffd..7cae1e4bb 100644 --- a/src/language.cpp +++ b/src/language.cpp @@ -1605,6 +1605,20 @@ const char *const language_strings[LANG_STRING_COUNT] = { _("Nick %s doesn't have a memo from you."), /* MEMO_NO_RSEND_SELF */ _("You can not request a receipt when sending a memo to yourself."), + /* MEMO_IGNORE_SYNTAX */ + _("IGNORE [\037channel\037] {\002ADD|DEL|LIST\002} [\037entry\037]"), + /* MEMO_IGNORE_ADD */ + _("\002%s\002 added to your ignore list."), + /* MEMO_IGNORE_ALREADY_IGNORED */ + _("\002%s\002 is already on your ignore list."), + /* MEMO_IGNORE_DEL */ + _("\002%s\002 removed from your ignore list."), + /* MEMO_IGNORE_NOT_IGNORED */ + _("\002%s\002 is not on your ignore list."), + /* MEMO_IGNORE_LIST_EMPTY */ + _("Your memo ignore list is empty."), + /* MEMO_IGNORE_LIST_HEADER */ + _("Ignore list:"), /* BOT_DOES_NOT_EXIST */ _("Bot %s does not exist."), /* BOT_NOT_ASSIGNED */ @@ -4185,6 +4199,8 @@ const char *const language_strings[LANG_STRING_COUNT] = { _(" SENDALL Send a memo to all registered users"), /* MEMO_HELP_CMD_STAFF */ _(" STAFF Send a memo to all opers/admins"), + /* MEMO_HELP_CMD_IGNORE */ + _(" IGNORE Manage your memo ignore list"), /* MEMO_HELP_HEADER */ _("%S is a utility allowing IRC users to send short\n" "messages to other IRC users, whether they are online at\n" @@ -4341,6 +4357,11 @@ const char *const language_strings[LANG_STRING_COUNT] = { " \n" "Checks whether the _last_ memo you sent to nick has been read\n" "or not. Note that this does only work with nicks, not with chans."), + /* MEMO_HELP_IGNORE */ + _("Syntax: \002IGNORE [\037channek\037] {\002ADD|DEL|LIST\002} [\037entry\037]\n" + " \n" + "Allows you to ignore users by nick or host from memoing you. If someone on your\n" + "memo ignore list tries to memo you, they will not be told that you have them ignored."), /* OPER_HELP_CMD_GLOBAL */ _(" GLOBAL Send a message to all users"), /* OPER_HELP_CMD_STATS */ diff --git a/src/memoserv.cpp b/src/memoserv.cpp index ac455257f..eac54cc6d 100644 --- a/src/memoserv.cpp +++ b/src/memoserv.cpp @@ -211,6 +211,11 @@ void memo_send(User *u, const Anope::string &name, const Anope::string &text, in } else { + if (!z || z == 3) + u->SendMessage(MemoServ, MEMO_SENT, name.c_str()); + if ((!u->Account() || !u->Account()->IsServicesOper()) && mi->HasIgnore(u)) + return; + u->lastmemosend = Anope::CurTime; Memo *m = new Memo(); mi->memos.push_back(m); @@ -224,8 +229,6 @@ void memo_send(User *u, const Anope::string &name, const Anope::string &text, in /* Set receipt request flag */ if (z == 3) m->SetFlag(MF_RECEIPT); - if (!z || z == 3) - u->SendMessage(MemoServ, MEMO_SENT, name.c_str()); if (!ischan) { NickCore *nc = findnick(name)->nc; @@ -307,6 +310,14 @@ void MemoInfo::Del(Memo *memo) } } +bool MemoInfo::HasIgnore(User *u) +{ + for (unsigned i = 0; i < this->ignores.size(); ++i) + if (u->nick.equals_ci(this->ignores[i]) || (u->Account() && u->Account()->display.equals_ci(this->ignores[i])) || Anope::Match(u->GetMask(), Anope::string(this->ignores[i]))) + return true; + return false; +} + /*************************************************************************/ static bool SendMemoMail(NickCore *nc, MemoInfo *mi, Memo *m)