]>
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
3 * Copyright 2005-2006 X3 Development Team
5 * This file is part of x3.
7 * x3 is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with srvx; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 * /msg opserv bind nickserv * *memoserv.*
25 * If you want a dedicated MemoServ bot, make sure the service control
26 * commands are bound to OpServ:
27 * /msg opserv bind opserv service *modcmd.joiner
28 * /msg opserv bind opserv service\ add *modcmd.service\ add
29 * /msg opserv bind opserv service\ rename *modcmd.service\ rename
30 * /msg opserv bind opserv service\ trigger *modcmd.service\ trigger
31 * /msg opserv bind opserv service\ remove *modcmd.service\ remove
33 * /msg opserv service add MemoServ User-to-user Memorandum Service
34 * /msg opserv bind memoserv help *modcmd.help
35 * Restart srvx with the updated conf file (as above, butwith "bot"
36 * "MemoServ"), and bind the commands to it:
37 * /msg opserv bind memoserv * *memoserv.*
38 * /msg opserv bind memoserv set *memoserv.set
50 #define KEY_MAIN_ACCOUNTS "accounts"
51 #define KEY_FLAGS "flags"
52 #define KEY_LIMIT "limit"
54 #define KEY_MAIN_HISTORY "history"
55 #define KEY_MAIN_MEMOS "memos"
56 #define KEY_SENT "sent"
57 #define KEY_RECIPIENT "to"
58 #define KEY_FROM "from"
59 #define KEY_MESSAGE "msg"
60 #define KEY_READ "read"
61 #define KEY_RECIEPT "reciept"
65 static const struct message_entry msgtab
[] = {
66 { "MSMSG_CANNOT_SEND" , "You cannot send to account $b %s $b." },
67 { "MSMSG_UNKNOWN_SEND_FLAG" , "Unreccognised send flag ' %c ', message not sent." },
68 { "MSMSG_MEMO_SENT" , "Message sent to $b %s $b (ID# %d )." },
69 { "MSMSG_NO_MESSAGES" , "You have no messages." },
70 { "MSMSG_MEMOS_FOUND" , "Found $b %d $b matches." },
71 { "MSMSG_HOWTO_READ" , "Use READ <ID> to read a message." },
72 { "MSMSG_CLEAN_INBOX" , "You have $b %d $b or more messages, please clean out your inbox. \n Use READ <ID> to read a message." },
73 { "MSMSG_LIST_HEAD" , "$bID$b $bFrom$b $bTime Sent$b" },
74 { "MSMSG_LIST_FORMAT" , "%-2u %s $b %s $b %s " },
75 { "MSMSG_HISTORY_HEADER" , "$bID$b $bTo$b $bTime Sent$b" },
76 { "MSMSG_HISTORY_FORMAT" , "%-2u %s %s " },
77 { "MSMSG_MEMO_HEAD" , "Memo %u From $b %s $b, received on %s :" },
78 { "MSMSG_MEMO_RECIEPT" , "$bRead Reciept$b requested, %s ." },
79 { "MSMSG_BAD_MESSAGE_ID" , "$b %s $b is not a valid message ID (it should be a number between 0 and %u )." },
80 { "MSMSG_NO_SUCH_MEMO" , "You have no memo with that ID." },
81 { "MSMSG_MEMO_DELETED" , "Memo $b %d $b deleted." },
82 { "MSMSG_MEMO_CANCEL_NUMBER" , "You must specify a number id" },
83 { "MSMSG_MEMO_DONT_OWN" , "You did not send memo# %d " },
84 { "MSMSG_MEMO_READ" , "Memo# %d has already been read, you cannot cancel it." },
85 { "MSMSG_MEMO_CANT_LOCATE" , "Could not locate memo# %d " },
86 { "MSMSG_EXPIRY_OFF" , "I am currently not expiring messages. (turned off)" },
87 { "MSMSG_EXPIRY" , "Messages will be expired when they are %s old ( %d seconds)." },
88 { "MSMSG_MESSAGES_EXPIRED" , "$b %l u$b message(s) expired." },
89 { "MSMSG_MEMOS_INBOX" , "You have $b %d $b new message(s) in your inbox and %d old messages. Use LIST to list them." },
90 { "MSMSG_NEW_MESSAGE" , "You have a new message from $b %s $b. Use LIST to see your messages." },
91 { "MSMSG_FULL_INBOX" , "$b %s $b cannot recieve anymore memos as their inbox is full" },
92 { "MSMSG_DELETED_ALL" , "Deleted all of your messages." },
93 { "MSMSG_USE_CONFIRM" , "Please use DELETE * $bCONFIRM$b to delete $uall$u of your messages." },
95 { "MSMSG_STATUS_HIST_TOTAL" , "I have $b %u $b history entries in my database." },
96 { "MSMSG_STATUS_TOTAL" , "I have $b %u $b memos in my database." },
97 { "MSMSG_STATUS_EXPIRED" , "$b %l d$b memos expired during the time I am awake." },
98 { "MSMSG_STATUS_SENT" , "$b %l d$b memos have been sent." },
100 { "MSMSG_INVALID_OPTION" , "$b %s $b is not a valid option." },
101 { "MSMSG_INVALID_BINARY" , "$b %s $b is an invalid binary value." },
102 { "MSMSG_SET_AUTHNOTIFY" , "$bAuthNotify$b: %s " },
103 { "MSMSG_SET_NEWNOTIFY" , "$bNewNotify$b: %s " },
104 { "MSMSG_SET_PRIVMSG" , "$bPrivmsg$b: %s " },
105 { "MSMSG_SET_PRIVATE" , "$bPrivate$b: %s " },
106 { "MSMSG_SET_IGNORERECIEPTS" , "$bIgnoreReciepts$b: %s " },
107 { "MSMSG_SET_SENDRECIEPTS" , "$bSendReciepts$b: %s " },
108 { "MSMSG_SET_LIMIT" , "$bLimit$b: %d " },
109 { "MSMSG_SET_OPTIONS" , "$bMessaging Options$b" },
110 { "MSMSG_SET_OPTIONS_END" , "-------------End of Options-------------" },
112 { "MSMSG_LIST_END" , "--------------End of Memos--------------" },
113 { "MSMSG_BAR" , "----------------------------------------" },
115 { "MSEMAIL_NEWMEMO_SUBJECT" , "New %s %s message from %s " },
116 { "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\n To delete this message just type in /msg %s delete %d when on %s next." },
118 { "MSMSG_DEFCON_NO_NEW_MEMOS" , "You cannot send new memos at this time, please try again soon." },
124 struct memo_account
* recipient
;
125 struct memo_account
* sender
;
129 unsigned int is_read
: 1 ;
130 unsigned int reciept
: 1 ;
134 struct memo_account
* recipient
;
135 struct memo_account
* sender
;
140 struct userNode
* memoserv
;
142 #define MEMOSERV_FUNC(NAME) MODCMD_FUNC(NAME)
143 #define MEMOSERV_SYNTAX() svccmd_send_help_brief(user, memoserv, cmd)
144 #define MEMOSERV_MIN_PARAMS(N) if(argc < (N)) { \
145 reply( "MSG_MISSING_PARAMS" , argv[0]); \
149 DECLARE_LIST ( memoList
, struct memo
*);
150 DEFINE_LIST ( memoList
, struct memo
*)
151 DECLARE_LIST ( historyList
, struct history
*);
152 DEFINE_LIST ( historyList
, struct history
*)
154 /* memo_account.flags fields */
155 #define MEMO_NOTIFY_NEW 0x00000001
156 #define MEMO_NOTIFY_LOGIN 0x00000002
157 #define MEMO_DENY_NONCHANNEL 0x00000004
158 #define MEMO_IGNORE_RECIEPTS 0x00000008
159 #define MEMO_ALWAYS_RECIEPTS 0x00000010
160 #define MEMO_USE_PRIVMSG 0x00000020
162 struct memo_account
{
163 struct handle_info
* handle
;
164 unsigned int flags
: 6 ;
166 struct memoList sent
;
167 struct memoList recvd
;
168 struct historyList hsent
;
169 struct historyList hrecvd
;
173 struct userNode
* bot
;
178 #define MEMOSERV_FUNC(NAME) MODCMD_FUNC(NAME)
179 #define OPTION_FUNC(NAME) int NAME(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
180 typedef OPTION_FUNC ( option_func_t
);
182 unsigned long memo_id
;
184 extern struct string_list
* autojoin_channels
;
185 const char * memoserv_module_deps
[] = { NULL
};
186 static struct module * memoserv_module
;
187 static struct log_type
* MS_LOG
;
188 static unsigned long memoCount
;
189 static unsigned long memosSent
;
190 static unsigned long memosExpired
;
191 static struct dict
* memos
; /* memo_account->handle->handle -> memo_account */
192 static struct dict
* historys
;
193 static dict_t memoserv_opt_dict
; /* contains option_func_t* */
195 static struct memo_account
*
196 memoserv_get_account ( struct handle_info
* hi
)
198 struct memo_account
* ma
;
201 ma
= dict_find ( memos
, hi
-> handle
, NULL
);
204 ma
= calloc ( 1 , sizeof (* ma
));
208 ma
-> flags
= MEMO_NOTIFY_NEW
| MEMO_NOTIFY_LOGIN
| MEMO_USE_PRIVMSG
;
209 ma
-> limit
= memoserv_conf
. limit
;
210 dict_insert ( memos
, ma
-> handle
-> handle
, ma
);
211 dict_insert ( historys
, ma
-> handle
-> handle
, ma
);
216 delete_memo ( struct memo
* memo
)
218 memoList_remove (& memo
-> recipient
-> recvd
, memo
);
219 memoList_remove (& memo
-> sender
-> sent
, memo
);
226 delete_history ( struct history
* history
)
228 historyList_remove (& history
-> recipient
-> hrecvd
, history
);
229 historyList_remove (& history
-> sender
-> hsent
, history
);
234 delete_memo_account ( void * data
)
236 struct memo_account
* ma
= data
;
238 while ( ma
-> recvd
. used
)
239 delete_memo ( ma
-> recvd
. list
[ 0 ]);
240 while ( ma
-> sent
. used
)
241 delete_memo ( ma
-> sent
. list
[ 0 ]);
242 memoList_clean (& ma
-> recvd
);
243 memoList_clean (& ma
-> sent
);
245 while ( ma
-> hrecvd
. used
)
246 delete_history ( ma
-> hrecvd
. list
[ 0 ]);
247 while ( ma
-> hsent
. used
)
248 delete_history ( ma
-> hsent
. list
[ 0 ]);
249 historyList_clean (& ma
-> hrecvd
);
250 historyList_clean (& ma
-> hsent
);
258 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
259 struct memo_account
* account
= iter_data ( it
);
261 for ( ii
= 0 ; ii
< account
-> sent
. used
; ++ ii
) {
262 struct memo
* memo
= account
-> sent
. list
[ ii
];
263 if (( now
- memo
-> sent
) > memoserv_conf
. message_expiry
) {
271 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
272 struct memo_account
* account
= iter_data ( it
);
274 for ( ii
= 0 ; ii
< account
-> hsent
. used
; ++ ii
) {
275 struct history
* history
= account
-> hsent
. list
[ ii
];
276 if (( now
- history
-> sent
) > memoserv_conf
. message_expiry
) {
277 delete_history ( history
);
286 expire_memos ( UNUSED_ARG ( void * data
))
288 if ( memoserv_conf
. message_expiry
) {
290 timeq_add ( now
+ memoserv_conf
. message_expiry
, expire_memos
, NULL
);
294 static struct history
*
295 add_history ( time_t sent
, struct memo_account
* recipient
, struct memo_account
* sender
, unsigned long id
)
297 struct history
* history
;
299 history
= calloc ( 1 , sizeof (* history
));
304 history
-> recipient
= recipient
;
305 historyList_append (& recipient
-> hrecvd
, history
);
306 history
-> sender
= sender
;
307 historyList_append (& sender
-> hsent
, history
);
308 history
-> sent
= sent
;
315 add_memo ( time_t sent
, struct memo_account
* recipient
, struct memo_account
* sender
, char * message
, int nfrom_read
)
319 memo
= calloc ( 1 , sizeof (* memo
));
328 memo
-> recipient
= recipient
;
329 memoList_append (& recipient
-> recvd
, memo
);
330 memo
-> sender
= sender
;
331 memoList_append (& sender
-> sent
, memo
);
333 memo
-> message
= strdup ( message
);
338 add_history ( sent
, recipient
, sender
, memo
-> id
);
344 memoserv_can_send ( struct userNode
* bot
, struct userNode
* user
, struct memo_account
* acct
)
346 extern struct userData
* _GetChannelUser ( struct chanData
* channel
, struct handle_info
* handle
, int override
, int allow_suspended
);
347 struct userData
* dest
;
348 unsigned int i
= 0 , match
= 0 ;
350 if (! user
-> handle_info
)
353 /* Sanity checks here because if the user doesnt have a limit set
354 the limit comes out at like 21233242 if you try and use it. */
355 if ( acct
-> limit
> memoserv_conf
. limit
)
356 acct
-> limit
= memoserv_conf
. limit
;
358 if ( acct
-> recvd
. used
> acct
-> limit
) {
359 send_message ( user
, bot
, "MSMSG_FULL_INBOX" , acct
-> handle
-> handle
);
360 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
364 if ( acct
-> handle
-> ignores
-> used
) {
365 for ( i
= 0 ; i
< acct
-> handle
-> ignores
-> used
; i
++) {
366 if ( user_matches_glob ( user
, acct
-> handle
-> ignores
-> list
[ i
], MATCH_USENICK
, 0 )) {
373 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
378 if (!( acct
-> flags
& MEMO_DENY_NONCHANNEL
))
381 for ( dest
= acct
-> handle
-> channels
; dest
; dest
= dest
-> u_next
)
382 if ( _GetChannelUser ( dest
-> channel
, user
-> handle_info
, 1 , 0 ))
385 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
389 static struct memo
* find_memo ( struct userNode
* user
, struct svccmd
* cmd
, struct memo_account
* ma
, const char * msgid
, unsigned int * id
)
392 if (! isdigit ( msgid
[ 0 ])) {
394 reply ( "MSMSG_BAD_MESSAGE_ID" , msgid
, ma
-> recvd
. used
- 1 );
396 reply ( "MSMSG_NO_MESSAGES" );
399 memoid
= atoi ( msgid
);
400 if ( memoid
>= ma
-> recvd
. used
) {
401 reply ( "MSMSG_NO_SUCH_MEMO" );
404 return ma
-> recvd
. list
[* id
= memoid
];
407 static MODCMD_FUNC ( cmd_send
)
410 int reciept
= 0 , inc
= 2 , email
= 0 ;
411 struct handle_info
* hi
;
412 struct memo_account
* ma
, * sender
;
414 char subject
[ 128 ], body
[ 4096 ];
416 const char * netname
, * fmt
;
418 MEMOSERV_MIN_PARAMS ( 3 );
420 if ( checkDefCon ( DEFCON_NO_NEW_MEMOS
) && ! IsOper ( user
)) {
421 reply ( "MSMSG_DEFCON_NO_NEW_MEMOS" );
425 if (!( hi
= modcmd_get_handle_info ( user
, argv
[ 1 ])))
428 if (!( sender
= memoserv_get_account ( user
-> handle_info
))
429 || !( ma
= memoserv_get_account ( hi
))) {
430 reply ( "MSG_INTERNAL_FAILURE" );
434 if (!( memoserv_can_send ( cmd
-> parent
-> bot
, user
, ma
)))
437 inc
= 2 ; /* Start of message on 3rd ([2]) word */
438 if ( argv
[ 2 ][ 0 ] == '-' && argv
[ 2 ][ 1 ] != '-' ) { /* first word is flags ('-r')*/
439 char * flags
= argv
[ 2 ];
440 inc
++; /* Start of message is now 1 word later */
441 for ( flags
++;* flags
; flags
++) {
448 /* Unknown mode. Give an error */
449 reply ( "MSMSG_UNKNOWN_SEND_FLAG" , * flags
);
455 inc
= 2 ; /* Start of message is word 2 */
457 message
= unsplit_string ( argv
+ inc
, argc
- inc
, NULL
);
458 memo
= add_memo ( now
, ma
, sender
, message
, 1 );
459 if (( reciept
== 1 ) || ( ma
-> flags
& MEMO_ALWAYS_RECIEPTS
))
462 if ( ma
-> flags
& MEMO_NOTIFY_NEW
) {
463 struct userNode
* other
;
465 for ( other
= ma
-> handle
-> users
; other
; other
= other
-> next_authed
)
466 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
);
469 estr
= conf_get_data ( "services/nickserv/email_enabled" , RECDB_QSTRING
);
470 netname
= conf_get_data ( "server/network" , RECDB_QSTRING
);
472 if ( email
&& ( ma
-> flags
& MEMO_NOTIFY_NEW
)) {
473 fmt
= handle_find_message ( hi
, "MSEMAIL_NEWMEMO_SUBJECT" );
474 snprintf ( subject
, sizeof ( subject
), fmt
, netname
, memoserv
-> nick
, user
-> nick
);
476 fmt
= handle_find_message ( hi
, "MSEMAIL_NEWMEMO_BODY" );
477 snprintf ( body
, sizeof ( body
), fmt
, user
-> nick
, memoserv
-> nick
, message
, memoserv
-> nick
, memo_id
, netname
);
479 mail_send ( memoserv
, hi
, subject
, body
, 0 );
482 reply ( "MSMSG_MEMO_SENT" , ma
-> handle
-> handle
, memo_id
);
486 static MODCMD_FUNC ( cmd_list
)
488 struct memo_account
* ma
;
494 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
497 reply ( "MSMSG_LIST_HEAD" );
499 if ( user
-> handle_info
&& user
-> handle_info
-> userlist_style
!= HI_STYLE_CLEAN
)
502 for ( ii
= 0 ; ( ii
< ma
-> recvd
. used
) && ( ii
< 15 ); ++ ii
) {
503 memo
= ma
-> recvd
. list
[ ii
];
504 localtime_r (& memo
-> sent
, & tm
);
505 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
506 reply ( "MSMSG_LIST_FORMAT" , ii
, memo
-> sender
-> handle
-> handle
, memo
-> reciept
? "(r)" : "" , posted
);
511 reply ( "MSMSG_CLEAN_INBOX" , ii
);
513 reply ( "MSMSG_MEMOS_FOUND" , ii
);
514 reply ( "MSMSG_HOWTO_READ" );
517 reply ( "MSMSG_LIST_END" );
522 static MODCMD_FUNC ( cmd_history
)
524 struct memo_account
* ma
;
525 struct history
* history
;
532 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
535 reply ( "MSMSG_HISTORY_HEADER" );
537 if ( user
-> handle_info
&& user
-> handle_info
-> userlist_style
!= HI_STYLE_CLEAN
)
540 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
542 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
) {
543 history
= ma
-> hrecvd
. list
[ ii
];
544 if (! strcasecmp ( history
-> sender
-> handle
-> handle
, user
-> handle_info
-> handle
)) {
546 localtime_r (& history
-> sent
, & tm
);
547 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
548 reply ( "MSMSG_HISTORY_FORMAT" , history
-> id
, history
-> recipient
-> handle
-> handle
, posted
);
556 reply ( "MSMSG_MEMOS_FOUND" , cc
);
558 reply ( "MSMSG_LIST_END" );
563 static MODCMD_FUNC ( cmd_read
)
565 struct memo_account
* ma
;
567 int rignore
= 0 , brk
= 0 , s
= 0 ;
574 char * argtwo
= argv
[ 2 ];
599 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
602 if (!( memo
= find_memo ( user
, cmd
, ma
, argv
[ 1 ], & memoid
)))
605 localtime_r (& memo
-> sent
, & tm
);
606 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
608 reply ( "MSMSG_MEMO_HEAD" , memoid
, memo
-> sender
-> handle
-> handle
, posted
);
609 send_message_type ( 4 , user
, cmd
-> parent
-> bot
, " %s " , memo
-> message
);
613 if ( ma
-> flags
& MEMO_IGNORE_RECIEPTS
)
616 if ( memo
-> reciept
== 1 ) {
618 reply ( "MSMSG_MEMO_RECIEPT" , rignore
? "ignoring" : "sending" );
620 struct memo_account
* ma
;
621 struct memo_account
* sender
;
622 char content
[ MAXLEN
];
624 ma
= memoserv_get_account ( user
-> handle_info
);
625 sender
= memoserv_get_account ( memo
-> sender
-> handle
);
627 sprintf ( content
, " %s has read your memo dated %s ." , ma
-> handle
-> handle
, posted
);
629 memo
= add_memo ( now
, sender
, ma
, content
, 1 );
630 reply ( "MSMSG_MEMO_SENT" , memob
-> sender
-> handle
-> handle
, memo_id
);
632 if ( sender
-> flags
& MEMO_NOTIFY_NEW
) {
633 struct userNode
* other
;
635 for ( other
= sender
-> handle
-> users
; other
; other
= other
-> next_authed
)
636 send_message_type (( ma
-> flags
& MEMO_USE_PRIVMSG
)? MSG_TYPE_PRIVMSG
: MSG_TYPE_NOTICE
, other
, cmd
-> parent
-> bot
, "MSMSG_NEW_MESSAGE" , ma
-> handle
-> handle
);
645 static MODCMD_FUNC ( cmd_delete
)
647 struct memo_account
* ma
;
651 MEMOSERV_MIN_PARAMS ( 2 );
653 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
655 if (! irccasecmp ( argv
[ 1 ], "*" ) || ! irccasecmp ( argv
[ 1 ], "all" )) {
656 if (( argc
< 3 ) || irccasecmp ( argv
[ 2 ], "confirm" )) {
657 reply ( "MSMSG_USE_CONFIRM" );
660 while ( ma
-> recvd
. used
)
661 delete_memo ( ma
-> recvd
. list
[ 0 ]);
662 reply ( "MSMSG_DELETED_ALL" );
666 if (!( memo
= find_memo ( user
, cmd
, ma
, argv
[ 1 ], & memoid
)))
669 reply ( "MSMSG_MEMO_DELETED" , memoid
);
673 static MODCMD_FUNC ( cmd_cancel
)
679 struct memo_account
* ma
;
681 MEMOSERV_MIN_PARAMS ( 2 );
683 if ( isdigit ( argv
[ 1 ][ 0 ])) {
684 id
= strtoul ( argv
[ 1 ], NULL
, 0 );
686 reply ( "MSMSG_MEMO_CANCEL_NUMBER" );
690 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
692 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
693 memo
= ma
-> recvd
. list
[ ii
];
695 if ( id
== memo
-> id
) {
696 if (! strcasecmp ( memo
-> sender
-> handle
-> handle
, user
-> handle_info
-> handle
)) {
698 reply ( "MSMSG_MEMO_READ" , id
);
702 reply ( "MSMSG_MEMO_DELETED" , id
);
706 reply ( "MSMSG_MEMO_DONT_OWN" , id
);
713 reply ( "MSMSG_MEMO_CANT_LOCATE" , id
);
717 static MODCMD_FUNC ( cmd_expire
)
719 unsigned long old_expired
= memosExpired
;
721 reply ( "MSMSG_MESSAGES_EXPIRED" , memosExpired
- old_expired
);
725 static MODCMD_FUNC ( cmd_expiry
)
727 char interval
[ INTERVALLEN
];
729 if (! memoserv_conf
. message_expiry
) {
730 reply ( "MSMSG_EXPIRY_OFF" );
734 intervalString ( interval
, memoserv_conf
. message_expiry
, user
-> handle_info
);
735 reply ( "MSMSG_EXPIRY" , interval
, memoserv_conf
. message_expiry
);
741 set_list ( struct svccmd
* cmd
, struct userNode
* user
, struct handle_info
* hi
, int override
)
745 char * set_display
[] = { "AUTHNOTIFY" , "NEWNOTIFY" , "PRIVMSG" , "PRIVATE" , "LIMIT" ,
746 "IGNORERECIEPTS" , "SENDRECIEPTS" };
748 reply ( "MSMSG_SET_OPTIONS" );
751 /* Do this so options are presented in a consistent order. */
752 for ( i
= 0 ; i
< ArrayLength ( set_display
); ++ i
)
753 if (( opt
= dict_find ( memoserv_opt_dict
, set_display
[ i
], NULL
)))
754 opt ( cmd
, user
, hi
, override
, 0 , NULL
);
755 reply ( "MSMSG_SET_OPTIONS_END" );
758 static MODCMD_FUNC ( cmd_set
)
760 struct handle_info
* hi
;
763 hi
= user
-> handle_info
;
765 set_list ( cmd
, user
, hi
, 0 );
769 if (!( opt
= dict_find ( memoserv_opt_dict
, argv
[ 1 ], NULL
))) {
770 reply ( "MSMSG_INVALID_OPTION" , argv
[ 1 ]);
774 return opt ( cmd
, user
, hi
, 0 , argc
- 1 , argv
+ 1 );
777 static MODCMD_FUNC ( cmd_oset
)
779 struct handle_info
* hi
;
782 MEMOSERV_MIN_PARAMS ( 2 );
784 if (!( hi
= get_victim_oper ( user
, argv
[ 1 ])))
788 set_list ( cmd
, user
, hi
, 0 );
792 if (!( opt
= dict_find ( memoserv_opt_dict
, argv
[ 2 ], NULL
))) {
793 reply ( "MSMSG_INVALID_OPTION" , argv
[ 2 ]);
797 return opt ( cmd
, user
, hi
, 1 , argc
- 2 , argv
+ 2 );
800 static OPTION_FUNC ( opt_newnotify
)
802 struct memo_account
* ma
;
805 if (!( ma
= memoserv_get_account ( hi
)))
809 if ( enabled_string ( choice
)) {
810 ma
-> flags
|= MEMO_NOTIFY_NEW
;
811 } else if ( disabled_string ( choice
)) {
812 ma
-> flags
&= ~ MEMO_NOTIFY_NEW
;
814 reply ( "MSMSG_INVALID_BINARY" , choice
);
819 choice
= ( ma
-> flags
& MEMO_NOTIFY_NEW
) ? "on" : "off" ;
820 reply ( "MSMSG_SET_NEWNOTIFY" , choice
);
824 static OPTION_FUNC ( opt_privmsg
)
826 struct memo_account
* ma
;
829 if (!( ma
= memoserv_get_account ( hi
)))
833 if ( enabled_string ( choice
)) {
834 ma
-> flags
|= MEMO_USE_PRIVMSG
;
835 } else if ( disabled_string ( choice
)) {
836 ma
-> flags
&= ~ MEMO_USE_PRIVMSG
;
838 reply ( "MSMSG_INVALID_BINARY" , choice
);
842 choice
= ( ma
-> flags
& MEMO_USE_PRIVMSG
) ? "on" : "off" ;
843 reply ( "MSMSG_SET_PRIVMSG" , choice
);
847 static OPTION_FUNC ( opt_authnotify
)
849 struct memo_account
* ma
;
852 if (!( ma
= memoserv_get_account ( hi
)))
856 if ( enabled_string ( choice
)) {
857 ma
-> flags
|= MEMO_NOTIFY_LOGIN
;
858 } else if ( disabled_string ( choice
)) {
859 ma
-> flags
&= ~ MEMO_NOTIFY_LOGIN
;
861 reply ( "MSMSG_INVALID_BINARY" , choice
);
866 choice
= ( ma
-> flags
& MEMO_NOTIFY_LOGIN
) ? "on" : "off" ;
867 reply ( "MSMSG_SET_AUTHNOTIFY" , choice
);
871 static OPTION_FUNC ( opt_ignorereciepts
)
873 struct memo_account
* ma
;
876 if (!( ma
= memoserv_get_account ( hi
)))
880 if ( enabled_string ( choice
)) {
881 ma
-> flags
|= MEMO_IGNORE_RECIEPTS
;
882 } else if ( disabled_string ( choice
)) {
883 ma
-> flags
&= ~ MEMO_IGNORE_RECIEPTS
;
885 reply ( "MSMSG_INVALID_BINARY" , choice
);
890 choice
= ( ma
-> flags
& MEMO_IGNORE_RECIEPTS
) ? "on" : "off" ;
891 reply ( "MSMSG_SET_IGNORERECIEPTS" , choice
);
895 static OPTION_FUNC ( opt_sendreciepts
)
897 struct memo_account
* ma
;
900 if (!( ma
= memoserv_get_account ( hi
)))
904 if ( enabled_string ( choice
)) {
905 ma
-> flags
|= MEMO_ALWAYS_RECIEPTS
;
906 } else if ( disabled_string ( choice
)) {
907 ma
-> flags
&= ~ MEMO_ALWAYS_RECIEPTS
;
909 reply ( "MSMSG_INVALID_BINARY" , choice
);
914 choice
= ( ma
-> flags
& MEMO_ALWAYS_RECIEPTS
) ? "on" : "off" ;
915 reply ( "MSMSG_SET_SENDRECIEPTS" , choice
);
919 static OPTION_FUNC ( opt_private
)
921 struct memo_account
* ma
;
924 if (!( ma
= memoserv_get_account ( hi
)))
928 if ( enabled_string ( choice
)) {
929 ma
-> flags
|= MEMO_DENY_NONCHANNEL
;
930 } else if ( disabled_string ( choice
)) {
931 ma
-> flags
&= ~ MEMO_DENY_NONCHANNEL
;
933 reply ( "MSMSG_INVALID_BINARY" , choice
);
938 choice
= ( ma
-> flags
& MEMO_DENY_NONCHANNEL
) ? "on" : "off" ;
939 reply ( "MSMSG_SET_PRIVATE" , choice
);
943 static OPTION_FUNC ( opt_limit
)
945 struct memo_account
* ma
;
948 if (!( ma
= memoserv_get_account ( hi
)))
951 choice
= atoi ( argv
[ 1 ]);
952 if ( choice
> memoserv_conf
. limit
)
953 choice
= memoserv_conf
. limit
;
958 reply ( "MSMSG_SET_LIMIT" , ma
-> limit
);
962 static MODCMD_FUNC ( cmd_status
)
964 struct memo_account
* ma
;
969 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
971 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
)
975 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
977 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
)
981 reply ( "MSMSG_STATUS_HIST_TOTAL" , hc
);
982 reply ( "MSMSG_STATUS_TOTAL" , memoCount
);
983 reply ( "MSMSG_STATUS_EXPIRED" , memosExpired
);
984 reply ( "MSMSG_STATUS_SENT" , memosSent
);
989 memoserv_conf_read ( void )
994 str
= "modules/memoserv" ;
995 if (!( conf_node
= conf_get_data ( str
, RECDB_OBJECT
))) {
996 log_module ( MS_LOG
, LOG_ERROR
, "config node ` %s ' is missing or has wrong type." , str
);
1000 str
= database_get_data ( conf_node
, "limit" , RECDB_QSTRING
);
1001 memoserv_conf
. limit
= str
? atoi ( str
) : 50 ;
1003 str
= database_get_data ( conf_node
, "message_expiry" , RECDB_QSTRING
);
1004 memoserv_conf
. message_expiry
= str
? ParseInterval ( str
) : 60 * 24 * 30 ;
1008 memoserv_user_read ( const char * key
, struct record_data
* hir
)
1011 struct memo_account
* ma
;
1012 struct handle_info
* hi
;
1014 if (!( hi
= get_handle_info ( key
)))
1017 ma
= dict_find ( memos
, hi
-> handle
, NULL
);
1022 ma
= calloc ( 1 , sizeof (* ma
));
1028 str
= database_get_data ( hir
-> d
. object
, KEY_FLAGS
, RECDB_QSTRING
);
1030 log_module ( MS_LOG
, LOG_ERROR
, "Flags not present in memo %s ; skipping" , key
);
1033 ma
-> flags
= strtoul ( str
, NULL
, 0 );
1035 str
= database_get_data ( hir
-> d
. object
, KEY_LIMIT
, RECDB_QSTRING
);
1037 log_module ( MS_LOG
, LOG_ERROR
, "Limit not present in memo %s ; skipping" , key
);
1040 ma
-> limit
= strtoul ( str
, NULL
, 0 );
1042 dict_insert ( memos
, ma
-> handle
-> handle
, ma
);
1043 dict_insert ( historys
, ma
-> handle
-> handle
, ma
);
1049 memoserv_memo_read ( const char * key
, struct record_data
* hir
)
1052 struct handle_info
* sender
, * recipient
;
1057 if ( hir
-> type
!= RECDB_OBJECT
) {
1058 log_module ( MS_LOG
, LOG_WARNING
, "Unexpected rectype %d for %s ." , hir
-> type
, key
);
1062 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_SENT
, RECDB_QSTRING
))) {
1063 log_module ( MS_LOG
, LOG_ERROR
, "Date sent not present in memo %s ; skipping" , key
);
1069 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_ID
, RECDB_QSTRING
))) {
1070 log_module ( MS_LOG
, LOG_ERROR
, "ID sent not present in memo %s ; skipping" , key
);
1073 id
= strtoul ( str
, NULL
, 0 );
1077 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_RECIPIENT
, RECDB_QSTRING
))) {
1078 log_module ( MS_LOG
, LOG_ERROR
, "Recipient not present in memo %s ; skipping" , key
);
1080 } else if (!( recipient
= get_handle_info ( str
))) {
1081 log_module ( MS_LOG
, LOG_ERROR
, "Invalid recipient %s in memo %s ; skipping" , str
, key
);
1085 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_FROM
, RECDB_QSTRING
))) {
1086 log_module ( MS_LOG
, LOG_ERROR
, "Sender not present in memo %s ; skipping" , key
);
1088 } else if (!( sender
= get_handle_info ( str
))) {
1089 log_module ( MS_LOG
, LOG_ERROR
, "Invalid sender %s in memo %s ; skipping" , str
, key
);
1093 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_MESSAGE
, RECDB_QSTRING
))) {
1094 log_module ( MS_LOG
, LOG_ERROR
, "Message not present in memo %s ; skipping" , key
);
1098 memo
= add_memo ( sent
, memoserv_get_account ( recipient
), memoserv_get_account ( sender
), str
, 0 );
1099 if (( str
= database_get_data ( hir
-> d
. object
, KEY_READ
, RECDB_QSTRING
)))
1102 if (( str
= database_get_data ( hir
-> d
. object
, KEY_RECIEPT
, RECDB_QSTRING
)))
1111 memoserv_history_read ( const char * key
, struct record_data
* hir
)
1114 struct handle_info
* sender
, * recipient
;
1118 if ( hir
-> type
!= RECDB_OBJECT
) {
1119 log_module ( MS_LOG
, LOG_WARNING
, "Unexpected rectype %d for %s ." , hir
-> type
, key
);
1123 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_SENT
, RECDB_QSTRING
))) {
1124 log_module ( MS_LOG
, LOG_ERROR
, "Date sent not present in history %s ; skipping" , key
);
1130 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_ID
, RECDB_QSTRING
))) {
1131 log_module ( MS_LOG
, LOG_ERROR
, "ID sent not present in history %s ; skipping" , key
);
1134 id
= strtoul ( str
, NULL
, 0 );
1136 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_RECIPIENT
, RECDB_QSTRING
))) {
1137 log_module ( MS_LOG
, LOG_ERROR
, "Recipient not present in history %s ; skipping" , key
);
1139 } else if (!( recipient
= get_handle_info ( str
))) {
1140 log_module ( MS_LOG
, LOG_ERROR
, "Invalid recipient %s in history %s ; skipping" , str
, key
);
1144 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_FROM
, RECDB_QSTRING
))) {
1145 log_module ( MS_LOG
, LOG_ERROR
, "Sender not present in history %s ; skipping" , key
);
1147 } else if (!( sender
= get_handle_info ( str
))) {
1148 log_module ( MS_LOG
, LOG_ERROR
, "Invalid sender %s in history %s ; skipping" , str
, key
);
1152 add_history ( sent
, memoserv_get_account ( recipient
), memoserv_get_account ( sender
), id
);
1158 memoserv_saxdb_read ( struct dict
* database
)
1160 struct dict
* section
;
1163 if (( section
= database_get_data ( database
, KEY_MAIN_ACCOUNTS
, RECDB_OBJECT
)))
1164 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1165 memoserv_user_read ( iter_key ( it
), iter_data ( it
));
1167 if (( section
= database_get_data ( database
, KEY_MAIN_MEMOS
, RECDB_OBJECT
)))
1168 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1169 memoserv_memo_read ( iter_key ( it
), iter_data ( it
));
1171 if (( section
= database_get_data ( database
, KEY_MAIN_HISTORY
, RECDB_OBJECT
)))
1172 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1173 memoserv_history_read ( iter_key ( it
), iter_data ( it
));
1179 memoserv_write_users ( struct saxdb_context
* ctx
, struct memo_account
* ma
)
1181 saxdb_start_record ( ctx
, ma
-> handle
-> handle
, 0 );
1183 saxdb_write_int ( ctx
, KEY_FLAGS
, ma
-> flags
);
1184 saxdb_write_int ( ctx
, KEY_LIMIT
, ma
-> limit
);
1186 saxdb_end_record ( ctx
);
1191 memoserv_write_memos ( struct saxdb_context
* ctx
, struct memo
* memo
)
1195 memset ( str
, '\0' , sizeof ( str
));
1196 saxdb_start_record ( ctx
, inttobase64 ( str
, memo
-> id
, sizeof ( str
)- 1 ), 0 );
1198 saxdb_write_int ( ctx
, KEY_SENT
, memo
-> sent
);
1199 saxdb_write_int ( ctx
, KEY_ID
, memo
-> id
);
1200 saxdb_write_string ( ctx
, KEY_RECIPIENT
, memo
-> recipient
-> handle
-> handle
);
1201 saxdb_write_string ( ctx
, KEY_FROM
, memo
-> sender
-> handle
-> handle
);
1202 saxdb_write_string ( ctx
, KEY_MESSAGE
, memo
-> message
);
1205 saxdb_write_int ( ctx
, KEY_READ
, 1 );
1208 saxdb_write_int ( ctx
, KEY_RECIEPT
, 1 );
1210 saxdb_end_record ( ctx
);
1215 memoserv_write_history ( struct saxdb_context
* ctx
, struct history
* history
)
1219 memset ( str
, '\0' , sizeof ( str
));
1220 saxdb_start_record ( ctx
, inttobase64 ( str
, history
-> id
, sizeof ( str
)- 1 ), 0 );
1222 saxdb_write_int ( ctx
, KEY_SENT
, history
-> sent
);
1223 saxdb_write_int ( ctx
, KEY_ID
, history
-> id
);
1224 saxdb_write_string ( ctx
, KEY_RECIPIENT
, history
-> recipient
-> handle
-> handle
);
1225 saxdb_write_string ( ctx
, KEY_FROM
, history
-> sender
-> handle
-> handle
);
1227 saxdb_end_record ( ctx
);
1232 memoserv_saxdb_write ( struct saxdb_context
* ctx
)
1235 struct memo_account
* ma
;
1237 struct history
* history
;
1241 saxdb_start_record ( ctx
, KEY_MAIN_ACCOUNTS
, 1 );
1242 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
1244 memoserv_write_users ( ctx
, ma
);
1246 saxdb_end_record ( ctx
);
1249 saxdb_start_record ( ctx
, KEY_MAIN_MEMOS
, 1 );
1250 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
1252 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
1253 memo
= ma
-> recvd
. list
[ ii
];
1254 memoserv_write_memos ( ctx
, memo
);
1257 saxdb_end_record ( ctx
);
1260 saxdb_start_record ( ctx
, KEY_MAIN_HISTORY
, 1 );
1261 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
1263 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
) {
1264 history
= ma
-> hrecvd
. list
[ ii
];
1265 memoserv_write_history ( ctx
, history
);
1268 saxdb_end_record ( ctx
);
1274 memoserv_cleanup ( UNUSED_ARG ( void * extra
))
1277 dict_delete ( historys
);
1281 memoserv_check_messages ( struct userNode
* user
, UNUSED_ARG ( struct handle_info
* old_handle
), UNUSED_ARG ( void * extra
))
1283 unsigned int ii
, unseen
;
1284 struct memo_account
* ma
;
1287 if (! user
-> uplink
-> burst
) {
1288 if (!( ma
= memoserv_get_account ( user
-> handle_info
))
1289 || !( ma
-> flags
& MEMO_NOTIFY_LOGIN
))
1291 for ( ii
= unseen
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
1292 memo
= ma
-> recvd
. list
[ ii
];
1296 if ( ma
-> recvd
. used
&& memoserv
)
1297 if ( unseen
) send_message_type (( ma
-> flags
& MEMO_USE_PRIVMSG
)? 1 : 0 , user
, memoserv
, "MSMSG_MEMOS_INBOX" , unseen
, ma
-> recvd
. used
- unseen
);
1302 memoserv_rename_account ( struct handle_info
* hi
, const char * old_handle
, UNUSED_ARG ( void * extra
))
1304 struct memo_account
* ma
;
1305 if (!( ma
= dict_find ( memos
, old_handle
, NULL
)))
1307 dict_remove2 ( memos
, old_handle
, 1 );
1308 dict_insert ( memos
, hi
-> handle
, ma
);
1310 dict_remove2 ( historys
, old_handle
, 1 );
1311 dict_insert ( historys
, hi
-> handle
, ma
);
1315 memoserv_unreg_account ( UNUSED_ARG ( struct userNode
* user
), struct handle_info
* handle
, UNUSED_ARG ( void * extra
))
1317 dict_remove ( memos
, handle
-> handle
);
1318 dict_remove ( historys
, handle
-> handle
);
1324 MS_LOG
= log_register_type ( "MemoServ" , "file:memoserv.log" );
1326 historys
= dict_new ();
1327 dict_set_free_data ( memos
, delete_memo_account
);
1328 reg_auth_func ( memoserv_check_messages
, NULL
);
1329 reg_handle_rename_func ( memoserv_rename_account
, NULL
);
1330 reg_unreg_func ( memoserv_unreg_account
, NULL
);
1331 conf_register_reload ( memoserv_conf_read
);
1332 reg_exit_func ( memoserv_cleanup
, NULL
);
1333 saxdb_register ( "MemoServ" , memoserv_saxdb_read
, memoserv_saxdb_write
);
1335 memoserv_module
= module_register ( "MemoServ" , MS_LOG
, "mod-memoserv.help" , NULL
);
1336 modcmd_register ( memoserv_module
, "send" , cmd_send
, 3 , MODCMD_REQUIRE_AUTHED
, NULL
);
1337 modcmd_register ( memoserv_module
, "list" , cmd_list
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1338 modcmd_register ( memoserv_module
, "read" , cmd_read
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1339 modcmd_register ( memoserv_module
, "delete" , cmd_delete
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1340 modcmd_register ( memoserv_module
, "cancel" , cmd_cancel
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1341 modcmd_register ( memoserv_module
, "history" , cmd_history
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1342 modcmd_register ( memoserv_module
, "expire" , cmd_expire
, 1 , MODCMD_REQUIRE_AUTHED
, "flags" , "+oper" , NULL
);
1343 modcmd_register ( memoserv_module
, "expiry" , cmd_expiry
, 1 , 0 , NULL
);
1344 modcmd_register ( memoserv_module
, "status" , cmd_status
, 1 , 0 , NULL
);
1345 modcmd_register ( memoserv_module
, "set" , cmd_set
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1346 modcmd_register ( memoserv_module
, "oset" , cmd_oset
, 1 , MODCMD_REQUIRE_AUTHED
, "flags" , "+helping" , NULL
);
1348 memoserv_opt_dict
= dict_new ();
1349 dict_insert ( memoserv_opt_dict
, "AUTHNOTIFY" , opt_authnotify
);
1350 dict_insert ( memoserv_opt_dict
, "NEWNOTIFY" , opt_newnotify
);
1351 dict_insert ( memoserv_opt_dict
, "PRIVMSG" , opt_privmsg
);
1352 dict_insert ( memoserv_opt_dict
, "PRIVATE" , opt_private
);
1353 dict_insert ( memoserv_opt_dict
, "IGNORERECIEPTS" , opt_ignorereciepts
);
1354 dict_insert ( memoserv_opt_dict
, "SENDRECIEPTS" , opt_sendreciepts
);
1355 dict_insert ( memoserv_opt_dict
, "LIMIT" , opt_limit
);
1357 message_register_table ( msgtab
);
1359 if ( memoserv_conf
. message_expiry
)
1360 timeq_add ( now
+ memoserv_conf
. message_expiry
, expire_memos
, NULL
);
1366 memoserv_finalize ( void ) {
1367 struct chanNode
* chan
;
1372 str
= "modules/memoserv" ;
1373 if (!( conf_node
= conf_get_data ( str
, RECDB_OBJECT
))) {
1374 log_module ( MS_LOG
, LOG_ERROR
, "config node ` %s ' is missing or has wrong type." , str
);
1378 str
= database_get_data ( conf_node
, "bot" , RECDB_QSTRING
);
1380 memoserv
= memoserv_conf
. bot
;
1381 const char * modes
= conf_get_data ( "modules/memoserv/modes" , RECDB_QSTRING
);
1382 memoserv
= AddLocalUser ( str
, str
, NULL
, "User-User Memorandum Services" , modes
);
1383 service_register ( memoserv
);
1385 log_module ( MS_LOG
, LOG_ERROR
, "database_get_data for memoserv_conf.bot failed!" );
1389 if ( autojoin_channels
&& memoserv
) {
1390 for ( i
= 0 ; i
< autojoin_channels
-> used
; i
++) {
1391 chan
= AddChannel ( autojoin_channels
-> list
[ i
], now
, "+nt" , NULL
, NULL
);
1392 AddChannelUser ( memoserv
, chan
)-> modes
|= MODE_CHANOP
;