X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/cbc5a1a4c23e241419fad790aef8dcb5eaca9b60..3f5b88017d6667911c6a82a82ffd3f967690347e:/src/mod-memoserv.c diff --git a/src/mod-memoserv.c b/src/mod-memoserv.c index caf1043..8bbf67f 100644 --- a/src/mod-memoserv.c +++ b/src/mod-memoserv.c @@ -49,6 +49,7 @@ #define KEY_FLAGS "flags" #define KEY_LIMIT "limit" +#define KEY_MAIN_HISTORY "history" #define KEY_MAIN_MEMOS "memos" #define KEY_SENT "sent" #define KEY_RECIPIENT "to" @@ -58,8 +59,10 @@ #define KEY_RECIEPT "reciept" #define KEY_ID "id" + static const struct message_entry msgtab[] = { { "MSMSG_CANNOT_SEND", "You cannot send to account $b%s$b." }, + { "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." }, @@ -86,6 +89,7 @@ static const struct message_entry msgtab[] = { { "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_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_STATUS_EXPIRED", "$b%ld$b memos expired during the time I am awake." }, { "MSMSG_STATUS_SENT", "$b%ld$b memos have been sent." }, @@ -117,8 +121,17 @@ struct memo { unsigned int reciept : 1; }; +struct history { + struct memo_account *recipient; + struct memo_account *sender; + time_t sent; + unsigned long id; +}; + DECLARE_LIST(memoList, struct memo*); DEFINE_LIST(memoList, struct memo*); +DECLARE_LIST(historyList, struct history*); +DEFINE_LIST(historyList, struct history*); /* memo_account.flags fields */ #define MEMO_NOTIFY_NEW 0x00000001 @@ -133,6 +146,8 @@ struct memo_account { unsigned int limit; struct memoList sent; struct memoList recvd; + struct historyList hsent; + struct historyList hrecvd; }; static struct { @@ -153,6 +168,7 @@ static struct module *memoserv_module; static struct log_type *MS_LOG; static unsigned long memosSent, 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* */ static struct memo_account * @@ -171,6 +187,7 @@ memoserv_get_account(struct handle_info *hi) ma->flags = MEMO_NOTIFY_NEW | MEMO_NOTIFY_LOGIN; ma->limit = memoserv_conf.limit; dict_insert(memos, ma->handle->handle, ma); + dict_insert(historys, ma->handle->handle, ma); return ma; } @@ -183,6 +200,14 @@ delete_memo(struct memo *memo) free(memo); } +static void +delete_history(struct history *history) +{ + historyList_remove(&history->recipient->hrecvd, history); + historyList_remove(&history->sender->hsent, history); + free(history); +} + static void delete_memo_account(void *data) { @@ -194,6 +219,13 @@ delete_memo_account(void *data) delete_memo(ma->sent.list[0]); memoList_clean(&ma->recvd); memoList_clean(&ma->sent); + + while (ma->hrecvd.used) + delete_history(ma->hrecvd.list[0]); + while (ma->hsent.used) + delete_history(ma->hsent.list[0]); + historyList_clean(&ma->hrecvd); + historyList_clean(&ma->hsent); free(ma); } @@ -213,6 +245,19 @@ do_expire(void) } } } + + for (it = dict_first(historys); it; it = iter_next(it)) { + struct memo_account *acct = iter_data(it); + unsigned int ii; + for (ii = 0; ii < acct->hsent.used; ++ii) { + struct history *history = acct->hsent.list[ii]; + if ((now - history->sent) > memoserv_conf.message_expiry) { + delete_history(history); + memosExpired++; + ii--; + } + } + } } static void @@ -224,10 +269,31 @@ expire_memos(UNUSED_ARG(void *data)) } } +static struct history* +add_history(time_t sent, struct memo_account *recipient, struct memo_account *sender, unsigned long id) +{ + struct history *history; + + history = calloc(1, sizeof(*history)); + if (!history) + return NULL; + + history->id = id; + history->recipient = recipient; + historyList_append(&recipient->hrecvd, history); + history->sender = sender; + historyList_append(&sender->hsent, history); + history->sent = sent; + + return history; +} + + static struct memo* 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) @@ -245,6 +311,10 @@ add_memo(time_t sent, struct memo_account *recipient, struct memo_account *sende memo->sent = sent; memo->message = strdup(message); memosSent++; + + if (nfrom_read) + history = add_history(sent, recipient, sender, memo->id); + return memo; } @@ -253,6 +323,7 @@ memoserv_can_send(struct userNode *bot, struct userNode *user, struct memo_accou { extern struct userData *_GetChannelUser(struct chanData *channel, struct handle_info *handle, int override, int allow_suspended); struct userData *dest; + unsigned int i = 0, match = 0; if (!user->handle_info) return 0; @@ -268,6 +339,20 @@ memoserv_can_send(struct userNode *bot, struct userNode *user, struct memo_accou return 0; } + 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)) { + match = 1; + break; + } + } + + if (match) { + send_message(user, bot, "MSMSG_CANNOT_SEND", acct->handle->handle); + return 0; + } + } + if (!(acct->flags & MEMO_DENY_NONCHANNEL)) return 1; @@ -300,7 +385,6 @@ static struct memo *find_memo(struct userNode *user, struct svccmd *cmd, struct static MODCMD_FUNC(cmd_send) { char *message; - int s = 0, brk = 0; int reciept = 0, inc = 2; struct handle_info *hi; struct memo_account *ma, *sender; @@ -318,33 +402,25 @@ static MODCMD_FUNC(cmd_send) if (!(memoserv_can_send(cmd->parent->bot, user, ma))) return 0; - char *flags = argv[2]; - while (*flags) { - switch (*flags) { - case '-': - if (s != 0) - brk = 1; - break; - - case 'r': - if (s > 0) + inc = 2; /* Start of message on 3rd ([2]) word */ + if(argv[2][0] == '-' && argv[2][1] != '-') { /* first word is flags ('-r')*/ + char *flags = argv[2]; + inc++; /* Start of message is now 1 word later */ + for(flags++;*flags;flags++) { + switch (*flags) { + case 'r': reciept = 1; break; default: - break; - } - - if (brk == 1) - break; - else { - s++; - flags++; + /* Unknown mode. Give an error */ + reply("MSMSG_UNKNOWN_SEND_FLAG", *flags); + return 0; + } } } - - if (s > 0) - inc = 3; + else + inc = 2; /* Start of message is word 2 */ message = unsplit_string(argv + inc, argc - inc, NULL); memo = add_memo(now, ma, sender, message, 1); @@ -399,7 +475,7 @@ static MODCMD_FUNC(cmd_list) static MODCMD_FUNC(cmd_history) { struct memo_account *ma; - struct memo *memo; + struct history *history; dict_iterator_t it; unsigned int ii = 0; unsigned int cc = 0; @@ -414,15 +490,15 @@ static MODCMD_FUNC(cmd_history) if(user->handle_info && user->handle_info->userlist_style != HI_STYLE_CLEAN) reply("MSMSG_BAR"); - for (it = dict_first(memos); it; it = iter_next(it)) { + for (it = dict_first(historys); it; it = iter_next(it)) { ma = iter_data(it); - for (ii = 0; ii < ma->recvd.used; ++ii) { - memo = ma->recvd.list[ii]; - if (!strcasecmp(memo->sender->handle->handle, user->handle_info->handle)) { + for (ii = 0; ii < ma->hrecvd.used; ++ii) { + history = ma->hrecvd.list[ii]; + if (!strcasecmp(history->sender->handle->handle, user->handle_info->handle)) { cc++; - localtime_r(&memo->sent, &tm); + localtime_r(&history->sent, &tm); strftime(posted, sizeof(posted), "%I:%M %p, %m/%d/%Y", &tm); - reply("MSMSG_HISTORY_FORMAT", memo->id, memo->sender->handle->handle, posted); + reply("MSMSG_HISTORY_FORMAT", history->id, history->recipient->handle->handle, posted); } } } @@ -443,6 +519,7 @@ static MODCMD_FUNC(cmd_read) unsigned int memoid; int rignore = 0, brk = 0, s = 0; struct memo *memo; + struct memo *memob; char posted[24]; struct tm tm; @@ -483,6 +560,7 @@ static MODCMD_FUNC(cmd_read) reply("MSMSG_MEMO_HEAD", memoid, memo->sender->handle->handle, posted); send_message_type(4, user, cmd->parent->bot, "%s", memo->message); memo->is_read = 1; + memob = memo; if (ma->flags & MEMO_IGNORE_RECIEPTS) rignore = 1; @@ -501,7 +579,7 @@ static MODCMD_FUNC(cmd_read) sprintf(content, "%s has read your memo dated %s.", ma->handle->handle, posted); memo = add_memo(now, sender, ma, content, 1); - reply("MSMSG_MEMO_SENT", memo->sender->handle, memo_id); + reply("MSMSG_MEMO_SENT", memob->sender->handle->handle, memo_id); if (sender->flags & MEMO_NOTIFY_NEW) { struct userNode *other; @@ -806,7 +884,25 @@ static OPTION_FUNC(opt_limit) static MODCMD_FUNC(cmd_status) { - reply("MSMSG_STATUS_TOTAL", dict_size(memos)); + struct memo_account *ma; + dict_iterator_t it; + int mc = 0, hc = 0; + unsigned int ii; + + for (it = dict_first(memos); it; it = iter_next(it)) { + ma = iter_data(it); + for (ii = 0; ii < ma->recvd.used; ++ii) + mc++; + } + + for (it = dict_first(historys); it; it = iter_next(it)) { + ma = iter_data(it); + for (ii = 0; ii < ma->hrecvd.used; ++ii) + hc++; + } + + reply("MSMSG_STATUS_HIST_TOTAL", hc); + reply("MSMSG_STATUS_TOTAL", mc); reply("MSMSG_STATUS_EXPIRED", memosExpired); reply("MSMSG_STATUS_SENT", memosSent); return 1; @@ -825,7 +921,7 @@ memoserv_conf_read(void) } str = database_get_data(conf_node, "limit", RECDB_QSTRING); - memoserv_conf.limit = atoi(str) ? : 50; + memoserv_conf.limit = str ? atoi(str) : 50; str = database_get_data(conf_node, "message_expiry", RECDB_QSTRING); memoserv_conf.message_expiry = str ? ParseInterval(str) : 60*24*30; @@ -867,6 +963,7 @@ memoserv_user_read(const char *key, struct record_data *hir) ma->limit = strtoul(str, NULL, 0); dict_insert(memos, ma->handle->handle, ma); + dict_insert(historys, ma->handle->handle, ma); return 0; } @@ -933,6 +1030,54 @@ memoserv_memo_read(const char *key, struct record_data *hir) return 0; } +static int +memoserv_history_read(const char *key, struct record_data *hir) +{ + char *str; + struct handle_info *sender, *recipient; + struct history *history; + unsigned long id; + time_t sent; + + if (hir->type != RECDB_OBJECT) { + log_module(MS_LOG, LOG_WARNING, "Unexpected rectype %d for %s.", hir->type, key); + return 0; + } + + if (!(str = database_get_data(hir->d.object, KEY_SENT, RECDB_QSTRING))) { + log_module(MS_LOG, LOG_ERROR, "Date sent not present in history %s; skipping", key); + return 0; + } + + sent = atoi(str); + + if (!(str = database_get_data(hir->d.object, KEY_ID, RECDB_QSTRING))) { + log_module(MS_LOG, LOG_ERROR, "ID sent not present in history %s; skipping", key); + return 0; + } + id = strtoul(str, NULL, 0); + + if (!(str = database_get_data(hir->d.object, KEY_RECIPIENT, RECDB_QSTRING))) { + log_module(MS_LOG, LOG_ERROR, "Recipient not present in history %s; skipping", key); + return 0; + } else if (!(recipient = get_handle_info(str))) { + log_module(MS_LOG, LOG_ERROR, "Invalid recipient %s in history %s; skipping", str, key); + return 0; + } + + if (!(str = database_get_data(hir->d.object, KEY_FROM, RECDB_QSTRING))) { + log_module(MS_LOG, LOG_ERROR, "Sender not present in history %s; skipping", key); + return 0; + } else if (!(sender = get_handle_info(str))) { + log_module(MS_LOG, LOG_ERROR, "Invalid sender %s in history %s; skipping", str, key); + return 0; + } + + history = add_history(sent, memoserv_get_account(recipient), memoserv_get_account(sender), id); + + return 0; +} + static int memoserv_saxdb_read(struct dict *database) { @@ -947,6 +1092,10 @@ memoserv_saxdb_read(struct dict *database) for(it = dict_first(section); it; it = iter_next(it)) memoserv_memo_read(iter_key(it), iter_data(it)); + if((section = database_get_data(database, KEY_MAIN_HISTORY, RECDB_OBJECT))) + for(it = dict_first(section); it; it = iter_next(it)) + memoserv_history_read(iter_key(it), iter_data(it)); + return 0; } @@ -985,12 +1134,29 @@ memoserv_write_memos(struct saxdb_context *ctx, struct memo *memo) return 0; } +static int +memoserv_write_history(struct saxdb_context *ctx, struct history *history) +{ + char str[7]; + + saxdb_start_record(ctx, inttobase64(str, history->id, sizeof(str)), 0); + + saxdb_write_int(ctx, KEY_SENT, history->sent); + saxdb_write_int(ctx, KEY_ID, history->id); + saxdb_write_string(ctx, KEY_RECIPIENT, history->recipient->handle->handle); + saxdb_write_string(ctx, KEY_FROM, history->sender->handle->handle); + + saxdb_end_record(ctx); + return 0; +} + static int memoserv_saxdb_write(struct saxdb_context *ctx) { dict_iterator_t it; struct memo_account *ma; struct memo *memo; + struct history *history; unsigned int ii; /* Accounts */ @@ -1001,7 +1167,7 @@ memoserv_saxdb_write(struct saxdb_context *ctx) } saxdb_end_record(ctx); - /* Channels */ + /* Memos */ saxdb_start_record(ctx, KEY_MAIN_MEMOS, 1); for (it = dict_first(memos); it; it = iter_next(it)) { ma = iter_data(it); @@ -1012,6 +1178,17 @@ memoserv_saxdb_write(struct saxdb_context *ctx) } saxdb_end_record(ctx); + /* History */ + saxdb_start_record(ctx, KEY_MAIN_HISTORY, 1); + for (it = dict_first(historys); it; it = iter_next(it)) { + ma = iter_data(it); + for (ii = 0; ii < ma->hrecvd.used; ++ii) { + history = ma->hrecvd.list[ii]; + memoserv_write_history(ctx, history); + } + } + saxdb_end_record(ctx); + return 0; } @@ -1019,6 +1196,7 @@ static void memoserv_cleanup(void) { dict_delete(memos); + dict_delete(historys); } static void @@ -1050,12 +1228,16 @@ memoserv_rename_account(struct handle_info *hi, const char *old_handle) return; dict_remove2(memos, old_handle, 1); dict_insert(memos, hi->handle, ma); + + dict_remove2(historys, old_handle, 1); + dict_insert(historys, hi->handle, ma); } static void memoserv_unreg_account(UNUSED_ARG(struct userNode *user), struct handle_info *handle) { dict_remove(memos, handle->handle); + dict_remove(historys, handle->handle); } int @@ -1063,6 +1245,7 @@ memoserv_init(void) { MS_LOG = log_register_type("MemoServ", "file:memoserv.log"); 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);