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 /** @} */