Tutorials:Module Help 1.8
Contents |
Anope Modules Tutorial: Creating Help
Introduction
So you've written your first module, but you're wondering how to add help to your module? Ok, i'm willing to show you how. Anyways, i assume you know the basics of module coding (as described in my first tutorial, if you understand the code below fully you know enough) and thus also a basic knowledge of C. If you lack any of those i can get pretty hard to follow later on. This tutorial will add help to our previously-made he_meow module (at least, some of us made it in the previous tutorial, others know what it does as they understand the code, or they say so at least). I've included the final code again below this introduction for your reference. So we're ready to go? Let's go then!
Our he_meow Code
#include "module.h"
#define AUTHOR "Anope"
#define VERSION "1.0.0"
/* Our function which meow's at the user */
int my_he_meow(User *u);
int AnopeInit(int argc, char **argv) {
/* We create the command we're going to use */
Command *c;
c = createCommand("meow", my_he_meow, NULL, -1, -1, -1, -1, -1);
/* We add the command to HelpServ and log it */
alog("he_meow: Add command 'meow' status: %d", moduleAddCommand(HELPSERV, c, MOD_HEAD));
/* We tell Anope who we are and what version this module is */
moduleAddAuthor(AUTHOR);
moduleAddVersion(VERSION);
/* Loading succeeded */
return MOD_CONT;
}
void AnopeFini(void) {
/* Nothing to clean up */
}
int my_he_meow(User *u) {
/* Meow at the user, (s)he wanted it so badly */
notice(s_HelpServ, u->nick, "MEOW! Specially for you \002%s\002 ;)", u->nick);
/* Halt processing */
return MOD_STOP;
}
/* EOF */
Our command in a single line
You know the lists of commands in the help of the various services which indicate what commands you can use, and what they do. Guess what? Our module can also add such a text! You have to choose to which service you're going to add it though, but that choice can't be very hard. It's HelpServ in this case, so we use the moduleSetHelpHelp command. This command returns void and has a single argument which contains the function to our help which has the following prototype:
void my_helpserv_help(User * u);
Ofcourse the name is free to choose, but this one is close to my general naming scheme ;) It should seem logical that, like with our Command-handling my_he_meow function, the paramenter indicates a user-record for the user requesting the help. This way you do some access checks to, for example, only show a command to services admins and higher. A sample help function for our helpserv help function looks like this:
void my_helpserv_help(User *u) {
if (is_services_root(u))
notice(s_HelpServ, u->nick, " MEOW Meow at the services root!");
else if (is_services_admin(u))
notice(s_HelpServ, u->nick, " MEOW Meow at the services admin!");
else if (is_services_oper(u))
notice(s_HelpServ, u->nick, " MEOW Meow at the services oper!");
else
notice(s_HelpServ, u->nick, " MEOW Meow at the user!");
}
You see that i can add a different text for every accesslevel you have. Also note that i used else if, because is_services_admin also responds with a true value if the specified user is a services root, and is_services_oper also responds with true on a services admin or root. For the rest you also see the notice command again (we all know it already, don't we? ;)), and we see the amount of spaces in there. It seems to work well with this amount of spaces (all commands aligned nicely etc), so you should copy such an example line and edit it. Commands should start at the same column as MEOW does in our example (with 4 spaces in front of it), and the description starts after 16 characters (4x4 spaces if you have no command which is actually never seen anyways). Remember to keep the description rather short (no more than 40, 45 characters) or it might look ugly on older clients.
Extended Help
Now, what should we do when a user requests help for our MEOW command? You actually have to install a HELP command handler, filter out your own commands, and return the according MOD_CONT or MOD_STOP to control the services' processing of the command. Oh wait, that's the old way..... Great Rob has fixed something easier :) Altough it's a bit tricky. You can use the moduleAddRootHelp, moduleAddAdminHelp, moduleAddOperHelp, moduleAddRegHelp and moduleAddHelp commands to accomplish this. They have the following prototypes:
int moduleAddRootHelp(Command * c, int (*func) (User * u)); int moduleAddAdminHelp(Command * c, int (*func) (User * u)); int moduleAddOperHelp(Command * c, int (*func) (User * u)); int moduleAddRegHelp(Command * c, int (*func) (User * u)); int moduleAddHelp(Command * c, int (*func) (User * u));
The first three commands will seem logical to you, altough the latter two might confuse you a bit. moduleAddRegHelpis to add help which is only displayed to registered users, and moduleAddHelp is displayed to every user (including services roots/admins/opers). I said this stuff is a bit tricky, and i'll explain why now. Say, for example, we want to display help to all services opers and up. We use a call to moduleAddOperHelp, so this help displays at services opers. But now you have a services admin which can't see it! Therefore we need to add the same help via moduleAddAdminHelp and via moduleAddRootHelp (for the nice services roots ;)) too. The same goes for moduleAddAdminHelp, but ofcourse not for moduleAddRootHelp, as there's nothing higher than root. Anyways, i'll explain the passed arguments too.
The Arguments
The Command * c points to the command you want to add the help to. We have a command called c (Command *c;) in our module, so we just pass c there. The second argument is the function we want to call when the help is requested. This one has nearly the same prototype as our my_helpserv_help function discussed above, apart from the fact that we DO return an int now, which can either be a MOD_STOP or MOD_CONT to let services know if we had a failure displaying the help. This will only very rarely fail ;) Let's see what our help function and its prototype look like:
int my_he_meow_help(User *u);
int my_he_meow_help(User *u) {
notice(s_HelpServ, u->nick, "Syntax: \002MEOW\002");
notice(s_HelpServ, u->nick, " ");
notice(s_HelpServ, u->nick, "This command makes ChanServ meow at the user which invoked");
notice(s_HelpServ, u->nick, "it. This is available for all users.");
}
Well, i agree it's a bit short, but so is our function ;) The essential help is there though: the syntax used for our command (there are general syntax rules, they're at Text_Formatting:Syntax), and an extended description of what the command does. Saying that all users can use this command is optional, unless the command is only available to priviledged users. Also note that it's best to put a space instead of nothing if you need to send an empty line, as some clients seem to ignore completely empty messages, so the text would end up without the empty line.
Final code
I'll put down the final code of our he_meow module.
#include "module.h"
#define AUTHOR "Anope"
#define VERSION "1.0.0"
/* Our function which meow's at the user */
int my_he_meow(User *u);
/* And it's help function */
int my_he_meow_help(User *u);
/* And our general HelpServ Help function */
void my_helpserv_help(User * u);
int AnopeInit(int argc, char **argv) {
/* We create the command we're going to use */
Command *c;
c = createCommand("meow", my_he_meow, NULL, -1, -1, -1, -1, -1);
/* And we add help to it */
moduleAddHelp(c, my_he_meow_help);
/* We add the command to HelpServ and log it */
alog("he_meow: Add command 'meow' status: %d", moduleAddCommand(HELPSERV, c, MOD_HEAD));
/* We say HelpServ to allow our function to be in the HELP too! */
moduleSetHelpHelp(my_helpserv_help);
/* We tell Anope who we are and what version this module is */
moduleAddAuthor(AUTHOR);
moduleAddVersion(VERSION);
/* Loading succeeded */
return MOD_CONT;
}
void AnopeFini(void) {
/* Nothing to clean up */
}
int my_he_meow(User *u) {
/* Meow at the user, (s)he wanted it so badly */
notice(s_HelpServ, u->nick, "MEOW! Specially for you \002%s\002 ;)", u->nick);
/* Halt processing */
return MOD_STOP;
}
int my_he_meow_help(User *u) {
/* Explain what our MEOW command obivously does */
notice(s_HelpServ, u->nick, "Syntax: \002MEOW\002");
notice(s_HelpServ, u->nick, " ");
notice(s_HelpServ, u->nick, "This command makes ChanServ meow at the user which invoked");
notice(s_HelpServ, u->nick, "it. This is available for all users.");
}
void my_helpserv_help(User *u) {
/* We append our command to HelpServ's help */
if (is_services_root(u))
notice(s_HelpServ, u->nick, " MEOW Meow at the services root!");
else if (is_services_admin(u))
notice(s_HelpServ, u->nick, " MEOW Meow at the services admin!");
else if (is_services_oper(u))
notice(s_HelpServ, u->nick, " MEOW Meow at the services oper!");
else
notice(s_HelpServ, u->nick, " MEOW Meow at the user!");
}
/* EOF */