]>
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
)
318 struct history
* history
;
320 memo
= calloc ( 1 , sizeof (* memo
));
329 memo
-> recipient
= recipient
;
330 memoList_append (& recipient
-> recvd
, memo
);
331 memo
-> sender
= sender
;
332 memoList_append (& sender
-> sent
, memo
);
334 memo
-> message
= strdup ( message
);
339 history
= add_history ( sent
, recipient
, sender
, memo
-> id
);
345 memoserv_can_send ( struct userNode
* bot
, struct userNode
* user
, struct memo_account
* acct
)
347 extern struct userData
* _GetChannelUser ( struct chanData
* channel
, struct handle_info
* handle
, int override
, int allow_suspended
);
348 struct userData
* dest
;
349 unsigned int i
= 0 , match
= 0 ;
351 if (! user
-> handle_info
)
354 /* Sanity checks here because if the user doesnt have a limit set
355 the limit comes out at like 21233242 if you try and use it. */
356 if ( acct
-> limit
> memoserv_conf
. limit
)
357 acct
-> limit
= memoserv_conf
. limit
;
359 if ( acct
-> recvd
. used
> acct
-> limit
) {
360 send_message ( user
, bot
, "MSMSG_FULL_INBOX" , acct
-> handle
-> handle
);
361 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
365 if ( acct
-> handle
-> ignores
-> used
) {
366 for ( i
= 0 ; i
< acct
-> handle
-> ignores
-> used
; i
++) {
367 if ( user_matches_glob ( user
, acct
-> handle
-> ignores
-> list
[ i
], MATCH_USENICK
, 0 )) {
374 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
379 if (!( acct
-> flags
& MEMO_DENY_NONCHANNEL
))
382 for ( dest
= acct
-> handle
-> channels
; dest
; dest
= dest
-> u_next
)
383 if ( _GetChannelUser ( dest
-> channel
, user
-> handle_info
, 1 , 0 ))
386 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
390 static struct memo
* find_memo ( struct userNode
* user
, struct svccmd
* cmd
, struct memo_account
* ma
, const char * msgid
, unsigned int * id
)
393 if (! isdigit ( msgid
[ 0 ])) {
395 reply ( "MSMSG_BAD_MESSAGE_ID" , msgid
, ma
-> recvd
. used
- 1 );
397 reply ( "MSMSG_NO_MESSAGES" );
400 memoid
= atoi ( msgid
);
401 if ( memoid
>= ma
-> recvd
. used
) {
402 reply ( "MSMSG_NO_SUCH_MEMO" );
405 return ma
-> recvd
. list
[* id
= memoid
];
408 static MODCMD_FUNC ( cmd_send
)
411 int reciept
= 0 , inc
= 2 , email
= 0 ;
412 struct handle_info
* hi
;
413 struct memo_account
* ma
, * sender
;
415 char subject
[ 128 ], body
[ 4096 ];
417 const char * netname
, * fmt
;
419 MEMOSERV_MIN_PARAMS ( 3 );
421 if ( checkDefCon ( DEFCON_NO_NEW_MEMOS
) && ! IsOper ( user
)) {
422 reply ( "MSMSG_DEFCON_NO_NEW_MEMOS" );
426 if (!( hi
= modcmd_get_handle_info ( user
, argv
[ 1 ])))
429 if (!( sender
= memoserv_get_account ( user
-> handle_info
))
430 || !( ma
= memoserv_get_account ( hi
))) {
431 reply ( "MSG_INTERNAL_FAILURE" );
435 if (!( memoserv_can_send ( cmd
-> parent
-> bot
, user
, ma
)))
438 inc
= 2 ; /* Start of message on 3rd ([2]) word */
439 if ( argv
[ 2 ][ 0 ] == '-' && argv
[ 2 ][ 1 ] != '-' ) { /* first word is flags ('-r')*/
440 char * flags
= argv
[ 2 ];
441 inc
++; /* Start of message is now 1 word later */
442 for ( flags
++;* flags
; flags
++) {
449 /* Unknown mode. Give an error */
450 reply ( "MSMSG_UNKNOWN_SEND_FLAG" , * flags
);
456 inc
= 2 ; /* Start of message is word 2 */
458 message
= unsplit_string ( argv
+ inc
, argc
- inc
, NULL
);
459 memo
= add_memo ( now
, ma
, sender
, message
, 1 );
460 if (( reciept
== 1 ) || ( ma
-> flags
& MEMO_ALWAYS_RECIEPTS
))
463 if ( ma
-> flags
& MEMO_NOTIFY_NEW
) {
464 struct userNode
* other
;
466 for ( other
= ma
-> handle
-> users
; other
; other
= other
-> next_authed
)
467 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
);
470 estr
= conf_get_data ( "services/nickserv/email_enabled" , RECDB_QSTRING
);
471 netname
= conf_get_data ( "server/network" , RECDB_QSTRING
);
473 if ( email
&& ( ma
-> flags
& MEMO_NOTIFY_NEW
)) {
474 fmt
= handle_find_message ( hi
, "MSEMAIL_NEWMEMO_SUBJECT" );
475 snprintf ( subject
, sizeof ( subject
), fmt
, netname
, memoserv
-> nick
, user
-> nick
);
477 fmt
= handle_find_message ( hi
, "MSEMAIL_NEWMEMO_BODY" );
478 snprintf ( body
, sizeof ( body
), fmt
, user
-> nick
, memoserv
-> nick
, message
, memoserv
-> nick
, memo_id
, netname
);
480 mail_send ( memoserv
, hi
, subject
, body
, 0 );
483 reply ( "MSMSG_MEMO_SENT" , ma
-> handle
-> handle
, memo_id
);
487 static MODCMD_FUNC ( cmd_list
)
489 struct memo_account
* ma
;
495 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
498 reply ( "MSMSG_LIST_HEAD" );
500 if ( user
-> handle_info
&& user
-> handle_info
-> userlist_style
!= HI_STYLE_CLEAN
)
503 for ( ii
= 0 ; ( ii
< ma
-> recvd
. used
) && ( ii
< 15 ); ++ ii
) {
504 memo
= ma
-> recvd
. list
[ ii
];
505 localtime_r (& memo
-> sent
, & tm
);
506 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
507 reply ( "MSMSG_LIST_FORMAT" , ii
, memo
-> sender
-> handle
-> handle
, memo
-> reciept
? "(r)" : "" , posted
);
512 reply ( "MSMSG_CLEAN_INBOX" , ii
);
514 reply ( "MSMSG_MEMOS_FOUND" , ii
);
515 reply ( "MSMSG_HOWTO_READ" );
518 reply ( "MSMSG_LIST_END" );
523 static MODCMD_FUNC ( cmd_history
)
525 struct memo_account
* ma
;
526 struct history
* history
;
533 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
536 reply ( "MSMSG_HISTORY_HEADER" );
538 if ( user
-> handle_info
&& user
-> handle_info
-> userlist_style
!= HI_STYLE_CLEAN
)
541 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
543 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
) {
544 history
= ma
-> hrecvd
. list
[ ii
];
545 if (! strcasecmp ( history
-> sender
-> handle
-> handle
, user
-> handle_info
-> handle
)) {
547 localtime_r (& history
-> sent
, & tm
);
548 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
549 reply ( "MSMSG_HISTORY_FORMAT" , history
-> id
, history
-> recipient
-> handle
-> handle
, posted
);
557 reply ( "MSMSG_MEMOS_FOUND" , cc
);
559 reply ( "MSMSG_LIST_END" );
564 static MODCMD_FUNC ( cmd_read
)
566 struct memo_account
* ma
;
568 int rignore
= 0 , brk
= 0 , s
= 0 ;
575 char * argtwo
= argv
[ 2 ];
600 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
603 if (!( memo
= find_memo ( user
, cmd
, ma
, argv
[ 1 ], & memoid
)))
606 localtime_r (& memo
-> sent
, & tm
);
607 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
609 reply ( "MSMSG_MEMO_HEAD" , memoid
, memo
-> sender
-> handle
-> handle
, posted
);
610 send_message_type ( 4 , user
, cmd
-> parent
-> bot
, " %s " , memo
-> message
);
614 if ( ma
-> flags
& MEMO_IGNORE_RECIEPTS
)
617 if ( memo
-> reciept
== 1 ) {
619 reply ( "MSMSG_MEMO_RECIEPT" , rignore
? "ignoring" : "sending" );
621 struct memo_account
* ma
;
622 struct memo_account
* sender
;
623 char content
[ MAXLEN
];
625 ma
= memoserv_get_account ( user
-> handle_info
);
626 sender
= memoserv_get_account ( memo
-> sender
-> handle
);
628 sprintf ( content
, " %s has read your memo dated %s ." , ma
-> handle
-> handle
, posted
);
630 memo
= add_memo ( now
, sender
, ma
, content
, 1 );
631 reply ( "MSMSG_MEMO_SENT" , memob
-> sender
-> handle
-> handle
, memo_id
);
633 if ( sender
-> flags
& MEMO_NOTIFY_NEW
) {
634 struct userNode
* other
;
636 for ( other
= sender
-> handle
-> users
; other
; other
= other
-> next_authed
)
637 send_message_type (( ma
-> flags
& MEMO_USE_PRIVMSG
)? MSG_TYPE_PRIVMSG
: MSG_TYPE_NOTICE
, other
, cmd
-> parent
-> bot
, "MSMSG_NEW_MESSAGE" , ma
-> handle
-> handle
);
646 static MODCMD_FUNC ( cmd_delete
)
648 struct memo_account
* ma
;
652 MEMOSERV_MIN_PARAMS ( 2 );
654 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
656 if (! irccasecmp ( argv
[ 1 ], "*" ) || ! irccasecmp ( argv
[ 1 ], "all" )) {
657 if (( argc
< 3 ) || irccasecmp ( argv
[ 2 ], "confirm" )) {
658 reply ( "MSMSG_USE_CONFIRM" );
661 while ( ma
-> recvd
. used
)
662 delete_memo ( ma
-> recvd
. list
[ 0 ]);
663 reply ( "MSMSG_DELETED_ALL" );
667 if (!( memo
= find_memo ( user
, cmd
, ma
, argv
[ 1 ], & memoid
)))
670 reply ( "MSMSG_MEMO_DELETED" , memoid
);
674 static MODCMD_FUNC ( cmd_cancel
)
680 struct memo_account
* ma
;
682 MEMOSERV_MIN_PARAMS ( 2 );
684 if ( isdigit ( argv
[ 1 ][ 0 ])) {
685 id
= strtoul ( argv
[ 1 ], NULL
, 0 );
687 reply ( "MSMSG_MEMO_CANCEL_NUMBER" );
691 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
693 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
694 memo
= ma
-> recvd
. list
[ ii
];
696 if ( id
== memo
-> id
) {
697 if (! strcasecmp ( memo
-> sender
-> handle
-> handle
, user
-> handle_info
-> handle
)) {
699 reply ( "MSMSG_MEMO_READ" , id
);
703 reply ( "MSMSG_MEMO_DELETED" , id
);
707 reply ( "MSMSG_MEMO_DONT_OWN" , id
);
714 reply ( "MSMSG_MEMO_CANT_LOCATE" , id
);
718 static MODCMD_FUNC ( cmd_expire
)
720 unsigned long old_expired
= memosExpired
;
722 reply ( "MSMSG_MESSAGES_EXPIRED" , memosExpired
- old_expired
);
726 static MODCMD_FUNC ( cmd_expiry
)
728 char interval
[ INTERVALLEN
];
730 if (! memoserv_conf
. message_expiry
) {
731 reply ( "MSMSG_EXPIRY_OFF" );
735 intervalString ( interval
, memoserv_conf
. message_expiry
, user
-> handle_info
);
736 reply ( "MSMSG_EXPIRY" , interval
, memoserv_conf
. message_expiry
);
742 set_list ( struct svccmd
* cmd
, struct userNode
* user
, struct handle_info
* hi
, int override
)
746 char * set_display
[] = { "AUTHNOTIFY" , "NEWNOTIFY" , "PRIVMSG" , "PRIVATE" , "LIMIT" ,
747 "IGNORERECIEPTS" , "SENDRECIEPTS" };
749 reply ( "MSMSG_SET_OPTIONS" );
752 /* Do this so options are presented in a consistent order. */
753 for ( i
= 0 ; i
< ArrayLength ( set_display
); ++ i
)
754 if (( opt
= dict_find ( memoserv_opt_dict
, set_display
[ i
], NULL
)))
755 opt ( cmd
, user
, hi
, override
, 0 , NULL
);
756 reply ( "MSMSG_SET_OPTIONS_END" );
759 static MODCMD_FUNC ( cmd_set
)
761 struct handle_info
* hi
;
764 hi
= user
-> handle_info
;
766 set_list ( cmd
, user
, hi
, 0 );
770 if (!( opt
= dict_find ( memoserv_opt_dict
, argv
[ 1 ], NULL
))) {
771 reply ( "MSMSG_INVALID_OPTION" , argv
[ 1 ]);
775 return opt ( cmd
, user
, hi
, 0 , argc
- 1 , argv
+ 1 );
778 static MODCMD_FUNC ( cmd_oset
)
780 struct handle_info
* hi
;
783 MEMOSERV_MIN_PARAMS ( 2 );
785 if (!( hi
= get_victim_oper ( user
, argv
[ 1 ])))
789 set_list ( cmd
, user
, hi
, 0 );
793 if (!( opt
= dict_find ( memoserv_opt_dict
, argv
[ 2 ], NULL
))) {
794 reply ( "MSMSG_INVALID_OPTION" , argv
[ 2 ]);
798 return opt ( cmd
, user
, hi
, 1 , argc
- 2 , argv
+ 2 );
801 static OPTION_FUNC ( opt_newnotify
)
803 struct memo_account
* ma
;
806 if (!( ma
= memoserv_get_account ( hi
)))
810 if ( enabled_string ( choice
)) {
811 ma
-> flags
|= MEMO_NOTIFY_NEW
;
812 } else if ( disabled_string ( choice
)) {
813 ma
-> flags
&= ~ MEMO_NOTIFY_NEW
;
815 reply ( "MSMSG_INVALID_BINARY" , choice
);
820 choice
= ( ma
-> flags
& MEMO_NOTIFY_NEW
) ? "on" : "off" ;
821 reply ( "MSMSG_SET_NEWNOTIFY" , choice
);
825 static OPTION_FUNC ( opt_privmsg
)
827 struct memo_account
* ma
;
830 if (!( ma
= memoserv_get_account ( hi
)))
834 if ( enabled_string ( choice
)) {
835 ma
-> flags
|= MEMO_USE_PRIVMSG
;
836 } else if ( disabled_string ( choice
)) {
837 ma
-> flags
&= ~ MEMO_USE_PRIVMSG
;
839 reply ( "MSMSG_INVALID_BINARY" , choice
);
843 choice
= ( ma
-> flags
& MEMO_USE_PRIVMSG
) ? "on" : "off" ;
844 reply ( "MSMSG_SET_PRIVMSG" , choice
);
848 static OPTION_FUNC ( opt_authnotify
)
850 struct memo_account
* ma
;
853 if (!( ma
= memoserv_get_account ( hi
)))
857 if ( enabled_string ( choice
)) {
858 ma
-> flags
|= MEMO_NOTIFY_LOGIN
;
859 } else if ( disabled_string ( choice
)) {
860 ma
-> flags
&= ~ MEMO_NOTIFY_LOGIN
;
862 reply ( "MSMSG_INVALID_BINARY" , choice
);
867 choice
= ( ma
-> flags
& MEMO_NOTIFY_LOGIN
) ? "on" : "off" ;
868 reply ( "MSMSG_SET_AUTHNOTIFY" , choice
);
872 static OPTION_FUNC ( opt_ignorereciepts
)
874 struct memo_account
* ma
;
877 if (!( ma
= memoserv_get_account ( hi
)))
881 if ( enabled_string ( choice
)) {
882 ma
-> flags
|= MEMO_IGNORE_RECIEPTS
;
883 } else if ( disabled_string ( choice
)) {
884 ma
-> flags
&= ~ MEMO_IGNORE_RECIEPTS
;
886 reply ( "MSMSG_INVALID_BINARY" , choice
);
891 choice
= ( ma
-> flags
& MEMO_IGNORE_RECIEPTS
) ? "on" : "off" ;
892 reply ( "MSMSG_SET_IGNORERECIEPTS" , choice
);
896 static OPTION_FUNC ( opt_sendreciepts
)
898 struct memo_account
* ma
;
901 if (!( ma
= memoserv_get_account ( hi
)))
905 if ( enabled_string ( choice
)) {
906 ma
-> flags
|= MEMO_ALWAYS_RECIEPTS
;
907 } else if ( disabled_string ( choice
)) {
908 ma
-> flags
&= ~ MEMO_ALWAYS_RECIEPTS
;
910 reply ( "MSMSG_INVALID_BINARY" , choice
);
915 choice
= ( ma
-> flags
& MEMO_ALWAYS_RECIEPTS
) ? "on" : "off" ;
916 reply ( "MSMSG_SET_SENDRECIEPTS" , choice
);
920 static OPTION_FUNC ( opt_private
)
922 struct memo_account
* ma
;
925 if (!( ma
= memoserv_get_account ( hi
)))
929 if ( enabled_string ( choice
)) {
930 ma
-> flags
|= MEMO_DENY_NONCHANNEL
;
931 } else if ( disabled_string ( choice
)) {
932 ma
-> flags
&= ~ MEMO_DENY_NONCHANNEL
;
934 reply ( "MSMSG_INVALID_BINARY" , choice
);
939 choice
= ( ma
-> flags
& MEMO_DENY_NONCHANNEL
) ? "on" : "off" ;
940 reply ( "MSMSG_SET_PRIVATE" , choice
);
944 static OPTION_FUNC ( opt_limit
)
946 struct memo_account
* ma
;
949 if (!( ma
= memoserv_get_account ( hi
)))
952 choice
= atoi ( argv
[ 1 ]);
953 if ( choice
> memoserv_conf
. limit
)
954 choice
= memoserv_conf
. limit
;
959 reply ( "MSMSG_SET_LIMIT" , ma
-> limit
);
963 static MODCMD_FUNC ( cmd_status
)
965 struct memo_account
* ma
;
970 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
972 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
)
976 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
978 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
)
982 reply ( "MSMSG_STATUS_HIST_TOTAL" , hc
);
983 reply ( "MSMSG_STATUS_TOTAL" , memoCount
);
984 reply ( "MSMSG_STATUS_EXPIRED" , memosExpired
);
985 reply ( "MSMSG_STATUS_SENT" , memosSent
);
990 memoserv_conf_read ( void )
995 str
= "modules/memoserv" ;
996 if (!( conf_node
= conf_get_data ( str
, RECDB_OBJECT
))) {
997 log_module ( MS_LOG
, LOG_ERROR
, "config node ` %s ' is missing or has wrong type." , str
);
1001 str
= database_get_data ( conf_node
, "limit" , RECDB_QSTRING
);
1002 memoserv_conf
. limit
= str
? atoi ( str
) : 50 ;
1004 str
= database_get_data ( conf_node
, "message_expiry" , RECDB_QSTRING
);
1005 memoserv_conf
. message_expiry
= str
? ParseInterval ( str
) : 60 * 24 * 30 ;
1009 memoserv_user_read ( const char * key
, struct record_data
* hir
)
1012 struct memo_account
* ma
;
1013 struct handle_info
* hi
;
1015 if (!( hi
= get_handle_info ( key
)))
1018 ma
= dict_find ( memos
, hi
-> handle
, NULL
);
1023 ma
= calloc ( 1 , sizeof (* ma
));
1029 str
= database_get_data ( hir
-> d
. object
, KEY_FLAGS
, RECDB_QSTRING
);
1031 log_module ( MS_LOG
, LOG_ERROR
, "Flags not present in memo %s ; skipping" , key
);
1034 ma
-> flags
= strtoul ( str
, NULL
, 0 );
1036 str
= database_get_data ( hir
-> d
. object
, KEY_LIMIT
, RECDB_QSTRING
);
1038 log_module ( MS_LOG
, LOG_ERROR
, "Limit not present in memo %s ; skipping" , key
);
1041 ma
-> limit
= strtoul ( str
, NULL
, 0 );
1043 dict_insert ( memos
, ma
-> handle
-> handle
, ma
);
1044 dict_insert ( historys
, ma
-> handle
-> handle
, ma
);
1050 memoserv_memo_read ( const char * key
, struct record_data
* hir
)
1053 struct handle_info
* sender
, * recipient
;
1058 if ( hir
-> type
!= RECDB_OBJECT
) {
1059 log_module ( MS_LOG
, LOG_WARNING
, "Unexpected rectype %d for %s ." , hir
-> type
, key
);
1063 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_SENT
, RECDB_QSTRING
))) {
1064 log_module ( MS_LOG
, LOG_ERROR
, "Date sent not present in memo %s ; skipping" , key
);
1070 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_ID
, RECDB_QSTRING
))) {
1071 log_module ( MS_LOG
, LOG_ERROR
, "ID sent not present in memo %s ; skipping" , key
);
1074 id
= strtoul ( str
, NULL
, 0 );
1078 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_RECIPIENT
, RECDB_QSTRING
))) {
1079 log_module ( MS_LOG
, LOG_ERROR
, "Recipient not present in memo %s ; skipping" , key
);
1081 } else if (!( recipient
= get_handle_info ( str
))) {
1082 log_module ( MS_LOG
, LOG_ERROR
, "Invalid recipient %s in memo %s ; skipping" , str
, key
);
1086 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_FROM
, RECDB_QSTRING
))) {
1087 log_module ( MS_LOG
, LOG_ERROR
, "Sender not present in memo %s ; skipping" , key
);
1089 } else if (!( sender
= get_handle_info ( str
))) {
1090 log_module ( MS_LOG
, LOG_ERROR
, "Invalid sender %s in memo %s ; skipping" , str
, key
);
1094 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_MESSAGE
, RECDB_QSTRING
))) {
1095 log_module ( MS_LOG
, LOG_ERROR
, "Message not present in memo %s ; skipping" , key
);
1099 memo
= add_memo ( sent
, memoserv_get_account ( recipient
), memoserv_get_account ( sender
), str
, 0 );
1100 if (( str
= database_get_data ( hir
-> d
. object
, KEY_READ
, RECDB_QSTRING
)))
1103 if (( str
= database_get_data ( hir
-> d
. object
, KEY_RECIEPT
, RECDB_QSTRING
)))
1112 memoserv_history_read ( const char * key
, struct record_data
* hir
)
1115 struct handle_info
* sender
, * recipient
;
1116 struct history
* history
;
1120 if ( hir
-> type
!= RECDB_OBJECT
) {
1121 log_module ( MS_LOG
, LOG_WARNING
, "Unexpected rectype %d for %s ." , hir
-> type
, key
);
1125 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_SENT
, RECDB_QSTRING
))) {
1126 log_module ( MS_LOG
, LOG_ERROR
, "Date sent not present in history %s ; skipping" , key
);
1132 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_ID
, RECDB_QSTRING
))) {
1133 log_module ( MS_LOG
, LOG_ERROR
, "ID sent not present in history %s ; skipping" , key
);
1136 id
= strtoul ( str
, NULL
, 0 );
1138 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_RECIPIENT
, RECDB_QSTRING
))) {
1139 log_module ( MS_LOG
, LOG_ERROR
, "Recipient not present in history %s ; skipping" , key
);
1141 } else if (!( recipient
= get_handle_info ( str
))) {
1142 log_module ( MS_LOG
, LOG_ERROR
, "Invalid recipient %s in history %s ; skipping" , str
, key
);
1146 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_FROM
, RECDB_QSTRING
))) {
1147 log_module ( MS_LOG
, LOG_ERROR
, "Sender not present in history %s ; skipping" , key
);
1149 } else if (!( sender
= get_handle_info ( str
))) {
1150 log_module ( MS_LOG
, LOG_ERROR
, "Invalid sender %s in history %s ; skipping" , str
, key
);
1154 history
= add_history ( sent
, memoserv_get_account ( recipient
), memoserv_get_account ( sender
), id
);
1160 memoserv_saxdb_read ( struct dict
* database
)
1162 struct dict
* section
;
1165 if (( section
= database_get_data ( database
, KEY_MAIN_ACCOUNTS
, RECDB_OBJECT
)))
1166 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1167 memoserv_user_read ( iter_key ( it
), iter_data ( it
));
1169 if (( section
= database_get_data ( database
, KEY_MAIN_MEMOS
, RECDB_OBJECT
)))
1170 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1171 memoserv_memo_read ( iter_key ( it
), iter_data ( it
));
1173 if (( section
= database_get_data ( database
, KEY_MAIN_HISTORY
, RECDB_OBJECT
)))
1174 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1175 memoserv_history_read ( iter_key ( it
), iter_data ( it
));
1181 memoserv_write_users ( struct saxdb_context
* ctx
, struct memo_account
* ma
)
1183 saxdb_start_record ( ctx
, ma
-> handle
-> handle
, 0 );
1185 saxdb_write_int ( ctx
, KEY_FLAGS
, ma
-> flags
);
1186 saxdb_write_int ( ctx
, KEY_LIMIT
, ma
-> limit
);
1188 saxdb_end_record ( ctx
);
1193 memoserv_write_memos ( struct saxdb_context
* ctx
, struct memo
* memo
)
1197 memset ( str
, '\0' , sizeof ( str
));
1198 saxdb_start_record ( ctx
, inttobase64 ( str
, memo
-> id
, sizeof ( str
)- 1 ), 0 );
1200 saxdb_write_int ( ctx
, KEY_SENT
, memo
-> sent
);
1201 saxdb_write_int ( ctx
, KEY_ID
, memo
-> id
);
1202 saxdb_write_string ( ctx
, KEY_RECIPIENT
, memo
-> recipient
-> handle
-> handle
);
1203 saxdb_write_string ( ctx
, KEY_FROM
, memo
-> sender
-> handle
-> handle
);
1204 saxdb_write_string ( ctx
, KEY_MESSAGE
, memo
-> message
);
1207 saxdb_write_int ( ctx
, KEY_READ
, 1 );
1210 saxdb_write_int ( ctx
, KEY_RECIEPT
, 1 );
1212 saxdb_end_record ( ctx
);
1217 memoserv_write_history ( struct saxdb_context
* ctx
, struct history
* history
)
1221 memset ( str
, '\0' , sizeof ( str
));
1222 saxdb_start_record ( ctx
, inttobase64 ( str
, history
-> id
, sizeof ( str
)- 1 ), 0 );
1224 saxdb_write_int ( ctx
, KEY_SENT
, history
-> sent
);
1225 saxdb_write_int ( ctx
, KEY_ID
, history
-> id
);
1226 saxdb_write_string ( ctx
, KEY_RECIPIENT
, history
-> recipient
-> handle
-> handle
);
1227 saxdb_write_string ( ctx
, KEY_FROM
, history
-> sender
-> handle
-> handle
);
1229 saxdb_end_record ( ctx
);
1234 memoserv_saxdb_write ( struct saxdb_context
* ctx
)
1237 struct memo_account
* ma
;
1239 struct history
* history
;
1243 saxdb_start_record ( ctx
, KEY_MAIN_ACCOUNTS
, 1 );
1244 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
1246 memoserv_write_users ( ctx
, ma
);
1248 saxdb_end_record ( ctx
);
1251 saxdb_start_record ( ctx
, KEY_MAIN_MEMOS
, 1 );
1252 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
1254 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
1255 memo
= ma
-> recvd
. list
[ ii
];
1256 memoserv_write_memos ( ctx
, memo
);
1259 saxdb_end_record ( ctx
);
1262 saxdb_start_record ( ctx
, KEY_MAIN_HISTORY
, 1 );
1263 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
1265 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
) {
1266 history
= ma
-> hrecvd
. list
[ ii
];
1267 memoserv_write_history ( ctx
, history
);
1270 saxdb_end_record ( ctx
);
1276 memoserv_cleanup ( UNUSED_ARG ( void * extra
))
1279 dict_delete ( historys
);
1283 memoserv_check_messages ( struct userNode
* user
, UNUSED_ARG ( struct handle_info
* old_handle
), UNUSED_ARG ( void * extra
))
1285 unsigned int ii
, unseen
;
1286 struct memo_account
* ma
;
1289 if (! user
-> uplink
-> burst
) {
1290 if (!( ma
= memoserv_get_account ( user
-> handle_info
))
1291 || !( ma
-> flags
& MEMO_NOTIFY_LOGIN
))
1293 for ( ii
= unseen
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
1294 memo
= ma
-> recvd
. list
[ ii
];
1298 if ( ma
-> recvd
. used
&& memoserv
)
1299 if ( unseen
) send_message_type (( ma
-> flags
& MEMO_USE_PRIVMSG
)? 1 : 0 , user
, memoserv
, "MSMSG_MEMOS_INBOX" , unseen
, ma
-> recvd
. used
- unseen
);
1304 memoserv_rename_account ( struct handle_info
* hi
, const char * old_handle
, UNUSED_ARG ( void * extra
))
1306 struct memo_account
* ma
;
1307 if (!( ma
= dict_find ( memos
, old_handle
, NULL
)))
1309 dict_remove2 ( memos
, old_handle
, 1 );
1310 dict_insert ( memos
, hi
-> handle
, ma
);
1312 dict_remove2 ( historys
, old_handle
, 1 );
1313 dict_insert ( historys
, hi
-> handle
, ma
);
1317 memoserv_unreg_account ( UNUSED_ARG ( struct userNode
* user
), struct handle_info
* handle
, UNUSED_ARG ( void * extra
))
1319 dict_remove ( memos
, handle
-> handle
);
1320 dict_remove ( historys
, handle
-> handle
);
1326 MS_LOG
= log_register_type ( "MemoServ" , "file:memoserv.log" );
1328 historys
= dict_new ();
1329 dict_set_free_data ( memos
, delete_memo_account
);
1330 reg_auth_func ( memoserv_check_messages
, NULL
);
1331 reg_handle_rename_func ( memoserv_rename_account
, NULL
);
1332 reg_unreg_func ( memoserv_unreg_account
, NULL
);
1333 conf_register_reload ( memoserv_conf_read
);
1334 reg_exit_func ( memoserv_cleanup
, NULL
);
1335 saxdb_register ( "MemoServ" , memoserv_saxdb_read
, memoserv_saxdb_write
);
1337 memoserv_module
= module_register ( "MemoServ" , MS_LOG
, "mod-memoserv.help" , NULL
);
1338 modcmd_register ( memoserv_module
, "send" , cmd_send
, 3 , MODCMD_REQUIRE_AUTHED
, NULL
);
1339 modcmd_register ( memoserv_module
, "list" , cmd_list
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1340 modcmd_register ( memoserv_module
, "read" , cmd_read
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1341 modcmd_register ( memoserv_module
, "delete" , cmd_delete
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1342 modcmd_register ( memoserv_module
, "cancel" , cmd_cancel
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1343 modcmd_register ( memoserv_module
, "history" , cmd_history
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1344 modcmd_register ( memoserv_module
, "expire" , cmd_expire
, 1 , MODCMD_REQUIRE_AUTHED
, "flags" , "+oper" , NULL
);
1345 modcmd_register ( memoserv_module
, "expiry" , cmd_expiry
, 1 , 0 , NULL
);
1346 modcmd_register ( memoserv_module
, "status" , cmd_status
, 1 , 0 , NULL
);
1347 modcmd_register ( memoserv_module
, "set" , cmd_set
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1348 modcmd_register ( memoserv_module
, "oset" , cmd_oset
, 1 , MODCMD_REQUIRE_AUTHED
, "flags" , "+helping" , NULL
);
1350 memoserv_opt_dict
= dict_new ();
1351 dict_insert ( memoserv_opt_dict
, "AUTHNOTIFY" , opt_authnotify
);
1352 dict_insert ( memoserv_opt_dict
, "NEWNOTIFY" , opt_newnotify
);
1353 dict_insert ( memoserv_opt_dict
, "PRIVMSG" , opt_privmsg
);
1354 dict_insert ( memoserv_opt_dict
, "PRIVATE" , opt_private
);
1355 dict_insert ( memoserv_opt_dict
, "IGNORERECIEPTS" , opt_ignorereciepts
);
1356 dict_insert ( memoserv_opt_dict
, "SENDRECIEPTS" , opt_sendreciepts
);
1357 dict_insert ( memoserv_opt_dict
, "LIMIT" , opt_limit
);
1359 message_register_table ( msgtab
);
1361 if ( memoserv_conf
. message_expiry
)
1362 timeq_add ( now
+ memoserv_conf
. message_expiry
, expire_memos
, NULL
);
1368 memoserv_finalize ( void ) {
1369 struct chanNode
* chan
;
1374 str
= "modules/memoserv" ;
1375 if (!( conf_node
= conf_get_data ( str
, RECDB_OBJECT
))) {
1376 log_module ( MS_LOG
, LOG_ERROR
, "config node ` %s ' is missing or has wrong type." , str
);
1380 str
= database_get_data ( conf_node
, "bot" , RECDB_QSTRING
);
1382 memoserv
= memoserv_conf
. bot
;
1383 const char * modes
= conf_get_data ( "modules/memoserv/modes" , RECDB_QSTRING
);
1384 memoserv
= AddLocalUser ( str
, str
, NULL
, "User-User Memorandum Services" , modes
);
1385 service_register ( memoserv
);
1387 log_module ( MS_LOG
, LOG_ERROR
, "database_get_data for memoserv_conf.bot failed!" );
1391 if ( autojoin_channels
&& memoserv
) {
1392 for ( i
= 0 ; i
< autojoin_channels
-> used
; i
++) {
1393 chan
= AddChannel ( autojoin_channels
-> list
[ i
], now
, "+nt" , NULL
, NULL
);
1394 AddChannelUser ( memoserv
, chan
)-> modes
|= MODE_CHANOP
;