/* * Notification of pending expiry or expired nicks and channels * * (C) 2016 - genius3000 (genius3000@g3k.solutions) * Please refer to the GPL License in use by Anope at: * https://github.com/anope/anope/blob/master/docs/COPYING * * Runs when NickServ and ChanServ check for expired * entries. Is capable of sending Notices via email or memo * for soon to expire or expired nicknames and channels. * * The Nick and Channel Expiry defaults are the same as Anope's defaults * in the case that the config values aren't read. * Configuration to put into your modules config: module { name = "m_expirenotice" ns_notice_expiring = yes ns_notice_expired = yes ns_notice_time = 7d ns_notice_mail = yes ns_notice_memo = no cs_notice_expiring = yes cs_notice_expired = yes cs_notice_time = 3d cs_notice_mail = yes cs_notice_memo = no ns_expiring_subject = "Nickname expiring" ns_expiring_message = "Your nickname %n will expire %t. %N IRC Administration" ns_expiring_memo = "Your nickname %n will expire %t." ns_expired_subject = "Nickname expired" ns_expired_message = "Your nickname %n has expired. %N IRC Administration" ns_expired_memo = "Your nickname %n has expired." cs_expiring_subject = "Channel expiring" cs_expiring_message = "Your channel %c will expire %t. %N IRC Administration" cs_expiring_memo = "Your channel %c will expire %t." cs_expired_subject = "Channel expired" cs_expired_message = "Your channel %c has expired. %N IRC Administration" cs_expired_memo = "Your channel %c has expired." } * */ #include "module.h" static ServiceReference memoserv("MemoServService", "MemoServ"); class ExpireNotice : public Module { bool ns_notice_expiring, ns_notice_expired, ns_notice_mail, ns_notice_memo; bool cs_notice_expiring, cs_notice_expired, cs_notice_mail, cs_notice_memo; time_t ns_expire_time, ns_notice_time; time_t cs_expire_time, cs_notice_time; time_t expiretimeout; Anope::string networkname; /* We check this to prevent a race condition of sending * a memo to a currently expiring NickCore. It seems * we mess up MemoServ when we do that. */ bool AllAliasesExpiring(NickCore *nc) { for (unsigned i = 0; i < nc->aliases->size(); ++i) { NickAlias *na = nc->aliases->at(i); if (Anope::CurTime - na->last_seen < ns_expire_time) return false; } return true; } public: ExpireNotice(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, THIRD) { if (Anope::VersionMajor() < 2) throw ModuleException("Requires version 2.x.x of Anope."); if (!ModuleManager::FindModule("nickserv") && !ModuleManager::FindModule("chanserv")) throw ModuleException("Neither NickServ nor ChanServ are loaded, this module is useless!"); this->SetAuthor("genius3000"); this->SetVersion("1.0.2"); } void OnPreNickExpire(NickAlias *na, bool &expire) anope_override { // If expired, not enabled or neither notice method is enabled, we do nothing if (expire || !ns_notice_expiring || (!ns_notice_mail && !ns_notice_memo)) return; // We don't do anything with unconfirmed or no_expire nicks if (na->nc->HasExt("UNCONFIRMED") || na->HasExt("NS_NO_EXPIRE")) return; // If notice_time is set too high, make it a quarter of the expire time if (ns_notice_time >= ns_expire_time) ns_notice_time = ns_expire_time / 4; time_t expire_at = na->last_seen + ns_expire_time; time_t notice_at = expire_at - ns_notice_time; // Send notice when time is between the notice_at and the next ExpireTick // This should keep from sending multiple notices if (Anope::CurTime >= notice_at && Anope::CurTime <= notice_at + expiretimeout - 2) { if (ns_notice_mail && !na->nc->email.empty()) { Anope::string subject = Config->GetModule(this)->Get("ns_expiring_subject"), message = Config->GetModule(this)->Get("ns_expiring_message"); message = message.replace_all_cs("%n", na->nick); message = message.replace_all_cs("%t", Anope::strftime(expire_at, na->nc)); message = message.replace_all_cs("%N", networkname); Mail::Send(na->nc, subject, message); } // If the NickCore has more than one NickAlias (not all expiring right now), send a memo if (ns_notice_memo && na->nc->aliases->size() > 1 && !AllAliasesExpiring(na->nc)) { Anope::string message = Config->GetModule(this)->Get("ns_expiring_memo"); message = message.replace_all_cs("%n", na->nick); message = message.replace_all_cs("%t", Anope::strftime(expire_at, na->nc)); memoserv->Send(Config->GetClient("NickServ")->nick, na->nc->display, message, true); } } } void OnNickExpire(NickAlias *na) anope_override { // Do nothing if not enabled or neither notice method is enabled if (!ns_notice_expired || (!ns_notice_mail && ! ns_notice_memo)) return; if (ns_notice_mail && !na->nc->email.empty()) { Anope::string subject = Config->GetModule(this)->Get("ns_expired_subject"), message = Config->GetModule(this)->Get("ns_expired_message"); message = message.replace_all_cs("%n", na->nick); message = message.replace_all_cs("%N", networkname); Mail::Send(na->nc, subject, message); } // If the NickCore has more than one NickAlias (not all expiring right now), send a memo if (ns_notice_memo && na->nc->aliases->size() > 1 && !AllAliasesExpiring(na->nc)) { Anope::string message = Config->GetModule(this)->Get("ns_expired_memo"); message = message.replace_all_cs("%n", na->nick); memoserv->Send(Config->GetClient("NickServ")->nick, na->nc->display, message, true); } } void OnPreChanExpire(ChannelInfo *ci, bool &expire) anope_override { // Do nothing if expired, not enabled or neither notice method is enabled if (expire || !cs_notice_expiring || (!cs_notice_mail && !cs_notice_memo)) return; // We don't do anything with no_expire chans if (ci->HasExt("CS_NO_EXPIRE")) return; // If notice_time is set too high, make it a quarter of the expire time if (cs_notice_time >= cs_expire_time) cs_notice_time = cs_expire_time / 4; time_t expire_at = ci->last_used + cs_expire_time; time_t notice_at = expire_at - cs_notice_time; // Send notice when time is between the notice_at and the next ExpireTick // This should keep from sending multiple notices if (Anope::CurTime >= notice_at && Anope::CurTime <= notice_at + expiretimeout - 2) { NickCore *founder = ci->GetFounder(), *successor = ci->GetSuccessor(); if (cs_notice_mail) { Anope::string subject = Config->GetModule(this)->Get("cs_expiring_subject"), message = Config->GetModule(this)->Get("cs_expiring_message"); message = message.replace_all_cs("%c", ci->name); message = message.replace_all_cs("%N", networkname); if (founder && !founder->email.empty()) { message = message.replace_all_cs("%t", Anope::strftime(expire_at, founder)); Mail::Send(founder, subject, message); } if (successor && !successor->email.empty()) { message = message.replace_all_cs("%t", Anope::strftime(expire_at, successor)); Mail::Send(successor, subject, message); } } if (cs_notice_memo) { Anope::string message = Config->GetModule(this)->Get("cs_expiring_memo"); message = message.replace_all_cs("%c", ci->name); if (founder && !AllAliasesExpiring(founder)) { message = message.replace_all_cs("%t", Anope::strftime(expire_at, founder)); memoserv->Send(Config->GetClient("ChanServ")->nick, founder->display, message, true); } if (successor && !AllAliasesExpiring(successor)) { message = message.replace_all_cs("%t", Anope::strftime(expire_at, successor)); memoserv->Send(Config->GetClient("ChanServ")->nick, successor->display, message, true); } } } } void OnChanExpire(ChannelInfo *ci) anope_override { // Do nothing if not enabled or neither notice method is enabled if (!cs_notice_expired || (!cs_notice_mail && !cs_notice_memo)) return; NickCore *founder = ci->GetFounder(), *successor = ci->GetSuccessor(); if (cs_notice_mail) { Anope::string subject = Config->GetModule(this)->Get("cs_expired_subject"), message = Config->GetModule(this)->Get("cs_expired_message"); message = message.replace_all_cs("%c", ci->name); message = message.replace_all_cs("%N", networkname); if (founder && !founder->email.empty()) Mail::Send(founder, subject, message); if (successor && !successor->email.empty()) Mail::Send(successor, subject, message); } if (cs_notice_memo) { //Anope::string message = _("Your channel %n has expired!"); Anope::string message = Config->GetModule(this)->Get("cs_expired_memo"); message = message.replace_all_cs("%c", ci->name); if (founder && !AllAliasesExpiring(founder)) memoserv->Send(Config->GetClient("ChanServ")->nick, founder->display, message, true); if (successor && !AllAliasesExpiring(successor)) memoserv->Send(Config->GetClient("ChanServ")->nick, successor->display, message, true); } } void OnReload(Configuration::Conf *conf) anope_override { // Load configuration values once at Config read ns_notice_expiring = Config->GetModule(this)->Get("ns_notice_expiring", "no"); ns_notice_expired = Config->GetModule(this)->Get("ns_notice_expired", "no"); ns_notice_mail = Config->GetModule(this)->Get("ns_notice_mail", "no"); ns_notice_memo = Config->GetModule(this)->Get("ns_notice_memo", "no"); ns_notice_time = Config->GetModule(this)->Get("ns_notice_time", "7d"); ns_expire_time = Config->GetModule("nickserv")->Get("expire", "21d"); cs_notice_expiring = Config->GetModule(this)->Get("cs_notice_expiring", "no"); cs_notice_expired = Config->GetModule(this)->Get("cs_notice_expired", "no"); cs_notice_mail = Config->GetModule(this)->Get("cs_notice_mail", "no"); cs_notice_memo = Config->GetModule(this)->Get("cs_notice_memo", "no"); cs_notice_time = Config->GetModule(this)->Get("cs_notice_time", "3d"); cs_expire_time = Config->GetModule("chanserv")->Get("expire", "14d"); expiretimeout = Config->GetBlock("options")->Get("expiretimeout", "30m"); networkname = Config->GetBlock("networkinfo")->Get("networkname"); if (!Config->GetBlock("mail")->Get("usemail")) ns_notice_mail = cs_notice_mail = false; if (!memoserv) ns_notice_memo = cs_notice_memo = false; } }; MODULE_INIT(ExpireNotice)