]>
jfr.im git - irc/evilnet/x3.git/blob - src/mod-memoserv.c
1 /* mod-memoserv.c - MemoServ module for srvx
2 * Copyright 2003-2004 Martijn Smit and srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 * /msg opserv bind nickserv * *memoserv.*
24 * If you want a dedicated MemoServ bot, make sure the service control
25 * commands are bound to OpServ:
26 * /msg opserv bind opserv service *modcmd.joiner
27 * /msg opserv bind opserv service\ add *modcmd.service\ add
28 * /msg opserv bind opserv service\ rename *modcmd.service\ rename
29 * /msg opserv bind opserv service\ trigger *modcmd.service\ trigger
30 * /msg opserv bind opserv service\ remove *modcmd.service\ remove
32 * /msg opserv service add MemoServ User-to-user Memorandum Service
33 * /msg opserv bind memoserv help *modcmd.help
34 * Restart srvx with the updated conf file (as above, butwith "bot"
35 * "MemoServ"), and bind the commands to it:
36 * /msg opserv bind memoserv * *memoserv.*
37 * /msg opserv bind memoserv set *modcmd.joiner
47 #define KEY_SENT "sent"
48 #define KEY_RECIPIENT "to"
49 #define KEY_FROM "from"
50 #define KEY_MESSAGE "msg"
51 #define KEY_READ "read"
52 #define KEY_RECIEPT "reciept"
54 static const struct message_entry msgtab
[] = {
55 { "MSMSG_CANNOT_SEND", "You cannot send to account $b%s$b." },
56 { "MSMSG_MEMO_SENT", "Message sent to $b%s$b." },
57 { "MSMSG_NO_MESSAGES", "You have no messages." },
58 { "MSMSG_MEMOS_FOUND", "Found $b%d$b matches.\nUse /msg $S READ <ID> to read a message." },
59 { "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." },
60 { "MSMSG_LIST_HEAD", "$bID$b $bFrom$b $bTime Sent$b" },
61 { "MSMSG_LIST_FORMAT", "%-2u %s $b%s$b %s" },
62 { "MSMSG_MEMO_HEAD", "Memo %u From $b%s$b, received on %s:" },
63 { "MSMSG_MEMO_RECIEPT", "$bRead Reciept$b requested, %s." },
64 { "MSMSG_BAD_MESSAGE_ID", "$b%s$b is not a valid message ID (it should be a number between 0 and %u)." },
65 { "MSMSG_NO_SUCH_MEMO", "You have no memo with that ID." },
66 { "MSMSG_MEMO_DELETED", "Memo $b%d$b deleted." },
67 { "MSMSG_EXPIRY_OFF", "I am currently not expiring messages. (turned off)" },
68 { "MSMSG_EXPIRY", "Messages will be expired when they are %s old (%d seconds)." },
69 { "MSMSG_MESSAGES_EXPIRED", "$b%lu$b message(s) expired." },
70 { "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." },
71 { "MSMSG_NEW_MESSAGE", "You have a new message from $b%s$b. /msg $S LIST" },
72 { "MSMSG_FULL_INBOX", "$b%s$b cannot recieve anymore memos as their inbox is full" },
73 { "MSMSG_DELETED_ALL", "Deleted all of your messages." },
74 { "MSMSG_USE_CONFIRM", "Please use /msg $S DELETE * $bCONFIRM$b to delete $uall$u of your messages." },
76 { "MSMSG_STATUS_TOTAL", "I have $b%u$b memos in my database." },
77 { "MSMSG_STATUS_EXPIRED", "$b%ld$b memos expired during the time I am awake." },
78 { "MSMSG_STATUS_SENT", "$b%ld$b memos have been sent." },
80 { "MSMSG_INVALID_OPTION", "$b%s$b is not a valid option." },
81 { "MSMSG_INVALID_BINARY", "$b%s$b is an invalid binary value." },
82 { "MSMSG_SET_NOTIFY", "$bNotify: $b %s" },
83 { "MSMSG_SET_AUTHNOTIFY", "$bAuthNotify: $b %s" },
84 { "MSMSG_SET_PRIVATE", "$bPrivate: $b %s" },
85 { "MSMSG_SET_LIMIT", "$bLimit: $b %d" },
86 { "MSMSG_SET_OPTIONS", "$bMessaging Options$b" },
87 { "MSMSG_SET_OPTIONS_END", "-------------End of Options-------------" },
89 { "MSMSG_LIST_END", "--------------End of Memos--------------" },
90 { "MSMSG_BAR", "----------------------------------------"},
96 struct memo_account
*recipient
;
97 struct memo_account
*sender
;
100 unsigned int is_read
: 1;
101 unsigned int reciept
: 1;
104 DECLARE_LIST(memoList
, struct memo
*);
105 DEFINE_LIST(memoList
, struct memo
*);
107 /* memo_account.flags fields */
108 #define MEMO_NOTIFY_NEW 1
109 #define MEMO_NOTIFY_LOGIN 2
110 #define MEMO_DENY_NONCHANNEL 4
112 struct memo_account
{
113 struct handle_info
*handle
;
116 struct memoList sent
;
117 struct memoList recvd
;
121 struct userNode
*bot
;
126 #define MEMOSERV_FUNC(NAME) MODCMD_FUNC(NAME)
127 #define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
128 typedef OPTION_FUNC(option_func_t
);
130 extern struct string_list
*autojoin_channels
;
131 const char *memoserv_module_deps
[] = { NULL
};
132 static struct module *memoserv_module
;
133 static struct log_type
*MS_LOG
;
134 static unsigned long memosSent
, memosExpired
;
135 static struct dict
*memos
; /* memo_account->handle->handle -> memo_account */
136 static dict_t memoserv_opt_dict
; /* contains option_func_t* */
138 static struct memo_account
*
139 memoserv_get_account(struct handle_info
*hi
)
141 struct memo_account
*ma
;
144 ma
= dict_find(memos
, hi
->handle
, NULL
);
147 ma
= calloc(1, sizeof(*ma
));
151 ma
->flags
= MEMO_NOTIFY_NEW
| MEMO_NOTIFY_LOGIN
;
152 dict_insert(memos
, ma
->handle
->handle
, ma
);
157 delete_memo(struct memo
*memo
)
159 memoList_remove(&memo
->recipient
->recvd
, memo
);
160 memoList_remove(&memo
->sender
->sent
, memo
);
166 delete_memo_account(void *data
)
168 struct memo_account
*ma
= data
;
170 while (ma
->recvd
.used
)
171 delete_memo(ma
->recvd
.list
[0]);
172 while (ma
->sent
.used
)
173 delete_memo(ma
->sent
.list
[0]);
174 memoList_clean(&ma
->recvd
);
175 memoList_clean(&ma
->sent
);
183 for (it
= dict_first(memos
); it
; it
= iter_next(it
)) {
184 struct memo_account
*acct
= iter_data(it
);
186 for (ii
= 0; ii
< acct
->sent
.used
; ++ii
) {
187 struct memo
*memo
= acct
->sent
.list
[ii
];
188 if ((now
- memo
->sent
) > memoserv_conf
.message_expiry
) {
198 expire_memos(UNUSED_ARG(void *data
))
200 if (memoserv_conf
.message_expiry
) {
202 timeq_add(now
+ memoserv_conf
.message_expiry
, expire_memos
, NULL
);
207 add_memo(time_t sent
, struct memo_account
*recipient
, struct memo_account
*sender
, char *message
)
211 memo
= calloc(1, sizeof(*memo
));
215 memo
->recipient
= recipient
;
216 memoList_append(&recipient
->recvd
, memo
);
217 memo
->sender
= sender
;
218 memoList_append(&sender
->sent
, memo
);
220 memo
->message
= strdup(message
);
226 memoserv_can_send(struct userNode
*bot
, struct userNode
*user
, struct memo_account
*acct
)
228 extern struct userData
*_GetChannelUser(struct chanData
*channel
, struct handle_info
*handle
, int override
, int allow_suspended
);
229 struct userData
*dest
;
231 if (!user
->handle_info
)
234 /* Sanity checks here because if the user doesnt have a limit set
235 the limit comes out at like 21233242 if you try and use it. */
236 if (acct
->limit
> memoserv_conf
.limit
)
237 acct
->limit
= memoserv_conf
.limit
;
239 if (acct
->recvd
.used
> acct
->limit
) {
240 send_message(user
, bot
, "MSMSG_FULL_INBOX", acct
->handle
->handle
);
241 send_message(user
, bot
, "MSMSG_CANNOT_SEND", acct
->handle
->handle
);
245 if (!(acct
->flags
& MEMO_DENY_NONCHANNEL
))
248 for (dest
= acct
->handle
->channels
; dest
; dest
= dest
->u_next
)
249 if (_GetChannelUser(dest
->channel
, user
->handle_info
, 1, 0))
252 send_message(user
, bot
, "MSMSG_CANNOT_SEND", acct
->handle
->handle
);
256 static struct memo
*find_memo(struct userNode
*user
, struct svccmd
*cmd
, struct memo_account
*ma
, const char *msgid
, unsigned int *id
)
259 if (!isdigit(msgid
[0])) {
261 reply("MSMSG_BAD_MESSAGE_ID", msgid
, ma
->recvd
.used
- 1);
263 reply("MSMSG_NO_MESSAGES");
266 memoid
= atoi(msgid
);
267 if (memoid
>= ma
->recvd
.used
) {
268 reply("MSMSG_NO_SUCH_MEMO");
271 return ma
->recvd
.list
[*id
= memoid
];
274 static MODCMD_FUNC(cmd_send
)
278 int reciept
= 0, inc
= 2;
279 struct handle_info
*hi
;
280 struct memo_account
*ma
, *sender
;
283 if (!(hi
= modcmd_get_handle_info(user
, argv
[1])))
286 if (!(sender
= memoserv_get_account(user
->handle_info
))
287 || !(ma
= memoserv_get_account(hi
))) {
288 reply("MSG_INTERNAL_FAILURE");
292 if (!(memoserv_can_send(cmd
->parent
->bot
, user
, ma
)))
295 char *flags
= argv
[2];
323 message
= unsplit_string(argv
+ inc
, argc
- inc
, NULL
);
324 memo
= add_memo(now
, ma
, sender
, message
);
328 if (ma
->flags
& MEMO_NOTIFY_NEW
) {
329 struct userNode
*other
;
331 for (other
= ma
->handle
->users
; other
; other
= other
->next_authed
)
332 send_message(other
, cmd
->parent
->bot
, "MSMSG_NEW_MESSAGE", user
->nick
);
335 reply("MSMSG_MEMO_SENT", ma
->handle
->handle
);
339 static MODCMD_FUNC(cmd_list
)
341 struct memo_account
*ma
;
347 if (!(ma
= memoserv_get_account(user
->handle_info
)))
350 reply("MSMSG_LIST_HEAD");
352 if(user
->handle_info
&& user
->handle_info
->userlist_style
!= HI_STYLE_CLEAN
)
355 for (ii
= 0; (ii
< ma
->recvd
.used
) && (ii
< 15); ++ii
) {
356 memo
= ma
->recvd
.list
[ii
];
357 localtime_r(&memo
->sent
, &tm
);
358 strftime(posted
, sizeof(posted
), "%I:%M %p, %m/%d/%Y", &tm
);
359 reply("MSMSG_LIST_FORMAT", ii
, memo
->sender
->handle
->handle
, memo
->reciept
? "(r)" : "", posted
);
364 reply("MSMSG_CLEAN_INBOX", ii
);
366 reply("MSMSG_MEMOS_FOUND", ii
);
368 reply("MSMSG_LIST_END");
373 static MODCMD_FUNC(cmd_read
)
375 struct memo_account
*ma
;
377 int rignore
= 0, brk
= 0, s
= 0;
382 if (!(ma
= memoserv_get_account(user
->handle_info
)))
384 if (!(memo
= find_memo(user
, cmd
, ma
, argv
[1], &memoid
)))
388 char *argtwo
= argv
[2];
413 localtime_r(&memo
->sent
, &tm
);
414 strftime(posted
, sizeof(posted
), "%I:%M %p, %m/%d/%Y", &tm
);
416 reply("MSMSG_MEMO_HEAD", memoid
, memo
->sender
->handle
->handle
, posted
);
417 send_message_type(4, user
, cmd
->parent
->bot
, "%s", memo
->message
);
420 if (memo
->reciept
== 1) {
422 reply("MSMSG_MEMO_RECIEPT", rignore
? "ignoring" : "sending");
424 struct memo_account
*ma
;
425 struct memo_account
*sender
;
426 char content
[MAXLEN
];
428 ma
= memoserv_get_account(user
->handle_info
);
429 sender
= memoserv_get_account(memo
->sender
->handle
);
431 sprintf(content
, "%s has read your memo dated %s.", ma
->handle
->handle
, posted
);
433 memo
= add_memo(now
, sender
, ma
, content
);
435 if (sender
->flags
& MEMO_NOTIFY_NEW
) {
436 struct userNode
*other
;
438 for (other
= sender
->handle
->users
; other
; other
= other
->next_authed
)
439 send_message(other
, cmd
->parent
->bot
, "MSMSG_NEW_MESSAGE", ma
->handle
->handle
);
448 static MODCMD_FUNC(cmd_delete
)
450 struct memo_account
*ma
;
454 if (!(ma
= memoserv_get_account(user
->handle_info
)))
456 if (!irccasecmp(argv
[1], "*") || !irccasecmp(argv
[1], "all")) {
457 if ((argc
< 3) || irccasecmp(argv
[2], "confirm")) {
458 reply("MSMSG_USE_CONFIRM");
461 while (ma
->recvd
.used
)
462 delete_memo(ma
->recvd
.list
[0]);
463 reply("MSMSG_DELETED_ALL");
467 if (!(memo
= find_memo(user
, cmd
, ma
, argv
[1], &memoid
)))
470 reply("MSMSG_MEMO_DELETED", memoid
);
474 static MODCMD_FUNC(cmd_expire
)
476 unsigned long old_expired
= memosExpired
;
478 reply("MSMSG_MESSAGES_EXPIRED", memosExpired
- old_expired
);
482 static MODCMD_FUNC(cmd_expiry
)
484 char interval
[INTERVALLEN
];
486 if (!memoserv_conf
.message_expiry
) {
487 reply("MSMSG_EXPIRY_OFF");
491 intervalString(interval
, memoserv_conf
.message_expiry
, user
->handle_info
);
492 reply("MSMSG_EXPIRY", interval
, memoserv_conf
.message_expiry
);
498 set_list(struct userNode
*user
, struct handle_info
*hi
, int override
)
502 char *set_display
[] = {"AUTHNOTIFY", "NOTIFY", "PRIVATE", "LIMIT"};
504 send_message(user
, memoserv_conf
.bot
, "MSMSG_SET_OPTIONS");
505 send_message(user
, memoserv_conf
.bot
, "MSMSG_BAR");
507 /* Do this so options are presented in a consistent order. */
508 for (i
= 0; i
< ArrayLength(set_display
); ++i
)
509 if ((opt
= dict_find(memoserv_opt_dict
, set_display
[i
], NULL
)))
510 opt(user
, hi
, override
, 0, NULL
);
511 send_message(user
, memoserv_conf
.bot
, "MSMSG_SET_OPTIONS_END");
514 static MODCMD_FUNC(cmd_set
)
516 struct handle_info
*hi
;
519 hi
= user
->handle_info
;
521 set_list(user
, hi
, 0);
525 if (!(opt
= dict_find(memoserv_opt_dict
, argv
[1], NULL
))) {
526 reply("MSMSG_INVALID_OPTION", argv
[1]);
530 return opt(user
, hi
, 0, argc
-1, argv
+1);
533 static MODCMD_FUNC(cmd_oset
)
535 struct handle_info
*hi
;
538 if (!(hi
= get_victim_oper(user
, argv
[1])))
542 set_list(user
, hi
, 0);
546 if (!(opt
= dict_find(memoserv_opt_dict
, argv
[2], NULL
))) {
547 reply("MSMSG_INVALID_OPTION", argv
[2]);
551 return opt(user
, hi
, 1, argc
-2, argv
+2);
554 static OPTION_FUNC(opt_notify
)
556 struct memo_account
*ma
;
559 if (!(ma
= memoserv_get_account(hi
)))
563 if (enabled_string(choice
)) {
564 ma
->flags
|= MEMO_NOTIFY_NEW
;
565 } else if (disabled_string(choice
)) {
566 ma
->flags
&= ~MEMO_NOTIFY_NEW
;
568 send_message(user
, memoserv_conf
.bot
, "MSMSG_INVALID_BINARY", choice
);
573 choice
= (ma
->flags
& MEMO_NOTIFY_NEW
) ? "on" : "off";
574 send_message(user
, memoserv_conf
.bot
, "MSMSG_SET_NOTIFY", choice
);
578 static OPTION_FUNC(opt_authnotify
)
580 struct memo_account
*ma
;
583 if (!(ma
= memoserv_get_account(hi
)))
587 if (enabled_string(choice
)) {
588 ma
->flags
|= MEMO_NOTIFY_LOGIN
;
589 } else if (disabled_string(choice
)) {
590 ma
->flags
&= ~MEMO_NOTIFY_LOGIN
;
592 send_message(user
, memoserv_conf
.bot
, "MSMSG_INVALID_BINARY", choice
);
597 choice
= (ma
->flags
& MEMO_NOTIFY_LOGIN
) ? "on" : "off";
598 send_message(user
, memoserv_conf
.bot
, "MSMSG_SET_AUTHNOTIFY", choice
);
602 static OPTION_FUNC(opt_private
)
604 struct memo_account
*ma
;
607 if (!(ma
= memoserv_get_account(hi
)))
611 if (enabled_string(choice
)) {
612 ma
->flags
|= MEMO_DENY_NONCHANNEL
;
613 } else if (disabled_string(choice
)) {
614 ma
->flags
&= ~MEMO_DENY_NONCHANNEL
;
616 send_message(user
, memoserv_conf
.bot
, "MSMSG_INVALID_BINARY", choice
);
621 choice
= (ma
->flags
& MEMO_DENY_NONCHANNEL
) ? "on" : "off";
622 send_message(user
, memoserv_conf
.bot
, "MSMSG_SET_PRIVATE", choice
);
626 static OPTION_FUNC(opt_limit
)
628 struct memo_account
*ma
;
631 if (!(ma
= memoserv_get_account(hi
)))
634 choice
= atoi(argv
[1]);
635 if (choice
> memoserv_conf
.limit
)
636 choice
= memoserv_conf
.limit
;
641 send_message(user
, memoserv_conf
.bot
, "MSMSG_SET_LIMIT", ma
->limit
);
645 static MODCMD_FUNC(cmd_status
)
647 reply("MSMSG_STATUS_TOTAL", dict_size(memos
));
648 reply("MSMSG_STATUS_EXPIRED", memosExpired
);
649 reply("MSMSG_STATUS_SENT", memosSent
);
654 memoserv_conf_read(void)
659 str
= "modules/memoserv";
660 if (!(conf_node
= conf_get_data(str
, RECDB_OBJECT
))) {
661 log_module(MS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", str
);
665 str
= database_get_data(conf_node
, "limit", RECDB_QSTRING
);
666 memoserv_conf
.limit
= atoi(str
) ? : 50;
668 str
= database_get_data(conf_node
, "message_expiry", RECDB_QSTRING
);
669 memoserv_conf
.message_expiry
= str
? ParseInterval(str
) : 60*24*30;
673 memoserv_saxdb_read(struct dict
*db
)
676 struct handle_info
*sender
, *recipient
;
677 struct record_data
*hir
;
682 for (it
= dict_first(db
); it
; it
= iter_next(it
)) {
684 if (hir
->type
!= RECDB_OBJECT
) {
685 log_module(MS_LOG
, LOG_WARNING
, "Unexpected rectype %d for %s.", hir
->type
, iter_key(it
));
689 if (!(str
= database_get_data(hir
->d
.object
, KEY_SENT
, RECDB_QSTRING
))) {
690 log_module(MS_LOG
, LOG_ERROR
, "Date sent not present in memo %s; skipping", iter_key(it
));
695 if (!(str
= database_get_data(hir
->d
.object
, KEY_RECIPIENT
, RECDB_QSTRING
))) {
696 log_module(MS_LOG
, LOG_ERROR
, "Recipient not present in memo %s; skipping", iter_key(it
));
698 } else if (!(recipient
= get_handle_info(str
))) {
699 log_module(MS_LOG
, LOG_ERROR
, "Invalid recipient %s in memo %s; skipping", str
, iter_key(it
));
703 if (!(str
= database_get_data(hir
->d
.object
, KEY_FROM
, RECDB_QSTRING
))) {
704 log_module(MS_LOG
, LOG_ERROR
, "Sender not present in memo %s; skipping", iter_key(it
));
706 } else if (!(sender
= get_handle_info(str
))) {
707 log_module(MS_LOG
, LOG_ERROR
, "Invalid sender %s in memo %s; skipping", str
, iter_key(it
));
711 if (!(str
= database_get_data(hir
->d
.object
, KEY_MESSAGE
, RECDB_QSTRING
))) {
712 log_module(MS_LOG
, LOG_ERROR
, "Message not present in memo %s; skipping", iter_key(it
));
716 memo
= add_memo(sent
, memoserv_get_account(recipient
), memoserv_get_account(sender
), str
);
717 if ((str
= database_get_data(hir
->d
.object
, KEY_READ
, RECDB_QSTRING
)))
720 if ((str
= database_get_data(hir
->d
.object
, KEY_RECIEPT
, RECDB_QSTRING
)))
727 memoserv_saxdb_write(struct saxdb_context
*ctx
)
730 struct memo_account
*ma
;
733 unsigned int id
= 0, ii
;
735 for (it
= dict_first(memos
); it
; it
= iter_next(it
)) {
737 for (ii
= 0; ii
< ma
->recvd
.used
; ++ii
) {
738 memo
= ma
->recvd
.list
[ii
];
739 saxdb_start_record(ctx
, inttobase64(str
, id
++, sizeof(str
)), 0);
740 saxdb_write_int(ctx
, KEY_SENT
, memo
->sent
);
741 saxdb_write_string(ctx
, KEY_RECIPIENT
, memo
->recipient
->handle
->handle
);
742 saxdb_write_string(ctx
, KEY_FROM
, memo
->sender
->handle
->handle
);
743 saxdb_write_string(ctx
, KEY_MESSAGE
, memo
->message
);
745 saxdb_write_int(ctx
, KEY_READ
, 1);
748 saxdb_write_int(ctx
, KEY_RECIEPT
, 1);
749 saxdb_end_record(ctx
);
756 memoserv_cleanup(void)
762 memoserv_check_messages(struct userNode
*user
, UNUSED_ARG(struct handle_info
*old_handle
))
764 unsigned int ii
, unseen
;
765 struct memo_account
*ma
;
768 if (!user
->uplink
->burst
) {
769 if (!(ma
= memoserv_get_account(user
->handle_info
))
770 || !(ma
->flags
& MEMO_NOTIFY_LOGIN
))
772 for (ii
= unseen
= 0; ii
< ma
->recvd
.used
; ++ii
) {
773 memo
= ma
->recvd
.list
[ii
];
777 if (ma
->recvd
.used
&& memoserv_conf
.bot
)
778 if(unseen
) send_message(user
, memoserv_conf
.bot
, "MSMSG_MEMOS_INBOX", unseen
, ma
->recvd
.used
- unseen
);
783 memoserv_rename_account(struct handle_info
*hi
, const char *old_handle
)
785 struct memo_account
*ma
;
786 if (!(ma
= dict_find(memos
, old_handle
, NULL
)))
788 dict_remove2(memos
, old_handle
, 1);
789 dict_insert(memos
, hi
->handle
, ma
);
793 memoserv_unreg_account(UNUSED_ARG(struct userNode
*user
), struct handle_info
*handle
)
795 dict_remove(memos
, handle
->handle
);
801 MS_LOG
= log_register_type("MemoServ", "file:memoserv.log");
803 dict_set_free_data(memos
, delete_memo_account
);
804 reg_auth_func(memoserv_check_messages
);
805 reg_handle_rename_func(memoserv_rename_account
);
806 reg_unreg_func(memoserv_unreg_account
);
807 conf_register_reload(memoserv_conf_read
);
808 reg_exit_func(memoserv_cleanup
);
809 saxdb_register("MemoServ", memoserv_saxdb_read
, memoserv_saxdb_write
);
811 memoserv_module
= module_register("MemoServ", MS_LOG
, "mod-memoserv.help", NULL
);
812 modcmd_register(memoserv_module
, "send", cmd_send
, 3, MODCMD_REQUIRE_AUTHED
, NULL
);
813 modcmd_register(memoserv_module
, "list", cmd_list
, 1, MODCMD_REQUIRE_AUTHED
, NULL
);
814 modcmd_register(memoserv_module
, "read", cmd_read
, 2, MODCMD_REQUIRE_AUTHED
, NULL
);
815 modcmd_register(memoserv_module
, "delete", cmd_delete
, 2, MODCMD_REQUIRE_AUTHED
, NULL
);
816 modcmd_register(memoserv_module
, "expire", cmd_expire
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+oper", NULL
);
817 modcmd_register(memoserv_module
, "expiry", cmd_expiry
, 1, 0, NULL
);
818 modcmd_register(memoserv_module
, "status", cmd_status
, 1, 0, NULL
);
819 modcmd_register(memoserv_module
, "set", cmd_set
, 1, MODCMD_REQUIRE_AUTHED
, NULL
);
820 modcmd_register(memoserv_module
, "oset", cmd_oset
, 1, MODCMD_REQUIRE_AUTHED
, "flags", "+helping", NULL
);
822 memoserv_opt_dict
= dict_new();
823 dict_insert(memoserv_opt_dict
, "AUTHNOTIFY", opt_authnotify
);
824 dict_insert(memoserv_opt_dict
, "NOTIFY", opt_notify
);
825 dict_insert(memoserv_opt_dict
, "PRIVATE", opt_private
);
826 dict_insert(memoserv_opt_dict
, "LIMIT", opt_limit
);
828 message_register_table(msgtab
);
830 if (memoserv_conf
.message_expiry
)
831 timeq_add(now
+ memoserv_conf
.message_expiry
, expire_memos
, NULL
);
837 memoserv_finalize(void) {
838 struct chanNode
*chan
;
843 str
= "modules/memoserv";
844 if (!(conf_node
= conf_get_data(str
, RECDB_OBJECT
))) {
845 log_module(MS_LOG
, LOG_ERROR
, "config node `%s' is missing or has wrong type.", str
);
849 str
= database_get_data(conf_node
, "bot", RECDB_QSTRING
);
851 memoserv_conf
.bot
= GetUserH(str
);
853 if (autojoin_channels
&& memoserv_conf
.bot
) {
854 for (i
= 0; i
< autojoin_channels
->used
; i
++) {
855 chan
= AddChannel(autojoin_channels
->list
[i
], now
, "+nt", NULL
, NULL
);
856 AddChannelUser(memoserv_conf
.bot
, chan
)->modes
|= MODE_CHANOP
;