/** * Simple module to allow voicing of Caps / lower / None / All nicks in a channel. * 1.0 Initial version **/ #include "module.h" #define AUTHOR "Rob" #define VERSION "1.0" /* The name of the default database to save info to */ #define DEFAULT_DB_NAME "avoice.db" /* Multi-language stuff */ #define LANG_NUM_STRINGS 7 #define CS_AVOICE_SYNTAX 0 #define CS_AVOICE_CAP_ON 1 #define CS_AVOICE_LOW_ON 2 #define CS_AVOICE_ALL_ON 3 #define CS_AVOICE_ALL_OFF 4 #define CS_AVOICE_HELP_STR 5 #define CS_AVOICE_HELP 6 /* Defines used in the code for types */ #define CAP "Cap" #define LOW "low" #define ALL "All" char *CSAVoiceDBName; int my_avoice(User * u); int mSaveData(int argc, char **argv); int mLoadData(void); int myIsCap(char *nick); int myIsLow(char *nick); int mEventJoin(int argc, char **argv); char myFirstChar(char *nick); int mLoadConfig(int argc, char **argv); void m_AddLanguages(void); int myChanServAvoiceHelp(User * u); void myChanServHelp(User * u); /** * AnopeInit - tell anope about what this module will do etc. **/ int AnopeInit(int argc, char **argv) { Command *c = NULL; EvtHook *hook = NULL; int status; CSAVoiceDBName = NULL; if (mLoadConfig(0, NULL)) return MOD_STOP; m_AddLanguages(); hook = createEventHook(EVENT_JOIN_CHANNEL, mEventJoin); status = moduleAddEventHook(hook); c = createCommand("avoice", my_avoice, NULL, -1, -1, -1, -1, -1); /* Create a "avoice" command on chanserv */ moduleAddCommand(CHANSERV, c, MOD_UNIQUE); moduleAddHelp(c, myChanServAvoiceHelp); /* Add pretty help */ moduleSetChanHelp(myChanServHelp); /* Add AVOICE to the chanserv help */ hook = createEventHook(EVENT_RELOAD, mLoadConfig); status = moduleAddEventHook(hook); mLoadData(); /* Load the database up */ hook = createEventHook(EVENT_DB_SAVING, mSaveData); status = moduleAddEventHook(hook); moduleAddAuthor(AUTHOR); moduleAddVersion(VERSION); return MOD_CONT; } /** * Unload the module **/ void AnopeFini(void) { char *av[1]; av[0] = sstrdup(EVENT_START); mSaveData(1, av); free(av[0]); if (CSAVoiceDBName) free(CSAVoiceDBName); } /** * Function to execute when someone does a /msg chanserv avoice **/ int my_avoice(User * u) { char *chan = strtok(NULL, " "); char *toggleStr = strtok(NULL, ""); ChannelInfo *ci = NULL; if (!chan || !toggleStr) { moduleNoticeLang(s_ChanServ, u, CS_AVOICE_SYNTAX); } if ((ci = cs_findchan(chan))) { if (!is_founder(u, ci)) { /* Only let the founder update this setting */ notice_lang(s_ChanServ, u, ACCESS_DENIED); return MOD_CONT; } if (strcasecmp(toggleStr, "Cap") == 0) { moduleAddData(&ci->moduleData, "avoice", CAP); moduleNoticeLang(s_ChanServ, u, CS_AVOICE_CAP_ON); } else if (strcasecmp(toggleStr, "low") == 0) { moduleAddData(&ci->moduleData, "avoice", LOW); moduleNoticeLang(s_ChanServ, u, CS_AVOICE_LOW_ON); } else if (strcasecmp(toggleStr, "All") == 0) { moduleAddData(&ci->moduleData, "avoice", ALL); moduleNoticeLang(s_ChanServ, u, CS_AVOICE_ALL_ON); } else if (strcasecmp(toggleStr, "Off") == 0) { moduleDelData(&ci->moduleData, "avoice"); moduleNoticeLang(s_ChanServ, u, CS_AVOICE_ALL_OFF); } else { moduleNoticeLang(s_ChanServ, u, CS_AVOICE_SYNTAX); } } else { notice_lang(s_ChanServ, u, CHAN_X_NOT_REGISTERED, chan); } return MOD_CONT; } /** * We recived a join message, check the avoice setting. **/ int mEventJoin(int argc, char **argv) { ChannelInfo *ci = NULL; char *data = NULL; int doit = 0; User *user = NULL; if (argc != 3) return MOD_CONT; if (strcmp(argv[0], EVENT_STOP) == 0) { user = finduser(argv[1]); /* Blame Rob if this user->na should be findnick(user->nick); -GD */ if (user) { if ((ci = cs_findchan(argv[2]))) { if ((data = moduleGetData(&ci->moduleData, "avoice"))) { if ((strcasecmp(data, CAP) == 0) && (myIsCap(user->nick) == 1)) { doit = 1; } else if ((strcasecmp(data, LOW) == 0) && (myIsLow(user->nick) == 1)) { doit = 1; } else if (strcasecmp(data, ALL) == 0) { doit = 1; } if (doit) { anope_cmd_mode(whosends(ci), ci->name, "+v %s", user->nick); /* Send the +v line */ chan_set_user_status(ci->c, user, CUS_VOICE); /* Tell anope's internals about it */ } free(data); } } } } return MOD_CONT; } /** * Is the given nick Cap ? * @param nick The nick to check * @return 1 = Yes, 0 = No **/ int myIsCap(char *nick) { char ch = myFirstChar(nick); if ((ch >= 'A') && (ch <= 'Z')) { return 1; } return 0; } /** * Is the given nick lower ? * @param nick The nick to check * @return 1 = Yes, 0 = No **/ int myIsLow(char *nick) { char ch = myFirstChar(nick); if ((ch >= 'a') && (ch <= 'z')) { return 1; } return 0; } /** * Find the first alphabetical char of the nick * @param nick The nick to find the start of - cant be NULL! * @return first alpha Char, or 0 for none **/ char myFirstChar(char *nick) { int i = 0; int len = strlen(nick); for (i = 0; i < len; i++) { if (isalpha(nick[i])) { return nick[i]; } } return 0; } /** * Load data from the db file, and populate our avoice settings * @return 0 for success **/ int mLoadData(void) { int ret = 0; FILE *in; char *type = NULL; char *name = NULL; ChannelInfo *ci = NULL; char buffer[2000]; /* will _never_ be this big thanks to the 512 limit of a message */ if ((in = fopen(CSAVoiceDBName, "r")) == NULL) { alog("cs_voice.so: HELP I cant open my data file! (it might not exist, this isnt fatal)"); ret = 1; } else { while (!feof(in)) { fgets(buffer, 1500, in); type = myStrGetToken(buffer, ' ', 0); name = myStrGetToken(buffer, ' ', 1); if (type) { if (name) { if ((ci = cs_findchan(name))) { /* Find the channel info record we want to add the setting for */ if (stricmp(type, CAP) == 0) { moduleAddData(&ci->moduleData, "avoice", CAP); } else if (stricmp(type, LOW) == 0) { moduleAddData(&ci->moduleData, "avoice", LOW); } else if (stricmp(type, ALL) == 0) { moduleAddData(&ci->moduleData, "avoice", ALL); } else { alog("cs_voice.so: Possible invalid entry [%s] in .db file, ignoring...", name); } } free(name); } free(type); } } } return ret; } /** * Save all our data to our db file * First walk through the nick CORE list, and any channel which has avoice attached to it, write to the file * Next do the same again for ChannelInfos * @return 0 for success **/ int mSaveData(int argc, char **argv) { ChannelInfo *ci = NULL; int i = 0; int ret = 0; char *data; FILE *out; if ((out = fopen(CSAVoiceDBName, "w")) == NULL) { alog("cs_voice.so: HELP I cant open my data file!"); anope_cmd_global(s_OperServ, "cs_voice.so: HELP I cant open my data file!"); ret = 1; } else { for (i = 0; i < 256; i++) { for (ci = chanlists[i]; ci; ci = ci->next) { if ((data = moduleGetData(&ci->moduleData, "avoice"))) { if (stricmp(data, CAP) == 0) { fprintf(out, "%s %s \n", CAP, ci->name); } else if (stricmp(data, LOW) == 0) { fprintf(out, "%s %s \n", LOW, ci->name); } else if (stricmp(data, ALL) == 0) { fprintf(out, "%s %s \n", ALL, ci->name); } else { alog("cs_voice.so: Invalid avoice setting for channel [%s] not saving this record!", ci->name); } free(data); } } } fclose(out); } moduleAddCallback("cs_voice: save me", time(NULL) + UpdateTimeout, mSaveData, 0, NULL); return ret; } /** * Load the configuration directives from Services configuration file. * @return 0 for success **/ int mLoadConfig(int argc, char **argv) { char *tmp = NULL; Directive d[] = { {"CSAVoiceDBName", {{PARAM_STRING, PARAM_RELOAD, &tmp}}}, }; moduleGetConfigDirective(d); if (CSAVoiceDBName) free(CSAVoiceDBName); if (tmp) { CSAVoiceDBName = tmp; } else { CSAVoiceDBName = sstrdup(DEFAULT_DB_NAME); alog("cs_avoice: CSAVoiceDBName is not defined in Services configuration file, using default %s", CSAVoiceDBName); } if (!CSAVoiceDBName) { alog("cs_avoice: FATAL: Can't read required configuration directives!"); return MOD_STOP; } else { alog("cs_avoice: Directive CSAVoiceDBName loaded (%s)...", CSAVoiceDBName); } return MOD_CONT; } /** * Function to deal with the "/msg chanserv help avoice" command **/ int myChanServAvoiceHelp(User * u) { moduleNoticeLang(s_NickServ, u, CS_AVOICE_SYNTAX); moduleNoticeLang(s_NickServ, u, CS_AVOICE_HELP); return MOD_CONT; } /** * What we should add to the "/msg chanserv help" screen, gotta tell people about us! **/ void myChanServHelp(User * u) { moduleNoticeLang(s_ChanServ, u, CS_AVOICE_HELP_STR); } /** * manages the multilanguage stuff **/ void m_AddLanguages(void) { /* English (US) */ char *langtable_en_us[] = { /* CS_AVOICE_SYNTAX */ "Syntax: AVOICE #channel [Cap|low|All|Off]", /* CS_AVOICE_CAP_ON */ "All Capped nicks will now be auto-voiced upon entering", /* CS_AVOICE_LOW_ON */ "All lower nicks will now be auto-voiced upon entering", /* CS_AVOICE_ALL_ON */ "All users will now be auto-voiced upon entering", /* CS_AVOICE_ALLO_OFF */ "No users will now be auto-voiced, except those on the channel vop list.", /* CS_AVOICE_HELP_STR */ " AVOICE Toggles auto-voicing when joining rooms", /* CS_AVOICE_HELP */ "This option allows to you automatically\n" "voice all Capped nicks, all lower \n" "nicks or everyone upon them joining the\n" "channel." }; moduleInsertLanguage(LANG_EN_US, LANG_NUM_STRINGS, langtable_en_us); } /* EOF */