moved cmd_extscript from NeonServ.mod to global.mod
[NeonServV5.git] / src / modules / global.mod / cmd_global_extscript.c
1 /* cmd_global_extscript.c - NeonServ v5.3
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 #include "cmd_global.h"
19 #include <fcntl.h>
20
21 /*
22 * argv[0]      'toys' if it's a toy command (check if toys are enabled)
23 * argv[0-*]    script name & parameter patterns
24 * argv[argc-1] all arguments passed to the command
25 */
26
27 static TIMEQ_CALLBACK(global_cmd_extscript_callback);
28
29 struct global_cmd_extscript_cache {
30     struct ClientSocket *client, *textclient;
31     struct Event *event;
32     struct UserNode *user;
33     struct ChanNode *chan;
34     int answere_channel;
35     FILE *pipe;
36 };
37
38 CMD_BIND(global_cmd_extscript) {
39     int i, j;
40     char *args[MAXNUMPARAMS];
41     int argpos = 0;
42     char *next, *curr;
43     char command[1024];
44     int commandpos = 0;
45     char part[MAXLEN];
46     int partpos;
47     int escape_param;
48     int answere_channel = 0;
49     //check first arg
50     if(argc && !stricmp(argv[0], "toys")) {
51         if(!chan) return; //toys are not allowed via query
52         MYSQL_RES *res;
53         MYSQL_ROW row;
54         printf_mysql_query("SELECT `channel_toys` FROM `channels` WHERE `channel_name` = '%s'", escape_string(chan->name));
55         res = mysql_use();
56         row = mysql_fetch_row(res);
57         if(!row || !strcmp(row[0], "0")) {
58             //disabled
59             reply(getTextBot(), user, "NS_FUN_DISABLED", chan->name);
60             return;
61         } else if(!strcmp(row[0], "2"))
62             answere_channel = 1;
63         argc--;
64         argv++;
65     }
66     //parse arguments
67     if(argc < 2) return;
68     curr = argv[argc-1];
69     while(curr) {
70         next = strstr(curr, " ");
71         args[argpos++] = curr;
72         if(next) {
73             *next = '\0';
74             curr = next+1;
75         } else
76             curr = NULL;
77     }
78     //parse command pattern and build command
79     commandpos = sprintf(command, "%s", argv[0]);
80     for(i = 1; i < argc-1; i++) {
81         partpos = 0;
82         escape_param = 1;
83         if(argv[i][0] == '$') {
84             argv[i]++;
85             if(argv[i][strlen(argv[i])-1] == '-') {
86                 argv[i][strlen(argv[i])-1] = '\0';
87                 j = atoi(argv[i]);
88                 if(j <= argpos)
89                     partpos = sprintf(part, "%s", merge_argv(args, j-1, argpos));
90             } else if((j = atoi(argv[i])) > 0) {
91                 if(j <= argpos)
92                     partpos = sprintf(part, "%s", args[j-1]);
93             } else if(!strcmp(argv[i], "c")) {
94                 partpos = sprintf(part, "%s", (chan ? chan->name : ""));
95             } else if(!strcmp(argv[i], "n")) {
96                 partpos = sprintf(part, "%s", user->nick);
97             } else if(!strcmp(argv[i], "a")) {
98                 partpos = sprintf(part, "%s", ((user->flags & USERFLAG_ISAUTHED) ? user->auth : ""));
99             } else if(!strcmp(argv[i], "access")) {
100                 if(chan)
101                     partpos = sprintf(part, "%d", getChannelAccess(user, chan));
102             }
103         } else {
104             partpos = sprintf(part, "%s", argv[i]);
105             escape_param = 0;
106         }
107         //escape shell argument
108         command[commandpos++] = ' ';
109         if(escape_param) {
110             command[commandpos++] = '\'';
111             for(j = 0; j < partpos; j++) {
112                 if(part[j] == '\'') {
113                     command[commandpos++] = '\'';
114                     command[commandpos++] = '\\';
115                     command[commandpos++] = '\'';
116                     command[commandpos++] = '\'';
117                 } else
118                     command[commandpos++] = part[j];
119             }
120             command[commandpos++] = '\'';
121         } else
122             commandpos += sprintf(command + commandpos, " %s", part);
123     }
124     command[commandpos] = '\0';
125     //we should now have a valid command
126     
127     struct global_cmd_extscript_cache *cache = malloc(sizeof(*cache));
128     if (!cache) {
129         perror("malloc() failed");
130         return;
131     }
132     cache->client = client;
133     cache->textclient = getTextBot();
134     cache->event = event;
135     cache->user = user;
136     cache->chan = chan;
137     cache->answere_channel = answere_channel;
138     cache->pipe = popen(command, "r");
139     #ifndef WIN32
140     fcntl(fileno(cache->pipe), F_SETFL, O_NONBLOCK);
141     #endif
142     timeq_uadd(200, module_id, global_cmd_extscript_callback, cache);
143 }
144
145 static TIMEQ_CALLBACK(global_cmd_extscript_callback) {
146     struct global_cmd_extscript_cache *cache = data;
147     char command[512];
148     char *a;
149     if(feof(cache->pipe)) {
150         pclose(cache->pipe);
151         free(cache);
152         return;
153     }
154     while (fgets(command, 512, cache->pipe) != NULL) {
155         if((a = strchr(command, '\n'))) 
156             *a = '\0';
157         if(!stricmp(command, "/log")) {
158             logEvent(cache->event);
159             continue;
160         }
161         if(cache->answere_channel)
162             putsock(cache->client, "PRIVMSG %s :%s", cache->chan->name, command);
163         else
164             reply(cache->textclient, cache->user, "%s", command);
165     }
166     timeq_uadd(200, module_id, global_cmd_extscript_callback, cache);
167 }
168
169
170