/** * This module modifies the manner in which memos are sent * to channels. Instead of having memos sent to one channel * they are sent to all users on the channel access list * who have the necessary access level. It prefixes the memo * with the channel name so the users know why they are * receiving it. For this section, the only thing you need * to modify is the MS_SECURE_MEMOS directive. If this is * defined, you must be on the channel access list, and have * the necessary access level (or be a services admin) to send * a memo to the channel. If not defined, anyone can send to * the channel. This can also be changed at run time. * * This module also can grant SA's or SRA's special access to * MemoServ. If MS_SA_MOREACCESS is uncommented, SA's can delete * memos for any user, and modify their notify options.If * MS_SA_ALLACCESS is uncommented, SA's have access to list, * read, and delete memos from any user. IF MS_GLB_ONSAUSE is * uncommented, MemoServ will send a GLOBOPS whenever these special * privileges are used. If MS_RESTRICT_SRA is defined in * conjunction with one of the above options, those privileges * become available only to SRA's. * * PLEASE REPORT BUGS! * * By: DaPrivateer * DaPrivateer@off-hours.com */ #include "../memoserv.c" #include "module.h" #define MYNAME "ms_chanmemo" #define AUTHOR "DaPrivateer" #define VERSION "1.0" /** * Uncomment this if you want to restrict SENDING * channel memos to people who have access to receive * them. This is modifiable at run time. */ //#define MS_SECURE_MEMOS /** * Uncomment this if you want SA's to have * slightly higher MemoServ privileges * (change NOTIFY options and delete memos * of other users). */ //#define MS_SA_MOREACCESS /** * Uncomment this if you want SA's to have * unlimited MemoServ privileges (change * any options of another user, read, list * and delete their memos. */ //#define MS_SA_ALLACCESS /** * Uncomment the following line to restrict the * above privileges to SRA, intead of SA. */ //#define MS_RESTRICT_SRA /** * Uncomment this if you want MemoServ to do * a GLOBOPS whenever an SA uses the above privileges */ //#define MS_GLB_ONSAUSE //Messages #define MS_CMD_OBS "This commmand is now obsolete. Channel memos are delivered to users." #define MS_CANCEL_SYNTAX "Syntax: \002/MemoServ CANCEL \037nick\037\002" #define MS_CANCEL_CHANNEL "Channel memos can not be canceled." #define MS_SEND_SYNTAX "Syntax: \002/MemoServ SEND { \037nick\037 | \037channel\037 } \037memo\037\002" #define MS_SET_SYNTAX "Syntax: \002/MemoServ SET \037option\037 \037parameter\037\002" #define MS_LIST_SYNTAX "Syntax: \002/MemoServ LIST [ \037list\037 | NEW ]\002" #define MS_READ_SYNTAX "Syntax: \002/MemoServ READ { \037num\037 | \037list\037 | LAST | NEW }\002" #define MS_DEL_SYNTAX "Syntax: \002/MemoServ DEL { \037num\037 | \037list\037 | LAST | NEW }\002" #define MS_INFO_SYNTAX "Syntax: \002/MemoServ INFO\002" #define MS_INFO_SA_SYNTAX "Syntax: \002/MemoServ INFO [ \037nick\037 ]\002" #define MS_SECURE_ALREADY "SECURE option is already set for CHANS" #define MS_SECURE_ON "Sending channel memos is restricted to authorized users" #define MS_UNSECURE_ALREADY "UNSECURE option is already set for CHANS" #define MS_UNSECURE_ON "Any registered user can send memo's to a channel" #define MS_SET_CHANS_SYNTAX "Syntax: \002/MemoServ SET CHANS [ SECURE | UNSECURE ]\002" #define MS_SET_LIMIT_SYNTAX "Syntax: \002/MemoServ SET LIMIT [ \037user\037 ] { \037limit\037 | NONE } [HARD]\002" #define MS_SA_SET_SYNTAX "Syntax: \002/MemoServ SET \037nick\037 \037option\037 \037parameter\037\002" #define MS_SA_SET_NOTIFY "Syntax: \002/MemoServ SET [ \037nick\037 ] NOTIFY { ON | LOGON | NEW | OFF }\002" #define MS_SA_READ_SYNTAX "Syntax: \002/MemoServ READ [ \037nick\037 ] { \037num\037 | \037list\037 | LAST | ALL }\002" #define MS_SA_LIST_SYNTAX "Syntax: \002/MemoServ LIST [ \037nick\037 ] { \037list\037 | NEW }\002" #define MS_SA_DEL_SYNTAX "Syntax: \002/MemoServ DEL [ \037nick\037 ] { \037num\037 | \037list\037 | LAST | ALL }\002" #define MS_SA_DELETED_ALL "All of \002%s\002's memos have been deleted." //******* DO NOT MODIFY ANYTHING BELOW THIS LINE ********* //******* UNLESS YOU KNOW WHAT YOU ARE DOING! ********* #ifdef MS_SA_ALLACCESS #define MS_SA_MOREACCESS #endif //Some globals... #define MAX_LENGTH 430 int secure_memos = 0; //Interactive Functions int m_send(User *u); int m_set(User *u); int m_cancel(User *u); int m_list(User *u); int m_read(User *u); int m_del(User *u); int m_info(User *u); //Help functions int ms_help_set(User *u); int ms_help_set_chans(User *u); int ms_help_set_limit(User *u); int ms_help_cancel(User *u); int ms_help_list(User *u); int ms_help_read(User *u); int ms_help_del(User *u); int ms_help_info(User *u); //Misc Functions int send_channel_memo(User *u, char *dest, char *memo); int send_user_memo(User *u, NickCore *nc, char *memo); int read_user_memo(User *u, char *nick, NickCore *nc); int list_user_memo(User *u, char *nick, NickCore *nc); int del_user_memo(User *u, char *nick, NickCore *nc); //********************************************************************************** /**************************************** * Module Init/Term Functions * ****************************************/ //Module initialization int AnopeInit(int argc, char **argv) { Command *c; int status = 0; c = createCommand("SEND", m_send, NULL, -1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); c = createCommand("SET", m_set, NULL, -1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); moduleAddHelp(c, ms_help_set); c = createCommand("SET CHANS", NULL, NULL, -1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); moduleAddHelp(c, ms_help_set_chans); c = createCommand("SET LIMIT", NULL, NULL, -1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); moduleAddHelp(c, ms_help_set_limit); c = createCommand("CANCEL", m_cancel, NULL,-1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); moduleAddHelp(c, ms_help_cancel); c = createCommand("LIST", m_list, NULL,-1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); moduleAddHelp(c, ms_help_list); c = createCommand("READ", m_read, NULL,-1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); moduleAddHelp(c, ms_help_read); c = createCommand("DEL", m_del, NULL,-1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); moduleAddHelp(c, ms_help_del); c = createCommand("INFO", m_info, NULL,-1,-1,-1,-1,-1); status += moduleAddCommand(MEMOSERV, c, MOD_HEAD); moduleAddHelp(c, ms_help_info); if (status == 0) { alog("[%s] Loaded successfully", MYNAME); } else { alog("[%s] FAILED to load - result %d", MYNAME, status); } #ifdef MS_SECURE_MEMOS secure_memos = 1; #endif moduleAddAuthor(AUTHOR); moduleAddVersion(VERSION); return MOD_CONT; } //Module termination void AnopeFini(void) { alog("[%s] Unloaded", MYNAME); } /**************************************** * Interactive Functions * ****************************************/ //Check if the memo is to a channel, and if so, send it int m_send(User *u) { char *args = moduleGetLastBuffer(); char *dest = NULL; char *memo = NULL; if (!args) { notice(s_MemoServ, u->nick, MS_SEND_SYNTAX); return MOD_STOP; } args = sstrdup(moduleGetLastBuffer()); dest = myStrGetToken(args,' ',0); if (!u) //Non-existant user? return MOD_STOP; if (!dest) { //No destination? notice(s_MemoServ, u->nick, MS_SEND_SYNTAX); return MOD_STOP; } if (*dest != '#') //Are we dealing with a channel? return MOD_CONT; memo = myStrGetTokenRemainder(args,' ',1); if (!memo) { //Duh, we need text to send! notice(s_MemoServ, u->nick, MS_SEND_SYNTAX); return MOD_STOP; } return send_channel_memo(u, dest, memo); } //Checks for SET options int m_set(User *u) { char *args = moduleGetLastBuffer(); char *cmd = NULL; char *nick = NULL; #ifdef MS_SA_MOREACCESS NickCore *nc = NULL; #endif if (!args) { notice(s_MemoServ, u->nick, MS_SET_SYNTAX); return MOD_STOP; } args = sstrdup(moduleGetLastBuffer()); cmd = myStrGetToken(args,' ',0); nick = myStrGetToken(args,' ',1); if (!u) //Non-existant user? return MOD_STOP; if (!cmd) { notice(s_MemoServ, u->nick, MS_SET_SYNTAX); return MOD_STOP; } if (!stricmp(cmd,"NOTIFY") || !stricmp(cmd,"LIMIT")) return MOD_CONT; if (!is_services_admin(u)) { notice(s_MemoServ, u->nick, MS_SET_SYNTAX); return MOD_STOP; } #ifdef MS_SA_MOREACCESS if (stricmp(cmd,"CHANS")) { nick = cmd; if ((nc=findcore(cmd))==NULL) { notice_lang(s_MemoServ, u, NICK_X_NOT_REGISTERED, nick); return MOD_STOP; } } else { #else if (!stricmp(cmd,"CHANS")) { #endif cmd = nick; if (!cmd) { notice(s_MemoServ, u->nick, (secure_memos) ? MS_SECURE_ON : MS_UNSECURE_ON); return MOD_STOP; } if (!stricmp(cmd,"SECURE")) { if (secure_memos) { notice(s_MemoServ, u->nick, MS_SECURE_ALREADY); return MOD_STOP; } else { secure_memos = 1; notice(s_MemoServ, u->nick, MS_SECURE_ON); return MOD_STOP; } } if (!stricmp(cmd,"UNSECURE")) { if (!secure_memos) { notice(s_MemoServ, u->nick, MS_UNSECURE_ALREADY); return MOD_STOP; } else { secure_memos = 0; notice(s_MemoServ, u->nick, MS_UNSECURE_ON); return MOD_STOP; } } notice(s_MemoServ, u->nick, MS_SET_CHANS_SYNTAX); return MOD_STOP; } #ifdef MS_SA_MOREACCESS #ifdef MS_RESTRICT_SRA if (!is_services_root(u)) { notice_lang(s_MemoServ, u, ACCESS_DENIED); return MOD_STOP; } #endif cmd = myStrGetToken(args,' ',1); if (!stricmp(cmd,"NOTIFY")) { cmd = myStrGetToken(args,' ',2); if (!cmd) { notice(s_MemoServ, u->nick, MS_SA_SET_SYNTAX); return MOD_STOP; } if (!stricmp(cmd,"ON")) { nc->flags |= NI_MEMO_SIGNON | NI_MEMO_RECEIVE; notice(s_MemoServ, u->nick, "MemoServ will notify \002%s\002 when they sign on and when they receive memos.", nick); return MOD_STOP; } if (!stricmp(cmd,"LOGON")) { nc->flags |= NI_MEMO_SIGNON; nc->flags &= ~NI_MEMO_RECEIVE; notice(s_MemoServ, u->nick, "MemoServ will notify \002%s\002 ONLY when they sign on.", nick); return MOD_STOP; } if (!stricmp(cmd,"NEW")) { nc->flags &= ~NI_MEMO_SIGNON; nc->flags |= NI_MEMO_RECEIVE; notice(s_MemoServ, u->nick, "MemoServ will notify \002%s\002 ONLY when they receive new memos.", nick); return MOD_STOP; } if (!stricmp(cmd,"OFF")) { nc->flags &= ~NI_MEMO_SIGNON; nc->flags &= ~NI_MEMO_RECEIVE; notice(s_MemoServ, u->nick, "MemoServ will NOT notify \002%s\002 about memos.", nick); return MOD_STOP; } notice(s_MemoServ, u->nick, MS_SA_SET_NOTIFY); return MOD_STOP; } notice(s_MemoServ, u->nick, MS_SA_SET_SYNTAX); return MOD_STOP; #else notice(s_MemoServ, u->nick, MS_SET_SYNTAX); return MOD_STOP; #endif } //Check if they are cancelling a channel memo int m_cancel(User *u) { char *args = moduleGetLastBuffer(); char *dest = NULL; if (!args) { notice(s_MemoServ, u->nick, MS_CANCEL_SYNTAX); return MOD_STOP; } args = sstrdup(moduleGetLastBuffer()); dest = myStrGetToken(args,' ',0); if (!u) //Non-existant user? return MOD_STOP; if (!dest) { //No destination? notice(s_MemoServ, u->nick, MS_CANCEL_SYNTAX); return MOD_STOP; } if (*dest != '#') //Are we dealing with a channel? return MOD_CONT; notice(s_MemoServ, u->nick, MS_CANCEL_CHANNEL); return MOD_STOP; } //Are they trying to list channel memos? int m_list(User *u) { char *args = moduleGetLastBuffer(); char *dest = NULL; #ifdef MS_SA_ALLACCESS NickCore *nc = NULL; #endif if (!args) { //No destination? return MOD_CONT; } args = sstrdup(moduleGetLastBuffer()); dest = myStrGetToken(args,' ',0); if (!u) //Non-existant user? return MOD_STOP; if (!dest) { //No destination? return MOD_CONT; } #ifdef MS_SA_ALLACCESS #ifdef MS_RESTRICT_SRA if (is_services_root(u)) { #else if (is_services_admin(u)) { #endif if ((nc=findcore(dest))) { list_user_memo(u, dest, nc); return MOD_STOP; } } #endif if (*dest != '#') //Are we dealing with a channel? return MOD_CONT; notice(s_MemoServ, u->nick, MS_CMD_OBS); return MOD_STOP; } //Are they trying to read a channel memo? int m_read(User *u) { char *args = moduleGetLastBuffer(); char *dest = NULL; #ifdef MS_SA_ALLACCESS char *opt = NULL; NickCore *nc = NULL; #endif if (!args) { //No destination? notice(s_MemoServ, u->nick, MS_READ_SYNTAX); return MOD_STOP; } args = sstrdup(moduleGetLastBuffer()); dest = myStrGetToken(args,' ',0); if (!u) //Non-existant user? return MOD_STOP; if (!dest) { //No destination? notice(s_MemoServ, u->nick, MS_READ_SYNTAX); return MOD_STOP; } #ifdef MS_SA_ALLACCESS #ifdef MS_RESTRICT_SRA if (is_services_root(u)) { #else if (is_services_admin(u)) { #endif opt = myStrGetToken(args,' ',1); if ((nc=findcore(dest)) && opt) { #ifdef MS_GLB_ONSAUSE wallops(s_MemoServ, "%s is reading %s's memos as Services Admin", u->nick, dest); #endif read_user_memo(u, dest, nc); return MOD_STOP; } } #endif if (*dest != '#') //Are we dealing with a channel? return MOD_CONT; notice(s_MemoServ, u->nick, MS_CMD_OBS); return MOD_STOP; } //Are they trying to delete a channel memo? int m_del(User *u) { char *args = moduleGetLastBuffer(); char *dest = NULL; #ifdef MS_SA_MOREACCESS char *opt = NULL; NickCore *nc = NULL; #endif if (!args) { //No destination? notice(s_MemoServ, u->nick, MS_DEL_SYNTAX); return MOD_STOP; } args = sstrdup(moduleGetLastBuffer()); dest = myStrGetToken(args,' ',0); if (!u) //Non-existant user? return MOD_STOP; if (!dest) { //No destination? notice(s_MemoServ, u->nick, MS_DEL_SYNTAX); return MOD_STOP; } #ifdef MS_SA_MOREACCESS #ifdef MS_RESTRICT_SRA if (is_services_root(u)) { #else if (is_services_admin(u)) { #endif opt = myStrGetToken(args,' ',1); if ((nc=findcore(dest)) && opt) { #ifdef MS_GLB_ONSAUSE wallops(s_MemoServ, "%s is deleting %s's memos as Services Admin", u->nick, dest); #endif del_user_memo(u, dest, nc); return MOD_STOP; } } #endif if (*dest != '#') //Are we dealing with a channel? return MOD_CONT; notice(s_MemoServ, u->nick, MS_CMD_OBS); return MOD_STOP; } //Are they trying to get info on a channel? int m_info(User *u) { char *args = moduleGetLastBuffer(); char *dest = NULL; if (!args) return MOD_CONT; args = sstrdup(moduleGetLastBuffer()); dest = myStrGetToken(args,' ',0); if (!u) //Non-existant user? return MOD_STOP; if (!dest) //No destination? return MOD_CONT; if (*dest != '#') //Are we dealing with a channel? return MOD_CONT; notice(s_MemoServ, u->nick, MS_CMD_OBS); return MOD_STOP; } /**************************************** * Help Functions * ****************************************/ int ms_help_send(User *u) { notice(s_MemoServ, u->nick, MS_SEND_SYNTAX); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Sends the named nick or channel a memo containing"); notice(s_MemoServ, u->nick, "memo-text. When sending to a nickname, the recipient will"); notice(s_MemoServ, u->nick, "receive a notice that he/she has a new memo. The target"); notice(s_MemoServ, u->nick, "nickname/channel must be registered."); if (secure_memos) { notice(s_MemoServ, u->nick, "To send to a channel you \002MUST\002 have access to receive memos"); notice(s_MemoServ, u->nick, "on that channel."); } return MOD_STOP; } int ms_help_set(User *u) { notice(s_MemoServ, u->nick, MS_SET_SYNTAX); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Sets various memo options. option can be one of:"); notice(s_MemoServ, u->nick, "\002NOTIFY\002 Changes when you will be notified about new memos"); notice(s_MemoServ, u->nick, "\002LIMIT\002 Sets the maximum number of memos you can receive"); if (is_services_admin(u)) { notice(s_MemoServ, u->nick, "\002CHANS\002 Sets security for channel memos"); } notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "\002/MemoServ HELP SET \037option\037\002 for more information"); notice(s_MemoServ, u->nick, "Services Admins can set the memo limit for a nick by doing:"); notice(s_MemoServ, u->nick, "\002/MemoServ SET LIMIT \037nick\037 { \037number\037 | NONE } [HARD]\002"); #ifdef MS_SA_MOREACCESS #ifdef MS_RESTRICT_SRA if (is_services_root(u)) { #else if (is_services_admin(u)) { #endif notice(s_MemoServ, u->nick, "Additionally, Services Admins can set the notify options"); notice(s_MemoServ, u->nick, "for any nick with the following syntax:"); notice(s_MemoServ, u->nick, MS_SA_SET_NOTIFY); } #endif return MOD_STOP; } int ms_help_set_limit(User *u) { notice(s_MemoServ, u->nick, MS_SET_LIMIT_SYNTAX); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Sets the maximum number of memos a user is"); notice(s_MemoServ, u->nick, "allowed to have. Setting the limit to 0 prevents the user"); notice(s_MemoServ, u->nick, "from receiving any memos; setting it to NONE allows the"); notice(s_MemoServ, u->nick, "user to receive and keep as many memos as they want. If"); notice(s_MemoServ, u->nick, "you do not give a nickname, your own limit is set."); notice(s_MemoServ, u->nick, "Adding \002HARD\002 prevents the user from changing the limit. Not"); notice(s_MemoServ, u->nick, "adding \002HARD\002 has the opposite effect, allowing the user to"); notice(s_MemoServ, u->nick, "change the limit (even if a previous limit was set with"); notice(s_MemoServ, u->nick, "\002HARD\002)."); notice(s_MemoServ, u->nick, "Setting limits for other users is restricted to Services"); notice(s_MemoServ, u->nick, "Admins. Other users may only enter a limit for themselves, may"); notice(s_MemoServ, u->nick, "not remove their limit, may not set a limit above 50, and may"); notice(s_MemoServ, u->nick, "not set a hard limit."); return MOD_STOP; } int ms_help_set_chans(User *u) { if (is_services_oper(u)) { notice(s_MemoServ, u->nick, MS_SET_CHANS_SYNTAX); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Sets security for channel memos. When \002SECURE\002 is"); notice(s_MemoServ, u->nick, "set, only someone who would have access to receive"); notice(s_MemoServ, u->nick, "a channel memo can send a memo to that channel. When"); notice(s_MemoServ, u->nick, "\002UNSECURE\002 is set, any registered user can send"); notice(s_MemoServ, u->nick, "a memo to any channel. To view the current setting,"); notice(s_MemoServ, u->nick, "run the command with no parameters."); notice(s_MemoServ, u->nick, "Limited to \002Services Administrators\002."); } return MOD_STOP; } int ms_help_cancel(User *u) { notice(s_MemoServ, u->nick, MS_CANCEL_SYNTAX); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Cancels the last memo you sent to the given nick,"); notice(s_MemoServ, u->nick, "provided it has not been read at the time you use the command."); return MOD_STOP; } int ms_help_list(User *u) { notice(s_MemoServ, u->nick, MS_LIST_SYNTAX); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Lists any memos you currently have. With \002NEW\002, lists only"); notice(s_MemoServ, u->nick, "new (unread) memos. Unread memos are marked with a '*'"); notice(s_MemoServ, u->nick, "to the left of the memo number. You can also specify a list"); notice(s_MemoServ, u->nick, "of numbers, as in the example below:"); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "\002LIST 2-5,7-9\002"); notice(s_MemoServ, u->nick, "Lists memos numbered 2 through 5 and 7 through 9."); #ifdef MS_SA_ALLACCESS #ifdef MS_RESTRICT_SRA if (is_services_root(u)) { #else if (is_services_admin(u)) { #endif notice(s_MemoServ, u->nick, "Additionally, Services Administrators can specify a"); notice(s_MemoServ, u->nick, "nick to run the command on. See below:"); notice(s_MemoServ, u->nick, MS_SA_LIST_SYNTAX); } #endif return MOD_STOP; } int ms_help_read(User *u) { notice(s_MemoServ, u->nick, MS_READ_SYNTAX); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Sends you the text of the memos specified. If \002LAST\002 is"); notice(s_MemoServ, u->nick, "given, sends you the memo you most recently received. If"); notice(s_MemoServ, u->nick, "\002NEW\002 is given, sends you all of your new memos. Otherwise,"); notice(s_MemoServ, u->nick, "sends you memo number num. You can also give a list of"); notice(s_MemoServ, u->nick, "numbers, as in this example:"); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "\002READ 2-5,7-9\002"); notice(s_MemoServ, u->nick, "Displays memos numbered 2 through 5 and 7 through 9."); #ifdef MS_SA_ALLACCESS #ifdef MS_RESTRICT_SRA if (is_services_root(u)) { #else if (is_services_admin(u)) { #endif notice(s_MemoServ, u->nick, "Additionally, Services Administrators can specify a"); notice(s_MemoServ, u->nick, "nick to run the command on. See below:"); notice(s_MemoServ, u->nick, MS_SA_READ_SYNTAX); } #endif return MOD_STOP; } int ms_help_del(User *u) { notice(s_MemoServ, u->nick, MS_DEL_SYNTAX); notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Deletes the specified memo or memos. You can supply"); notice(s_MemoServ, u->nick, "multiple memo numbers or ranges of numbers instead of a"); notice(s_MemoServ, u->nick, "single number, as in the second example below."); notice(s_MemoServ, u->nick, "If \002LAST\002 is given, the last memo will be deleted."); notice(s_MemoServ, u->nick, "If \002ALL\002 is given, deletes all of your memos."); notice(s_MemoServ, u->nick, "Examples:"); notice(s_MemoServ, u->nick, "\002DEL 1\002"); notice(s_MemoServ, u->nick, "Deletes your first memo."); notice(s_MemoServ, u->nick, "\002DEL 2-5,7-9\002"); notice(s_MemoServ, u->nick, "Deletes memos numbered 2 through 5 and 7 through 9."); #ifdef MS_SA_MOREACCESS #ifdef MS_RESTRICT_SRA if (is_services_root(u)) { #else if (is_services_admin(u)) { #endif notice(s_MemoServ, u->nick, "Additionally, Services Administrators can specify a"); notice(s_MemoServ, u->nick, "nick to run the command on. See below:"); notice(s_MemoServ, u->nick, MS_SA_DEL_SYNTAX); } #endif return MOD_STOP; } int ms_help_info(User *u) { if (is_services_admin(u)) { notice(s_MemoServ, u->nick, MS_INFO_SA_SYNTAX); } else { notice(s_MemoServ, u->nick, MS_INFO_SYNTAX); } notice(s_MemoServ, u->nick, " "); notice(s_MemoServ, u->nick, "Displays information on the number of memos you have,"); notice(s_MemoServ, u->nick, "how many of them are unread, and how many total memos"); notice(s_MemoServ, u->nick, "you can receive."); if (is_services_admin(u)) { notice(s_MemoServ, u->nick, "With a nickname parameter, displays the same information"); notice(s_MemoServ, u->nick, "for the given nickname."); notice(s_MemoServ, u->nick, "This use limited to \002Services Administrators\002."); } return MOD_STOP; } /**************************************** * Misc Functions * ****************************************/ int send_channel_memo(User *u, char *dest, char *memo) { ChannelInfo *ci; time_t now = time(NULL); int serv_admin = is_services_admin(u); char memotext[MAX_LENGTH]; int i=0, acc=0, fndr=0; if (readonly) { notice_lang(s_MemoServ, u, MEMO_SEND_DISABLED); return MOD_STOP; } if (checkDefCon(DEFCON_NO_NEW_MEMOS)) { notice_lang(s_MemoServ, u, OPER_DEFCON_DENIED); return MOD_STOP; } if (!nick_recognized(u)) { notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ); return MOD_STOP; } if ((ci=cs_findchan(dest))==NULL) { notice_lang(s_MemoServ, u, CHAN_X_NOT_REGISTERED, dest); return MOD_STOP; } if (!serv_admin && (MSSendDelay > 0) && ((u->lastmemosend + MSSendDelay) > now)) { notice_lang(s_MemoServ, u, MEMO_SEND_PLEASE_WAIT, MSSendDelay); return MOD_STOP; } if (!secure_memos || serv_admin || check_access(u, ci, CA_MEMO)) { u->lastmemosend = now; //Prefix message with channel name memotext[0] = '['; strcpy(&memotext[1], ci->name); i = strlen(ci->name) + 1; memotext[i++] = ']'; memotext[i++] = ' '; //Look, if it goes over the text limit, let's just truncate it. //That's what the user expects... isn't it? -DaP strncpy(&memotext[i], memo, (MAX_LENGTH-i)); i += strlen(memo); memotext[i] = '\0'; acc = ci->levels[CA_MEMO]; for (i=0; iaccesscount; i++) { if (ci->access[i].in_use && (ci->access[i].level >= acc) && (ci->access[i].nc != u->na->nc)) { if (ci->access[i].nc == ci->founder) fndr = 1; send_user_memo(u, ci->access[i].nc, memotext); } } if (!fndr) { send_user_memo(u, ci->founder, memotext); } notice_lang(s_MemoServ, u, MEMO_SENT, ci->name); return MOD_STOP; } else { notice_lang(s_MemoServ, u, ACCESS_DENIED); return MOD_STOP; } //We shouldn't get here... but just in case :-D return MOD_STOP; } //Send the individual memos to the users int send_user_memo(User *u, NickCore *nc, char *memo) { MemoInfo *mi = &nc->memos; NickAlias *na; Memo *m = NULL; User *u2; mi->memocount++; mi->memos=srealloc(mi->memos, sizeof(Memo) * mi->memocount); m = &mi->memos[mi->memocount-1]; strscpy(m->sender, u->nick, NICKMAX); if (mi->memocount > 1) { m->number = m[-1].number + 1; if (m->number < 1) { int i; for (i=0; i < mi->memocount; i++) mi->memos[i].number = i + 1; m->number = 1; //Add } } else { m->number = 1; } m->time = time(NULL); m->text = sstrdup(memo); m->flags = MF_UNREAD; if (MSNotifyAll) { if ((nc->flags & NI_MEMO_RECEIVE) && get_ignore(nc->display) == NULL) { int i; for (i = 0; i < nc->aliases.count; i++) { na = nc->aliases.list[i]; if (na->u && nick_identified(na->u)) notice_lang(s_MemoServ, na->u, MEMO_NEW_MEMO_ARRIVED, u->nick, s_MemoServ, m->number); } } else { if ((u2 = finduser(nc->display)) && nick_identified(u2)) notice_lang(s_MemoServ, u2, MEMO_NEW_MEMO_ARRIVED, u->nick, s_MemoServ, m->number); } } return MOD_STOP; } #ifdef MS_SA_ALLACCESS //Read a users memos int read_user_memo(User *u, char *nick, NickCore *nc) { MemoInfo *mi; char *numstr = strtok(NULL, " "); int num, count; numstr = strtok(NULL, " "); mi = &nc->memos; num = numstr ? atoi(numstr) : -1; if (!numstr || (stricmp(numstr, "LAST") != 0 && stricmp(numstr, "NEW") != 0 && num <= 0)) { notice(s_MemoServ, u->nick, MS_SA_READ_SYNTAX); } else if (mi->memocount == 0) { notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_MEMOS, nick); } else { int i; if (stricmp(numstr, "NEW") == 0) { int readcount = 0; for (i = 0; i < mi->memocount; i++) { if (mi->memos[i].flags & MF_UNREAD) { read_memo(u, i, mi, NULL); readcount++; } } if (!readcount) { notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_NEW_MEMOS, nick); } } else if (stricmp(numstr, "LAST") == 0) { for (i = 0; i < mi->memocount - 1; i++); read_memo(u, i, mi, NULL); } else { /* number[s] */ if (!process_numlist(numstr, &count, read_memo_callback, u, mi, NULL)) { if (count == 1) notice_lang(s_MemoServ, u, MEMO_DOES_NOT_EXIST, num); else notice_lang(s_MemoServ, u, MEMO_LIST_NOT_FOUND, numstr); } } } return MOD_STOP; } //List a users memos int list_user_memo(User *u, char *nick, NickCore *nc) { char *param = strtok(NULL, " "); MemoInfo *mi; Memo *m; int i; param = strtok(NULL, " "); mi = &nc->memos; if (param && !isdigit(*param) && stricmp(param, "NEW") != 0) { notice(s_MemoServ, u->nick, MS_SA_LIST_SYNTAX); } else if (mi->memocount == 0) { notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_MEMOS, nick); } else { int sent_header = 0; if (param && isdigit(*param)) { process_numlist(param, NULL, list_memo_callback, u, mi, &sent_header, nick); } else { if (param) { for (i = 0, m = mi->memos; i < mi->memocount; i++, m++) { if (m->flags & MF_UNREAD) break; } if (i == mi->memocount) { notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_NEW_MEMOS, nick); return MOD_STOP; } } for (i = 0, m = mi->memos; i < mi->memocount; i++, m++) { if (param && !(m->flags & MF_UNREAD)) continue; list_memo(u, i, mi, &sent_header, param != NULL, nick); } } } return MOD_STOP; } #endif #ifdef MS_SA_MOREACCESS //Delete a user's memos int del_user_memo(User *u, char *nick, NickCore *nc) { MemoInfo *mi; char *numstr = strtok(NULL," "); int last, last0, i; char buf[BUFSIZE], *end; int delcount, count, left; numstr = strtok(NULL, ""); mi = &nc->memos; if (!numstr || (!isdigit(*numstr) && stricmp(numstr, "ALL") != 0 && stricmp(numstr, "LAST") != 0)) { notice(s_MemoServ, u->nick, MS_SA_DEL_SYNTAX); } else if (mi->memocount == 0) { notice_lang(s_MemoServ, u, MEMO_X_HAS_NO_MEMOS, nick); } else { if (isdigit(*numstr)) { /* Delete a specific memo or memos. */ last = -1; /* Last memo deleted */ last0 = -1; /* Beginning of range of last memos deleted */ end = buf; left = sizeof(buf); delcount = process_numlist(numstr, &count, del_memo_callback, u, mi, &last, &last0, &end, &left); if (last != -1) { /* Some memos got deleted; tell them which ones. */ if (delcount > 1) { if (last0 != last) end += snprintf(end, sizeof(buf) - (end - buf), ",%d-%d", last0, last); else end += snprintf(end, sizeof(buf) - (end - buf), ",%d", last); /* "buf+1" here because *buf == ',' */ notice_lang(s_MemoServ, u, MEMO_DELETED_SEVERAL, buf + 1); } else { notice_lang(s_MemoServ, u, MEMO_DELETED_ONE, last); } } else { /* No memos were deleted. Tell them so. */ if (count == 1) notice_lang(s_MemoServ, u, MEMO_DOES_NOT_EXIST, atoi(numstr)); else notice_lang(s_MemoServ, u, MEMO_DELETED_NONE); } } else if (stricmp(numstr, "LAST") == 0) { /* Delete last memo. */ for (i = 0; i < mi->memocount; i++) last = mi->memos[i].number; delmemo(mi, last); notice_lang(s_MemoServ, u, MEMO_DELETED_ONE, last); } else { /* Delete all memos. */ for (i = 0; i < mi->memocount; i++) free(mi->memos[i].text); free(mi->memos); mi->memos = NULL; mi->memocount = 0; notice(s_MemoServ, u->nick, MS_SA_DELETED_ALL, nick); } /* Reset the order */ for (i = 0; i < mi->memocount; i++) mi->memos[i].number = i + 1; } return MOD_STOP; } #endif