fixed path of mysql/errmsg.h (OSX compilation fix)
[NeonServV5.git] / src / QServer.c
1 /* QServer.c - NeonServ v5.6
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 "QServer.h"
19 #include "UserNode.h"
20 #include "ChanNode.h"
21 #include "ModeNode.h"
22 #include "ChanUser.h"
23 #include "ClientSocket.h"
24 #include "WHOHandler.h"
25 #include "ConfigParser.h"
26 #include "bots.h"
27 #include "IOHandler.h"
28
29 #ifdef WIN32
30 typedef uint32_t socklen_t;
31 #endif
32
33 #define QSERVER_TIMEOUT 30
34 #define QSERVER_MAXCLIENTS 100
35
36 #define QSERVER_FLAG_AUTHED     0x01
37 #define QSERVER_FLAG_IN_USE     0x02
38
39 struct QServerClient {
40     struct IODescriptor *iofd;
41     unsigned int flags;
42     int references;
43     struct QServerClient *next;
44 };
45
46 static struct IODescriptor *server_iofd = NULL;
47 struct QServerClient *qserver_clients = NULL;
48 static int qserver_clientcount = 0;
49
50 static IOHANDLER_CALLBACK(qserver_callback);
51
52 void qserver_init() {
53     if(get_int_field("QServer.enabled")) {
54         char *host = get_string_field("QServer.host");
55         if(!host)
56             host = "0.0.0.0";
57         int port = get_int_field("QServer.port");
58         if(!port)
59             port = 7499;
60         server_iofd = iohandler_listen(host, port, qserver_callback);
61     }
62 }
63
64 void qserver_free() {
65     if(!server_iofd)
66         return;
67     struct QServerClient *client, *next;
68     for (client = qserver_clients; client; client = next) {
69         next = client->next;
70         if(client->iofd)
71             iohandler_close(client->iofd);
72         free(client);
73     }
74     qserver_clients = NULL;
75     qserver_clientcount = 0;
76     iohandler_close(server_iofd);
77     server_iofd = NULL;
78 }
79
80 static int qserver_write(struct QServerClient *client, char* msg, int len) {
81     if (!client || !client->iofd) return 0;
82     if(!len)
83         len = strlen(msg);
84         iohandler_send(client->iofd, msg, len);
85     return 1;
86 }
87
88 static void qserver_put(struct QServerClient *client, const char *text, ...) {
89     va_list arg_list;
90     char sendBuf[MAXLEN];
91     int pos;
92     if (!client || !client->iofd) return;
93     sendBuf[0] = '\0';
94     va_start(arg_list, text);
95     pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
96     va_end(arg_list);
97     if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
98     sendBuf[pos] = '\n';
99     sendBuf[pos+1] = '\0';
100     qserver_write(client, sendBuf, pos+1);
101 }
102
103 static void qserver_update_lastmsg(struct QServerClient *client) {
104     struct timeval timeout;
105     gettimeofday(&timeout, NULL);
106     timeout.tv_sec += QSERVER_TIMEOUT;
107     iohandler_set_timeout(client->iofd, &timeout);
108 }
109
110 static void qserver_parse_A(struct QServerClient *client, char **argv, int argc) {
111     if(client->flags & QSERVER_FLAG_AUTHED) {
112         qserver_put(client, "E :Already Authed");
113         return;
114     }
115     if(!argv) {
116         qserver_put(client, "E :Missing Parameter");
117         return;
118     }
119     if(strcmp(argv[0], get_string_field("QServer.pass"))) {
120         qserver_put(client, "E :Wrong Password");
121         return;
122     }
123     client->flags |= QSERVER_FLAG_AUTHED;
124     qserver_update_lastmsg(client);
125     qserver_put(client, "A :Logged in");
126 }
127
128 #define QSERVER_COMMAND_HEADER {\
129     if(!(client->flags & QSERVER_FLAG_AUTHED)) {\
130         qserver_put(client, "E :Not Authed");\
131         return;\
132     }\
133     qserver_update_lastmsg(client);\
134 }
135
136 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc);
137 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc);
138 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc);
139 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc);
140 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc);
141
142 static void qserver_parse(struct QServerClient *client, char *line) {
143     int argc = 0;
144     char *argv[MAXNUMPARAMS];
145     while(*line) {
146         //skip leading spaces
147         while (*line == ' ')
148             *line++ = 0;
149         if (*line == ':') {
150            //the rest is a single parameter
151            argv[argc++] = line + 1;
152            break;
153         }
154         argv[argc++] = line;
155         if (argc >= MAXNUMPARAMS)
156             break;
157         while (*line != ' ' && *line)
158             line++;
159     }
160     if(!stricmp(argv[0], "A")) //AUTH
161         qserver_parse_A(client, argv+1, argc-1);
162     else if(!stricmp(argv[0], "U")) //get User
163         qserver_parse_U(client, argv+1, argc-1);
164     else if(!stricmp(argv[0], "C")) //get Channel
165         qserver_parse_C(client, argv+1, argc-1);
166     else if(!stricmp(argv[0], "AC")) //get All Channels
167         qserver_parse_AC(client, argv+1, argc-1);
168     else if(!stricmp(argv[0], "ACU")) //get All ChannelUsers
169         qserver_parse_ACU(client, argv+1, argc-1);
170     else if(!stricmp(argv[0], "R")) //RAW
171         qserver_parse_R(client, argv+1, argc-1);
172     else
173         qserver_put(client, "E :Unknown Command");
174 }
175
176 static void qserver_accept(int sockfd) {
177     struct IODescriptor *client_iofd = iohandler_add(sockfd, IOTYPE_CLIENT, NULL, qserver_callback);
178     client_iofd->state = IO_CONNECTED;
179     iohandler_update(client_iofd);
180     if(qserver_clientcount >= QSERVER_MAXCLIENTS) {
181         iohandler_printf(client_iofd, "E :Maximum QServer Connections reached");
182         iohandler_close(client_iofd);
183         return;
184     }
185     struct QServerClient *client = malloc(sizeof(*client));
186     client->iofd = client_iofd;
187     client->references = 0;
188     client->next = qserver_clients;
189     qserver_clients = client;
190     qserver_clientcount++;
191 }
192
193 static void qserver_cleanup() {
194     struct QServerClient *client, *next, *prev = NULL;
195     for (client = qserver_clients; client; client = next) {
196         next = client->next;
197         if(client->iofd == NULL && !(client->flags & QSERVER_FLAG_IN_USE)) {
198             if(prev) 
199                 prev->next = client->next;
200             else
201                 qserver_clients = client->next;
202             qserver_clientcount--;
203             free(client);
204         }
205     }
206 }
207
208 static IOHANDLER_CALLBACK(qserver_callback) {
209     struct QServerClient *client = event->iofd->data;
210     switch(event->type) {
211     case IOEVENT_TIMEOUT:
212         qserver_put(client, "E :Timeout");
213         client->iofd = NULL;
214         break;
215     case IOEVENT_RECV:
216         qserver_parse(client, event->data.recv_str);
217         break;
218     case IOEVENT_CLOSED:
219         iohandler_close(client->iofd);
220         client->iofd = NULL;
221         break;
222     case IOEVENT_ACCEPT:
223         qserver_accept(event->data.accept_fd);
224         break;
225     default:
226         break;
227     }
228     qserver_cleanup();
229 }
230
231 /* 
232 * Command functions
233 */
234
235 static USERAUTH_CALLBACK(qserver_parse_U_async);
236 static void qserver_parse_U(struct QServerClient *client, char **argv, int argc) {
237     QSERVER_COMMAND_HEADER;
238     if(!argv) {
239         qserver_put(client, "E :Missing Parameter");
240         return;
241     }
242     struct UserNode *cuser = getUserByNick(argv[0]);
243     if(!cuser) {
244         cuser = createTempUser(argv[0]);
245         if(!cuser) {
246             qserver_put(client, "U 0 :Unknown User");
247             return;
248         }
249         cuser->flags |= USERFLAG_ISTMPUSER;
250     }
251     client->references++;
252     client->flags |= QSERVER_FLAG_IN_USE;
253     get_userauth(cuser, 0, qserver_parse_U_async, client);
254 }
255
256 static USERAUTH_CALLBACK(qserver_parse_U_async) {
257     struct QServerClient *qclient = data;
258     qclient->references--;
259     if(!qclient->references)
260         qclient->flags &= ~QSERVER_FLAG_IN_USE;
261     if(!user) {
262         qserver_put(qclient, "U 0 :Unknown User");
263         return;
264     }
265     qserver_put(qclient, "U 1 %s %s %s %s :%s", user->nick, user->ident, user->host, ((user->flags & USERFLAG_ISAUTHED) ? user->auth : "0"), user->realname);
266 }
267
268 static void qserver_parse_C(struct QServerClient *client, char **argv, int argc) {
269     QSERVER_COMMAND_HEADER;
270     if(!argv) {
271         qserver_put(client, "E :Missing Parameter");
272         return;
273     }
274     struct ChanNode *chan = getChanByName(argv[0]);
275     if(!chan) {
276         qserver_put(client, "C 0 :Unknown Channel");
277         return;
278     }
279     char tmpStr[MAXLEN];
280     getModeString(chan->modes, tmpStr);
281     qserver_put(client, "C 1 %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
282 }
283
284 static void qserver_parse_AC(struct QServerClient *client, char **argv, int argc) {
285     QSERVER_COMMAND_HEADER;
286     struct ChanNode *chan;
287     char tmpStr[MAXLEN];
288     for(chan = getAllChans(NULL); chan; chan = getAllChans(chan)) {
289         getModeString(chan->modes, tmpStr);
290         qserver_put(client, "AC %s %d %s :%s", chan->name, chan->usercount, tmpStr, chan->topic);
291     }
292     qserver_put(client, "ACE"); //AllChannelsEnd
293 }
294
295 static USERLIST_CALLBACK(qserver_parse_ACU_async);
296 static void qserver_parse_ACU(struct QServerClient *client, char **argv, int argc) {
297     QSERVER_COMMAND_HEADER;
298     if(!argv) {
299         qserver_put(client, "E :Missing Parameter");
300         return;
301     }
302     struct ChanNode *chan = getChanByName(argv[0]);
303     if(!chan) {
304         qserver_put(client, "ACUE 0 :Unknown Channel");
305         return;
306     }
307     if(argc > 1 && !stricmp(argv[1], "1")) {
308         client->references++;
309         client->flags |= QSERVER_FLAG_IN_USE;
310         get_userlist_if_invisible(chan, 0, qserver_parse_ACU_async, client);
311         return;
312     }
313     char tmpStr[6];
314     int tmpStrPos;
315     struct ChanUser *chanuser;
316     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
317         tmpStrPos = 0;
318         if(chanuser->flags & CHANUSERFLAG_OPPED)
319             tmpStr[tmpStrPos++] = '@';
320         if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
321             tmpStr[tmpStrPos++] = '%';
322         if(chanuser->flags & CHANUSERFLAG_VOICED)
323             tmpStr[tmpStrPos++] = '+';
324         if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
325             tmpStr[tmpStrPos++] = '<';
326         tmpStr[tmpStrPos] = '\0';
327         qserver_put(client, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
328     }
329     qserver_put(client, "ACUE 1");
330 }
331
332 static USERLIST_CALLBACK(qserver_parse_ACU_async) {
333     struct QServerClient *qclient = data;
334     qclient->references--;
335     if(!qclient->references)
336         qclient->flags &= ~QSERVER_FLAG_IN_USE;
337     char tmpStr[6];
338     int tmpStrPos;
339     struct ChanUser *chanuser;
340     for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
341         tmpStrPos = 0;
342         if(chanuser->flags & CHANUSERFLAG_OPPED)
343             tmpStr[tmpStrPos++] = '@';
344         if(chanuser->flags & CHANUSERFLAG_HALFOPPED)
345             tmpStr[tmpStrPos++] = '%';
346         if(chanuser->flags & CHANUSERFLAG_VOICED)
347             tmpStr[tmpStrPos++] = '+';
348         if(chanuser->flags & CHANUSERFLAG_INVISIBLE)
349             tmpStr[tmpStrPos++] = '<';
350         tmpStr[tmpStrPos] = '\0';
351         qserver_put(qclient, "ACU %s %s %s", chanuser->user->nick, ((chanuser->user->flags & USERFLAG_ISAUTHED) ? chanuser->user->auth : "0"), tmpStr);
352     }
353     qserver_put(qclient, "ACUE 1");
354 }
355
356 static void qserver_parse_R(struct QServerClient *client, char **argv, int argc) {
357     QSERVER_COMMAND_HEADER;
358     if(argc < 3) {
359         qserver_put(client, "E :Missing Parameter");
360         return;
361     }
362     struct ClientSocket *bot;
363     if(!strcmp(argv[0], "1")) {
364         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
365             if(!stricmp(bot->user->nick, argv[1])) break;
366         }
367     } else {
368         struct ClientSocket *low_bot;
369         int botid = resolve_botalias(argv[1]);
370         if(botid == -1)
371             botid = atoi(argv[1]);
372         for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
373             if(bot->botid == botid) {
374                 if(bot->flags & SOCKET_FLAG_PREFERRED) break;
375                 low_bot = bot;
376             }
377         }
378         if(!bot)
379             bot = low_bot;
380     }
381     if(!bot) {
382         qserver_put(client, "R 0 :Bot not found");
383         return;
384     }
385     putsock(bot, "%s", argv[2]);
386     qserver_put(client, "R 1");
387 }