*** VERSION 5.2.0 ***
[NeonServV5.git] / src / modcmd.c
index 4b1d2cc1eeeb767b7fb9663874980c5e00f4cec9..3f51761a0f30bbf5e3e47abdc3b82027fcffe0ba 100644 (file)
@@ -1,3 +1,19 @@
+/* modcmd.c - NeonServ v5.2
+ * Copyright (C) 2011  Philipp Kreil (pk910)
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License 
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. 
+ */
 
 #include "modcmd.h"
 #include "IRCEvents.h"
@@ -25,7 +41,7 @@ struct command_check_user_cache {
     struct ChanNode *chan, *sent_chan;
     char **argv;
     int argc;
-    char *message;
+    char *message, *args_buffer;
     struct cmd_binding *cbind;
 };
 
@@ -100,6 +116,9 @@ static USERAUTH_CALLBACK(command_checked_auth) {
     tmp_text_client = cache->textclient;
     handle_command_async(cache->client, user, cache->chan, cache->sent_chan, cache->cbind, cache->argv, cache->argc);
     free(cache->message);
+    if(cache->args_buffer)
+        free(cache->args_buffer);
+    free(cache->argv);
     free(cache);
 }
 
@@ -118,6 +137,7 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s
     message = strdup(message);
     int bind_index = get_binds_index(message[0]);
     char *args = strstr(message, " ");
+    char *args_buffer = NULL; //we need this to save a possible pointer to a allocation we need to free
     if(args) {
         *args = '\0';
         args++;
@@ -152,47 +172,69 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s
                     chan = chan2;
                 }
             }
-            if(cbind->parameters) {
+            if(cbind->paramcount) {
                 //userdefined parameters...
+                args_buffer = malloc(MAXLEN * 2 * sizeof(*args_buffer));
+                int args_pos = 0;
                 char *uargs[MAXNUMPARAMS];
                 int uargc = 0;
-                char *a,*b = cbind->parameters;
+                char *b;
+                int i;
                 int allargs, argi;
-                do {
-                    a = strstr(b, " ");
-                    if(a) *a = '\0';
+                for(i = 0; i < cbind->paramcount; i++) {
+                    b = cbind->parameters[i];
                     if(b[0] == '%') {
                         b++;
                         if(b[strlen(b)-1] == '-') {
+                            allargs = strlen(b)-1;
+                            b[allargs] = '\0';
+                            argi = atoi(b);
+                            b[allargs] = '-';
                             allargs = 1;
-                            b[strlen(b)-1] = '\0';
+                        } else if(b[strlen(b)-1] == '+') {
+                            allargs = strlen(b)-1;
+                            b[allargs] = '\0';
                             argi = atoi(b);
-                            b[strlen(b)-1] = '-';
+                            b[allargs] = '+';
+                            allargs = 2;
                         } else {
                             allargs = 0;
                             argi = atoi(b);
                         }
                         if(argi > 0) {
                             if(argi <= argc) {
-                                uargs[uargc++] = argv[argi-1];
-                                if(allargs) {
-                                    for(argi++; argi <= argc; argi++)
-                                        uargs[uargc++] = argv[argi-1];
+                                uargs[uargc++] = args_buffer + args_pos;
+                                if(allargs == 0) {
+                                    args_pos += sprintf(args_buffer + args_pos, "%s", argv[argi-1]) + 1;
+                                } else if(allargs == 1) {
+                                    args_pos += sprintf(args_buffer + args_pos, "%s", argv[argi-1]) + 1;
+                                    for(argi++; argi <= argc; argi++) {
+                                        uargs[uargc++] = args_buffer + args_pos;
+                                        args_pos += sprintf(args_buffer + args_pos, "%s", argv[argi-1]) + 1;
+                                    }
+                                } else if(allargs == 2) {
+                                    for(;argi <= argc; argi++) {
+                                        args_pos += sprintf(args_buffer + args_pos, (allargs ? "%s" : " %s"), argv[argi-1]);
+                                        allargs = 0;
+                                    }
+                                    args_pos++;
                                 }
+                            } else if((cbind->func->flags & CMDFLAG_EMPTY_ARGS)) {
+                                uargs[uargc++] = args_buffer + args_pos;
+                                args_buffer[args_pos++] = '\0';
                             }
                         } else if(!strcmp(b, "c")) {
-                            uargs[uargc++] = (chan ? chan->name : NULL);
+                            uargs[uargc++] = args_buffer + args_pos;
+                            args_pos += sprintf(args_buffer + args_pos, "%s", (chan ? chan->name : "")) + 1;
                         } else if(!strcmp(b, "n")) {
-                            uargs[uargc++] = user->nick;
+                            uargs[uargc++] = args_buffer + args_pos;
+                            args_pos += sprintf(args_buffer + args_pos, "%s", user->nick) + 1;
                         }
                     } else {
-                        uargs[uargc++] = b;
-                    }
-                    if(a) {
-                        *a = ' ';
-                        b = a+1;
+                        uargs[uargc++] = args_buffer + args_pos;
+                        args_pos += sprintf(args_buffer + args_pos, "%s", b) + 1;
                     }
-                } while(a);
+                }
                 argv = uargs;
                 argc = uargc;
             }
@@ -220,6 +262,7 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s
                 data->chan = chan;
                 data->sent_chan = sent_chan;
                 data->message = message;
+                data->args_buffer = args_buffer;
                 data->cbind = cbind;
                 data->textclient = tmp_text_client;
                 get_userauth(user, command_checked_auth, data);
@@ -230,6 +273,8 @@ static void handle_command(struct ClientSocket *client, struct UserNode *user, s
         }
     }
     free(message);
+    if(args_buffer)
+        free(args_buffer);
 }
 
 static void handle_command_async(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct ChanNode *sent_chan, struct cmd_binding *cbind, char **argv, int argc) {
@@ -472,7 +517,7 @@ int bind_cmd_to_function(int botid, char *cmd, struct cmd_function *func) {
     cbind->botid = botid;
     cbind->cmd = strdup(cmd);
     cbind->func = func;
-    cbind->parameters = NULL;
+    cbind->paramcount = 0;
     cbind->global_access = 0;
     cbind->channel_access = NULL;
     cbind->flags = 0;
@@ -503,7 +548,7 @@ int bind_cmd_to_command(int botid, char *cmd, char *func) {
     cbind->cmd = strdup(cmd);
     cbind->func = cmdfunc;
     cbind->next = cmd_binds[bind_index];
-    cbind->parameters = NULL;
+    cbind->paramcount = 0;
     cbind->global_access = 0;
     cbind->channel_access = NULL;
     cbind->flags = 0;
@@ -521,8 +566,11 @@ int unbind_cmd(int botid, char *cmd) {
             else
                 cmd_binds[bind_index] = cbind->next;
             free(cbind->cmd);
-            if(cbind->parameters)
-                free(cbind->parameters);
+            if(cbind->paramcount) {
+                int i;
+                for(i = 0; i < cbind->paramcount; i++)
+                    free(cbind->parameters[i]);
+            }
             free(cbind);
             return 1;
         } else
@@ -558,8 +606,11 @@ void free_modcmd() {
         for(cbind = cmd_binds[i]; cbind; cbind = next) {
             next = cbind->next;
             free(cbind->cmd);
-            if(cbind->parameters)
-                free(cbind->parameters);
+            if(cbind->paramcount) {
+                int j;
+                for(j = 0; j < cbind->paramcount; j++)
+                    free(cbind->parameters[j]);
+            }
             if(cbind->channel_access)
                 free(cbind->channel_access);
             free(cbind);
@@ -586,9 +637,19 @@ void bind_set_parameters(int botid, char *cmd, char *parameters) {
     struct cmd_binding *cbind;
     for(cbind = cmd_binds[bind_index]; cbind; cbind = cbind->next) {
         if(cbind->botid == botid && strcmp(cbind->cmd, cmd) == 0) {
-            if(cbind->parameters)
-                free(cbind->parameters);
-            cbind->parameters = strdup(parameters);
+            if(cbind->paramcount) {
+                int i;
+                for(i = 0; i < cbind->paramcount; i++)
+                    free(cbind->parameters[i]);
+                cbind->paramcount = 0;
+            }
+            char *a, *b = parameters;
+            do {
+                a = strstr(b, " ");
+                if(a) *a = '\0';
+                cbind->parameters[cbind->paramcount++] = strdup(b);
+                if(a) b = a+1;
+            } while(a);
             return;
         }
     }