diff options
| author | Adam <Adam@anope.org> | 2010-06-19 11:54:08 -0400 |
|---|---|---|
| committer | Adam <Adam@anope.org> | 2010-06-19 11:54:08 -0400 |
| commit | 52058fe87b4b0475b1775198c725af14e540d355 (patch) | |
| tree | c3597d6411a006ffbb670d2ce761101b9640e9b6 /src/core/os_news.cpp | |
| parent | 43e951aed54f838ba55a4c1552214773aee2fb2f (diff) | |
| parent | df9d291bcba9788e51d11424ebaf6f05c26cc80f (diff) | |
Merge remote branch 'origin/1.9.3' into 1.9
Diffstat (limited to 'src/core/os_news.cpp')
| -rw-r--r-- | src/core/os_news.cpp | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/src/core/os_news.cpp b/src/core/os_news.cpp new file mode 100644 index 000000000..7be0bc5f7 --- /dev/null +++ b/src/core/os_news.cpp @@ -0,0 +1,486 @@ +/* OperServ core functions + * + * (C) 2003-2010 Anope Team + * Contact us at info@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 lenof(a) (sizeof(a) / sizeof(*(a))) + +/* List of messages for each news type. This simplifies message sending. */ + +#define MSG_SYNTAX 0 +#define MSG_LIST_HEADER 1 +#define MSG_LIST_ENTRY 2 +#define MSG_LIST_NONE 3 +#define MSG_ADD_SYNTAX 4 +#define MSG_ADD_FULL 5 +#define MSG_ADDED 6 +#define MSG_DEL_SYNTAX 7 +#define MSG_DEL_NOT_FOUND 8 +#define MSG_DELETED 9 +#define MSG_DEL_NONE 10 +#define MSG_DELETED_ALL 11 +#define MSG_MAX 11 + +struct newsmsgs msgarray[] = { + {NEWS_LOGON, "LOGON", + {NEWS_LOGON_SYNTAX, + NEWS_LOGON_LIST_HEADER, + NEWS_LOGON_LIST_ENTRY, + NEWS_LOGON_LIST_NONE, + NEWS_LOGON_ADD_SYNTAX, + NEWS_LOGON_ADD_FULL, + NEWS_LOGON_ADDED, + NEWS_LOGON_DEL_SYNTAX, + NEWS_LOGON_DEL_NOT_FOUND, + NEWS_LOGON_DELETED, + NEWS_LOGON_DEL_NONE, + NEWS_LOGON_DELETED_ALL} + }, + {NEWS_OPER, "OPER", + {NEWS_OPER_SYNTAX, + NEWS_OPER_LIST_HEADER, + NEWS_OPER_LIST_ENTRY, + NEWS_OPER_LIST_NONE, + NEWS_OPER_ADD_SYNTAX, + NEWS_OPER_ADD_FULL, + NEWS_OPER_ADDED, + NEWS_OPER_DEL_SYNTAX, + NEWS_OPER_DEL_NOT_FOUND, + NEWS_OPER_DELETED, + NEWS_OPER_DEL_NONE, + NEWS_OPER_DELETED_ALL} + }, + {NEWS_RANDOM, "RANDOM", + {NEWS_RANDOM_SYNTAX, + NEWS_RANDOM_LIST_HEADER, + NEWS_RANDOM_LIST_ENTRY, + NEWS_RANDOM_LIST_NONE, + NEWS_RANDOM_ADD_SYNTAX, + NEWS_RANDOM_ADD_FULL, + NEWS_RANDOM_ADDED, + NEWS_RANDOM_DEL_SYNTAX, + NEWS_RANDOM_DEL_NOT_FOUND, + NEWS_RANDOM_DELETED, + NEWS_RANDOM_DEL_NONE, + NEWS_RANDOM_DELETED_ALL} + } +}; + +static void DisplayNews(User *u, NewsType Type) +{ + int msg; + static unsigned current_news = 0; + + if (Type == NEWS_LOGON) + msg = NEWS_LOGON_TEXT; + else if (Type == NEWS_OPER) + msg = NEWS_OPER_TEXT; + else if (Type == NEWS_RANDOM) + msg = NEWS_RANDOM_TEXT; + else + { + Alog() << "news: Invalid type (" << Type << ") to display_news()"; + return; + } + + unsigned displayed = 0; + bool NewsExists = false; + for (unsigned i = 0; i < News.size(); ++i) + { + if (News[i]->type == Type) + { + tm *tm; + char timebuf[64]; + + NewsExists = true; + + if (Type == NEWS_RANDOM && i == current_news) + continue; + + tm = localtime(&News[i]->time); + strftime_lang(timebuf, sizeof(timebuf), u, STRFTIME_SHORT_DATE_FORMAT, tm); + notice_lang(Config.s_GlobalNoticer, u, msg, timebuf, News[i]->Text.c_str()); + + ++displayed; + + if (Type == NEWS_RANDOM) + { + current_news = i; + return; + } + else if (displayed >= Config.NewsCount) + return; + } + + /* Reset to head of list to get first random news value */ + if (i + 1 == News.size() && Type == NEWS_RANDOM && NewsExists) + i = 0; + } +} + +static int add_newsitem(User * u, const char *text, NewsType type) +{ + int num = 0; + + for (unsigned i = News.size(); i > 0; --i) + { + if (News[i - 1]->type == type) + { + num = News[i - 1]->num; + break; + } + } + + NewsItem *news = new NewsItem; + news->type = type; + news->num = num + 1; + news->Text = text; + news->time = time(NULL); + news->who = u->nick; + + News.push_back(news); + + return num + 1; +} + +static int del_newsitem(unsigned num, NewsType type) +{ + int count = 0; + + for (unsigned i = News.size(); i > 0; --i) + { + if (News[i - 1]->type == type && (num == 0 || News[i - 1]->num == num)) + { + delete News[i - 1]; + News.erase(News.begin() + i - 1); + ++count; + } + } + + return count; +} + +static int *findmsgs(NewsType type, const char **type_name) +{ + for (unsigned i = 0; i < lenof(msgarray); i++) { + if (msgarray[i].type == type) { + if (type_name) + *type_name = msgarray[i].name; + return msgarray[i].msgs; + } + } + return NULL; +} + +class NewsBase : public Command +{ + protected: + CommandReturn DoList(User *u, NewsType type, int *msgs) + { + int count = 0; + char timebuf[64]; + struct tm *tm; + + for (unsigned i = 0; i < News.size(); ++i) + { + if (News[i]->type == type) + { + if (!count) + notice_lang(Config.s_OperServ, u, msgs[MSG_LIST_HEADER]); + tm = localtime(&News[i]->time); + strftime_lang(timebuf, sizeof(timebuf), u, STRFTIME_DATE_TIME_FORMAT, tm); + notice_lang(Config.s_OperServ, u, msgs[MSG_LIST_ENTRY], News[i]->num, timebuf, !News[i]->who.empty() ? News[i]->who.c_str() : "<unknown>", News[i]->Text.c_str()); + ++count; + } + } + if (!count) + notice_lang(Config.s_OperServ, u, msgs[MSG_LIST_NONE]); + else + notice_lang(Config.s_OperServ, u, END_OF_ANY_LIST, "News"); + + return MOD_CONT; + } + + CommandReturn DoAdd(User *u, const std::vector<ci::string> ¶ms, NewsType type, int *msgs) + { + const char *text = params.size() > 1 ? params[1].c_str() : NULL; + int n; + + if (!text) + this->OnSyntaxError(u, "ADD"); + else + { + if (readonly) + { + notice_lang(Config.s_OperServ, u, READ_ONLY_MODE); + return MOD_CONT; + } + n = add_newsitem(u, text, type); + if (n < 0) + notice_lang(Config.s_OperServ, u, msgs[MSG_ADD_FULL]); + else + notice_lang(Config.s_OperServ, u, msgs[MSG_ADDED], n); + } + + return MOD_CONT; + } + + CommandReturn DoDel(User *u, const std::vector<ci::string> ¶ms, NewsType type, int *msgs) + { + const char *text = params.size() > 1 ? params[1].c_str() : NULL; + unsigned num; + + if (!text) + this->OnSyntaxError(u, "DEL"); + else + { + if (readonly) + { + notice_lang(Config.s_OperServ, u, READ_ONLY_MODE); + return MOD_CONT; + } + if (stricmp(text, "ALL")) + { + num = atoi(text); + if (num > 0 && del_newsitem(num, type)) + { + notice_lang(Config.s_OperServ, u, msgs[MSG_DELETED], num); + for (unsigned i = 0; i < News.size(); ++i) + { + if (News[i]->type == type && News[i]->num > num) + --News[i]->num; + } + } + else + notice_lang(Config.s_OperServ, u, msgs[MSG_DEL_NOT_FOUND], num); + } + else + { + if (del_newsitem(0, type)) + notice_lang(Config.s_OperServ, u, msgs[MSG_DELETED_ALL]); + else + notice_lang(Config.s_OperServ, u, msgs[MSG_DEL_NONE]); + } + } + + return MOD_CONT; + } + + CommandReturn DoNews(User *u, const std::vector<ci::string> ¶ms, NewsType type) + { + ci::string cmd = params[0]; + const char *type_name; + int *msgs; + + msgs = findmsgs(type, &type_name); + if (!msgs) + { + Alog() << "news: Invalid type to do_news()"; + return MOD_CONT; + } + + if (cmd == "LIST") + return this->DoList(u, type, msgs); + else if (cmd == "ADD") + return this->DoAdd(u, params, type, msgs); + else if (cmd == "DEL") + return this->DoDel(u, params, type, msgs); + else + this->OnSyntaxError(u, ""); + + return MOD_CONT; + } + public: + NewsBase(const ci::string &newstype) : Command(newstype, 1, 2, "operserv/news") + { + } + + virtual ~NewsBase() + { + } + + virtual CommandReturn Execute(User *u, const std::vector<ci::string> ¶ms) = 0; + + virtual bool OnHelp(User *u, const ci::string &subcommand) = 0; + + virtual void OnSyntaxError(User *u, const ci::string &subcommand) = 0; +}; + +class CommandOSLogonNews : public NewsBase +{ + public: + CommandOSLogonNews() : NewsBase("LOGONNEWS") + { + } + + CommandReturn Execute(User *u, const std::vector<ci::string> ¶ms) + { + return this->DoNews(u, params, NEWS_LOGON); + } + + bool OnHelp(User *u, const ci::string &subcommand) + { + notice_help(Config.s_OperServ, u, NEWS_HELP_LOGON, Config.NewsCount); + return true; + } + + void OnSyntaxError(User *u, const ci::string &subcommand) + { + syntax_error(Config.s_OperServ, u, "LOGONNEWS", NEWS_LOGON_SYNTAX); + } + + void OnServHelp(User *u) + { + notice_lang(Config.s_OperServ, u, OPER_HELP_CMD_LOGONNEWS); + } +}; + +class CommandOSOperNews : public NewsBase +{ + public: + CommandOSOperNews() : NewsBase("OPERNEWS") + { + } + + CommandReturn Execute(User *u, const std::vector<ci::string> ¶ms) + { + return this->DoNews(u, params, NEWS_OPER); + } + + bool OnHelp(User *u, const ci::string &subcommand) + { + notice_help(Config.s_OperServ, u, NEWS_HELP_OPER, Config.NewsCount); + return true; + } + + void OnSyntaxError(User *u, const ci::string &subcommand) + { + syntax_error(Config.s_OperServ, u, "OPERNEWS", NEWS_OPER_SYNTAX); + } + + void OnServHelp(User *u) + { + notice_lang(Config.s_OperServ, u, OPER_HELP_CMD_OPERNEWS); + } +}; + +class CommandOSRandomNews : public NewsBase +{ + public: + CommandOSRandomNews() : NewsBase("RANDOMNEWS") + { + } + + CommandReturn Execute(User *u, const std::vector<ci::string> ¶ms) + { + return this->DoNews(u, params, NEWS_RANDOM); + } + + bool OnHelp(User *u, const ci::string &subcommand) + { + notice_help(Config.s_OperServ, u, NEWS_HELP_RANDOM); + return true; + } + + void OnSyntaxError(User *u, const ci::string &subcommand) + { + syntax_error(Config.s_OperServ, u, "RANDOMNEWS", NEWS_RANDOM_SYNTAX); + } + + void OnServHelp(User *u) + { + notice_lang(Config.s_OperServ, u, OPER_HELP_CMD_RANDOMNEWS); + } +}; + +class OSNews : public Module +{ + public: + OSNews(const std::string &modname, const std::string &creator) : Module(modname, creator) + { + this->SetAuthor("Anope"); + this->SetVersion(VERSION_STRING); + this->SetType(CORE); + + this->AddCommand(OperServ, new CommandOSLogonNews()); + this->AddCommand(OperServ, new CommandOSOperNews()); + this->AddCommand(OperServ, new CommandOSRandomNews()); + + Implementation i[] = { I_OnUserModeSet, I_OnUserConnect, I_OnDatabaseRead, I_OnDatabaseWrite }; + ModuleManager::Attach(i, this, 4); + } + + ~OSNews() + { + for (std::vector<NewsItem *>::iterator it = News.begin(); it != News.end(); ++it) + delete *it; + News.clear(); + } + + void OnUserModeSet(User *u, UserModeName Name) + { + if (Name == UMODE_OPER) + { + DisplayNews(u, NEWS_OPER); + } + } + + void OnUserConnect(User *u) + { + DisplayNews(u, NEWS_LOGON); + DisplayNews(u, NEWS_RANDOM); + } + + EventReturn OnDatabaseRead(const std::vector<std::string> ¶ms) + { + if (params[0] == "OS" && params.size() >= 7 && params[1] == "NEWS") + { + NewsItem *n = new NewsItem; + n->num = atoi(params[2].c_str()); + n->time = strtol(params[3].c_str(), NULL, 10); + n->who = params[4]; + if (params[5] == "LOGON") + n->type = NEWS_LOGON; + else if (params[5] == "RANDOM") + n->type = NEWS_RANDOM; + else if (params[5] == "OPER") + n->type = NEWS_OPER; + n->Text = params[6]; + News.push_back(n); + + return EVENT_STOP; + } + + return EVENT_CONTINUE; + } + + void OnDatabaseWrite(void (*Write)(const std::string &)) + { + for (std::vector<NewsItem *>::iterator it = News.begin(); it != News.end(); ++it) + { + NewsItem *n = *it; + char buf[512]; const char* ntype; + if (n->type == NEWS_LOGON) + ntype = "LOGON"; + else if (n->type == NEWS_RANDOM) + ntype = "RANDOM"; + else if (n->type == NEWS_OPER) + ntype = "OPER"; + snprintf(buf, sizeof(buf), "OS NEWS %d %ld %s %s :%s", n->num, n->time, n->who.c_str(), ntype, n->Text.c_str()); + Write(buf); + } + } +}; + +MODULE_INIT(OSNews) |
