]>
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 memosSent
, memosExpired
;
189 static struct dict
* memos
; /* memo_account->handle->handle -> memo_account */
190 static struct dict
* historys
;
191 static dict_t memoserv_opt_dict
; /* contains option_func_t* */
193 static struct memo_account
*
194 memoserv_get_account ( struct handle_info
* hi
)
196 struct memo_account
* ma
;
199 ma
= dict_find ( memos
, hi
-> handle
, NULL
);
202 ma
= calloc ( 1 , sizeof (* ma
));
206 ma
-> flags
= MEMO_NOTIFY_NEW
| MEMO_NOTIFY_LOGIN
| MEMO_USE_PRIVMSG
;
207 ma
-> limit
= memoserv_conf
. limit
;
208 dict_insert ( memos
, ma
-> handle
-> handle
, ma
);
209 dict_insert ( historys
, ma
-> handle
-> handle
, ma
);
214 delete_memo ( struct memo
* memo
)
216 memoList_remove (& memo
-> recipient
-> recvd
, memo
);
217 memoList_remove (& memo
-> sender
-> sent
, memo
);
223 delete_history ( struct history
* history
)
225 historyList_remove (& history
-> recipient
-> hrecvd
, history
);
226 historyList_remove (& history
-> sender
-> hsent
, history
);
231 delete_memo_account ( void * data
)
233 struct memo_account
* ma
= data
;
235 while ( ma
-> recvd
. used
)
236 delete_memo ( ma
-> recvd
. list
[ 0 ]);
237 while ( ma
-> sent
. used
)
238 delete_memo ( ma
-> sent
. list
[ 0 ]);
239 memoList_clean (& ma
-> recvd
);
240 memoList_clean (& ma
-> sent
);
242 while ( ma
-> hrecvd
. used
)
243 delete_history ( ma
-> hrecvd
. list
[ 0 ]);
244 while ( ma
-> hsent
. used
)
245 delete_history ( ma
-> hsent
. list
[ 0 ]);
246 historyList_clean (& ma
-> hrecvd
);
247 historyList_clean (& ma
-> hsent
);
255 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
256 struct memo_account
* acct
= iter_data ( it
);
258 for ( ii
= 0 ; ii
< acct
-> sent
. used
; ++ ii
) {
259 struct memo
* memo
= acct
-> sent
. list
[ ii
];
260 if (( now
- memo
-> sent
) > memoserv_conf
. message_expiry
) {
268 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
269 struct memo_account
* acct
= iter_data ( it
);
271 for ( ii
= 0 ; ii
< acct
-> hsent
. used
; ++ ii
) {
272 struct history
* history
= acct
-> hsent
. list
[ ii
];
273 if (( now
- history
-> sent
) > memoserv_conf
. message_expiry
) {
274 delete_history ( history
);
283 expire_memos ( UNUSED_ARG ( void * data
))
285 if ( memoserv_conf
. message_expiry
) {
287 timeq_add ( now
+ memoserv_conf
. message_expiry
, expire_memos
, NULL
);
291 static struct history
*
292 add_history ( time_t sent
, struct memo_account
* recipient
, struct memo_account
* sender
, unsigned long id
)
294 struct history
* history
;
296 history
= calloc ( 1 , sizeof (* history
));
301 history
-> recipient
= recipient
;
302 historyList_append (& recipient
-> hrecvd
, history
);
303 history
-> sender
= sender
;
304 historyList_append (& sender
-> hsent
, history
);
305 history
-> sent
= sent
;
312 add_memo ( time_t sent
, struct memo_account
* recipient
, struct memo_account
* sender
, char * message
, int nfrom_read
)
315 struct history
* history
;
317 memo
= calloc ( 1 , sizeof (* memo
));
326 memo
-> recipient
= recipient
;
327 memoList_append (& recipient
-> recvd
, memo
);
328 memo
-> sender
= sender
;
329 memoList_append (& sender
-> sent
, memo
);
331 memo
-> message
= strdup ( message
);
335 history
= add_history ( sent
, recipient
, sender
, memo
-> id
);
341 memoserv_can_send ( struct userNode
* bot
, struct userNode
* user
, struct memo_account
* acct
)
343 extern struct userData
* _GetChannelUser ( struct chanData
* channel
, struct handle_info
* handle
, int override
, int allow_suspended
);
344 struct userData
* dest
;
345 unsigned int i
= 0 , match
= 0 ;
347 if (! user
-> handle_info
)
350 /* Sanity checks here because if the user doesnt have a limit set
351 the limit comes out at like 21233242 if you try and use it. */
352 if ( acct
-> limit
> memoserv_conf
. limit
)
353 acct
-> limit
= memoserv_conf
. limit
;
355 if ( acct
-> recvd
. used
> acct
-> limit
) {
356 send_message ( user
, bot
, "MSMSG_FULL_INBOX" , acct
-> handle
-> handle
);
357 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
361 if ( acct
-> handle
-> ignores
-> used
) {
362 for ( i
= 0 ; i
< acct
-> handle
-> ignores
-> used
; i
++) {
363 if ( user_matches_glob ( user
, acct
-> handle
-> ignores
-> list
[ i
], MATCH_USENICK
)) {
370 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
375 if (!( acct
-> flags
& MEMO_DENY_NONCHANNEL
))
378 for ( dest
= acct
-> handle
-> channels
; dest
; dest
= dest
-> u_next
)
379 if ( _GetChannelUser ( dest
-> channel
, user
-> handle_info
, 1 , 0 ))
382 send_message ( user
, bot
, "MSMSG_CANNOT_SEND" , acct
-> handle
-> handle
);
386 static struct memo
* find_memo ( struct userNode
* user
, struct svccmd
* cmd
, struct memo_account
* ma
, const char * msgid
, unsigned int * id
)
389 if (! isdigit ( msgid
[ 0 ])) {
391 reply ( "MSMSG_BAD_MESSAGE_ID" , msgid
, ma
-> recvd
. used
- 1 );
393 reply ( "MSMSG_NO_MESSAGES" );
396 memoid
= atoi ( msgid
);
397 if ( memoid
>= ma
-> recvd
. used
) {
398 reply ( "MSMSG_NO_SUCH_MEMO" );
401 return ma
-> recvd
. list
[* id
= memoid
];
404 static MODCMD_FUNC ( cmd_send
)
407 int reciept
= 0 , inc
= 2 , email
= 0 ;
408 struct handle_info
* hi
;
409 struct memo_account
* ma
, * sender
;
411 char subject
[ 128 ], body
[ 4096 ];
413 const char * netname
, * fmt
;
415 MEMOSERV_MIN_PARAMS ( 3 );
417 if ( checkDefCon ( DEFCON_NO_NEW_MEMOS
) && ! IsOper ( user
)) {
418 reply ( "MSMSG_DEFCON_NO_NEW_MEMOS" );
422 if (!( hi
= modcmd_get_handle_info ( user
, argv
[ 1 ])))
425 if (!( sender
= memoserv_get_account ( user
-> handle_info
))
426 || !( ma
= memoserv_get_account ( hi
))) {
427 reply ( "MSG_INTERNAL_FAILURE" );
431 if (!( memoserv_can_send ( cmd
-> parent
-> bot
, user
, ma
)))
434 inc
= 2 ; /* Start of message on 3rd ([2]) word */
435 if ( argv
[ 2 ][ 0 ] == '-' && argv
[ 2 ][ 1 ] != '-' ) { /* first word is flags ('-r')*/
436 char * flags
= argv
[ 2 ];
437 inc
++; /* Start of message is now 1 word later */
438 for ( flags
++;* flags
; flags
++) {
445 /* Unknown mode. Give an error */
446 reply ( "MSMSG_UNKNOWN_SEND_FLAG" , * flags
);
452 inc
= 2 ; /* Start of message is word 2 */
454 message
= unsplit_string ( argv
+ inc
, argc
- inc
, NULL
);
455 memo
= add_memo ( now
, ma
, sender
, message
, 1 );
456 if (( reciept
== 1 ) || ( ma
-> flags
& MEMO_ALWAYS_RECIEPTS
))
459 if ( ma
-> flags
& MEMO_NOTIFY_NEW
) {
460 struct userNode
* other
;
462 for ( other
= ma
-> handle
-> users
; other
; other
= other
-> next_authed
)
463 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
);
466 estr
= conf_get_data ( "services/nickserv/email_enabled" , RECDB_QSTRING
);
467 netname
= conf_get_data ( "server/network" , RECDB_QSTRING
);
469 if ( email
&& ( ma
-> flags
& MEMO_NOTIFY_NEW
)) {
470 fmt
= handle_find_message ( hi
, "MSEMAIL_NEWMEMO_SUBJECT" );
471 snprintf ( subject
, sizeof ( subject
), fmt
, netname
, memoserv
-> nick
, user
-> nick
);
473 fmt
= handle_find_message ( hi
, "MSEMAIL_NEWMEMO_BODY" );
474 snprintf ( body
, sizeof ( body
), fmt
, user
-> nick
, memoserv
-> nick
, message
, memoserv
-> nick
, memo_id
, netname
);
476 sendmail ( memoserv
, hi
, subject
, body
, 0 );
479 reply ( "MSMSG_MEMO_SENT" , ma
-> handle
-> handle
, memo_id
);
483 static MODCMD_FUNC ( cmd_list
)
485 struct memo_account
* ma
;
491 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
494 reply ( "MSMSG_LIST_HEAD" );
496 if ( user
-> handle_info
&& user
-> handle_info
-> userlist_style
!= HI_STYLE_CLEAN
)
499 for ( ii
= 0 ; ( ii
< ma
-> recvd
. used
) && ( ii
< 15 ); ++ ii
) {
500 memo
= ma
-> recvd
. list
[ ii
];
501 localtime_r (& memo
-> sent
, & tm
);
502 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
503 reply ( "MSMSG_LIST_FORMAT" , ii
, memo
-> sender
-> handle
-> handle
, memo
-> reciept
? "(r)" : "" , posted
);
508 reply ( "MSMSG_CLEAN_INBOX" , ii
);
510 reply ( "MSMSG_MEMOS_FOUND" , ii
);
511 reply ( "MSMSG_HOWTO_READ" );
514 reply ( "MSMSG_LIST_END" );
519 static MODCMD_FUNC ( cmd_history
)
521 struct memo_account
* ma
;
522 struct history
* history
;
529 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
532 reply ( "MSMSG_HISTORY_HEADER" );
534 if ( user
-> handle_info
&& user
-> handle_info
-> userlist_style
!= HI_STYLE_CLEAN
)
537 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
539 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
) {
540 history
= ma
-> hrecvd
. list
[ ii
];
541 if (! strcasecmp ( history
-> sender
-> handle
-> handle
, user
-> handle_info
-> handle
)) {
543 localtime_r (& history
-> sent
, & tm
);
544 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
545 reply ( "MSMSG_HISTORY_FORMAT" , history
-> id
, history
-> recipient
-> handle
-> handle
, posted
);
553 reply ( "MSMSG_MEMOS_FOUND" , cc
);
555 reply ( "MSMSG_LIST_END" );
560 static MODCMD_FUNC ( cmd_read
)
562 struct memo_account
* ma
;
564 int rignore
= 0 , brk
= 0 , s
= 0 ;
571 char * argtwo
= argv
[ 2 ];
596 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
599 if (!( memo
= find_memo ( user
, cmd
, ma
, argv
[ 1 ], & memoid
)))
602 localtime_r (& memo
-> sent
, & tm
);
603 strftime ( posted
, sizeof ( posted
), " %I : %M %p , %m / %d / %Y " , & tm
);
605 reply ( "MSMSG_MEMO_HEAD" , memoid
, memo
-> sender
-> handle
-> handle
, posted
);
606 send_message_type ( 4 , user
, cmd
-> parent
-> bot
, " %s " , memo
-> message
);
610 if ( ma
-> flags
& MEMO_IGNORE_RECIEPTS
)
613 if ( memo
-> reciept
== 1 ) {
615 reply ( "MSMSG_MEMO_RECIEPT" , rignore
? "ignoring" : "sending" );
617 struct memo_account
* ma
;
618 struct memo_account
* sender
;
619 char content
[ MAXLEN
];
621 ma
= memoserv_get_account ( user
-> handle_info
);
622 sender
= memoserv_get_account ( memo
-> sender
-> handle
);
624 sprintf ( content
, " %s has read your memo dated %s ." , ma
-> handle
-> handle
, posted
);
626 memo
= add_memo ( now
, sender
, ma
, content
, 1 );
627 reply ( "MSMSG_MEMO_SENT" , memob
-> sender
-> handle
-> handle
, memo_id
);
629 if ( sender
-> flags
& MEMO_NOTIFY_NEW
) {
630 struct userNode
* other
;
632 for ( other
= sender
-> handle
-> users
; other
; other
= other
-> next_authed
)
633 send_message_type (( ma
-> flags
& MEMO_USE_PRIVMSG
)? MSG_TYPE_PRIVMSG
: MSG_TYPE_NOTICE
, other
, cmd
-> parent
-> bot
, "MSMSG_NEW_MESSAGE" , ma
-> handle
-> handle
);
642 static MODCMD_FUNC ( cmd_delete
)
644 struct memo_account
* ma
;
648 MEMOSERV_MIN_PARAMS ( 2 );
650 if (!( ma
= memoserv_get_account ( user
-> handle_info
)))
652 if (! irccasecmp ( argv
[ 1 ], "*" ) || ! irccasecmp ( argv
[ 1 ], "all" )) {
653 if (( argc
< 3 ) || irccasecmp ( argv
[ 2 ], "confirm" )) {
654 reply ( "MSMSG_USE_CONFIRM" );
657 while ( ma
-> recvd
. used
)
658 delete_memo ( ma
-> recvd
. list
[ 0 ]);
659 reply ( "MSMSG_DELETED_ALL" );
663 if (!( memo
= find_memo ( user
, cmd
, ma
, argv
[ 1 ], & memoid
)))
666 reply ( "MSMSG_MEMO_DELETED" , memoid
);
670 static MODCMD_FUNC ( cmd_cancel
)
676 struct memo_account
* ma
;
678 MEMOSERV_MIN_PARAMS ( 2 );
680 if ( isdigit ( argv
[ 1 ][ 0 ])) {
681 id
= strtoul ( argv
[ 1 ], NULL
, 0 );
683 reply ( "MSMSG_MEMO_CANCEL_NUMBER" );
687 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
689 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
690 memo
= ma
-> recvd
. list
[ ii
];
692 if ( id
== memo
-> id
) {
693 if (! strcasecmp ( memo
-> sender
-> handle
-> handle
, user
-> handle_info
-> handle
)) {
695 reply ( "MSMSG_MEMO_READ" , id
);
699 reply ( "MSMSG_MEMO_DELETED" , id
);
703 reply ( "MSMSG_MEMO_DONT_OWN" , id
);
710 reply ( "MSMSG_MEMO_CANT_LOCATE" , id
);
714 static MODCMD_FUNC ( cmd_expire
)
716 unsigned long old_expired
= memosExpired
;
718 reply ( "MSMSG_MESSAGES_EXPIRED" , memosExpired
- old_expired
);
722 static MODCMD_FUNC ( cmd_expiry
)
724 char interval
[ INTERVALLEN
];
726 if (! memoserv_conf
. message_expiry
) {
727 reply ( "MSMSG_EXPIRY_OFF" );
731 intervalString ( interval
, memoserv_conf
. message_expiry
, user
-> handle_info
);
732 reply ( "MSMSG_EXPIRY" , interval
, memoserv_conf
. message_expiry
);
738 set_list ( struct svccmd
* cmd
, struct userNode
* user
, struct handle_info
* hi
, int override
)
742 char * set_display
[] = { "AUTHNOTIFY" , "NEWNOTIFY" , "PRIVMSG" , "PRIVATE" , "LIMIT" ,
743 "IGNORERECIEPTS" , "SENDRECIEPTS" };
745 reply ( "MSMSG_SET_OPTIONS" );
748 /* Do this so options are presented in a consistent order. */
749 for ( i
= 0 ; i
< ArrayLength ( set_display
); ++ i
)
750 if (( opt
= dict_find ( memoserv_opt_dict
, set_display
[ i
], NULL
)))
751 opt ( cmd
, user
, hi
, override
, 0 , NULL
);
752 reply ( "MSMSG_SET_OPTIONS_END" );
755 static MODCMD_FUNC ( cmd_set
)
757 struct handle_info
* hi
;
760 hi
= user
-> handle_info
;
762 set_list ( cmd
, user
, hi
, 0 );
766 if (!( opt
= dict_find ( memoserv_opt_dict
, argv
[ 1 ], NULL
))) {
767 reply ( "MSMSG_INVALID_OPTION" , argv
[ 1 ]);
771 return opt ( cmd
, user
, hi
, 0 , argc
- 1 , argv
+ 1 );
774 static MODCMD_FUNC ( cmd_oset
)
776 struct handle_info
* hi
;
779 MEMOSERV_MIN_PARAMS ( 2 );
781 if (!( hi
= get_victim_oper ( cmd
, user
, argv
[ 1 ])))
785 set_list ( cmd
, user
, hi
, 0 );
789 if (!( opt
= dict_find ( memoserv_opt_dict
, argv
[ 2 ], NULL
))) {
790 reply ( "MSMSG_INVALID_OPTION" , argv
[ 2 ]);
794 return opt ( cmd
, user
, hi
, 1 , argc
- 2 , argv
+ 2 );
797 static OPTION_FUNC ( opt_newnotify
)
799 struct memo_account
* ma
;
802 if (!( ma
= memoserv_get_account ( hi
)))
806 if ( enabled_string ( choice
)) {
807 ma
-> flags
|= MEMO_NOTIFY_NEW
;
808 } else if ( disabled_string ( choice
)) {
809 ma
-> flags
&= ~ MEMO_NOTIFY_NEW
;
811 reply ( "MSMSG_INVALID_BINARY" , choice
);
816 choice
= ( ma
-> flags
& MEMO_NOTIFY_NEW
) ? "on" : "off" ;
817 reply ( "MSMSG_SET_NEWNOTIFY" , choice
);
821 static OPTION_FUNC ( opt_privmsg
)
823 struct memo_account
* ma
;
826 if (!( ma
= memoserv_get_account ( hi
)))
830 if ( enabled_string ( choice
)) {
831 ma
-> flags
|= MEMO_USE_PRIVMSG
;
832 } else if ( disabled_string ( choice
)) {
833 ma
-> flags
&= ~ MEMO_USE_PRIVMSG
;
835 reply ( "MSMSG_INVALID_BINARY" , choice
);
839 choice
= ( ma
-> flags
& MEMO_USE_PRIVMSG
) ? "on" : "off" ;
840 reply ( "MSMSG_SET_PRIVMSG" , choice
);
844 static OPTION_FUNC ( opt_authnotify
)
846 struct memo_account
* ma
;
849 if (!( ma
= memoserv_get_account ( hi
)))
853 if ( enabled_string ( choice
)) {
854 ma
-> flags
|= MEMO_NOTIFY_LOGIN
;
855 } else if ( disabled_string ( choice
)) {
856 ma
-> flags
&= ~ MEMO_NOTIFY_LOGIN
;
858 reply ( "MSMSG_INVALID_BINARY" , choice
);
863 choice
= ( ma
-> flags
& MEMO_NOTIFY_LOGIN
) ? "on" : "off" ;
864 reply ( "MSMSG_SET_AUTHNOTIFY" , choice
);
868 static OPTION_FUNC ( opt_ignorereciepts
)
870 struct memo_account
* ma
;
873 if (!( ma
= memoserv_get_account ( hi
)))
877 if ( enabled_string ( choice
)) {
878 ma
-> flags
|= MEMO_IGNORE_RECIEPTS
;
879 } else if ( disabled_string ( choice
)) {
880 ma
-> flags
&= ~ MEMO_IGNORE_RECIEPTS
;
882 reply ( "MSMSG_INVALID_BINARY" , choice
);
887 choice
= ( ma
-> flags
& MEMO_IGNORE_RECIEPTS
) ? "on" : "off" ;
888 reply ( "MSMSG_SET_IGNORERECIEPTS" , choice
);
892 static OPTION_FUNC ( opt_sendreciepts
)
894 struct memo_account
* ma
;
897 if (!( ma
= memoserv_get_account ( hi
)))
901 if ( enabled_string ( choice
)) {
902 ma
-> flags
|= MEMO_ALWAYS_RECIEPTS
;
903 } else if ( disabled_string ( choice
)) {
904 ma
-> flags
&= ~ MEMO_ALWAYS_RECIEPTS
;
906 reply ( "MSMSG_INVALID_BINARY" , choice
);
911 choice
= ( ma
-> flags
& MEMO_ALWAYS_RECIEPTS
) ? "on" : "off" ;
912 reply ( "MSMSG_SET_SENDRECIEPTS" , choice
);
916 static OPTION_FUNC ( opt_private
)
918 struct memo_account
* ma
;
921 if (!( ma
= memoserv_get_account ( hi
)))
925 if ( enabled_string ( choice
)) {
926 ma
-> flags
|= MEMO_DENY_NONCHANNEL
;
927 } else if ( disabled_string ( choice
)) {
928 ma
-> flags
&= ~ MEMO_DENY_NONCHANNEL
;
930 reply ( "MSMSG_INVALID_BINARY" , choice
);
935 choice
= ( ma
-> flags
& MEMO_DENY_NONCHANNEL
) ? "on" : "off" ;
936 reply ( "MSMSG_SET_PRIVATE" , choice
);
940 static OPTION_FUNC ( opt_limit
)
942 struct memo_account
* ma
;
945 if (!( ma
= memoserv_get_account ( hi
)))
948 choice
= atoi ( argv
[ 1 ]);
949 if ( choice
> memoserv_conf
. limit
)
950 choice
= memoserv_conf
. limit
;
955 reply ( "MSMSG_SET_LIMIT" , ma
-> limit
);
959 static MODCMD_FUNC ( cmd_status
)
961 struct memo_account
* ma
;
966 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
968 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
)
972 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
974 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
)
978 reply ( "MSMSG_STATUS_HIST_TOTAL" , hc
);
979 reply ( "MSMSG_STATUS_TOTAL" , mc
);
980 reply ( "MSMSG_STATUS_EXPIRED" , memosExpired
);
981 reply ( "MSMSG_STATUS_SENT" , memosSent
);
986 memoserv_conf_read ( void )
991 str
= "modules/memoserv" ;
992 if (!( conf_node
= conf_get_data ( str
, RECDB_OBJECT
))) {
993 log_module ( MS_LOG
, LOG_ERROR
, "config node ` %s ' is missing or has wrong type." , str
);
997 str
= database_get_data ( conf_node
, "limit" , RECDB_QSTRING
);
998 memoserv_conf
. limit
= str
? atoi ( str
) : 50 ;
1000 str
= database_get_data ( conf_node
, "message_expiry" , RECDB_QSTRING
);
1001 memoserv_conf
. message_expiry
= str
? ParseInterval ( str
) : 60 * 24 * 30 ;
1005 memoserv_user_read ( const char * key
, struct record_data
* hir
)
1008 struct memo_account
* ma
;
1009 struct handle_info
* hi
;
1011 if (!( hi
= get_handle_info ( key
)))
1014 ma
= dict_find ( memos
, hi
-> handle
, NULL
);
1019 ma
= calloc ( 1 , sizeof (* ma
));
1025 str
= database_get_data ( hir
-> d
. object
, KEY_FLAGS
, RECDB_QSTRING
);
1027 log_module ( MS_LOG
, LOG_ERROR
, "Flags not present in memo %s ; skipping" , key
);
1030 ma
-> flags
= strtoul ( str
, NULL
, 0 );
1032 str
= database_get_data ( hir
-> d
. object
, KEY_LIMIT
, RECDB_QSTRING
);
1034 log_module ( MS_LOG
, LOG_ERROR
, "Limit not present in memo %s ; skipping" , key
);
1037 ma
-> limit
= strtoul ( str
, NULL
, 0 );
1039 dict_insert ( memos
, ma
-> handle
-> handle
, ma
);
1040 dict_insert ( historys
, ma
-> handle
-> handle
, ma
);
1046 memoserv_memo_read ( const char * key
, struct record_data
* hir
)
1049 struct handle_info
* sender
, * recipient
;
1054 if ( hir
-> type
!= RECDB_OBJECT
) {
1055 log_module ( MS_LOG
, LOG_WARNING
, "Unexpected rectype %d for %s ." , hir
-> type
, key
);
1059 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_SENT
, RECDB_QSTRING
))) {
1060 log_module ( MS_LOG
, LOG_ERROR
, "Date sent not present in memo %s ; skipping" , key
);
1066 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_ID
, RECDB_QSTRING
))) {
1067 log_module ( MS_LOG
, LOG_ERROR
, "ID sent not present in memo %s ; skipping" , key
);
1070 id
= strtoul ( str
, NULL
, 0 );
1074 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_RECIPIENT
, RECDB_QSTRING
))) {
1075 log_module ( MS_LOG
, LOG_ERROR
, "Recipient not present in memo %s ; skipping" , key
);
1077 } else if (!( recipient
= get_handle_info ( str
))) {
1078 log_module ( MS_LOG
, LOG_ERROR
, "Invalid recipient %s in memo %s ; skipping" , str
, key
);
1082 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_FROM
, RECDB_QSTRING
))) {
1083 log_module ( MS_LOG
, LOG_ERROR
, "Sender not present in memo %s ; skipping" , key
);
1085 } else if (!( sender
= get_handle_info ( str
))) {
1086 log_module ( MS_LOG
, LOG_ERROR
, "Invalid sender %s in memo %s ; skipping" , str
, key
);
1090 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_MESSAGE
, RECDB_QSTRING
))) {
1091 log_module ( MS_LOG
, LOG_ERROR
, "Message not present in memo %s ; skipping" , key
);
1095 memo
= add_memo ( sent
, memoserv_get_account ( recipient
), memoserv_get_account ( sender
), str
, 0 );
1096 if (( str
= database_get_data ( hir
-> d
. object
, KEY_READ
, RECDB_QSTRING
)))
1099 if (( str
= database_get_data ( hir
-> d
. object
, KEY_RECIEPT
, RECDB_QSTRING
)))
1108 memoserv_history_read ( const char * key
, struct record_data
* hir
)
1111 struct handle_info
* sender
, * recipient
;
1112 struct history
* history
;
1116 if ( hir
-> type
!= RECDB_OBJECT
) {
1117 log_module ( MS_LOG
, LOG_WARNING
, "Unexpected rectype %d for %s ." , hir
-> type
, key
);
1121 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_SENT
, RECDB_QSTRING
))) {
1122 log_module ( MS_LOG
, LOG_ERROR
, "Date sent not present in history %s ; skipping" , key
);
1128 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_ID
, RECDB_QSTRING
))) {
1129 log_module ( MS_LOG
, LOG_ERROR
, "ID sent not present in history %s ; skipping" , key
);
1132 id
= strtoul ( str
, NULL
, 0 );
1134 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_RECIPIENT
, RECDB_QSTRING
))) {
1135 log_module ( MS_LOG
, LOG_ERROR
, "Recipient not present in history %s ; skipping" , key
);
1137 } else if (!( recipient
= get_handle_info ( str
))) {
1138 log_module ( MS_LOG
, LOG_ERROR
, "Invalid recipient %s in history %s ; skipping" , str
, key
);
1142 if (!( str
= database_get_data ( hir
-> d
. object
, KEY_FROM
, RECDB_QSTRING
))) {
1143 log_module ( MS_LOG
, LOG_ERROR
, "Sender not present in history %s ; skipping" , key
);
1145 } else if (!( sender
= get_handle_info ( str
))) {
1146 log_module ( MS_LOG
, LOG_ERROR
, "Invalid sender %s in history %s ; skipping" , str
, key
);
1150 history
= add_history ( sent
, memoserv_get_account ( recipient
), memoserv_get_account ( sender
), id
);
1156 memoserv_saxdb_read ( struct dict
* database
)
1158 struct dict
* section
;
1161 if (( section
= database_get_data ( database
, KEY_MAIN_ACCOUNTS
, RECDB_OBJECT
)))
1162 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1163 memoserv_user_read ( iter_key ( it
), iter_data ( it
));
1165 if (( section
= database_get_data ( database
, KEY_MAIN_MEMOS
, RECDB_OBJECT
)))
1166 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1167 memoserv_memo_read ( iter_key ( it
), iter_data ( it
));
1169 if (( section
= database_get_data ( database
, KEY_MAIN_HISTORY
, RECDB_OBJECT
)))
1170 for ( it
= dict_first ( section
); it
; it
= iter_next ( it
))
1171 memoserv_history_read ( iter_key ( it
), iter_data ( it
));
1177 memoserv_write_users ( struct saxdb_context
* ctx
, struct memo_account
* ma
)
1179 saxdb_start_record ( ctx
, ma
-> handle
-> handle
, 0 );
1181 saxdb_write_int ( ctx
, KEY_FLAGS
, ma
-> flags
);
1182 saxdb_write_int ( ctx
, KEY_LIMIT
, ma
-> limit
);
1184 saxdb_end_record ( ctx
);
1189 memoserv_write_memos ( struct saxdb_context
* ctx
, struct memo
* memo
)
1193 memset ( str
, '\0' , sizeof ( str
));
1194 saxdb_start_record ( ctx
, inttobase64 ( str
, memo
-> id
, sizeof ( str
)- 1 ), 0 );
1196 saxdb_write_int ( ctx
, KEY_SENT
, memo
-> sent
);
1197 saxdb_write_int ( ctx
, KEY_ID
, memo
-> id
);
1198 saxdb_write_string ( ctx
, KEY_RECIPIENT
, memo
-> recipient
-> handle
-> handle
);
1199 saxdb_write_string ( ctx
, KEY_FROM
, memo
-> sender
-> handle
-> handle
);
1200 saxdb_write_string ( ctx
, KEY_MESSAGE
, memo
-> message
);
1203 saxdb_write_int ( ctx
, KEY_READ
, 1 );
1206 saxdb_write_int ( ctx
, KEY_RECIEPT
, 1 );
1208 saxdb_end_record ( ctx
);
1213 memoserv_write_history ( struct saxdb_context
* ctx
, struct history
* history
)
1217 memset ( str
, '\0' , sizeof ( str
));
1218 saxdb_start_record ( ctx
, inttobase64 ( str
, history
-> id
, sizeof ( str
)- 1 ), 0 );
1220 saxdb_write_int ( ctx
, KEY_SENT
, history
-> sent
);
1221 saxdb_write_int ( ctx
, KEY_ID
, history
-> id
);
1222 saxdb_write_string ( ctx
, KEY_RECIPIENT
, history
-> recipient
-> handle
-> handle
);
1223 saxdb_write_string ( ctx
, KEY_FROM
, history
-> sender
-> handle
-> handle
);
1225 saxdb_end_record ( ctx
);
1230 memoserv_saxdb_write ( struct saxdb_context
* ctx
)
1233 struct memo_account
* ma
;
1235 struct history
* history
;
1239 saxdb_start_record ( ctx
, KEY_MAIN_ACCOUNTS
, 1 );
1240 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
1242 memoserv_write_users ( ctx
, ma
);
1244 saxdb_end_record ( ctx
);
1247 saxdb_start_record ( ctx
, KEY_MAIN_MEMOS
, 1 );
1248 for ( it
= dict_first ( memos
); it
; it
= iter_next ( it
)) {
1250 for ( ii
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
1251 memo
= ma
-> recvd
. list
[ ii
];
1252 memoserv_write_memos ( ctx
, memo
);
1255 saxdb_end_record ( ctx
);
1258 saxdb_start_record ( ctx
, KEY_MAIN_HISTORY
, 1 );
1259 for ( it
= dict_first ( historys
); it
; it
= iter_next ( it
)) {
1261 for ( ii
= 0 ; ii
< ma
-> hrecvd
. used
; ++ ii
) {
1262 history
= ma
-> hrecvd
. list
[ ii
];
1263 memoserv_write_history ( ctx
, history
);
1266 saxdb_end_record ( ctx
);
1272 memoserv_cleanup ( void )
1275 dict_delete ( historys
);
1279 memoserv_check_messages ( struct userNode
* user
, UNUSED_ARG ( struct handle_info
* old_handle
))
1281 unsigned int ii
, unseen
;
1282 struct memo_account
* ma
;
1285 if (! user
-> uplink
-> burst
) {
1286 if (!( ma
= memoserv_get_account ( user
-> handle_info
))
1287 || !( ma
-> flags
& MEMO_NOTIFY_LOGIN
))
1289 for ( ii
= unseen
= 0 ; ii
< ma
-> recvd
. used
; ++ ii
) {
1290 memo
= ma
-> recvd
. list
[ ii
];
1294 if ( ma
-> recvd
. used
&& memoserv
)
1295 if ( unseen
) send_message_type (( ma
-> flags
& MEMO_USE_PRIVMSG
)? 1 : 0 , user
, memoserv
, "MSMSG_MEMOS_INBOX" , unseen
, ma
-> recvd
. used
- unseen
);
1300 memoserv_rename_account ( struct handle_info
* hi
, const char * old_handle
)
1302 struct memo_account
* ma
;
1303 if (!( ma
= dict_find ( memos
, old_handle
, NULL
)))
1305 dict_remove2 ( memos
, old_handle
, 1 );
1306 dict_insert ( memos
, hi
-> handle
, ma
);
1308 dict_remove2 ( historys
, old_handle
, 1 );
1309 dict_insert ( historys
, hi
-> handle
, ma
);
1313 memoserv_unreg_account ( UNUSED_ARG ( struct userNode
* user
), struct handle_info
* handle
)
1315 dict_remove ( memos
, handle
-> handle
);
1316 dict_remove ( historys
, handle
-> handle
);
1322 MS_LOG
= log_register_type ( "MemoServ" , "file:memoserv.log" );
1324 historys
= dict_new ();
1325 dict_set_free_data ( memos
, delete_memo_account
);
1326 reg_auth_func ( memoserv_check_messages
);
1327 reg_handle_rename_func ( memoserv_rename_account
);
1328 reg_unreg_func ( memoserv_unreg_account
);
1329 conf_register_reload ( memoserv_conf_read
);
1330 reg_exit_func ( memoserv_cleanup
);
1331 saxdb_register ( "MemoServ" , memoserv_saxdb_read
, memoserv_saxdb_write
);
1333 memoserv_module
= module_register ( "MemoServ" , MS_LOG
, "mod-memoserv.help" , NULL
);
1334 modcmd_register ( memoserv_module
, "send" , cmd_send
, 3 , MODCMD_REQUIRE_AUTHED
, NULL
);
1335 modcmd_register ( memoserv_module
, "list" , cmd_list
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1336 modcmd_register ( memoserv_module
, "read" , cmd_read
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1337 modcmd_register ( memoserv_module
, "delete" , cmd_delete
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1338 modcmd_register ( memoserv_module
, "cancel" , cmd_cancel
, 2 , MODCMD_REQUIRE_AUTHED
, NULL
);
1339 modcmd_register ( memoserv_module
, "history" , cmd_history
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1340 modcmd_register ( memoserv_module
, "expire" , cmd_expire
, 1 , MODCMD_REQUIRE_AUTHED
, "flags" , "+oper" , NULL
);
1341 modcmd_register ( memoserv_module
, "expiry" , cmd_expiry
, 1 , 0 , NULL
);
1342 modcmd_register ( memoserv_module
, "status" , cmd_status
, 1 , 0 , NULL
);
1343 modcmd_register ( memoserv_module
, "set" , cmd_set
, 1 , MODCMD_REQUIRE_AUTHED
, NULL
);
1344 modcmd_register ( memoserv_module
, "oset" , cmd_oset
, 1 , MODCMD_REQUIRE_AUTHED
, "flags" , "+helping" , NULL
);
1346 memoserv_opt_dict
= dict_new ();
1347 dict_insert ( memoserv_opt_dict
, "AUTHNOTIFY" , opt_authnotify
);
1348 dict_insert ( memoserv_opt_dict
, "NEWNOTIFY" , opt_newnotify
);
1349 dict_insert ( memoserv_opt_dict
, "PRIVMSG" , opt_privmsg
);
1350 dict_insert ( memoserv_opt_dict
, "PRIVATE" , opt_private
);
1351 dict_insert ( memoserv_opt_dict
, "IGNORERECIEPTS" , opt_ignorereciepts
);
1352 dict_insert ( memoserv_opt_dict
, "SENDRECIEPTS" , opt_sendreciepts
);
1353 dict_insert ( memoserv_opt_dict
, "LIMIT" , opt_limit
);
1355 message_register_table ( msgtab
);
1357 if ( memoserv_conf
. message_expiry
)
1358 timeq_add ( now
+ memoserv_conf
. message_expiry
, expire_memos
, NULL
);
1364 memoserv_finalize ( void ) {
1365 struct chanNode
* chan
;
1370 str
= "modules/memoserv" ;
1371 if (!( conf_node
= conf_get_data ( str
, RECDB_OBJECT
))) {
1372 log_module ( MS_LOG
, LOG_ERROR
, "config node ` %s ' is missing or has wrong type." , str
);
1376 str
= database_get_data ( conf_node
, "bot" , RECDB_QSTRING
);
1378 memoserv
= memoserv_conf
. bot
;
1379 const char * modes
= conf_get_data ( "modules/memoserv/modes" , RECDB_QSTRING
);
1380 memoserv
= AddService ( str
, modes
? modes
: NULL
, "User-User Memorandum Services" , NULL
);
1383 log_module ( MS_LOG
, LOG_ERROR
, "database_get_data for memoserv_conf.bot failed!" );
1387 if ( autojoin_channels
&& memoserv
) {
1388 for ( i
= 0 ; i
< autojoin_channels
-> used
; i
++) {
1389 chan
= AddChannel ( autojoin_channels
-> list
[ i
], now
, "+nt" , NULL
, NULL
);
1390 AddChannelUser ( memoserv
, chan
)-> modes
|= MODE_CHANOP
;