*
* x3 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* Restart srvx with the updated conf file (as above, butwith "bot"
* "MemoServ"), and bind the commands to it:
* /msg opserv bind memoserv * *memoserv.*
- * /msg opserv bind memoserv set *modcmd.joiner
+ * /msg opserv bind memoserv set *memoserv.set
*/
#include "chanserv.h"
#include "conf.h"
#include "modcmd.h"
#include "nickserv.h"
+#include "opserv.h"
#include "saxdb.h"
+#include "mail.h"
#include "timeq.h"
#define KEY_MAIN_ACCOUNTS "accounts"
{ "MSMSG_UNKNOWN_SEND_FLAG", "Unreccognised send flag '%c', message not sent." },
{ "MSMSG_MEMO_SENT", "Message sent to $b%s$b (ID# %d)." },
{ "MSMSG_NO_MESSAGES", "You have no messages." },
- { "MSMSG_MEMOS_FOUND", "Found $b%d$b matches.\nUse /msg $S READ <ID> to read a message." },
- { "MSMSG_CLEAN_INBOX", "You have $b%d$b or more messages, please clean out your inbox.\nUse /msg $S READ <ID> to read a message." },
+ { "MSMSG_MEMOS_FOUND", "Found $b%d$b matches." },
+ { "MSMSG_HOWTO_READ", "Use READ <ID> to read a message." },
+ { "MSMSG_CLEAN_INBOX", "You have $b%d$b or more messages, please clean out your inbox.\nUse READ <ID> to read a message." },
{ "MSMSG_LIST_HEAD", "$bID$b $bFrom$b $bTime Sent$b" },
{ "MSMSG_LIST_FORMAT", "%-2u %s $b%s$b %s" },
{ "MSMSG_HISTORY_HEADER", "$bID$b $bTo$b $bTime Sent$b" },
{ "MSMSG_EXPIRY_OFF", "I am currently not expiring messages. (turned off)" },
{ "MSMSG_EXPIRY", "Messages will be expired when they are %s old (%d seconds)." },
{ "MSMSG_MESSAGES_EXPIRED", "$b%lu$b message(s) expired." },
- { "MSMSG_MEMOS_INBOX", "You have $b%d$b new message(s) in your inbox and %d old messages. Use /msg $S LIST to list them." },
- { "MSMSG_NEW_MESSAGE", "You have a new message from $b%s$b. /msg $S LIST" },
+ { "MSMSG_MEMOS_INBOX", "You have $b%d$b new message(s) in your inbox and %d old messages. Use LIST to list them." },
+ { "MSMSG_NEW_MESSAGE", "You have a new message from $b%s$b. Use LIST to see your messages." },
{ "MSMSG_FULL_INBOX", "$b%s$b cannot recieve anymore memos as their inbox is full" },
{ "MSMSG_DELETED_ALL", "Deleted all of your messages." },
- { "MSMSG_USE_CONFIRM", "Please use /msg $S DELETE * $bCONFIRM$b to delete $uall$u of your messages." },
+ { "MSMSG_USE_CONFIRM", "Please use DELETE * $bCONFIRM$b to delete $uall$u of your messages." },
{ "MSMSG_STATUS_HIST_TOTAL", "I have $b%u$b history entries in my database." },
{ "MSMSG_STATUS_TOTAL", "I have $b%u$b memos in my database." },
{ "MSMSG_INVALID_OPTION", "$b%s$b is not a valid option." },
{ "MSMSG_INVALID_BINARY", "$b%s$b is an invalid binary value." },
- { "MSMSG_SET_NOTIFY", "$bNotify: $b %s" },
- { "MSMSG_SET_AUTHNOTIFY", "$bAuthNotify: $b %s" },
- { "MSMSG_SET_PRIVATE", "$bPrivate: $b %s" },
- { "MSMSG_SET_IGNORERECIEPTS", "$bIgnoreReciepts:$b %s" },
- { "MSMSG_SET_SENDRECIEPTS", "$bSendReciepts: $b %s" },
- { "MSMSG_SET_LIMIT", "$bLimit: $b %d" },
+ { "MSMSG_SET_AUTHNOTIFY", "$bAuthNotify$b: %s" },
+ { "MSMSG_SET_NEWNOTIFY", "$bNewNotify$b: %s" },
+ { "MSMSG_SET_PRIVMSG", "$bPrivmsg$b: %s" },
+ { "MSMSG_SET_PRIVATE", "$bPrivate$b: %s" },
+ { "MSMSG_SET_IGNORERECIEPTS", "$bIgnoreReciepts$b: %s" },
+ { "MSMSG_SET_SENDRECIEPTS", "$bSendReciepts$b: %s" },
+ { "MSMSG_SET_LIMIT", "$bLimit$b: %d" },
{ "MSMSG_SET_OPTIONS", "$bMessaging Options$b" },
{ "MSMSG_SET_OPTIONS_END", "-------------End of Options-------------" },
{ "MSMSG_LIST_END", "--------------End of Memos--------------" },
{ "MSMSG_BAR", "----------------------------------------"},
+ { "MSEMAIL_NEWMEMO_SUBJECT", "New %s %s message from %s" },
+ { "MSEMAIL_NEWMEMO_BODY", "This email has been sent to let you know that %s has sent you a message via %s.\n\n The message is: %s.\n\nTo delete this message just type in /msg %s delete %d when on %s next." },
+
+ { "MSMSG_DEFCON_NO_NEW_MEMOS", "You cannot send new memos at this time, please try again soon." },
+
{ NULL, NULL }
};
unsigned long id;
};
+struct userNode *memoserv;
+
+#define MEMOSERV_FUNC(NAME) MODCMD_FUNC(NAME)
+#define MEMOSERV_SYNTAX() svccmd_send_help_brief(user, memoserv, cmd)
+#define MEMOSERV_MIN_PARAMS(N) if(argc < (N)) { \
+ reply("MSG_MISSING_PARAMS", argv[0]); \
+ MEMOSERV_SYNTAX(); \
+ return 0; }
+
DECLARE_LIST(memoList, struct memo*);
-DEFINE_LIST(memoList, struct memo*);
+DEFINE_LIST(memoList, struct memo*)
DECLARE_LIST(historyList, struct history*);
-DEFINE_LIST(historyList, struct history*);
+DEFINE_LIST(historyList, struct history*)
/* memo_account.flags fields */
#define MEMO_NOTIFY_NEW 0x00000001
#define MEMO_DENY_NONCHANNEL 0x00000004
#define MEMO_IGNORE_RECIEPTS 0x00000008
#define MEMO_ALWAYS_RECIEPTS 0x00000010
+#define MEMO_USE_PRIVMSG 0x00000020
struct memo_account {
struct handle_info *handle;
- unsigned int flags;
+ unsigned int flags : 6;
unsigned int limit;
struct memoList sent;
struct memoList recvd;
const char *memoserv_module_deps[] = { NULL };
static struct module *memoserv_module;
static struct log_type *MS_LOG;
-static unsigned long memosSent, memosExpired;
+static unsigned long memoCount;
+static unsigned long memosSent;
+static unsigned long memosExpired;
static struct dict *memos; /* memo_account->handle->handle -> memo_account */
static struct dict *historys;
static dict_t memoserv_opt_dict; /* contains option_func_t* */
if (!ma)
return ma;
ma->handle = hi;
- ma->flags = MEMO_NOTIFY_NEW | MEMO_NOTIFY_LOGIN;
+ ma->flags = MEMO_NOTIFY_NEW | MEMO_NOTIFY_LOGIN | MEMO_USE_PRIVMSG;
ma->limit = memoserv_conf.limit;
dict_insert(memos, ma->handle->handle, ma);
dict_insert(historys, ma->handle->handle, ma);
memoList_remove(&memo->sender->sent, memo);
free(memo->message);
free(memo);
+ memoCount--;
}
static void
{
dict_iterator_t it;
for (it = dict_first(memos); it; it = iter_next(it)) {
- struct memo_account *acct = iter_data(it);
+ struct memo_account *account = iter_data(it);
unsigned int ii;
- for (ii = 0; ii < acct->sent.used; ++ii) {
- struct memo *memo = acct->sent.list[ii];
+ for (ii = 0; ii < account->sent.used; ++ii) {
+ struct memo *memo = account->sent.list[ii];
if ((now - memo->sent) > memoserv_conf.message_expiry) {
delete_memo(memo);
memosExpired++;
}
for (it = dict_first(historys); it; it = iter_next(it)) {
- struct memo_account *acct = iter_data(it);
+ struct memo_account *account = iter_data(it);
unsigned int ii;
- for (ii = 0; ii < acct->hsent.used; ++ii) {
- struct history *history = acct->hsent.list[ii];
+ for (ii = 0; ii < account->hsent.used; ++ii) {
+ struct history *history = account->hsent.list[ii];
if ((now - history->sent) > memoserv_conf.message_expiry) {
delete_history(history);
memosExpired++;
add_memo(time_t sent, struct memo_account *recipient, struct memo_account *sender, char *message, int nfrom_read)
{
struct memo *memo;
- struct history *history;
memo = calloc(1, sizeof(*memo));
if (!memo)
memo->sent = sent;
memo->message = strdup(message);
memosSent++;
+ memoCount++;
if (nfrom_read)
- history = add_history(sent, recipient, sender, memo->id);
+ add_history(sent, recipient, sender, memo->id);
return memo;
}
if (acct->handle->ignores->used) {
for (i=0; i < acct->handle->ignores->used; i++) {
- if (user_matches_glob(user, acct->handle->ignores->list[i], MATCH_USENICK)) {
+ if (user_matches_glob(user, acct->handle->ignores->list[i], MATCH_USENICK, 0)) {
match = 1;
break;
}
static MODCMD_FUNC(cmd_send)
{
char *message;
- int reciept = 0, inc = 2;
+ int reciept = 0, inc = 2, email = 0;
struct handle_info *hi;
struct memo_account *ma, *sender;
struct memo *memo;
+ char subject[128], body[4096];
+ char *estr;
+ const char *netname, *fmt;
+
+ MEMOSERV_MIN_PARAMS(3);
+
+ if (checkDefCon(DEFCON_NO_NEW_MEMOS) && !IsOper(user)) {
+ reply("MSMSG_DEFCON_NO_NEW_MEMOS");
+ return 0;
+ }
if (!(hi = modcmd_get_handle_info(user, argv[1])))
return 0;
struct userNode *other;
for (other = ma->handle->users; other; other = other->next_authed)
- send_message(other, cmd->parent->bot, "MSMSG_NEW_MESSAGE", user->nick);
+ send_message_type((ma->flags & MEMO_USE_PRIVMSG)? MSG_TYPE_PRIVMSG : MSG_TYPE_NOTICE, other, memoserv ? memoserv : cmd->parent->bot, "MSMSG_NEW_MESSAGE", user->nick);
+ }
+
+ estr = conf_get_data("services/nickserv/email_enabled", RECDB_QSTRING);
+ netname = conf_get_data("server/network", RECDB_QSTRING);
+ email = atoi(estr);
+ if (email && (ma->flags & MEMO_NOTIFY_NEW)) {
+ fmt = handle_find_message(hi, "MSEMAIL_NEWMEMO_SUBJECT");
+ snprintf(subject, sizeof(subject), fmt, netname, memoserv->nick, user->nick);
+
+ fmt = handle_find_message(hi, "MSEMAIL_NEWMEMO_BODY");
+ snprintf(body, sizeof(body), fmt, user->nick, memoserv->nick, message, memoserv->nick, memo_id, netname);
+
+ mail_send(memoserv, hi, subject, body, 0);
}
reply("MSMSG_MEMO_SENT", ma->handle->handle, memo_id);
reply("MSG_NONE");
else if (ii == 15)
reply("MSMSG_CLEAN_INBOX", ii);
- else
+ else {
reply("MSMSG_MEMOS_FOUND", ii);
+ reply("MSMSG_HOWTO_READ");
+ }
reply("MSMSG_LIST_END");
char posted[24];
struct tm tm;
- if (!(ma = memoserv_get_account(user->handle_info)))
- return 0;
- if (!(memo = find_memo(user, cmd, ma, argv[1], &memoid)))
- return 0;
-
- if (argv[2]) {
+ if (argc > 2) {
char *argtwo = argv[2];
while (*argtwo) {
switch (*argtwo) {
}
}
+ if (!(ma = memoserv_get_account(user->handle_info)))
+ return 0;
+
+ if (!(memo = find_memo(user, cmd, ma, argv[1], &memoid)))
+ return 0;
+
localtime_r(&memo->sent, &tm);
strftime(posted, sizeof(posted), "%I:%M %p, %m/%d/%Y", &tm);
struct userNode *other;
for (other = sender->handle->users; other; other = other->next_authed)
- send_message(other, cmd->parent->bot, "MSMSG_NEW_MESSAGE", ma->handle->handle);
+ send_message_type((ma->flags & MEMO_USE_PRIVMSG)? MSG_TYPE_PRIVMSG : MSG_TYPE_NOTICE, other, cmd->parent->bot, "MSMSG_NEW_MESSAGE", ma->handle->handle);
}
struct memo *memo;
unsigned int memoid;
+ MEMOSERV_MIN_PARAMS(2);
+
if (!(ma = memoserv_get_account(user->handle_info)))
return 0;
if (!irccasecmp(argv[1], "*") || !irccasecmp(argv[1], "all")) {
struct memo *memo;
struct memo_account *ma;
+ MEMOSERV_MIN_PARAMS(2);
+
if (isdigit(argv[1][0])) {
id = strtoul(argv[1], NULL, 0);
} else {
{
option_func_t *opt;
unsigned int i;
- char *set_display[] = {"AUTHNOTIFY", "NOTIFY", "PRIVATE", "LIMIT",
+ char *set_display[] = {"AUTHNOTIFY", "NEWNOTIFY", "PRIVMSG", "PRIVATE", "LIMIT",
"IGNORERECIEPTS", "SENDRECIEPTS"};
reply("MSMSG_SET_OPTIONS");
struct handle_info *hi;
option_func_t *opt;
- if (!(hi = get_victim_oper(cmd, user, argv[1])))
+ MEMOSERV_MIN_PARAMS(2);
+
+ if (!(hi = get_victim_oper(user, argv[1])))
return 0;
if (argc < 3) {
return opt(cmd, user, hi, 1, argc-2, argv+2);
}
-static OPTION_FUNC(opt_notify)
+static OPTION_FUNC(opt_newnotify)
{
struct memo_account *ma;
char *choice;
}
choice = (ma->flags & MEMO_NOTIFY_NEW) ? "on" : "off";
- reply("MSMSG_SET_NOTIFY", choice);
+ reply("MSMSG_SET_NEWNOTIFY", choice);
+ return 1;
+}
+
+static OPTION_FUNC(opt_privmsg)
+{
+ struct memo_account *ma;
+ char *choice;
+
+ if (!(ma = memoserv_get_account(hi)))
+ return 0;
+ if (argc > 1) {
+ choice = argv[1];
+ if (enabled_string(choice)) {
+ ma->flags |= MEMO_USE_PRIVMSG;
+ } else if (disabled_string(choice)) {
+ ma->flags &= ~MEMO_USE_PRIVMSG;
+ } else {
+ reply("MSMSG_INVALID_BINARY", choice);
+ return 0;
+ }
+ }
+ choice = (ma->flags & MEMO_USE_PRIVMSG) ? "on" : "off";
+ reply("MSMSG_SET_PRIVMSG", choice);
return 1;
}
}
reply("MSMSG_STATUS_HIST_TOTAL", hc);
- reply("MSMSG_STATUS_TOTAL", mc);
+ reply("MSMSG_STATUS_TOTAL", memoCount);
reply("MSMSG_STATUS_EXPIRED", memosExpired);
reply("MSMSG_STATUS_SENT", memosSent);
return 1;
{
char *str;
struct handle_info *sender, *recipient;
- struct history *history;
unsigned long id;
time_t sent;
return 0;
}
- history = add_history(sent, memoserv_get_account(recipient), memoserv_get_account(sender), id);
+ add_history(sent, memoserv_get_account(recipient), memoserv_get_account(sender), id);
return 0;
}
static int
memoserv_write_memos(struct saxdb_context *ctx, struct memo *memo)
{
- char str[7];
+ char str[20];
- saxdb_start_record(ctx, inttobase64(str, memo->id, sizeof(str)), 0);
+ memset(str, '\0', sizeof(str));
+ saxdb_start_record(ctx, inttobase64(str, memo->id, sizeof(str)-1), 0);
saxdb_write_int(ctx, KEY_SENT, memo->sent);
saxdb_write_int(ctx, KEY_ID, memo->id);
static int
memoserv_write_history(struct saxdb_context *ctx, struct history *history)
{
- char str[7];
+ char str[20];
- saxdb_start_record(ctx, inttobase64(str, history->id, sizeof(str)), 0);
+ memset(str, '\0', sizeof(str));
+ saxdb_start_record(ctx, inttobase64(str, history->id, sizeof(str)-1), 0);
saxdb_write_int(ctx, KEY_SENT, history->sent);
saxdb_write_int(ctx, KEY_ID, history->id);
}
static void
-memoserv_cleanup(void)
+memoserv_cleanup(UNUSED_ARG(void *extra))
{
dict_delete(memos);
dict_delete(historys);
}
static void
-memoserv_check_messages(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
+memoserv_check_messages(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle), UNUSED_ARG(void *extra))
{
unsigned int ii, unseen;
struct memo_account *ma;
if (!memo->is_read)
unseen++;
}
- if (ma->recvd.used && memoserv_conf.bot)
- if(unseen) send_message(user, memoserv_conf.bot, "MSMSG_MEMOS_INBOX", unseen, ma->recvd.used - unseen);
+ if (ma->recvd.used && memoserv)
+ if(unseen) send_message_type((ma->flags & MEMO_USE_PRIVMSG)? 1 : 0, user, memoserv, "MSMSG_MEMOS_INBOX", unseen, ma->recvd.used - unseen);
}
}
static void
-memoserv_rename_account(struct handle_info *hi, const char *old_handle)
+memoserv_rename_account(struct handle_info *hi, const char *old_handle, UNUSED_ARG(void *extra))
{
struct memo_account *ma;
if (!(ma = dict_find(memos, old_handle, NULL)))
}
static void
-memoserv_unreg_account(UNUSED_ARG(struct userNode *user), struct handle_info *handle)
+memoserv_unreg_account(UNUSED_ARG(struct userNode *user), struct handle_info *handle, UNUSED_ARG(void *extra))
{
dict_remove(memos, handle->handle);
dict_remove(historys, handle->handle);
memos = dict_new();
historys = dict_new();
dict_set_free_data(memos, delete_memo_account);
- reg_auth_func(memoserv_check_messages);
- reg_handle_rename_func(memoserv_rename_account);
- reg_unreg_func(memoserv_unreg_account);
+ reg_auth_func(memoserv_check_messages, NULL);
+ reg_handle_rename_func(memoserv_rename_account, NULL);
+ reg_unreg_func(memoserv_unreg_account, NULL);
conf_register_reload(memoserv_conf_read);
- reg_exit_func(memoserv_cleanup);
+ reg_exit_func(memoserv_cleanup, NULL);
saxdb_register("MemoServ", memoserv_saxdb_read, memoserv_saxdb_write);
memoserv_module = module_register("MemoServ", MS_LOG, "mod-memoserv.help", NULL);
memoserv_opt_dict = dict_new();
dict_insert(memoserv_opt_dict, "AUTHNOTIFY", opt_authnotify);
- dict_insert(memoserv_opt_dict, "NOTIFY", opt_notify);
+ dict_insert(memoserv_opt_dict, "NEWNOTIFY", opt_newnotify);
+ dict_insert(memoserv_opt_dict, "PRIVMSG", opt_privmsg);
dict_insert(memoserv_opt_dict, "PRIVATE", opt_private);
dict_insert(memoserv_opt_dict, "IGNORERECIEPTS", opt_ignorereciepts);
dict_insert(memoserv_opt_dict, "SENDRECIEPTS", opt_sendreciepts);
}
str = database_get_data(conf_node, "bot", RECDB_QSTRING);
- if (str)
- memoserv_conf.bot = GetUserH(str);
- else
+ if (str) {
+ memoserv = memoserv_conf.bot;
+ const char *modes = conf_get_data("modules/memoserv/modes", RECDB_QSTRING);
+ memoserv = AddLocalUser(str, str, NULL, "User-User Memorandum Services", modes);
+ service_register(memoserv);
+ } else {
log_module(MS_LOG, LOG_ERROR, "database_get_data for memoserv_conf.bot failed!");
+ exit(1);
+ }
- if (autojoin_channels && memoserv_conf.bot) {
+ if (autojoin_channels && memoserv) {
for (i = 0; i < autojoin_channels->used; i++) {
chan = AddChannel(autojoin_channels->list[i], now, "+nt", NULL, NULL);
- AddChannelUser(memoserv_conf.bot, chan)->modes |= MODE_CHANOP;
+ AddChannelUser(memoserv, chan)->modes |= MODE_CHANOP;
}
}