X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/68cb9c2caacc034a857614f0576fc4cba21b7448..63c0b8ad3980b46f5c9052c1966a36ce15f6e440:/src/mod-memoserv.c diff --git a/src/mod-memoserv.c b/src/mod-memoserv.c index c800b3e..84880c2 100644 --- a/src/mod-memoserv.c +++ b/src/mod-memoserv.c @@ -6,7 +6,7 @@ * * 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, @@ -35,14 +35,16 @@ * 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" @@ -65,8 +67,9 @@ static const struct message_entry msgtab[] = { { "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 to read a message." }, - { "MSMSG_CLEAN_INBOX", "You have $b%d$b or more messages, please clean out your inbox.\nUse /msg $S READ to read a message." }, + { "MSMSG_MEMOS_FOUND", "Found $b%d$b matches." }, + { "MSMSG_HOWTO_READ", "Use READ to read a message." }, + { "MSMSG_CLEAN_INBOX", "You have $b%d$b or more messages, please clean out your inbox.\nUse READ 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" }, @@ -83,11 +86,11 @@ static const struct message_entry msgtab[] = { { "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." }, @@ -96,18 +99,24 @@ static const struct message_entry msgtab[] = { { "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 } }; @@ -138,9 +147,9 @@ struct userNode *memoserv; 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 @@ -148,10 +157,11 @@ DEFINE_LIST(historyList, struct history*); #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; @@ -175,7 +185,9 @@ extern struct string_list *autojoin_channels; 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* */ @@ -193,7 +205,7 @@ memoserv_get_account(struct handle_info *hi) 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); @@ -207,6 +219,7 @@ delete_memo(struct memo *memo) memoList_remove(&memo->sender->sent, memo); free(memo->message); free(memo); + memoCount--; } static void @@ -243,10 +256,10 @@ do_expire(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++; @@ -256,10 +269,10 @@ do_expire(void) } 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++; @@ -320,6 +333,7 @@ add_memo(time_t sent, struct memo_account *recipient, struct memo_account *sende memo->sent = sent; memo->message = strdup(message); memosSent++; + memoCount++; if (nfrom_read) history = add_history(sent, recipient, sender, memo->id); @@ -350,7 +364,7 @@ memoserv_can_send(struct userNode *bot, struct userNode *user, struct memo_accou 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; } @@ -394,13 +408,21 @@ static struct memo *find_memo(struct userNode *user, struct svccmd *cmd, struct 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; @@ -442,7 +464,20 @@ static MODCMD_FUNC(cmd_send) 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); @@ -475,8 +510,10 @@ static MODCMD_FUNC(cmd_list) 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"); @@ -534,11 +571,6 @@ static MODCMD_FUNC(cmd_read) 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 (argc > 2) { char *argtwo = argv[2]; while (*argtwo) { @@ -565,6 +597,12 @@ static MODCMD_FUNC(cmd_read) } } + 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); @@ -596,7 +634,7 @@ static MODCMD_FUNC(cmd_read) 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); } @@ -705,7 +743,7 @@ set_list(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, int { 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"); @@ -744,7 +782,7 @@ static MODCMD_FUNC(cmd_oset) MEMOSERV_MIN_PARAMS(2); - if (!(hi = get_victim_oper(cmd, user, argv[1]))) + if (!(hi = get_victim_oper(user, argv[1]))) return 0; if (argc < 3) { @@ -760,7 +798,7 @@ static MODCMD_FUNC(cmd_oset) 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; @@ -780,7 +818,30 @@ static OPTION_FUNC(opt_notify) } 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; } @@ -919,7 +980,7 @@ static MODCMD_FUNC(cmd_status) } 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; @@ -1131,9 +1192,10 @@ memoserv_write_users(struct saxdb_context *ctx, struct memo_account *ma) 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); @@ -1154,9 +1216,10 @@ memoserv_write_memos(struct saxdb_context *ctx, struct memo *memo) 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); @@ -1233,12 +1296,12 @@ memoserv_check_messages(struct userNode *user, UNUSED_ARG(struct handle_info *ol unseen++; } if (ma->recvd.used && memoserv) - if(unseen) send_message(user, memoserv, "MSMSG_MEMOS_INBOX", unseen, ma->recvd.used - unseen); + 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))) @@ -1265,7 +1328,7 @@ memoserv_init(void) 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_handle_rename_func(memoserv_rename_account, NULL); reg_unreg_func(memoserv_unreg_account); conf_register_reload(memoserv_conf_read); reg_exit_func(memoserv_cleanup); @@ -1286,7 +1349,8 @@ memoserv_init(void) 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); @@ -1316,8 +1380,12 @@ memoserv_finalize(void) { str = database_get_data(conf_node, "bot", RECDB_QSTRING); if (str) { memoserv = memoserv_conf.bot; - } else + const char *modes = conf_get_data("modules/memoserv/modes", RECDB_QSTRING); + memoserv = AddLocalUser(str, str, NULL, "User-User Memorandum Services", modes); + } else { log_module(MS_LOG, LOG_ERROR, "database_get_data for memoserv_conf.bot failed!"); + exit(1); + } if (autojoin_channels && memoserv) { for (i = 0; i < autojoin_channels->used; i++) {