memoserv.cpp

Go to the documentation of this file.
00001 /* MemoServ core functions
00002  *
00003  * (C) 2003-2012 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 #include "memoserv.h"
00016 
00017 static bool SendMemoMail(NickCore *nc, MemoInfo *mi, Memo *m)
00018 {
00019         Anope::string subject = translate(nc, Config->MailMemoSubject.c_str());
00020         Anope::string message = translate(nc, Config->MailMemoMessage.c_str());
00021 
00022         subject = subject.replace_all_cs("%n", nc->display);
00023         subject = subject.replace_all_cs("%s", m->sender);
00024         subject = subject.replace_all_cs("%d", mi->GetIndex(m));
00025         subject = subject.replace_all_cs("%t", m->text);
00026 
00027         message = message.replace_all_cs("%n", nc->display);
00028         message = message.replace_all_cs("%s", m->sender);
00029         message = message.replace_all_cs("%d", mi->GetIndex(m));
00030         message = message.replace_all_cs("%t", m->text);
00031 
00032         return Mail(nc, subject, message);
00033 }
00034 
00035 class MyMemoServService : public MemoServService
00036 {
00037  public:
00038         MyMemoServService(Module *m) : MemoServService(m) { }
00039 
00040         MemoInfo *GetMemoInfo(const Anope::string &target, bool &ischan) anope_override
00041         {
00042                 if (!target.empty() && target[0] == '#')
00043                 {
00044                         ischan = true;
00045                         ChannelInfo *ci = cs_findchan(target);
00046                         if (ci != NULL)
00047                                 return &ci->memos;
00048                 }
00049                 else
00050                 {
00051                         ischan = false;
00052                         NickAlias *na = findnick(target);
00053                         if (na != NULL)
00054                                 return &na->nc->memos;
00055                 }
00056 
00057                 return NULL;
00058         }
00059 
00060         MemoResult Send(const Anope::string &source, const Anope::string &target, const Anope::string &message, bool force) anope_override
00061         {
00062                 bool ischan;
00063                 MemoInfo *mi = this->GetMemoInfo(target, ischan);
00064 
00065                 if (mi == NULL)
00066                         return MEMO_INVALID_TARGET;
00067 
00068                 User *sender = finduser(source);
00069                 if (sender != NULL && !sender->HasPriv("memoserv/no-limit") && !force)
00070                 {
00071                         if (Config->MSSendDelay > 0 && sender->lastmemosend + Config->MSSendDelay > Anope::CurTime)
00072                                 return MEMO_TOO_FAST;
00073                         else if (!mi->memomax)
00074                                 return MEMO_TARGET_FULL;
00075                         else if (mi->memomax > 0 && mi->memos->size() >= static_cast<unsigned>(mi->memomax))
00076                                 return MEMO_TARGET_FULL;
00077                         else if (mi->HasIgnore(sender))
00078                                 return MEMO_SUCCESS;
00079                 }
00080 
00081                 if (sender != NULL)
00082                         sender->lastmemosend = Anope::CurTime;
00083 
00084                 Memo *m = new Memo();
00085                 mi->memos->push_back(m);
00086                 m->owner = target;
00087                 m->sender = source;
00088                 m->time = Anope::CurTime;
00089                 m->text = message;
00090                 m->SetFlag(MF_UNREAD);
00091 
00092                 FOREACH_MOD(I_OnMemoSend, OnMemoSend(source, target, mi, m));
00093 
00094                 if (ischan)
00095                 {
00096                         ChannelInfo *ci = cs_findchan(target);
00097 
00098                         if (ci->c)
00099                         {
00100                                 for (CUserList::iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end; ++it)
00101                                 {
00102                                         UserContainer *cu = *it;
00103 
00104                                         if (ci->AccessFor(cu->user).HasPriv("MEMO"))
00105                                         {
00106                                                 if (cu->user->Account() && cu->user->Account()->HasFlag(NI_MEMO_RECEIVE))
00107                                                         cu->user->SendMessage(findbot(Config->MemoServ), MEMO_NEW_X_MEMO_ARRIVED, ci->name.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), ci->name.c_str(), mi->memos->size());
00108                                         }
00109                                 }
00110                         }
00111                 }
00112                 else
00113                 {
00114                         NickCore *nc = findnick(target)->nc;
00115 
00116                         if (nc->HasFlag(NI_MEMO_RECEIVE))
00117                         {
00118                                 for (std::list<serialize_obj<NickAlias> >::const_iterator it = nc->aliases.begin(), it_end = nc->aliases.end(); it != it_end;)
00119                                 {
00120                                         const NickAlias *na = *it++;
00121                                         if (!na)
00122                                                 continue;
00123                                         User *user = finduser(na->nick);
00124                                         if (user && user->IsIdentified())
00125                                                 user->SendMessage(findbot(Config->MemoServ), MEMO_NEW_MEMO_ARRIVED, source.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), mi->memos->size());
00126                                 }
00127                         }
00128 
00129                         /* let's get out the mail if set in the nickcore - certus */
00130                         if (nc->HasFlag(NI_MEMO_MAIL))
00131                                 SendMemoMail(nc, mi, m);
00132                 }
00133 
00134                 return MEMO_SUCCESS;
00135         }
00136 
00137         void Check(User *u)
00138         {
00139                 const NickCore *nc = u->Account();
00140                 if (!nc)
00141                         return;
00142                 const BotInfo *ms = findbot(Config->MemoServ);
00143 
00144                 unsigned i = 0, end = nc->memos.memos->size(), newcnt = 0;
00145                 for (; i < end; ++i)
00146                         if (nc->memos.GetMemo(i)->HasFlag(MF_UNREAD))
00147                                 ++newcnt;
00148                 if (newcnt > 0)
00149                         u->SendMessage(ms, newcnt == 1 ? _("You have 1 new memo.") : _("You have %d new memos."), newcnt);
00150                 if (nc->memos.memomax > 0 && nc->memos.memos->size() >= static_cast<unsigned>(nc->memos.memomax))
00151                 {
00152                         if (nc->memos.memos->size() > static_cast<unsigned>(nc->memos.memomax))
00153                                 u->SendMessage(ms, _("You are over your maximum number of memos (%d). You will be unable to receive any new memos until you delete some of your current ones."), nc->memos.memomax);
00154                         else
00155                                 u->SendMessage(ms, _("You have reached your maximum number of memos (%d). You will be unable to receive any new memos until you delete some of your current ones."), nc->memos.memomax);
00156                 }
00157         }
00158 };
00159 
00160 class MemoServCore : public Module
00161 {
00162         MyMemoServService mymemoserv;
00163  public:
00164         MemoServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00165                 mymemoserv(this)
00166         {
00167                 this->SetAuthor("Anope");
00168 
00169                 if (!findbot(Config->MemoServ))
00170                         throw ModuleException("No bot named " + Config->MemoServ);
00171 
00172                 Implementation i[] = { I_OnNickIdentify, I_OnJoinChannel, I_OnUserAway, I_OnNickUpdate, I_OnPreHelp, I_OnPostHelp };
00173                 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00174         }
00175 
00176         void OnNickIdentify(User *u) anope_override
00177         {
00178                 this->mymemoserv.Check(u);
00179         }
00180 
00181         void OnJoinChannel(User *u, Channel *c) anope_override
00182         {
00183                 if (c->ci && c->ci->AccessFor(u).HasPriv("MEMO") && c->ci->memos.memos->size() > 0)
00184                 {
00185                         if (c->ci->memos.memos->size() == 1)
00186                                 u->SendMessage(findbot(Config->MemoServ), _("There is \002%d\002 memo on channel %s."), c->ci->memos.memos->size(), c->ci->name.c_str());
00187                         else
00188                                 u->SendMessage(findbot(Config->MemoServ), _("There are \002%d\002 memos on channel %s."), c->ci->memos.memos->size(), c->ci->name.c_str());
00189                 }
00190         }
00191 
00192         void OnUserAway(User *u, const Anope::string &message) anope_override
00193         {
00194                 if (message.empty())
00195                         this->mymemoserv.Check(u);
00196         }
00197 
00198         void OnNickUpdate(User *u) anope_override
00199         {
00200                 this->mymemoserv.Check(u);
00201         }
00202 
00203         EventReturn OnPreHelp(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00204         {
00205                 if (!params.empty() || source.c || source.service->nick != Config->MemoServ)
00206                         return EVENT_CONTINUE;
00207                 source.Reply(_("\002%s\002 is a utility allowing IRC users to send short\n"
00208                         "messages to other IRC users, whether they are online at\n"
00209                         "the time or not, or to channels(*). Both the sender's\n"
00210                         "nickname and the target nickname or channel must be\n"
00211                         "registered in order to send a memo.\n"
00212                         "%s's commands include:"), Config->MemoServ.c_str(), Config->MemoServ.c_str());
00213                 return EVENT_CONTINUE;
00214         }
00215 
00216         void OnPostHelp(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00217         {
00218                 if (!params.empty() || source.c || source.service->nick != Config->MemoServ)
00219                         return;
00220                 source.Reply(_(" \n"
00221                         "Type \002%s%s HELP \037command\037\002 for help on any of the\n"
00222                         "above commands.\n"
00223                         "(*) By default, any user with at least level 10 access on a\n"
00224                         "    channel can read that channel's memos. This can be\n"
00225                         "    changed with the %s \002LEVELS\002 command."), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), Config->ChanServ.c_str());
00226         }
00227 };
00228 
00229 MODULE_INIT(MemoServCore)
00230