unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

api-command.c (8698B)

      1 /************************************************************************
      2  *   Unreal Internet Relay Chat Daemon, src/api-command.c
      3  *   Copyright (C) 2004 Dominick Meglio and The UnrealIRCd Team
      4  *
      5  *   This program is free software; you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation; either version 1, or (at your option)
      8  *   any later version.
      9  *
     10  *   This program is distributed in the hope that it will be useful,
     11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  *   GNU General Public License for more details.
     14  *
     15  *   You should have received a copy of the GNU General Public License
     16  *   along with this program; if not, write to the Free Software
     17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     18  */
     19 
     20 /** @file
     21  * @brief Command API - both for modules and the core
     22  */
     23 #include "unrealircd.h"
     24 
     25 /* Forward declarations */
     26 static Command *CommandAddInternal(Module *module, const char *cmd, CmdFunc func, AliasCmdFunc aliasfunc, unsigned char params, int flags);
     27 static RealCommand *add_Command_backend(const char *cmd);
     28 
     29 /** @defgroup CommandAPI Command API
     30  * @{
     31  */
     32 
     33 /** Returns 1 if the specified command exists
     34  */
     35 int CommandExists(const char *name)
     36 {
     37 	RealCommand *p;
     38 	
     39 	for (p = CommandHash[toupper(*name)]; p; p = p->next)
     40 	{
     41 		if (!strcasecmp(p->cmd, name))
     42 			return 1;
     43 	}
     44 
     45 	return 0;
     46 }
     47 
     48 /** Register a new command.
     49  * @param module	The module (usually modinfo->handle)
     50  * @param cmd		The command name (eg: "SOMECMD")
     51  * @param func		The command handler function
     52  * @param params	Number of parameters or MAXPARA
     53  * @param flags		Who may execute this command - one or more CMD_* flags
     54  * @returns The newly registered command, or NULL in case of error (eg: already exist)
     55  */
     56 Command *CommandAdd(Module *module, const char *cmd, CmdFunc func, unsigned char params, int flags)
     57 {
     58 	if (flags & CMD_ALIAS)
     59 	{
     60 		config_error("Command '%s' used CommandAdd() to add a command alias, "
     61 		             "but should have used AliasAdd() instead. "
     62 		             "Old 3rd party module %s? Check for updates!",
     63 		             cmd,
     64 		             module ? module->header->name : "");
     65 		return NULL;
     66 	}
     67 	return CommandAddInternal(module, cmd, func, NULL, params, flags);
     68 }
     69 
     70 /** Register a new alias.
     71  * @param module	The module (usually modinfo->handle)
     72  * @param cmd		The alias name (eg: "SOMECMD")
     73  * @param func		The alias handler function
     74  * @param params	Number of parameters or MAXPARA
     75  * @param flags		Who may execute this command - one or more CMD_* flags
     76  * @returns The newly registered command (alias), or NULL in case of error (eg: already exist)
     77  */
     78 Command *AliasAdd(Module *module, const char *cmd, AliasCmdFunc aliasfunc, unsigned char params, int flags)
     79 {
     80 	if (!(flags & CMD_ALIAS))
     81 		flags |= CMD_ALIAS;
     82 	return CommandAddInternal(module, cmd, NULL, aliasfunc, params, flags);
     83 }
     84 
     85 /** @} */
     86 
     87 static Command *CommandAddInternal(Module *module, const char *cmd, CmdFunc func, AliasCmdFunc aliasfunc, unsigned char params, int flags)
     88 {
     89 	Command *command = NULL;
     90 	RealCommand *c;
     91 
     92 	if ((c = find_command(cmd, flags)) && (c->flags == flags))
     93 	{
     94 		if (module)
     95 			module->errorcode = MODERR_EXISTS;
     96 		return NULL;
     97 	}
     98 	
     99 	if (!flags)
    100 	{
    101 		config_error("CommandAdd(): Could not add command '%s': flags are 0", cmd);
    102 		if (module)
    103 			module->errorcode = MODERR_INVALID;
    104 		return NULL;
    105 	}
    106 	
    107 	c = add_Command_backend(cmd);
    108 	c->parameters = (params > MAXPARA) ? MAXPARA : params;
    109 	c->flags = flags;
    110 	c->func = func;
    111 	c->aliasfunc = aliasfunc;
    112 
    113 	if (module)
    114 	{
    115 		ModuleObject *cmdobj = safe_alloc(sizeof(ModuleObject));
    116 		command = safe_alloc(sizeof(Command));
    117 		command->cmd = c;
    118 		command->cmd->owner = module;
    119 		command->cmd->friend = NULL;
    120 		cmdobj->object.command = command;
    121 		cmdobj->type = MOBJ_COMMAND;
    122 		AddListItem(cmdobj, module->objects);
    123 		module->errorcode = MODERR_NOERROR;
    124 	}
    125 
    126 	return command;
    127 }
    128 
    129 /** Delete a command - only used internally.
    130  * @param command	The command (can be NULL)
    131  * @param cmd		The "real" command
    132  */
    133 void CommandDelX(Command *command, RealCommand *cmd)
    134 {
    135 	CommandOverride *ovr, *ovrnext;
    136 
    137 	DelListItem(cmd, CommandHash[toupper(*cmd->cmd)]);
    138 	if (command && cmd->owner)
    139 	{
    140 		ModuleObject *cmdobj;
    141 		for (cmdobj = cmd->owner->objects; cmdobj; cmdobj = cmdobj->next)
    142 		{
    143 			if (cmdobj->type == MOBJ_COMMAND && cmdobj->object.command == command)
    144 			{
    145 				DelListItem(cmdobj,cmd->owner->objects);
    146 				safe_free(cmdobj);
    147 				break;
    148 			}
    149 		}
    150 	}
    151 	for (ovr = cmd->overriders; ovr; ovr = ovrnext)
    152 	{
    153 		ovrnext = ovr->next;
    154 		CommandOverrideDel(ovr);
    155 	}
    156 	safe_free(cmd->cmd);
    157 	safe_free(cmd);
    158 	if (command)
    159 		safe_free(command);
    160 }
    161 
    162 /** De-register a command - not called by modules, only internally.
    163  * For modules this is done automatically.
    164  */
    165 void CommandDel(Command *command)
    166 {
    167 	CommandDelX(command, command->cmd);
    168 }
    169 
    170 /** @defgroup CommandAPI Command API
    171  * @{
    172  */
    173 
    174 /** Calls the specified command for the user, as if it was received
    175  * that way on IRC.
    176  * @param client	Client that is the source.
    177  * @param mtags		Message tags for this command (or NULL).
    178  * @param cmd		Command to run, eg "JOIN".
    179  * @param parc		Parameter count plus 1.
    180  * @param parv		Parameter array.
    181  * @note Make sure you terminate the last parv[] parameter with NULL,
    182  *       this can easily be forgotten, but certain functions depend on it,
    183  *       you risk crashes otherwise.
    184  * @note Once do_cmd() has returned, be sure to check IsDead(client) to
    185  *       see if the client has been killed. This may happen due to various
    186  *       reasons, including spamfilter kicking in or some other security
    187  *       measure.
    188  * @note Do not pass insane parameters. The combined size of all parameters
    189  *       should not exceed 510 bytes, since that is what all code expects.
    190  *       Similarly, you should not exceed MAXPARA for parc.
    191  * @note If mtags is NULL then new message tags are created for the command
    192  *       (and destroyed before return).
    193  */
    194 void do_cmd(Client *client, MessageTag *mtags, const char *cmd, int parc, const char *parv[])
    195 {
    196 	RealCommand *cmptr;
    197 
    198 	cmptr = find_command_simple(cmd);
    199 	if (cmptr)
    200 	{
    201 		int gen_mtags = (mtags == NULL) ? 1 : 0;
    202 		if (gen_mtags)
    203 			new_message(client, NULL, &mtags);
    204 		(*cmptr->func) (client, mtags, parc, parv);
    205 		if (gen_mtags)
    206 			free_message_tags(mtags);
    207 	}
    208 }
    209 
    210 /** @} */
    211 
    212 /**** This is the "real command" API *****
    213  * Perhaps one day we will merge the two, if possible.
    214  */
    215 
    216 RealCommand *CommandHash[256]; /* one per letter */
    217 
    218 /** Initialize the command API - executed on startup.
    219  * This also registers some core functions.
    220  */
    221 void init_CommandHash(void)
    222 {
    223 	memset(CommandHash, 0, sizeof(CommandHash));
    224 	CommandAdd(NULL, MSG_ERROR, cmd_error, MAXPARA, CMD_UNREGISTERED|CMD_SERVER);
    225 	CommandAdd(NULL, MSG_VERSION, cmd_version, MAXPARA, CMD_UNREGISTERED|CMD_USER|CMD_SERVER);
    226 	CommandAdd(NULL, MSG_INFO, cmd_info, MAXPARA, CMD_USER);
    227 	CommandAdd(NULL, MSG_DNS, cmd_dns, MAXPARA, CMD_USER);
    228 	CommandAdd(NULL, MSG_REHASH, cmd_rehash, MAXPARA, CMD_USER|CMD_SERVER);
    229 	CommandAdd(NULL, MSG_RESTART, cmd_restart, 2, CMD_USER);
    230 	CommandAdd(NULL, MSG_DIE, cmd_die, MAXPARA, CMD_USER);
    231 	CommandAdd(NULL, MSG_CREDITS, cmd_credits, MAXPARA, CMD_USER);
    232 	CommandAdd(NULL, MSG_LICENSE, cmd_license, MAXPARA, CMD_USER);
    233 	CommandAdd(NULL, MSG_MODULE, cmd_module, MAXPARA, CMD_USER);
    234 }
    235 
    236 static RealCommand *add_Command_backend(const char *cmd)
    237 {
    238 	RealCommand *c = safe_alloc(sizeof(RealCommand));
    239 
    240 	safe_strdup(c->cmd, cmd);
    241 
    242 	/* Add in hash with hash value = first byte */
    243 	AddListItem(c, CommandHash[toupper(*cmd)]);
    244 
    245 	return c;
    246 }
    247 
    248 /** @defgroup CommandAPI Command API
    249  * @{
    250  */
    251 
    252 /** Find a command by name and flags */
    253 RealCommand *find_command(const char *cmd, int flags)
    254 {
    255 	RealCommand *p;
    256 	for (p = CommandHash[toupper(*cmd)]; p; p = p->next)
    257 	{
    258 		if (flags & CMD_CONTROL)
    259 		{
    260 			if (!(p->flags & CMD_CONTROL))
    261 				continue;
    262 		} else
    263 		{
    264 			if ((flags & CMD_UNREGISTERED) && !(p->flags & CMD_UNREGISTERED))
    265 				continue;
    266 			if ((flags & CMD_SHUN) && !(p->flags & CMD_SHUN))
    267 				continue;
    268 			if ((flags & CMD_VIRUS) && !(p->flags & CMD_VIRUS))
    269 				continue;
    270 			if ((flags & CMD_ALIAS) && !(p->flags & CMD_ALIAS))
    271 				continue;
    272 			if (p->flags & CMD_CONTROL)
    273 				continue; /* important to also filter it this way ;) */
    274 		}
    275 
    276 		if (!strcasecmp(p->cmd, cmd))
    277 			return p;
    278 	}
    279 	return NULL;
    280 }
    281 
    282 /** Find a command by name (no access rights check) */
    283 RealCommand *find_command_simple(const char *cmd)
    284 {
    285 	RealCommand *c;
    286 
    287 	for (c = CommandHash[toupper(*cmd)]; c; c = c->next)
    288 	{
    289 		if (!strcasecmp(c->cmd, cmd))
    290 				return c;
    291 	}
    292 
    293 	return NULL;
    294 }
    295 
    296 /** @} */